(日々の記録)デジタルオシロを買った。(金)FreeRTOSマルチタスク対応UARTとガイガーカウンターキットLCDをはずしてもFreeRTOSが動くようにする。ロジアナ大活躍(6/28/2011)FreeROSのセマフォーが解決して、ちょっと一息ついた。たいしたことでもないものに、自分で自分を追い込んで解決に血道を上げる。確かに、前記事で頂いたコメントの通り、自虐趣味かもしれない(少しむきになって否定したけれど)。単調な日常生活にこれほどドラマを作ってくれる趣味は、ちょっと他に見あたらない。テニスやスキーなどにもドラマはあるが、ドラマを作るためには、多大な精進と肉体を苛めるトレーニングが要求される(これは自虐とは言わない)。電子工作の場合は、こだわるものは目の前に無尽蔵に転がっている。盛んに研究されているプログラムライターなどもそうだ。別のライターで書いたからといってフラッシュに2倍のサイズが書き込めるわけではない。書き込みが速くなるといっても、精々数十キロのフラッシュROMにどれだけ早く書けたところでたかが知れている。みなさんのこだわりようは、尋常ではない。それはともかく、当面解決すべき課題がなくなり、体の中にぽっかり空き地が出来たようだ。これまでのメモを取り出して、やろうとしていたことを整理し、優先順位をつけながら次のプロジェクトの準備をぼちぼち進め始めた。本来なら、前にも書いたようにUARTのマルチタスク対応なのだが、どうも気分が乗らない。いうときは手を動かしているのが一番だ。LCDを次のプロジェクトに備えて外す作業を始めた。元のLPCMプレーヤー(テストベンチとしてブレッドボードに常駐)の方に戻し、LCDなしでARM(LPC2388)基板のFreeRTOSを動かそうとした。ふーむ、LPCMプレーヤーはLCDをはずしていても動いていたのに、何故、ARMでは動かない?ソースを見て原因はすぐわかった。I2Cの初期化で、LCDからレスポンスが返ってくるのをループで待ち続けている。これは一番確実な方法だけれど、ここはLCDがなくても事情を理解して先に行って欲しい。いわゆるソフトウエアのRobustness(堅牢さ)というやつである。必要とされる初期化待ち時間を仕様(300ms)の倍くらいにして、このループをはずす。あれえ、これでも動かない。傍らを見ると、これまでの解析に使っていたロジックアナライザーが出たままになっているのに気づいた。16128)にはI2Cのプロトコルアナライザーがついているはずだが、まだ使ったことがない。良い機会なのでロジアナでI2Cの波形を見てみることにした。うーむ、待ち時間を倍にしても、レディにならずにスタックしている。ループを使った元の状態に戻す。10回ほどリトライした後レディになっているが、その時間は増やした待ち時間より短いではないか。待て、クロックはどうだ。おやあ、2.2μsしかない。このLCDのI2C最大クロックは400khz(2.5μs)のはずだ。これじゃあ速度違反だ。4μsまで下げる(250khz)。これでも10回近くリトライし続ける。待っているだけではレディにならないのは同じ。元のAVRのLPCMプレーヤーのI2Cをついでにロジアナで見てみる。これは全く問題なくリトライせずに一回の初期化でACKを返している。おかしい、ARMでは何故一回でOKにならない。同じ待ち時間なのに、と、さらに調べそうになって、先に進むのをかろうじてやめた。今自分が何をやっているかに気付いた。これはこれくらいにしておこう。セマフォーに続き、本筋に関係のないことに首をつっこみすぎだ。愚直に、ARMのI2Cに有限回ループ処理を加えて戦線を撤収した(20回リトライして、動かなければLCDタスクをサスペンド)。これでARM基板のFreeRTOSはLCDなしでも動くようになった。16128)が大活躍だ。I2Cのデータの解析(スタートコンディションやデータ解析)がプロトコルアナライザーで大幅に楽になるだけでなく。宣伝にもあるデータ圧縮が素晴らしい。電源をトリガーにしても、LCDがオープニングメッセージを出すところまでのデータが取れる。この間2秒以上離れているが、データ圧縮のお陰でメッセージデータが記録出来ている。サンプリングクロックを10Mhzとするとメモリが128KBなので、普通にデータをとっていれば、2チャンネル(I2C)だけとしても、60msの間しかデータが取れないところである。ロジアナは事象の起きているところを正確に把握することが、とても難しいのだが(膨大な期間があるので)、こういう風に長期間測定できるとその時点の特定が簡単になり解析が非常に楽になる。FreeRTOSのキューでUARTを動かす(7/2/2011)道草を食っているときではない。FreeRTOSの残された課題を早く解決しておこう。UART環境の整備だ。これは、これからマルチタスクでロボットなどを動かして行く時の強力なデバッグツールになる。これまでの記事にあるように、FreeRTOSのUARTを含めた割り込み環境はRTCと合わせ、やっとのことで何時間動かしてもフリーズしない安定した状況になっている。UARTそのものはまだ、リエントラントになっていない。誰でも(どのタスクでも)、任意にUARTに送信リクエストを送っても正しくメッセージが出るようにはなっていない。マルチタスクOSであるFreeRTOSのUARTとしては、これはまずい。データが化けるくらいならともかく、下手をすると簡単にフリーズしてしまう。デバッグツールには使えない。OSの持っている機能、キューでデータをやりとりすれば良いということはわかっているが、このあたりはソースリストをいじって簡単に解決できるレベルではない。抽象的なレベルに上げて検討する必要がある。実装の対象は、ChaNさんのUARTソースである。抽象レベルではわかっていても、このFIFO、入出力バッファー付きのUARTを、どうキュー仕立てのマルチタスク対応UARTにすれば良いのか具体的な手順が見つからない。うまい方法が見つからず、何枚もメモシートを書き潰していて、あるとき、突然気がついた。考えて見たら、ひとつのUARTの受信ポートに複数のタスクが集まって、データを取り合うことは現実にあり得ない。競合を心配する必要がない。これまでは、送受信を対称的に考え、両方を同じ仕様で作ろうとあれこれ考えていた。今度のUARTは送受信ともハードのFIFO、ユーザーのバッファーと、2段の非同期プロセスが存在する。送信は、検討の初期から別タスクを起こして処理することを考えていたが、どうしても受信プロセスがうまくいかなかった。受信は難しく考える必要がない。受信割り込みでデータをキューに送るだけで、ユーザー関数はそれを待てば良いのである。UARTの受信の速度は、CPUのキューの処理に較べれば圧倒的に遅い。バッファーも必要ないくらいだ。送信は、ユーザー関数をキューで受けて、別の常駐タスクを作り、ここで実際のUARTハードへの送り込みをキューイベントをトリガーとして行う。printfがリエントラントでないので、これに対しては、Mutexなどでガードしてやる必要があるが、こうしておけば複数のタスクからの送信要求は安全に処理される。コンセプトが明確になったので、コーディングにとりかかる。ユーザー向けの送受信関数は、キューステートメント1行のえらい簡単な関数になった。UARTタスクからMonitorタスクを分離し(これが今後のモニターコマンド処理を担う)、UARTタスクはハードの初期化と、送信キューの送出のみに絞る。