« 2009年4月 | トップページ | 2009年6月 »

2009年5月の5件の記事

2009年5月28日 (木)

SysTickを使ったSTM32のUSB仮想UARTの速度測定

転送速度を測ろうとはじめたタイマーの設定に難航する(5/22/09)
 RTC(リアルタイムクロック)のプロジェクトの前に、もう少し仮想UARTモニターをまともなものにしようと色々考えている。週2日出ている事務所の往復がこういうロジックをまとめる格好の時間だ。

 今のプログラムの送信データ量はパケット1個あたり、わずか1バイトだ。USBの送信ポーリング周期を1msとすると、ボーレートは8kbpsしかいかない。今はキーボードからテストメッセージを出しているだけだからこれでも良いが、SDカードあたりのテストでは、少々遅すぎる気がする。

 ダブルバッファーにすれば、理論上では、エンドポイントのパケットバッファーが64バイトあるので、64×8×1000、512kbpsまでスピードを速めることが出来る。これならUARTの最速460kbpsでも楽々だ。やりかたはそう難しくない。バッファーを2つ作って、セマフォーのようなフラグを立て、空いている方へデータを移動させればよい。バッファーが満杯になれば、そこが0になるのを待つだけである。ついでにインターバルタイマーを入れて経過時間を表示するようにすれば改良の成果が良く分かるし、タイマーの勉強にもなる。これは面白そうだ。当面の目標をこれに決めた。

 そこで、STM32のタイマーを詳しく調べ始めたが、これがAVRと違って設定がとんでもなく大変である。高機能タイマーでなく、汎用のタイマーでも設定するレジスターの数は、数えてみたら何と20個もある。こちらはPWMのような複雑なことをやるわけでなく単純なインタバルタイマーが欲しいだけなのだが、これでは、まともに設定するまでどれだけ時間がかかることやら見当がつかない。どこかの応用例を見て組んだほうが早そうだ。Stm32

 タイマーなら、最初のテストに使った雑誌(DWM2008/6)のGNUサンプルソースにもあり、10ms単位で時間が測れる。しかし、こちらはSysTickを使ったタイマーで、ここでの設定はレジスターを直打ちで定義しているため、現在のソースに簡単には組み込めない。SystickはCPUの根幹部分であり下手に設定を変えると全く動かなくなる恐れがある。これも容易な作業ではない。

 どちらも壁が高いので、とりあえずは今動いている仮想UARTモニターから、不要なコードを取ってスリムにし、追加開発を楽にしようとした。ところが、これも結構難しいのである。もともとこのコード(蛙がピョン)はSTマイクロのVCP(Virtual COM Port)デモプログラムをベースにしている。ADCやDMAはそう問題なく削除できたが、UARTの関数群がはずせない。仮想UARTと言っても、外にだすわけではない。モニターの内部でUSBとの仮想UARTの入出力をするだけだから、外部のUARTは全く不要なのだが、これが微妙にUSBルーチンとからんで、取りすぎるとコンパイルエラーになったり、暴走したりする。

sprintfの不具合解消。リンカースクリプトの不整合だった(5/24/09)
 少しづつコードは減ってきたのだが、そのうち、仮想UARTモニターが途中でリセットがかかるようになってしまった。最初は、データを出力した直後一回リセットされるだけで、そのあとは問題なかったのだが、コードを減らしていくうち、遂に出力も出さずハングアップしてしまう。

 どうも、以前AVRで経験したスタックがデータをつぶしていく不具合に似ている。プログラムサイズをかえるとトラブルが変化するというのは、こういうときの典型的な現象だ。sprintfの実行で暴走するようなので、sprintfを再びコメントアウトするとOKとなった。やっぱりここが原因だ。うーむ、ヒープ開始アドレスがうまく伝わっていない感じである(ハングとは関係ないがsprintfをとるとフラッシュサイズは37 KBから11KBまで劇的に下がった。そうかGNUではこのへんがタコなのだなと納得)。

 良くわからないがマップファイルを調べる。ARMのマップファイルはAVRのnmコマンドと同じくらいの情報量があり(恐らく同じコマンド)、何とか書いてあることがわかる。ヒープアドレスを示す_endも載っている。あれえ、このアドレスがmain.cのSRAM変数の最初をさしている。このままではもろにかぶるはずだ。おかしい。

 暴走の原因を確認するため、とりあえずはヒープのスタートアドレスをmain.cの変数が終わったところのアドレスに、マップファイルを参考に決め打ちし、sprintfを入れてテストしてみた。おおお、うまくいった。リセットもせず快調にsprintfが動く。

 やっぱり、データのかぶりだった。しかし、何故、_endが正しくエリアの最後を指さないのだろう。今まで敬遠していたリンカースクリプトの勉強が必要になってきた。ウェブで調べ始める。このあたりはコンピューターシステムの専門分野でも一番奥の技術に相当ししかも機種依存が大きく、メーカーの技術者でもここに詳しい人は滅多にいなかった。

 昔はほとんど情報が外に出ない部分だったが、さすがはGNUである。沢山情報がある。ありがたい時代になったものだ。おおよその文法がわかったので、ウェブから拝借してきたリンカースクリプトファイル、memory.defを調べる。

 もういちど、マップファイルにもどって中身を見てみる。おや、COMMONというセクションがあり、これらがすべて.bssのあとに割り付けられている。これはmain.cの変数だ。

 おやおや、COMMONは、リンカースクリプトの.bssの範囲に入れないと全部外に出されてしまう。なんだやり方が書いてあるではないか。オブジェクトファイルかリンカーオプションの宣言の不一致だ。COMMONを.bssの中に入れなおす。

  .bss : {
        . = ALIGN(4);
        _sbss = .;
        *(.bss)
        *(COMMON)      /* ここを追加する  5/24/09 */
        . = ALIGN(4);
        _ebss = .;
    } > RAM          

 コンパイルする。やった。きれいに最終アドレスが_endに入った(sprintfで_endを表示させて確認)。やっとリンカーの仕組みもわかってきた。いやあ、組み込み系は奥が深い。30年前にやっていた大型機のオンラインシステムのシステム生成(シスジェンと言っていた)の経験が役に立つとは。この経験があったから、リンカースクリプトもそれほど恐怖感なく眺められたが、経験のない人にとっては、恐らく記号の密林に立ちすくむばかりだろう。ここはやはりかなり特殊な世界だ。_endj

 いつになく気分が良い。今度のトラブルシューティングは、昼なお暗いジャングルか真っ暗闇の洞窟のアドベンチャーゲームで、何か動いたのであてずっぽうに撃ったライフルの弾が見事に怪獣に命中したのと同じような気分だが、それでも全く偶然ではない。仮説にもとづいて手順を考え、その結果トラブルが解消したときは、どんなささいなことでも格別良い気分である。嬉しいことにもうひとつの不具合も解消した。

 NOP_Process( )がないとハングする原因は、「ねむい」さんからコメントがあり、コンパイラーの最適化のやりすぎではとの指摘があった。これまでテストできなかったが、ついでなので指摘どおり、外部参照宣言(extern)にもvolatileをつけてコンパイルしてみた。結果はその通りでどちらのNOPも必要なく、プログラムは問題なく動いた。変数宣言の方にはvolatileをつけていたが、externにまで必要とは思わなかった。

1バイト送信で57kbpsも出ていることがわかる(5/27/09)
 タイマーの勉強はなかなか進まない。8ビットのAVRのときは楽だった。単純な8ビットタイマーのオーバーフローから始めて自然に複雑なコンペアレジスターを使ったPWM制御まで理解できたが、いきなり10個以上のレジスターを前にして、さあ設定しろと言われても簡単にできるわけがない。32ビットプロセッサーは明らかに初心者向けではない。付録基板のついた雑誌には季節的に良く初心者向け特集などと銘打ってあるが、これは明らかに誤りだ。

 本当に初心者向けに基板を付録にするなら8ビットプロセッサーでないと無理だと思う。もっともこれでは基板に魅力がなくなり売れないのだろうけれど、32ビットプロセッサーの付録基板で、向学心に燃えた初心者が、途方もない壁にはばまれてどれだけたくさん挫折しているかと思うと心が痛む。ステップを踏みさえすれば、そう難しいものではないのに。

 それにしても、良いお手本が見つからない。見つかってもレジスターを直打ちで設定しているソースコードなので、STマイクロのデモソースベースのコードで動くか自信がない。SysTickを使ったタイマーの方が簡単そうなので、STマイクロのハードマニュアルや、ライブラリのSystick.cのソースを調べるが、ソースはいつもの長ったらしい変数の山で全くイメージがつかめない。マニュアルはOSのTick割り込みを意識した書きかたでこれも良くわからない。

 それでも収穫はあった。SysTickはシステムクロックとは独立したリソースで、Tickをだすタイミングを設定するレジスターは根幹部分のクロックリソースとは独立しているということである。そうなると、このあいだのGNUサンプルのSysTickを使ったタイマーが使えそうだ。

 定義を仔細にみていくと、SysTick関係の定義部分だけ持ち出せば、他に影響がなさそうだ。始め関係があると思ったのは、システムクロックの変数が大量に使われていたためだが、よく読むと、これは単に参照しているだけで本体とは関係ないことがわかった。

 まあ、何かがこわれるわけではない。SysTickハンドラーの割り込み先は、デモソースの中に既に定義済みだ。ここにカウンターを入れて、GNUサンプルの定義部分を慎重にとりだし、適当なテキスト表示の前後にタイマーステートメントをはさむ。

 動かしてみた。最初は0としか表示されなかったが、設定を変えると、1という数字が表示された。おお、動いている。少しづつ設定を調整して、それらしい時間がでるようになった。sprintfを直しておいて良かった。プロンプトの前にmsで時間を表示するモニターが動き始めた。リターンキーを打つ間隔がこれで測れる。

 雑誌では10msのTickということで、定義を調整し(それらしい定数を10倍した)、1msにしたが、どうも少し早い。ストップウォッチで時間を測る。1秒で、1500位のTickだ。さらに調整して1msのTickにする。いよいよ転送速度の測定だ。Photo

 おやあ、想定した8kbpsよりもっと早い転送速度だ。56kbpsは出ている。何度か、計算式を確かめる。間違いない。USBの外への転送ポーリングは1msだが、中はもっと早いタイミングなようだ。少なくとも8倍近く早い。そうか、STマイクロのVCPデモプログラムがV3でも改善されていないのはこのへんまでは破綻をしないためだ。これは今度のダブルバッファーの実装は楽しみになってきた。115kbpsや、230kbpsでも動くVCPは喜ばれるはずだ。

| | コメント (0) | トラックバック (0)

2009年5月22日 (金)

JTAGは気難しい。恐れていた事態が現実になる

 Eclipseの環境が出来て一息入れたのも束の間、がた老AVR研究所は、次々に事件、出来事が発生し、その対応に追われて仕事どころ(あ、いや、一応、まだ週2日程仕事しています)ではない。

BeagleBoardが届いた(5/14/09)A5141832
 4/29に発注して、連休中毎日のようにDigiKeyのサイトをチェックしていたが、注文受理から、なかなか発送のステイタスに変わらずイライラしていた。アメリカも連休だったのだろうか。しかし、11日にステイタスが出荷済みになってからは早かった。何と2日で配達されてきた。13日は家人が不在で、今日14日に無事手元に届いた。電話で用途を聞かれたりするそうだが、全くそれらしいことはなし。ハンコを持って受け取りに行ったら、ポータブル端末のスタイラスペンを渡されてサインを求められる。さすが海外便だ。A5141833

 受け取ると、中身が入っているのかと疑うほど軽い。初の海外からの通信販売品である。記念写真をとる。充填材の中から可愛い箱が出てきて、いよいよあこがれのBeagleBoardとのご対面。電源アダプターには親切に5Vの表示ラベルが張ってある。モジュラージャックだと思っていたソケットはビデオのS端子だった。え、Sケーブルでも良いの?

 がた老AVR研究所のハイエA5141834ンドマシンである。このあいだ8 ビットプロセッサーから32ビットにいきなりあがって大変だったが、今度も大飛躍である。CPUチップはARM一族のハイエンドから2番目のARM CortexA8(ARM11の後継)コアとDSP、ビデオコントローラーを内蔵し、RAMがRevBの128MBからRevCでは256MBと増えている。クロックは600Mhzと一昔前のパソコンのスペックに近い。これが7センチ四方のボードに納まっている。

 気をつけなければならないのは、アプリケーションがどんどんパソコンに近づいていくことである。省電力、ファンレスだといくら威張ってみても所詮はローエンドのPCにも負ける。PCと同じような機能を開発してみても始まらない。本当の用途、最終目標が何なのかをよーく考えておかないと何をしているのかわからなくなる。パソコンで出来ることを何を苦労して作っているの?と笑われるのがオチである。

 接続に必要なケーブルで入手が難しいと言われる、USB-Aメス--ミニBオスのケーブルとHDMI--DVI-Dケーブル(これは入手難というより市販品が金メッキなどで異常に高い)は¥680と、¥1300でアマゾンで発注済である。とりあえず動かすのに必要な部品は、シリアルDSUB9ピンコネクターとボードのシリアルピンに接続するケーブルだけとなった。A5141838

 具体的なアプリケーションはまだ全く決まっていない。折角AVインタフェースが充実しているので動画関係に使いたいところだが、直接の用途が思いつかない。Linuxを入れてUSB経由のLANとHDDをつけ、とりあえずはディスクサーバーのようなことをやってみようかと思っている。まあ、これも少し先の話だ。DigiKeyでは私が買った数日後、案の定、在庫が0になって売り切れた。ひそかにほくそえんでいたのだが、昨日見たら在庫が25に戻っていた。何だ。次のロットは遅れるなどと言っていたのは誰だ。少々あせりすぎたかもしれない。しかし所有欲だけは十分満たされた。しばらくは棚に飾って喜んでいよう。

やっとフラッシュにJTAGのOCDコマンドでイメージが書き込めた(5/17/09)
 BeagleBoardはさておき、ARMの開発である。次の目標はRTCと決めてあるが、それまでに片付けておきたいことが沢山ある。GDBによるソースコードデバッグは余り深入りするつもりはない。USBやシリアルなどタイムディペンドな機能の開発ではプログラムを途中でブレークすると動作状況が変わってデバッグにならなくなる。恐らくSDカードのアクセスも同じだ。

 ハングアップしたときなどは威力を発揮すると思うが全体がまだわかっていないので使いこなせるかどうか。それにフラッシュ上ではブレークポイントが限られており、自在に止めるにはSRAM上にコードを移す必要がある。しかしSTM32はSRAMが20KBしかないので今のプログラム(既に38KBもある。もっとスリムに出来ると思うがこれも未着手)でも、もう移動不能である。

 で、やろうとしていることはピンを切り替えたり、リセットすることなしに、Eclipseの下でプログラムが書き込め、そのままテストに入れる環境を作ることである。Eclipseにこだわるのは、ここの豊富なソースコードの編集・検索機能だ。表示されているマクロステートメントにカーソルを当てるだけでプロジェクトの中の定義元を調べてマクロを展開してくれるし、外部変数や関数の所在も一発でわかる。沢山のモジュールで構成されるプロダクトではありがたい機能だ。まだ他にも沢山機能があるらしいが調べ切れていない。

ファーム書き込みのスクリプトを作る前に、コマンド入力で、フラッシュ書き込みのテストをする。要は、プロテクトをoffにし、フラッシュを消去し、書き込むと良いはずなのだが、これがこの前に書いたようにとても難渋した。

バンク、セクター、アドレス、オフセットの設定が難しい。まずバンクである。こういうJTAGのような組み込み系ではいくつもあるのが常識なのだろうが、こちらはAll in oneのワンチップコンピューターの世界しか知らない。コマンドにバンク番号を必ず入れるのがなかなか慣れない。

 バンクが常時0なのは良いとして、セクターの数え方が難しい。STM32では消去の単位がセクターではなく独自のサイズを持っており、4セクター単位にきっちりスタートとエンドを入れないと言う事を聞いてくれない。

 アドレスもそうだ。コマンドの指定するスタートアドレスは、0から始まる相対アドレスなのか、実際にメモリマップしたあとの絶対アドレスなのか、コマンドによって違うような気がする。

 flash write_image ファイル名 <offset> というコマンドのoffsetも良くわからない。ファイルの種類によって違うような気がする。.binファイルなら良いが、elf、hexのような絶対アドレスが内容に指定されているイメージファイルはどうなるんだろう。offsetされるとそれもずれるのだろうか。いや、わからないことだらけである。

困ったときのGoogle頼みだが、的確な情報がない。仕方なく少しづつ実際に確かめて進めるしかない。アドレスを間違えても大丈夫なように、フラッシュの後半のアドレスに狙いをさだめて、コマンドを確かめてみる。

 何度か怒られながら、0xE000のフラッシュエリアに1KB余りのbinファイルを書きこみ、消去するまでの過程を実現するのに成功した。

flash erase_sector  0 46 49                            セクター4KB単位に消去(必ず4K単位)
flash write_image  XXXX.bin 0x800E000  bin     設定アドレスからファイル書き込み
flash  erase_ check  0                   バンク0のフラッシュのerase状態の表示Ocd

以上のコマンドの投入で、0x0800E000のセクターがnot erasedになり書き込まれたことが確認できた。このあと、mdw  0x0800E000  256などで、書き込まれた内容を確認する。
さらに、同じflash erase_sectorをかけて再び内容が 0xFFFF…..になっていることを見る。やっとのことで、Eclipseのフラッシュスクリプトを作る目処がたった。

突然JTAGがR/Wエラーでおかしくなる(5/19/09)
 残るは、いよいよEclipseでのフラッシュ消去、書き込みのコマンドスクリプトの作成である。フラッシュを全て消すのでなく、0x3000以降だけを消去するコマンドを作る。OCDのフラッシュコマンドの基本はセクター単位(1KB )で消去の単位は4KBなので、flash erase_sector 0 XX  YYとして、XXを4、YYを127でよいはずである。このあとはアドレスは考慮しなくて良い(はず)。というよりGDBでロードするから、このコマンドはいらない。

 スクリプトにする前に手動でやってみる。ところが、さっきまで動いていたflash erase_sector が言うことを聞いてくれない。何回かやるうちに何とか書き込むべきアドレス0x08003000以降がerasedになったので、flash write_imageでelfファイルを書き込んでみた。ちゃんと書かれたか、flash erase_check 0 で確かめる。

 おやあ、Dfuが書き残してerasedになっていた、0x08002000から3000までのセクターもnot erasedになってしまっている。不吉な予感がよぎる。Eclipseを止めてJTAGをはずし、基板だけで動かす。全く動かない。不安が高まる。動作モードをDfuに変え、再立ち上げ。うわあDfuSeが基板を認識しない。やってしまった。Dfuを上書きしてしまったようだ。

 JTAGを接続しなおし、DOS窓でOpenOCDを立ち上げフラッシュの状況を見ようとした。これがBlock Read Errorのメッセージで見ることすら出来ない。当然、さっき動いたflash write_imageもエラーリターンする。えらい事になってしまった。予想されていた最悪の事態だ。だいたいflash probe 0というフラッシュの全体状況を表示するコマンドも、サイズはわからないけれど、だいたい128Kくらいかなあ、などという頼りない返事が返ってくる。

 こわしてしまったのだろうか。現象はハードエラーのような感じだ。なるべく冷静になって状況を確認する。JTAGはいわばコンピューターの心臓部に直接、検査針をつっこんで制御しているようなところがある。しかし、コマンドで動かしている限り、ハード的に装置をこわしてしまうようなことはないはずだ。ファームに何かを書いたためにCPUが暴走し、JTAGが正しい結果を返せないと考えるのが妥当だろう(そう思いたい)。

 そういえば、前のLPC2388で何もプログラムが入っていない状態では、JTAGでファームに書くことが出来なかった。そうだそれに違いない。気分が少し明るくなった。何か動くプログラムを書き込めば良いはずだ。しかし、Dfuは消えてしまったし、JTAGはこんな状態だ。

 このあいだ「ねむい」さんのコメントを見て、「十分注意しているから、こんな事態にはなるまい」とたかをくくっていた事態が急に現実になり苦笑いである。第三の方法、ROMブートローダーの出番である。この方法があるのは知っていたし、UART1はこの前のGNUサンプルを動かすときに配線済みだが、実際の手順は「ねむい」さんの記事が大変役に立った。「ねむい」さんありがとう。

 手順が決まっていれば後は作業だけである。BOOT0をHighにするピンヘッダーを立て、STマイクロからPC側のダウンローダーを落とし、UART1を秋月のUSB-UARTアダプターとつなぐ。うむ、STM32を認識した。何、フラッシュが全部プロテクトされているぞ。これが原因だったのか。どうせなら、Dfuを復元してやろう。「ねむい」さんのところからDfuのhexファイルを頂きファームに焼きこむ。よーし。USBをつなぐとPCが反応し、DfuSeがSTM32を認識した。A5221938_2

 これでJTAGが動けば、完全に元に戻ったことになる。あせる気持ちを抑えJTAGケーブルを基板に接続し、OpenOCDを立ち上げる。Telnetを開きコマンドを入れる。万歳!これまでのおかしなレスポンスは全くなく正常な状態に戻った。

 やれやれJTAGは気難しい。Block R/Wエラーが頻発しプロテクトの状態がコマンドを入れるたびにおかしな状況になるのは、ターゲットのCPUが暴走していたからに違いない。しかし逆に言うと、CPUを暴走させてしまうとJTAGが動かない状況に簡単になってしまうということだ。これはやっぱり相当経験を積んでからでないと使いこなせないツールのようだ。

| | コメント (0) | トラックバック (0)

2009年5月13日 (水)

EclipseでARMのソースコードデバッグが出来るようになった

STM32基板にバッテリーバックアップ機能を組み込む(5/9/09)
 STM32でのUSBの仮想COMポート(VCP)がやっとのことで動き、がた老「AVR」研究所の「ARM」プロジェクトは大きく前進した。しかし、折角入れたJTAGとEclipseが活用できていない。ファームのコンパイルはDOS窓からだし、書き込みもDfu経由である。

 なりふり構わず当面の目的に突き進んでVCPモニターが動くところまでは行ったが、他は殆ど手がついていないままである。現在の開発手順、Dfuからのファーム書き込みは、沢山の画面を経由するだけでなく、ターゲットのモードをいちいちジャンパーピンで切り替えてリセットしなおさねばならない。いくらなんでも能率が低すぎる。

 Eclipseの環境は、前のLPC2388基板では実現し、STM32ではUART1を使ったGNUのサンプルがJTAGインターフェースで動くところまで進んだ。しかしどちらもまだ、止めたり動かしたりできるだけで、ソースコードデバッグまで行っていない。統合環境と言っても断片的にしか使えていない。目指す山はまだまだ高く、深い。

 それにSTM32基板の方は、Eclipseでビルドだけはやったが、ターゲットへのファーム書き込みはDfu経由である。参考にしているウェブサイトの書き込みスクリプトには、stm32x mass_erase 0というコマンドがあり、これは明らかに全部のフラッシュを消すコマンドで、これをそのまま使うわけにはいかない。Dfuを消してしまう。

 貧乏性というわけではない。JTAGでファームが間違いなく書ける保証がないのに、Dfuを消してしまうと、失敗したとき当面の書き込み手段をすべて失ってしまうのが怖い。これらとは別に書き込み手段があるのはわかっているが、そのツールのインストール、テストだけでもまた手間がかかる。余計な作業が増えるばかりである。Stm32vbat

 これは長年システム開発をしてきた人間の一種の職業病だろう。全体の所要作業量とリスクを最小にしようとして、些細なところに神経質になる。それで結果として先に進めなくなる。困ったものだ。それにしても、調べなければならないことが多すぎる。何から手をつけて良いかわからない。間口を広げすぎて完全な手詰まり状態におちいった。

 こういうときは気持ちを落ち着けるために何も考えないですむ手作業が良い。STM32基板にボタン電池(CR2032)をつけてRTC(リアルタイムクロック)のバッテリーバックアップの機能を実装することにした。付録基板を入手した直後、言われるまま手持ちのクロック用の32.768khzの水晶をハンダ付けしたが、電源をバックアップしていなければRTCは何の意味もなく宝の持ち腐れである。これでこの部品の顔も立ててやれるというものだ。

 付録LPC2388基板のバックアップ用の電源ピンVbatは、Vccにパタンで直結されてしまっているが、このSTM32基板は感心なことに配線図を見ると0Ωの抵抗(R1)でVccにつながっている。0Ωの抵抗なんて何の役に立つのだろうと以前は思っていたが、これはアイデアである。表面実装のこのチップ抵抗を外して、ここへバッテリーからの配線をつなげば電源回路を簡単に分離することが出来るからだ。

 久しぶりにハンダごてに電気を入れる。配線図のR1は基板上ですぐ見つかった。クロック用の水晶のすぐ近くにある。隣に並んでいる0.1μのパスコンまではずしてしまわないように、慎重にチップ抵抗だけにフラックスをつけ素早く両側を暖めてハンダを溶Stm32vbat1かす。

 とれた。いけない。0Ωの抵抗チップがどこかへ吹っ飛んでしまった。これを探すのはさすがに止めた。電池フォルダーをベース基板に固定しUEW線で接続する。予想していたより早く簡単にバックアップ回路が完成した。これでSDカードの書き込みで正しいTODを記録することができるし、目覚ましやタイマーなど応用の範囲が広がると言うものだ。楽しみである。

ARMとGDBの参考書を買ってきた(5/10/09)
 ARMにしてもEclipseにしても雑誌とウェブの情報だけでは、どうしても断片的な知識になりやすく系統的な知識がなかなか身につかない。今の行き詰まりを打開するためにも、ここはひとつちゃんとした参考書で基本的なところを押さえようと、このあたりでは一番本が揃っている新宿の紀伊国屋本店に足を運んだ。

 ARMの参考書はいくつかあったが、どうも帯に短し、たすきに長しである。結局、「ARM組み込みソフトウエア入門 」CQ出版社¥4,620を選んだ。この本、入門と銘打つわりには店頭にある本の中で、一番高度な内容が書かれており、参考になりそうだ。 ついでにクロス開発用のGDBの参考書「GDBを使った実践的デバッグ手法」CQ出版社¥2,310も買う。Arm

 結果から言えば、この2冊とも、今こちらが直面している具体的な疑問には何も答えてくれなかった。どちらも今の自分には少しレベルが高すぎるようだ。背伸びはするものではない。2年前AVRを始めたとき、PINとPORTを間違えて動かない、動かないと悩んでいたことを思い出した。現在の問題(割込みを止められない、外部変数をループで待っても変化しない)は余りにも基本的な事なのでそれに関することは何も書いていない。

 ただ、ARM入門のほうで、スピード向上とフラッシュの節約のためCでは1バイト変数ではなく、4バイト変数を使えと言う説明は参考になった。Gdbもちろん変数を入れるSRAMとのトレードオフになるが、ARMのレジスターとメモリの受け渡しはすべて4バイト単位なので、1バイトにするために無駄なコードが発生するのだそうである。

 GDBの本の方は、直接は何の参考にもならなかったが、皮肉にも今まで悩んでいたコマンドがすべてOCD(On Chip Debugger)のコマンドであることがわかり、ウェブにあるWikiのOCDのコマンドマニュアルを読むことで、結果として飛躍的に知識レベルが上がった。マニュアルは英語だけで、日本語訳がないが、ここに抄訳がある。

 マニュアルを読むうち、OCD のflashコマンドに必須のバンク番号という意味がやっとわかった。STM32 などはフラッシュメモリが一組しかないので、0で良いのである。組み込み系では常識なのだろうが、私のように大型機育ちで、バンク、セグメントが乱立する86系を毛嫌いし、Z80のザイログやモトローラ(Macintoshでアセンブラを少しやった)のリニアなアドレス空間を好んでいた人間にはバンクの概念が薄い。

 昔話はさておき、少し気分が落ち着いてきたのでARMプロジェクトの懸案事項を整理し優先順位をつけて作業を始めることにした。10余りの懸案が揃った。ひとつのグループは先のARMのコードに関する懸案、次がOCD、GDBのデバッグ環境、もうひとつはEclipseの全体環境の懸案である。このEclipse、作業名がプロジェクト単位に独立しておらず、スクリプトをすべてユニークな名前にする必要がある。それでいてやることは同じだ。どうも矛盾があるような気がする。しかし何かまた勘違いしているのかもしれない。

GDBが知らないうちにフラッシュを書いていた(5/11/09)
 とりあえずはデバッグ環境の整備が一番優先順位が高い。コードの問題解決やEclipseの環境整備は、その先の話とする。 で、ひとつ前のUART1で動くプロジェクトをEclipseで開けるようにした。STM32 基板のJTAGインターフェースは、この前実装し、Telnetレベルで動くことを確認しただけでEclipseで動かすのは始めてである。ファーム書き込みは前に書いたように出来ないので、GDBだけでも動くのを確かめようと、OCDのスクリプトを書いてテストしてみた。STM32のフラッシュは前のVCPモニターのままである。

 違うフラッシュに別の情報を持ってGDBが立ち上がるのだから、すぐ止まるだろう。動くことが確認できれば良い。予想通り、GDBは沢山のエラーメッセージを出して、普通はエラーリターンするところを、怒りすぎたのか死んでしまった(GDBコマンドがkillされた)。

 まあ、これは想定どおりだ。しかし、エラーメッセージを頭から見直して行って顔が青ざめてきた。GDBはフラッシュにどうもイメージを書き込んでいる。エラーは別のところだ。 確かにOCDのGDB起動スクリプトには、load main.elfというステートメントがある。これはGDBのPC側の実行空間にelfファイルを展開しているのだろうと思っていたのだが、どうもそうではなさそうだ。

 これはいかん。Dfuを消してしまったか。UART1のプログラムはDfuを避けてロードされるはずなので大丈夫だとは思うが心配だ。折角ここまで我慢してDfuを残しておいたのにと、あわてて、基板のピンをDfuモードにしてPCでDfuローダーを立ち上げる。

 良かった。Dfuは消されていなかった。Dfuローダーにファームの存在を示すメッセージが出た。胸をなでおろす。ということは、前のUART1のイメージがフラッシュに書かれたのか。半信半疑で、STM32基板のUART端子をつなぎPCのUART端末を開く。

 はっはっは。 端末からはADコンバータの数字が出力され0,1のキーでLEDが点滅する。UART1のプログラムがちゃんと動いている。知らぬ間にGDBがフラッシュに正しくファームを書いてしまったのだ。このあいだからフラッシュへのファーム書き込みは、TenetからのOCDコマンド入力でさんざんテストしていたのだが一度も成功していない。

 その都度、セクター番号が違うだの、プロテクトされていて駄目だの、書く前にフラッシュを消しておけだのと叱られて門前払いを喰らっている。それがいとも簡単に出来てしまった。GDBがさっきの煩雑な手続きを全部済ませてしまったのだ。

Eclipseでソースコードデバッグが出来るようになった(5/12/09)
 期せずしてJTAGによるファーム書き込みに成功して、プロジェクトは更に進んだ。もう、これでDfuをいつでも消せる。JTAGで書けるので、必要ならDfuをrestoreすることができる。残った基本的な機能の実現は、GDBによるソースコードデバッグである。

 それにしても、この環境は、ウェブでこぼしていた人がいたように、複雑で、一筋縄では行かない。EclipseとOCD、それにGDBの3つの環境がそれぞれ並列的に動いている。
Eclipseとは別にTelnetを開きコマンドレベルで色々いじっていると、何が何だかわからなくなってくる。

 しかも、EclipseはもともとはJAVAの統合環境なので、GNUのC/C++の開発環境はあとから加えたプラグイン的な扱いであり、どうもしっくりこない。しかし機能の豊富さは大変なものだ。まだ殆ど理解できていないが、数え切れないくらいの沢山の機能がある。

 でも、ソースコードデバッグは、あっけなく実現した。参考にしていたウエブサイトは、このあたりから「ご自分でどうぞ」という姿勢なのでもう頼りにできず、心配していたが、ほどなく必要なGDBコマンドが見つかった。symbol-file  <ターゲットファイル> である。必要なリソースは、GDBが勝手に探してロードしてくれるらしい。Ws000000

 早速、GDBの起動スクリプトにこのコマンドを入れて試してみる。おお、動いた動いた。フラッシュ上のコードなのでブレークポイントの数が少ないが、止まったところのソースの行番号を表示しhaltしてくれる。しかし、VCPモニターをデバッグしたところ、USBのタイムアウト(?)でステップごとのデバッグは無理とわかる。どうもタイムアウトが起きてすぐHardエラーのルーチンに飛んで行ってしまう。このあたりが、私がICEを敬遠してきた理由である。外部条件を良く考えて動かさないと、まともなデバッグが出来ない。まあ、ここも奥の深い世界だ。あわてずじっくり進めていこう。

 先月からほぼ丸1ヶ月、ARM環境整備プロジェクトはこれでおおよその目標を達成した。まだまだほんの入り口に立ったにすぎないが、STM32の開発環境は一応揃ったことになる。これからは楽しいプログラム開発が待っている。まずRTCを組み込んで時計を作ってみよう。SDカードソケットが実装されているので、ここでもファイルシステムを入れてSDカードプレーヤーARM版にしても良い。裸ではコーディングが面倒なので簡易なOSを入れたほうが良いかもしれない。夢がふくらむ。

| | コメント (4) | トラックバック (0)

2009年5月 8日 (金)

STM32のUSB仮想UARTモニター遂に完成

 今年の連休は殆ど外に出かけず、いわゆるCQ-STARMと呼ばれるDWM2008年5月号の付録基板、STM32F103をGNUベースで開発するプロジェクトに没頭していた。こんなに夢中になったのも久しぶりである。やっとのことでUSBの仮想COMポートが実用レベルの域に達した。PCから簡易モニターが開けるのでUARTを通じて開発を進めることが出来る。いやあ今度も大冒険だった。

仮想UARTからの送信データが抜ける(5/4/09)
 STM32のUSB仮想UARTは、とりあえず送受信は出来るようになった。しかし、この雑誌のファーム(蛙がピョン)が使っているUSBへの送信関数は不安定極まりない。特に、連続して送ると前のメッセージを無視して最後の送信メッセージしかPCに届かない。

 受信は出来ているようなので1文字単位のエコーバックは出来るが、ARM側からの連続した送信は全く駄目である。それに受信に関しては不審なことがある。この前、書いたようにデバッグ用に用意されている2文字のコマンドがCD-ROMに入っていたオリジナルのファームに戻してみても、全く機能していないことである。どうもおかしい。

 ソースコードを調べて行ってその原因がわかった。メインループの中で受信バッファーにデータがあるかどうかをバッファーのデータサイズ変数(count_out)で聞いている。受信バッファーは、USBの受信エンドポイントから直接移しているだけでキューイングなどはやっていない。しかもこの変数、count_outは、このループの最後でクリアされている。キーボードの入力はどんなに早くても1/10秒単位である。これでは2文字のデータがUSBのエンドポイントのバッファーに揃うことは絶対にありえない。

 送信がおかしいのは、恐らく送信バッファーで、まだ送っていない前のデータを新しいデータで塗りつぶしているからであろう。USBはホスト(PC側)が完全な主導権を握っており、UARTのときは、ディバイス(ARM)側から送信は、ホストのVCPドライバーからのポーリングで送信するはずで確か、最小でも1ms間隔だったと記憶している。バッファーから正しくデータが送られてバッファーが空にならない限り、次のデータは送れないはずだが、このコードはそういう制御は何もしていない。

 受信の方の不備といい、送信のところといい、どうもこのソースコードの作者は、USBが非同期で沢山のバッファーを通して動いていることを理解しているか疑わしい。困ったことになった。お手本が頼りにならない。加速度センサーのADコンバータが既に動いているし、これをベースにアプリが広げられるという最初の期待はもろくも裏切られた。

 確かにキーボードから「*」の入力で連続した加速度センサーの数値を表示することには成功している。しかし、これは加速度センサーの表示タイミングがUSBの送信間隔よりはるかに遅く、せいぜい10msに一回程度だから、たまたまボロが出なかっただけである。これはオリジナルのSTマイクロのVCPソースからじっくり調べる必要がある。

sprintfは動いたぞ(5/5/09)
 こどもの日の今日は雨。晴れのときは何となく落ち着かないが、雨のときは心置きなくARMマイコンと過ごすことが出来る。このところARMの話題ばかりで、がた老AVR研究所と名前をつけた手前、AVRのことを期待して来られる読者には申し訳ないが、アクセスログを見ていると殆どの読者はキーワード検索で来られるようだ。余り気にすることはないのかもしれない。Sbrk

 それはともかく、何とか動かすためにこのあいだコメントアウトしたsprintfである。書式付の出力関数は、フラッシュが大きくなっているので気楽に使えるし、今後のデバッグの生産性のためにも生き返らせたい。仮想UARTの不具合究明を少しお休みし、こちらの方をやってみることにした。

 まず、この前のウェブの情報には、問題の_sbrkのミニマムコードが掲載されている。真面目にコードを読んでいく。何だ、そんなに難しいことはやっていない。ヒープアドレスのエントリーを要求に応じて上げているだけだ。その間が確保したメモリというわけだ。メモリの解放は考える必要はない。スタックと被るとエラーを出すようになっているが、これも今のところいらないだろう。

 _endという外部変数が気になったが、リンカーが設定するというコメントを信じてソースを追加しコンパイルしてみた。おおー、NO ERRORである。調子に乗って、オリジナルソースのsprintfのコメントの部分をはずしビルドする。これも問題ない。いよいよテストだ。「*」を入れる。やった。やりました。加速度センサーの数字が見事に出力された。オリジナルと全く同じ機能が、GNUベースで実現した。

 STM32で、GNUの標準ライブラリが使えないというのは、このあたりに原因があるのかも知れない。私の場合、リンクエラーが出たので顕在化したが、どこかのライブラリの中でもし何もしない_sbrkのスタブルーチンが用意されてしまっていると動かないことになる。

仮想UARTは本家のSTマイクロのサイトでも紛糾(5/6/09)
 お手本にしようとした雑誌の内蔵ファーム(蛙がピョン)の応用をあきらめて、もとのSTマイクロのVirtualComPort(以後VCP)のデモプログラムで仮想UARTの実装を始めた。内蔵ファームの仮想UARTの部分は、このVCPのソースを殆どそっくり利用していたので、理解が早い。送信バッファーの取り扱いがわかった。最初から書き込まず、足しこんでいる。そうか、これなら内蔵ファームのようにデータは失われない。

 その内蔵ファームについて前回の記事では、その後の情報収集で少し誤解があったようなので訂正しておきたい。2文字コマンドは絶対動かないと書いたのだが、これはGainerプロジェクトの仕様なのだそうだ。キーボードでなく、別のマシンからの入力を想定しているのでバグではない。キーボードから入れるときは、端末プログラムで入力コマンドをカット&ペーストすると動くと言う。

 実際に試してみて動くことを確認した。情報源のサイトでは「変な仕様だなあ」などのコメントがついていたが、同誌の次号6月号3章の記事を読み直して少し謎がとけた。この記事の中で、コマンドがすべてASCIIなのに端末側にわざわざフリーウエアのAcknowrich(アクノリッチ)を要求している理由が全くわからなかったのだが、こういうことだったのである。それなら最初から、そう書いてくれれば混乱することはなかったし、アクノリッチを使うこともなかったように思うのだが。

 それはさておき、STマイクロのVCPデモソースの解析の方である。ここではmain.cとhwconfig.cで、USBの受信バッファーのデータサイズ(count_out)分をUARTへ送り、UARTからのデータは、UARTの受信割込みの度に、USBの送信バッファーに書き足している。USBの送信バッファーはエンドポイントの割込みを処理するusb_endp.cで定期的にハードのパケットレジスターに送信バッファーサイズ(count_in)だけ書き込まれる。いずれも処理のあとにバッファーサイズの値は0にリセットされる。

 問題なさそうである。これを元に鼻歌まじりで、1文字送受信関数、USB_putc、USB_getcを作り、USB_putcを使って、文字列用のUSB_putlineまで用意して、仮想UART超簡易モニターを実装した。STM32の開発ベースになるものである。とりあえずは、入力をエコーバックし、リターンキーでこれまでのデータを送出、0、1、でLEDのOFF/ONという仕様だ。ファームを書き換え、意気揚々とテストに入る。

 と、これが言うことをきかないのである。受信は問題ないが、ホストへの送信が前と同じようにうまくいかない。一文字なら良いが(エコーバックは完全だ)、一気に送るとデータ落ちが激しい。それにおかしなことにデバッグ用のLEDをONするステートメントをメインループからはずすとハングする。???である。

 おかしいな。送信バッファーは64バイトもある。いくら実際のUARTよりはるかに早いタイミングでプログラムからバッファーを書き換えても、USBの割込みが入ってハードのエンドポイントレジスターに書き込むときは、正しいバッファーの内容と、そのサイズを示しているはずだ。現象はあきらかに書き足す処理の時に割込みが入って、サイズとバッファーの内容との不整合が起きているとしか考えられない。バッファー転送とサイズ変更の間で割り込まれないようにしておく必要がある。

 しかし、STM32で割込み禁止をかける方法がわからない。8ビットのAVRと違ってSTM32 の割込み環境は目茶目茶複雑だ。下手にかけると他がおかしくなる。それにLEDのステートメントがないとハングアップするというのも奇怪な話である。

 USBの知識も生半可なので少し勉強し直し、色々いじってみたが改善しない。うーむ、よくわからない。思い余って、このあいだ試して味をしめた生のステートメントをGoogleに投げる方法をやってみた。キーワードは、ユーザーバッファーから実際のエンドポイントにデータを移すSTマイクロ提供のライブラリ関数、UserToPMABufferCopy(...)である。Pmabuf

 すると、また当たったのである。こんどもSTマイクロのフォーラムだ。それも私と全く同じ仮想UARTのデータ抜けで困っている人たちの議論である。3ページ分ある。英語の斜め読みなので、完全に理解したとは言い難いが、UARTが低速のときはUSBがパケットを送るタイミングとぶつからないが、高速になると取りこぼすバグの対処の議論である。

 色々な改善案の出し合いがあって、最終的には、一方がsystickを使った新しいコードを提案してスレッドは終わっている。しかし、このコードはのちほど本人が否定して、問題は解決されていない。STマイクロの対応(発言)はない。去年(2008年4月)の話なのでソースはV1.0ベースだ。これを受けて次のバージョン(V2)でどうなったか、USBライブラリをダウンロードしてみたが、何も変わっていなかった。ただこれはこの関数UserToPMABufferCopyだけの問題ではない。V3のVCPのデモソースは見つけられなかった。

 さて、どうするか、である。割込みを止めようとウェブを探し回ったら、何とユーザーモードでは割込みをペンディングできないことがわかった。うーむ、やっぱり32ビットプロセッサーは難しい。LEDを動かさないと何も動かずハングするとか、count_outなどの外部変数を監視していても変化しないとか、まだわからないことだらけだ。

NOP_PROCESS()ですべてが解決した(5/8/09)
 AVRだと気楽に割込みを止めてアトミックオペレーションに備えることが出来るが、ARMあたりはRTOS(リアルタイムOS)を意識しているので、そう簡単にユーザーレベルで割込みを止められたら確かにおかしくなることはわかる。ただ、今の現象はあきらかに、USBのエンドポイントの送出割込みがバッファー転送中に起きていると思われる現象だ。

  向こうが待ってくれないなら、こちらで待つ(バッファーが0になるのを待つ)ようにしようとしたが、これも出来ない。モニターに使うUARTだから早さは求めない。バッファーサイズが0になるのを待って、1バイトづつ送っても問題ないのだが、whileループで、これを調べても変化しない。ここでループしたままになる。ユーザープログラムからこのバッファーサイズ(正確には変化)が見えないのである。

 別のお手本を探すしかないかと、あきらめ気分になっていたとき、STマイクロのソースを見ていてふと目に留まったものがある。何かのフラグを調べているプロセスでwhileのあとの処理クローズにNOP_Process()という関数が入っている。これは何だろう。コンパイラーの最適オプションでおかしくなるのをさけるためなら、インラインアセンブラのasm("nop")で良いのに何故わざわざ別の関数を呼んでいるのだろう。

 頭の中に何か灯りがともった。何かにおう。これが長年この世界にいた勘かもしれない。もしかしたらもしかするかもしれない。エンドポイントにデータを送る関数USB_Putc()でbuffer_outが0になるまで、このNOP_Process()で待ってみることにしてみた。バッファーを送った直後なら、次のデータ転送の時に割り込まれる可能性は殆どない。ついでにはずすとハングするLEDのステートメントもこの関数にしてみる。だめもとである。あまり期待もせずテストしてみた。

 何と、何と、これが見事に機能したのである。長いメッセージも全くデータ落ちなく出力される。LEDプロセスがなくても問題なく動く。なぜ動くのか理由はわからない。ただ山勘でやってみたのがあたった。一回の転送タイミングで1バイトしか送れない(1msのタイミングで8kbps)が、今はこれで十分である。調整していけばもう少し早くなるだろう。Stm32monitor

 いやあ、嬉しい。世の中がばら色に見える。寝ている女房を起こして喜びを分かち合いたい気分である。STマイクロのフォーラムであれほど紛糾していたのだから、殆どあきらめていた。それが低速とは言え、モニタープログラムが問題なく動いた。鼻が高い。リターンキーで、貯めこんだメッセージを1字も抜けずに表示するし、LEDも0、1のキーで点滅する。満足、満足である。

 今のところ高速化は必要ないが、バッファーをリングバッファーにするか、バッファーを書き換えるのときにUSBの割込みをペンディングする方法が見つかれば、もっと高速に送れる。まあ、これは先の話である。それよりも次はJTAG環境を整備したい。Dfu経由だと一回の書き換えに25クリックもかかる。

| | コメント (2) | トラックバック (0)

2009年5月 4日 (月)

STM32基板のUSB仮想COMポートがGNUで動いた

LPC2388は少し休んでSTM32の方に専念する(4/27/09)
 LPC2388基板を付録にしたインターフェース誌の次号(6月号)が出たので買ってきた。chaNさんが本名で2章にわたって執筆されている。UARTやUSBホストの解説もある。うーむ、みんなやろうとしていたことばかりだ。何か急に道が広くなって歩きやすくなると同時に、生来のへそ曲がりが出て逆に何となく意欲が失せてしまった。

 昔からこうだ。みんなが進んでいく方向についていくのが嫌いで、違う方、変わった方に行きたがる。今度の号でも一番の情報は、LAN&SDカードソケット拡張基板のイーサネット物理層のトランシーバーICの型番がわかったことである。 LAN8187とある。Ws000000

 実は、今度のLPC2388はイーサネットの論理層(MAC層を含む)をサポートしていると知り、ネットでこの物理層のICを探していた。しかし目に付くのは殆どがギガビットイーサのICばかりで、10/100MあたりのICはDigiKeyで見ると流通在庫のない旧製品が多く1個からは売ってくれない。残念ながらLAN8187もDigiKeyでヒットしたが、販売最低個数は800ヶで手が出ない。

 そう、この別売りのLAN&SDカード拡張基板の自作を企んでいる。買えば¥6800だそうだが、今度も、いくら何でも「ぼったくり」だ。SDカードソケット、モジュラージャック(パルストランス付き)、AタイプUSBソケット(これは余計)を合わせても小売価格で\1000しない。それに物理層ICが\500前後としても部品代は¥2000以下、基板を起こす費用が1枚あたりそれくらいかかったとしても、売価がその倍というのはないだろう。秋月なら半分で売る。

 この前の雑誌付録のフリースケールのイーサネットマイコンのときもそうだった。別売りの部品セットの法外な価格に反発して、秋月のモジュラーを無理につけてピンを折り、パルストランスを外付けして動かした(2008/9/9の記事)。今度も恐らく誰かが私と同じようなことをしようとしているに違いない。データシートさえあればやっていることはそう難しくない。外付け部品は発振子だけで、あとは結線するだけだ。いずれ物理(PHY)層ICを手に入れて作ってやる。

 それはともかく、新しい号の雑誌で逆に関心の方向がLPC2388より、去年の雑誌付録STM32基板(Cortex-M3 STM32F103)の方に移ってしまった。32ビットプロセッサーと言ってもこの石は、Thumb2という16ビット命令でしか動かない廉価版だが、せっかくSDカードソケットをつけたのに活用していない。 それにこちらの方が情報が少なく難しそうである。へそ曲がりに加えて、例の中毒だ。出来ないこと、難しいことを克服したときの充実感がたまらない。いつのまにか険しい先の見えない脇道にそれてしまう。

STM32をGNU環境で開発する(4/29/09)
 STM32はこのあいだUARTが動いたが、これは普通のTTL-UARTで、USBを経由していない。このSTM32はUSBがついているのが特長だ。USBインターフェースの勉強のためにもUSBを通してPCとお話がしたい。

 しかしUSBを動かすには、複雑で面倒な設定が必要で自前で作るのは大変だ。ライブラリに頼って開発しないと効率が悪い。このライブラリ(USBLib)やデモプログラムは、雑誌のCD-ROMに他のペリフェラルのライブラリ(FWLib)とともに入っているが、これらのソースはIARやKeilの商用コンパイラーをプラットホームにしていて、GNU向けのソースではない。 仕様は殆ど変わらないはずだが、肝心のMakefileとリンカースクリプトがない。

 それでも、「STM32 gnu」で検索したら結構沢山のサイトが見つかった。探した中で一番簡単そうな、ここのサイトのMakefileとリンカースクリプトを拝借してコンパイルしてみることにした。お手本のソースは雑誌のデモ(蛙が跳ぶやつ)のファームウエアだ。知らなかったが、雑誌付録のCD-ROMにちゃんとソース一式が入っていた。

 しかし、このMakefileはこの前と比較にならないほど複雑でちょっと見ただけでは何をやっているのかよく分からない。ウェブ上のマニュアルと首っ引きで、やっとのことでWINARMからCodeSourcery G++の環境に移し、ソースのコンパイルまではうまくいくようになった。

 はじめはライブラリの構築がうまくいかず途方に暮れた。一部の$で囲まれる変数、$(CFILES)などが置き換わらず、Nullデータになってライブラリが作れない。お手本にしたMakefileはCygwinのUNIXベースのもので、こちらの環境はDOS窓だ。/ではなくて¥(バックスラッシュ)などのセバレータが入るとおかしくなるのかと思ったが、それが原因ではなかった。

 変数に入れるファイル名をひとつだけにするとうまくいったので、DOS窓の環境変数などのバッファーのオーバーフローかと、少しづつ増やしていった。ところが、いくら増やしてもエラーにならない。結局、元の全部を入れても相変わらず正常にライブラリが構築される。直ってしまったのである。???であるが、余り深く詮索するのはやめる。とにかくすべてのソースのコンパイルは、いくつかの警告メッセージがでるもののOKとなった。

 しかし喜んだのも束の間、リンカーで以下のようなメッセージをだして失敗する。f:/gcc/bin/../lib/gcc/arm-none-eabi/4.3.2/../../../../arm-none-eabi/lib\
libc.a(lib_a-sbrkr.o): In function `_sbrk_r':
sbrkr.c:(.text+0x18): undefined reference to `_sbrk'
f:/gcc/bin/../lib/gcc/arm-none-eabi/4.3.2/../../../../arm-none-eabi/lib\
libc.a(lib_a-writer.o): In function `_write_r':
writer.c:(.text+0x20): undefined reference to `_write'
f:/gcc/bin/../lib/gcc/arm-none-eabi/4.3.2/../../../../arm-none-eabi/lib\
libc.a(lib_a-closer.o): In function `_close_r':
closer.c:(.text+0x18): undefined reference to `_close'

 これは標準Cライブラリの中のエラーだ。ヘッダーファイルと実際のシステムライブラリとがどうも不整合を起こしているようだ。うーむ、やっぱり駄目か。しかし、せっかくここまできてあと少しなのに残念だ。このあたりはビルドのなかでも一番難しいところでこれ以上は手が出ない。ライブラリのリンクではLinuxで散々苦労した。やっぱりウェブと同じWINARMに替えるしかないか。

 殆ど諦めたが、寝る前の最後に頼みのGoogleに、だめもとで上記のメッセージのうち環境に依存しない部分の
libc.a(lib_a-sbrkr.o): In function `_sbrk_r':
sbrkr.c:(.text+0x18): undefined reference to `_sbrk'
をぶちこんで検索してみた。すると何と該当するサイトが見つかったのである。

 STマイクロのサポートのページで全く同じメッセージを出して立ち往生している人の質問であった。幸いなことに回答が出ている。英語なので今ひとつはっきりしないが、要はsyscalls.cなどのOS用のルーチンを組み込まないでコンパイルすると、それ向けの関数がないのでエラーになる。 syscallを使っていないのならこのエントリのダミールーチン(stub)を作れば良いということである。

   言われるまま、ユーザー関数を入れている適当なファイルhw_config.cに、_sbrk _writeなどの関数を追加する(中ではなにもしない)。祈る気持ちでmakeする。おおお、NO ERRORだ。Makefileどおりelfファイルとhexファイルができた。勢い込んでDfuでファームを書き込む。動かしてみた。順調にVirtualComPortが認識され、LEDが点いた。よーし、動いたぞと、キーボードから入力する。残念。キーボードの反応はない。やれやれやっぱりまだ駄目か。まあ、ゆっくりデバッグしていこう。

遂にBeagle Board RevCを発注してしまった(4/30/09)Ws000001
 前から、目の前のプロジェクトが上手く行かないと新しいリソースに手を出す癖がある。素直に雑誌の環境でコンパイルすれば良いものを、わざわざ茨(いばら)の道を選んでGNUで苦闘している。こういうときが危ない。このあいだのイーサの物理層ICを探したときにDigiKeyに寄って、見るともなくBeagleBoardのページに行ったら、何と在庫が25に減っている。しかも価格は円高でこの前見た価格より\1000以上安い¥16,062だ。

 確かこの前は3桁の在庫があったはずだ。うむむ、こういうものは次のロットは遅れることが多い。よし買ってしまおう。7,500円以上なので2000円もする送料が無料だ。この際、色々な手に入りにくい小物を手に入れるチャンスでもある。フリースケールのイーサネットマイコンのモジュラーはすぐ思いついた。今度のイーサ物理層のICも買っておきたい。しかし、ひとつから買える適当なICがなかなか見つからない。

 買うとなると気がせいてきて、とうとうICが見つからぬまま29日の深夜、モジュラージャック2ヶと合わせて発注のクリックを押してしまった。代金は消費税を入れて¥17,700。いやあ、これで、がた老AVR研究所に遂にハイエンドの組み込みボードが来ることになった。暫くは気分が高揚して何も手がつかない。このあいだ6年乗った車を乗り換えたが、これほどの感動はなかった。

 恐らく品物が届いても、簡単にはすぐ手が出せないだろうが、可能性だけはやたらに広がった。FPGAと云い、趣味の世界でこれだけ興奮できるというのも幸せなことである。モニターをこいつのために新調する必要がある。ビデオ出力がデジタルだからだ。現在のメインモニターは、もう10年以上使っている古い17インチブラウン管モニターでディジタル端子などついていない。そのかわり今や珍しいケーブル5本のRGBコンポーネント端子がついている(接続はもうひとつのアナログ15ピンの方だが)。しかし目に優しく長く使っても疲れない。とても愛用している。このあと30万近く出して買ったナナオの液晶モニターにはDVI端子がついているが、これは娘にやってしまった。

 発注してしまってから、イーサ物理層ICのMicrel社のKSZ8721BLがDigiKeyで1個売りしているのが見つかった。0.5ミリピッチのLQFPで48ピン。変換基板で対応可能である。データシートも完全にある。価格は¥497。しかし、後の祭りである。

GNU環境でやっと仮想COMポートが動いた(5/3/09)
 STM32開発のその後の進展は、はかばかしくない。LEDの点灯までは動いたが、USBからのレスポンスは全くないままだ。PC側からはVirtualComPortとしてポートが見えるのでUSBの初期化はうまくいっていると思われるが、その後が進まない。

 ソースは「蛙がピョン」のオリジナルのままである。「*」を入れると3軸の加速度を表示するはずだが、全く表示しない。ソースの中にデバッグ用と見られるいくつかのコマンドがあるので(「?*」でバージョン表示、「Q*」でリセットなど)入れてみるが、それにも反応がない。main.cに手を入れて無条件でメッセージをUSBに出力するステートメントを加えたが、反応なし。どうもLEDを点灯したあと暴走している感じだ。

 ここでJTAGインターフェースが使えれば、もう言うことなしなのだが、デバッガーの設定はプロジェクト単位にする必要があり、今のところは全く手が出ない。たとえ入れても何をデバッグしているのかわからないだろう。頼みはやっぱりウェブによる先人たちの経験報告である。

 Makefileを貰ったサイトでは、動いているように書かれているが、同じWINARMを使って仮想UARTを動かそうとしているサイトではGNUでは動かないというレポートが多い。あるサイトで「STM32はThumb2命令で動くので、ARM命令で作った標準ライブラリは駄目」とあるのを見て、慌ててCodeSourceryのディレクトリチェーンから、それらしいライブラリパスを指定して(gcc/arm-none-eabi/libからgcc/arm-none-eabi/lib/thumb2)みるが、前と同じ。

 やっぱり、リンクエラーをなくすためにライブラリのスタブルーチンを入れたことが原因だろうか。それに関連して、断片的な記述で良くわからないが、sprintfを入れようとしてsyscalls.cを要求され開発をあきらめたというこの記事がどうも気にかかる。そういえばこのあいだのスタブルーチンの説明にも、syscallsを作るとか何かという話があったことを思い出した。

 念のため、ターゲットのコードを見てみる。何と、sprintfが加速度を表示するために使われているではないか。もしかしたらこれが原因かもしれない。もう一度、スタブルーチンを入れろと言った記事を詳しく読み直す。「sprintfは、一時メモリをmallocで取るので、これを使うときは、_sbrkだけはまともに書け」とあるではないか。これだ。_sbrkのエントリーは今度のダミールーチンに入っていて何もしていない。これに違いない。

 正しい作り方が良くわからないので、とりあえずこのsprintfの部分をコメントアウトしてmain.cを適当に作り替え(キー入力をループバック)、ビルドし直す。今度は少し動くような予感がする。hexファイルをdfuファイルに変換し(結構面倒だ)、Dfuローダーで書き込む。ピンを差し替え(早くJTAGにしよう)、USBソケットを抜き差しし(うーむ気があせる)、PCのTeraTermを起動させ、仮想COMポートを選ぶ。

 勘が見事に当たった。TeraTermからは文字化けしているが連続して文字が出てくる。思ったようには出力されていないが、始めて仮想COMポートが動いた瞬間だ。いやあ嬉しい。何度も書いているが、この快感がたまらない。いや、やっぱり相当中毒が進んでいるか。

 行末のNULLキャラクターを調整して、とりあえずキーボードからの入力を忠実にエコーバックする仮想端末が完成した。まだ、USBソケットを抜き差しすると端末がCOMポートを認めなくなったり、最初のウェルカムメッセージが想定どおり出ないなどの不具合は残っているが、これでSTM32の開発環境は大きく前進した。端末からターゲットの状況が手に取るようにわかるモニター機能は、これからの機能の開発には欠かせないからだ。

| | コメント (5) | トラックバック (0)

« 2009年4月 | トップページ | 2009年6月 »