(日々の記録)デジタルオシロを買った。(土)FreeRTOSでユーザー割り込み環境が動いたここ1週間、悩んできたFreeRTOSのユーザー割り込み環境がやっとのことで通った。2年前のソースの作者にまでお助けメールを出して大騒ぎしていた一件は、何とか解決した。振り返ってみれば、何でこんなに遠回りしたのだろうと呆れるばかりだが、トラブルシューティングというのは大体こんなものだ。今度の顛末(てんまつ)も、「問題解決」という命題には恰好のケーススタディになるだろう。LPC2388の割り込み環境を研究する(5/28/2011)前回の記事で、雑誌付録ARM基板(LPC2388)に入れたOS、FreeRTOSでRTC(リアルタイマークロック)が動き出したことを報告した。このRTCでは割り込みを使っていない。OSの元では、RTCは必ずしも割り込みを使う必要はない。それぞれのタスクが独立して動けるので、OSのタイマー(システムに戻るだけでループしていない)で1秒ごとにタスクを起して、時刻を表示させれば、自分で割り込みを使うより簡単に時刻表示が実現できる。割り込みにこだわるのは、実はUARTにある。現在のテストベンチのUARTは、割り込みを使ったBufferedモードが動かず、受信は10msごとにバッファーにデータが来ているかを調べるポーリング方式である。UARTの受信はPCからのキーボード入力だけなので、このままで特に何の問題もない。それよりも、このテストベンチをこれからモーター制御や、カメラ制御などに使っていくためには、むしろUART送信の方を割り込み方式にしておく必要がある。割り込みを使わない現在の送信ロジックは、送信レジスターにデータを入れたら送り終わるのをただ待っているだけである。CPUの処理に較べれば、死ぬほど遅い(CPUは数十ナノセカンド、UARTは数百マイクロセカンド)UART送信が終わるまでループして待っていたら、たとえその間のCPUをOSに返すとしても、デバッグ対象のタスク環境が乱れてデバッグにならなくなる。UARTは是非割り込みで動かしておきたい。RTCが動き出して気持ちにゆとりが生まれた。UARTを割り込み化するのは簡単ではないので、このRTCをベンチに、少し腰をすえてARMの割り込みを基本から勉強する気になった。2年前に買ったまま放ってあった「ARM組み込みソフトウエア入門」(CQ出版社)などを取り出して読み始める。ここには1章、30ページ近くを費やして割り込みの詳しい解説がある。するうちに、ねむいさんから返事が返ってきた。なになに、ソースにヘッダーファイル、irq.hをインクルードして、__irqオプションを生かせば動くのではと言うメールだった。これで動けばラッキーこのうえない。割り込みを勉強する必要もない。喜び勇んで、RTC_support.cにirq.hを入れて動かしてみた。残念ながら、コンパイルエラーはなくなったが、ハングする状態に変わりはなかった。念のためUARTにも入れてみたが、動かないことは同じ。FreeRTOSでユーザー割り込みは使えないのか(5/30/2011)FreeRTOSのソースは読みにくい。外国人のソースコードの特徴は変数がやたらと長いことで、英語が母国語の彼らにはこれで可読性が高まるのだろうが、日本人にはただ読みにくいだけで馴染めない。FreeRTOSも変数だけでなく、変数タイプにも長ったらしいprefixを追加したりしているのでなおさらのこと読みにくい。入れてみて文句を言ってみても始まらないが、FreeRTOSのtutrial(教育環境)はあまり親切とはいえない(ちょっとまともなリファレンスブックは有料になってしまう)。実践的なところの解説が不足している。移植性を謳うのなら、機種ごとに、systickタイマーを何にしているのか、どんなリソースをOSが使うのか(割り込みベクターなど)くらいの基本的なことが、書いてあれば助かるのだが、このあたりの情報は少ない。ソースコードを見れば、ということなのか。八つ当たりしているのは、FreeRTOSで割り込みを使って、しかも動いているサンプルコードがなかなか見つからないからだ。同じ機種でないと、このあたりは参考にならない。新しく入れたRTCはともかく、既にFrerRTOSのサンプルソースに入っているUARTの割り込みが動かないのが謎である。割り込み環境を用意するirq.cには、ユーザーが簡単に割り込みベクターを追加して割り込み処理を加えるサービス関数install_irq()が用意されている。それなのに、それを使った割り込み環境のUARTはハングして動かない。スタンドアロン(ベアメタルと最近は格好良く呼ぶ)では、みんな楽々割り込みを動かしている。それはスタートアップルーチンにアセンブラーで補完した多重割り込みに備える処理が加えられているからだ。参考書や、ウェブの解説で見るとおりのことをしている。ところがFreeRTOSのスタートアップルーチンboot.sは殆ど裸に等しい。それに、このクラスのARMのCPUは、32ビットのARMモードと、16ビットのThumbモードの命令系統が混在しており、余計事態をややこしくしている。FreeRTOSで動くARMのUART、タイマーのサンプルコードくらいWebで探せばいくらでも見つかると思ったが、意外に少ない。Thomas氏のUARTを元にしている。UARTなのに、FreeRTOSではコメントアウトされている。そのうち、彼のベアメタルのソースに気になるコメントを見つけた。これが犯人のような感じだ。uartサンプルでのコメントである。サービスルーチンのひとつarmVIC.cのヘッダーファイルarmVIC.hには、次のようなマクロの定義がある。code.「現在のARM用gccコンパイラーは、Thumbモードのコードでは正しい割り込みルーチンを作れない」とある。このあと、このソースコードにはこのマクロが使われている。Thumbモードでは、gccコンパイラーが適正なコードを作れないようだ。uart.cや、rtc_support.cはThumbモードのソースである。ウェブを見てみると確かに、gccコンパイラーの、バージョン3は、こういうバグがあったみたいだが、4では改善されたように見える。公式のARMの情報センターでは、現在のバージョンでもThumbモードでの多重割り込みは、gccコンパイラーではアセンブラーをつけないと動かないと書いてある。いうことで、藁にでもすがる思いで、コンパイラーを最新のものに換えてみることにした。2011.03-42)をインストールする。gccは、2年前の、4.3.2から、4.5.2に上がった。予想したとおり結果は同じだった。コンパイルのオプションエラーになっていたno-dwarf2-cfi-asmオプションはエラーが出なくなったが、何故かファームのフラッシュサイズが20%以上増えた。このオプションのせいでもない。デバッグ用にLEDを実装するが状況は暗い(5/31/2011)霧が深い。割り込みルーチンをARMモードにしてみることも考えたが、副作用が怖い。やってみようという気にならない。#ifdefで割り込みUARTをコメントアウトしてあるということは、どちらでも動くからで、もし駄目なら何らかのコメントがあるはずだ。Thumbモードで動いていたのではないか。ARMモードにする理由が見つからない。仕方がないので、もう少し動かしながらデバッグしてみようと、LEDを2つ追加して実装した。このあたりのデバッグは、前にも書いたように、printfでは話にならない。UARTでメッセージを出す間もなくハングアップしてしまうからだ。LEDのI/Oピンは、WebのCGIを動かしているIOページのピンを選ぶ。しておけば動作確認が簡単にできる。問題なくウェブからLEDのON/OFFが出来るようになった。本当はそれどころでないのだが、暫くウェブでLEDを点けたり消したりして遊ぶ。割り込みルーチンにLEDの出力ステートメントを入れる。予想に反してここへ来ていないことがわかった。これまで調べていたレジスターのセーブ/リストアといった問題でない。割り込みベクターの設定がおかしい。事態は振り出しに戻ってしまった。割り込み環境は調べれば調べるほど難しい。霧が深まるばかりで出口は見えない。あの参考書には、多重割り込み優先度つきなどという複雑な処理の方法が延々と解説されているだけで、頭の中の混乱は返って増すばかりである。FreeRTOSの簡単なインストールを解説したサイトを見つけた。これを見ていると割り込み環境が余りにも複雑なので、ChaNさんのFatFSプログラムをFreeRTOS化したほうが早そうな気がする妄想にとりつかれる。いやいやそんなわけはないのだけど。頭を冷やしてもっと合理的なアプローチを考え直す(6/1/2011)4日近く、調べまわってやることがなくなった。頭を冷やすことにした。今やっていることの本当の目的は何なのか、自問してみる。FreeRTOSで沢山の仕事を同時に簡単に動かせるような環境を作るのが目的で、OSの中のロジックを理解することではない(これはこれで面白いが)。それなら、現在動いているソースのなかから、割り込みを使っているところを調べて、徹底的にこれを真似れば動くはずだ。要するに、大上段に振りかざして正面から問題を解決するのではなく、コバンザメのように利用できるものは何でも利用する姿勢でないと、こういう複雑な環境はいじれない。Thumbモードで割り込みを動かそうと四苦八苦しているが、何もそれにこだわることはない。現在のFreeRTOSでは、割り込みを使っているところはすべてARMモードでコンパイルしている。ここにカギがありそうだ。今動いているルーチンをそっくり真似てみよう。FreeRTOSのソースから、苦労して、割り込みハンドラーと、割り込みの初期設定しているコードを洗い出す。systickタイマーのTimer0のところport_ISR.cと、イーサネットのuIPの下部ルーチンEMAC_ISR.cのところだ。調べた結果、これらは2つとも自前で割り込みベクターを設定していて、例のirq.cの設定サービス関数を使っていない。ウェブを探していると、意外なメッセージを発見した。ねむいさんがUSBの独自ルーチンを開発する時、「FreeRTOSのやりかたを真似て割り込みルーチンを作った」とある。あ、これ、これ、これだ。ねむいさんが追加したUSB仮想COM、vcom.cは、インストールしたときハードがないので早々とコメントアウトして中味を見ていない。いえばMakefileでもこのvcom.cはARMモードでコンパイルするようになっていた。ことで割り込みが通った(6/3/2011)そうか、これだ。山が当ったような気がする。vcom.cをあらためて詳しく調べる。・__irqオプションは使っていない。__attribute__オプションもつけない。・Thumbモードでなく、ARMモードでコンパイルする。・普通のVIC設定関数install_irq()で割り込みベクターを設定する。・FrerRTOSのコンテキストセーブ/リストアをするマクロ、portSAVE_CONTEXT()と、portRESTORE_CONTEXT()を使う。このためFreeRTOS.hをインクルードする。0などで、処理終了を知らせる。(6/13/2011追記)早速、rtc_support.cのRTC_Handler()に適用する。たいした変更ではない。ARMモードのコンパイルで副作用が出るのが心配されたが、無事何事もなくビルドは終了した。コアサイズも前と変わらない。今度は何か上手くいきそうな予感がする。FlashMagicのファーム書き込みが終わるのがもどかしい。JTAG環境を作って書き込みを早くしたいのだが、その暇はない。ファーム書き込みが終わった。おおー、動作中を示すLEDのブリンクが止まらない。割込みルーチンに入れたLEDが点灯する。