(日々の記録)デジタルオシロを買った。雑誌付録ARM(LPC2388)基板のFreeRTOS7.0.0で、ChaNさんのバッファー付きUARTを動かすことには成功したが、セマフォーを使った受信処理はうまく動かず後味の悪い結果が残った。前記事にあるように、UART出力が数十分後にフリーズするという不具合がどうしても解決できない。・ChaNさんのFatFSをFreeRTOSで動かしてSDカードが読み書きできるようにする。・UARTをすべてOSのキューを使って入出力し、マルチタスクに対応させる。このあたりまで動けば、この基板のOSはロボットなどの多重同時制御のプラットホームとして十分な機能を持つことになり、ネットを使ったカメラ制御などのアプリケーションが簡単に開発できるようになる。FatFSを完全なマルチタスクで動くようにするのは、そう簡単ではない。コードそのものはリエントラントで書かれているが、これをいくつものタスクが同時に動いても良いようにするには、コードだけでなくディスクなどの単一リソースの排他制御を完全に行わないと、デタラメな書き込みでディスクは、あっという間に破壊される。最初はシングルタスクで動くだけで良いと思っていても、頭の中で、何かがひっかかって先に進まない。セマフォー不具合の問題が頭から離れないのである。それにしても、このしつこさは何だろう。これが仕事だったら、こんな瑣末なことにこだわっていたら仕事にならない。上司から大目玉を喰らうか、プロジェクトだったら大迷走、中小企業だったら間違いなく倒産である。これは現役時代の反動ではないかと思う。人は笑うかもしれないが、不思議なことに、こういう下らないことにこだわってあれこれ悩んでいる時の方が、逆に自分が自由な気分になっていることに気づく。仕事の時はこんな悠長なことを考えている余裕はなかった。一時(いっとき)でも全体から見て効果、実効のある方向を模索することが求められ、始終あせっていた。その焦燥感が、現役を退くと消えた。まわりを気にせず解決を求めてさ迷っていても、誰もとがめる人はいない。気配り心配りする方がストレスは溜まるのだ。単純に思考しているほうがむしろ幸せなときなのである。それに悩んだことが大きければ大きいほど、それが解決した時には大きなご褒美が待っている。セマフォーを解析して不具合を追及する(6/19/2011)そんなことで、次の課題はぶちあげたものの、実は、あまりやる気が起こらず、暇さえあればセマフォーのトラブルシューティングをやっていた。不具合の状況を整理する。セマフォーを導入する前は、リアルタイマークロック(RTC)からの1秒毎のUARTのメッセージを何時間出していても全くトラブルがないのに対し、受信割り込みを待つためにセマフォーを使うと、20分前後で全タスクがフリーズする。セマフォーが動くUART受信部を全く動かさなくても、不思議なことにフリーズする。時刻を表示しなければ、セマフォーを入れていても症状は発生しない。フリーズするタイミングは時間ではない。UARTから出力するデータの数である。セマフォーを組み込むことで、時刻表示のUART出力に不具合が生じ、時限爆弾のように、何千回かあとで問題が顕在化する(そう見えるだけなのかもしれないが)。フリーズするまでの時間は最初10分程度だったのが、いつのころからか20~30分程度に伸びた。正確な時間をとってみると、最初は13分で、増えたときが26分。時間がちょうど倍と言うのが悩ましい。セマフォーの中のソースコードを解析する。セマフォーは独自のソースではなく、キューの関数を流用している。サイズが0でキューの数が1のキューをハンドリングする。mallocでメモリ(わずかだが)を取っていることがわかった。いえば、時刻を表示するのに使うprintfは、mallocを使っている。printfはリエントラントではないので、受信のエコーバックと被ればおかしくなる可能性はあるが、別に被っているわけではなく(受信を一切しなくても起きる)、これがフリーズの原因とは考えにくい。念のため、printfをやめて自前の送信関数を作って時刻表示させてみる。フリーズすることに変わりがない。FreeRTOSのメモリ管理は、いくつか種類があって、良く見たら、ねむいさんが公式デモソースのメモリ管理の設定をスタティック管理(heap_2.c)から、gcc標準のmallocを使ったダイナミック管理(heap_3.c)に換えていた。これかと、heap_2.cに戻してテストしてみた。フラッシュサイズが20%近く増えただけで、結果は全く変わらなかった。いやあ、難しいものだ。Interruptで不正番地)がわかるだけで、このあとの解析はARMやFreeRTOSの内部環境を熟知していなければ、簡単には手をつけられない。最初から徹底的に調べるも万策がつきる(6/20/2011)だいたい、最初にセマフォーが動き始めた時から動きが不審である。1回空振りをしないとセマフォーが働かなかった。何か、セマフォーに関して不具合報告はないかと、ウェブでキーワードを換えて何度も検索するが、それらしい記述は、前のSTマイクロのときのようにヒットしてくれない。お、似たようなことをしていると良く見ると、自分のブログの記事だったりして苦笑いである。悔しいことに、このデモソースの中の別のセマフォーは何の問題なく動いている。他の例でも問題があるような話は何もない。それなのに、自分のだけがおかしいのである。不愉快なこと極まりない。なったら意地になるのがいつもの癖である。いちからセマフォーを少しづつ設定して動きを探ることにした。セマフォーハンドルのメモリ上の定義だけをして、他はすべてコメントアウトしてビルドしテストする。これは問題ない(まあ、当たり前か)。次は、セマフォーハンドルの初期化。これは以前、タスクでやって問題を起こしているが、もう一度、main()と、vUartTask()でそれぞれ初期化してみる。これもどちらも問題なし。続いて、セマフォーのTakeステートメント(待つ方)を入れる。Give(許可する方)が動いていないので、キーボード入力は出来ないが、そのまま動かしてみる。これも問題なく時刻を吐き続ける。今度は、セマフォーのGiveFromISRステートメントを割り込みルーチンに組み込み、テストする。キーボード入力しなければここは通らないので問題ないはずだ。これだけでフリーズした。ここを一回も通っていないのは、ロジックアナライザーで確かめてある。通っていないルーチンの組み込みでトラブルが起きる。これは一体どうしたことだ。セマフォーを入れたことによって、割込みルーチンの構造が変わったのか。コードを入れただけで命令を実行しなくてもトラブルが起きる。うーむ、根が深そうだ。フリーズの原因と見られる、RTCタスクのprintfの出力は、最終的にはUARTタスクの中の関数、uart0_putを使う。セマフォーを動かしているのはuart0_getという全く関係のない関数だ。それで無関係のuart0_putを使うタスクがフリーズするのか理解できない。割り込みルーチンが共通なので、このあたりが臭いことは確かだ。セマフォーを入れることで、何かコンテキストスイッチのルーチンが組み込まれたのか。Takeなら、コンテキストスイッチが起きて、状態が変わる可能性があるが、GiveFromISRは、単にキューエリアに何か書くだけだ。状態が変わるとは思えない。その発行もしていないのだ。キューを調べ始めて意外なものを発見(6/23/2011)悔しいけれどセマフォーの不具合究明はこれ以上は諦めることにする。諦めるのは2回目である。