APIモードのラジコン制御成功モーター制御をするはずだったのが、XbeeのAPIモードに寄り道し、XbeeのAPI汎用モニターをでっちあげてしまった。そのついでに、これまで気になっていたUARTの改善にはまりこんでしまう。完全な「寄り道の寄り道」である。ソフトUARTをC言語化する(4/1/2011)Xbee自体が道草だったのだが、さらに迷路である。このISP-UARTは、最初ChaNさんが作られたもので、ISPシリアルライター(AVRSP)でプログラムを書き込んだ後ケーブルをつなぎかえる必要もなく、そのままの状態でUARTに使えるというのがウリである。AVRに取り組んですぐ、ChaNさんのオリジナルUARTソース(アセンブラー)に、受信が割り込みで動くようにC言語でロジックを追加した。この改修で、UARTは入力待ちで止まらないので(入力があるとフラグを返す関数を使う)、モニター代わりに当研究所では殆どのシステムに入れてある。デバッグが済めばUARTを使わないシステムでは完成後はずせばよい(フラッシュに余裕のある時は結線をはずすだけ)。中の変数を簡単に出力でき、プログラムをLEDなどでデバッグするより格段に効率が良いので、大変重宝している。前から不満が残っていた。それは、ソースコードに、ChaNさんのアセンブラールーチンが残っていて、使うたびに、アセンブラーのファイル(.S)とUART本体のファイル(.C)の2つをインクルードしなければならないことである。それと以前、アセンブラーの部分をすべてCに換えようとして、うまくいかずあきらめて残した経緯がある。それ以来、何となくわだかまりが残っている。ISPのラインを使わず(MOSI/MISO/SCK)、通常のGPIOで、このUARTが使えるようにしたことはあるが、このASMルーチンは残したままであった。ISP-UARTは、通常のUARTと違い、ISPのプログラム書き込みの関係か、UARTのデータラインが正論理(スタートビットがHigh)になっており、このときはこれを負論理に置き換えただけである。アセンブラーで書いた部分をC言語に出来なかったのは、時間遅れを正確に把握できず、受信がどうしても安定しなかったためと記憶している。あのころに較べたらオシロもロジアナもあるし、開発環境は格段に進歩している。良い機会なので、XbeeのAPI汎用モニターをより汎用化するため、GPIOのC言語だけのUARTを作ってしまおうと決意した。意気込みは良かったが、やっぱり今度も、四苦八苦した。送信は何とか動くようになって、マイコンからのオープニングメッセージが出るようになったが、PCからのデータ受信が難しい。キーボードからの1文字だけの入力なのだが、どうしても正しい文字を受け取れない。ロジックアナライザーの出番が必要になった。GPIOでボーレートに従ってピンの入力を調べるところへ、ロジアナに信号を送るプローブピン(ピンをトグルするステートメント)を入れ、時間を測った。UARTはどんなに早くても1ビット数十から数百μsの世界だが、AVRのクロックは4Mhzでも1/4μsで少々プローブを入れても影響は殆どない。コンパイルし直してロジックアナライザーを動かす。これでGPIOの動きが一目瞭然になる。これが一番強力なデバッグ法だ。これができなくて前は挫折したのだ。画面を注意深く検討する。うーむ、想定どおりのタイミングでデータを読み込んでいるぞ。データをとっているようだな。スタートビット、ストップビットをカウントしている。チャートで見る限りは正しい文字を得ているはずだ。それなのに出力がおかしい。わかってしまえば、馬鹿馬鹿しくなるほど簡単な間違いなのだが、この段階でも原因はつかめなかった。デバッグというのはこういうものだ。一生懸命、タイミングを調べていたが、ロジアナで見る限り、データを採取するタイミングは間違っていない。最初、割り込み直後の待ち時間が長すぎて、全体が後ろにずれていたが、これを補正してコンパイルしなおしても正しいデータはとれない。すると原因はここではない。採集した1バイトデータがこのあとおかしくなっていることになる。1バイトデータはシフトレジスター的に1ビットづつ移動しながらデータを取る。ふーむ、前もこんなことがあったような....もしかして出来上がったデータを最後にさらに回してはいないかい。あ、あ、あ、やっぱりここでもやっていた。いやあ、時間がかかった。whileのように終了条件を後にしても解決しない。8ビットのデータを得ながら、8回シフトすれば、データは1ビットずれる。出力する側をシフトするのでなく、マスクする側をシフトするようにロジックを変更する。よーし、受信も問題なく動くようになった。C言語での割り込みのオーバーヘッドはやはり思った以上にASMよりかなり大きかった。ASMではビットレートの半分くらいをスタートビットから待っていたが、この部分はCでは殆ど必要がないくらいだった。クロック4Mhzで14μsもかかっている(38.4kbpsで1ビット26μs)。読み込みが始まれば割り込みを経由しないので、ほぼ想定どおりの待ち時間でまわっている。CPUクロックが4Mhzとかなり低い(たまたまこの水晶しかなかっただけだが)のでクロックを上げたときには、もう少し補正する必要があるかもしれない。それにしてもChaNさんのコーディングは何時見ても実に素晴らしい。このUARTの送信の部分のアセンブラーコードなどは惚れ惚れする。UARTのスタートビットとストップビットの追加は、普通なら別のステップを用意するところを、10回のループをまわしているだけで実現している。スタートビットは、まずCOMという命令でデータを反転させ(このUARTは正論理なのでこれが必要)、ついでにこのときできたキャリービットをスタートビットに使う。最後のストップビットは、シフトの空振りで出来るゼロビットで実現だ。送受信とも命令数は10あるかないか。皮肉なことにフラッシュサイズは、全部Cにしたら数十バイト増えてしまった。要するにこれだけ苦労して必要なファイル数をひとつ減らしたに過ぎない。これで全部自前のコードになったというつまらないプライドは満足させることができた。タクトスイッチを使ったXbeeのデジタル出力が実現した(4/5/2011)それはともかく、Xbeeのラジコン制御である。ラジコンだけなら、面倒な汎用モニターの大部分(キーボード入力文字をデコードする部分)のコードは不要である。しようか迷ったが、ラジコン制御のロジックも今のAPI汎用モニターに組み込んでしまうことにする。汎用モニターもまだ修正するところがあるだろうし、ソースをひとまとめに管理していた方が楽だ。すべての処理はイベントドリブンで動いているので、どちらもオーバーヘッドになることはない(ifのところだけ)。フラッシュにも余裕がある。モーターにひとつづつタクトスイッチを割り当て、スイッチの押下でモーター起動、離すと停止するコマンドを送ることにする。前進、後進の切り替えは、スナップスイッチで別のピンを設定する。このピンを見ながら、それぞれのモータードライバーの2本の制御線のどちらかをONにすればラジコン側は、4本の出力ピンだけで前後進、左右転回ができる理屈である。手始めに、一方のモーターの前進部分だけを実装する。モータードライバーへの供給電圧と、XbeeのVccが違うのに気がついて、最初はLEDを使う。タクトスイッチのチャタリングは、これまでのインタバルタイマーの時間を20msから5msに短縮(プリスケールを1024から256に)し、ピンチェンジ割り込みをスイッチポートに設定し、割り込みが起きてから5ms待つことで防止する。大した作業量ではない。ほどなくスイッチを押すとLEDが点灯し、離すと消えるという機能が実現した。心配していたが、応答速度は、想定していた通り、100ms内外に納まる。最初は通信が確立していないので、1秒位待つ時があるが、その後は、殆ど変わらない。UARTからメッセージが滝のように流れるが、これはXbeeからのレスポンスデータなので、タクトスイッチのレスポンスには影響がない。子供のように子機を遠くに離してLEDが点いたり消えたりするのを楽しむ。XbeeのAPIモードを使ったラジコンの操縦に成功(4/7/2011)LEDで成功したので、いよいよモータードライバーへの接続である。子機のXbeeの電源はレギュレーターで3.3Vにしているが、モーターは大きなレギュレーターがないのでリチウム電池そのままで、この間にはレベルシフターが必要になってきた。XbeeからいきなりモータードライバーTA7291Pにつなぐのも心配だったので丁度良い。手持ちの2SC1213などのトランジスタでバッファーをブレッドボードに組んだ。Xbeeを載せたブレッドボードは落ちないようにモーターの上にマジックテープで仮止めし、電池フォルダーもモータードライバーのサブ基板のすきまに放り込んだ。急回転するとどちらも落ちそうだが、早く動くところを見たいので激しい手抜きである。