2011年7月28日木曜日

Stellaris ICDIドライバの更新(裏技)

Stellarisの評価ボードについてくるStellarisWare CDに入っているICD用ドライバはちょっと古いままで更新されていないようだ。


  • windows7/vistaでICDを接続したままスリープすると、復帰したときにICDにアクセスできない・USBデバイスの取り外し・追加ができない
という問題が起きる。

ICDのドライバと言っても、要はFTDIドライバの使い回しなので、ここからダウンロードして適宜infファイルを書き換えてやれば最新版ドライバに更新できるはず、と考えていたけれど・・・。

StellarisのICDではUSBのプロダクトIDが変更されているのでその部分だけinfファイルを書き換えて、catファイルを再生成すればうまくいくだろうと思っていたけれど、なぜか「このドライバは署名されていません」となってしまった。

裏技として、素のままのFTDIデバイス(VID/PIDを書き換えていないもの)があればそれを接続して最新版ドライバをインストール、すると結果としてStellaris ICD側のドライバも更新されるのではないか?という予想のものやってみると、確かにICDでも新しいドライバが使われるようになった。これで、スリープ時の変なハングアップから解放されるなぁ。

(やはり)奥が深いTCP/IP・・・

簡易httpサーバを実装中に勉強になったことを記録しておく。

今回、知ったのは"2MSL待ち"という状態のことだ。

実装中のhttpサーバをテスト中、何度かhttpコマンドのやりとりをしたあと、なぜか急にhttpサーバがウェブブラウザからのアクセスに反応しなくなる。Wiresharkでプロトコルを見てみると、ブラウザからのSYN要求に対してサーバはRSTを返して接続を拒否している。サーバそのものが死んでいる訳ではないようだ。さっきまで動いていたのに、急になぜ?

調べてみると、TCPのステートマシンがTIME_WAIT状態に入っているようだ。この状態では、2MSL時間だけ続くようで、実装によってはそれは4分くらいの時間になることもあるらしい。そもそもこのTIME_WAITステートは何のためにあるのか?

それは、通信相手が最後に送ってくるFINに対して、このサーバがACKを返す期間を設けるためのようだ。TCPはロスの無い通信路を提供するモノだけれど、そのTCP制御パケットを送る下位レイヤー(通常IP)はパケットの到達の正否を保証しないので、相手が送ってくるFINに対するACK応答が正しく相手に伝わったかどうかは分からない。もしACKが伝わっていなければ相手は再度FINを要求してくるかもしれない、そのためにこのTIME_WAITステートにとどまる必要がある、と理解した。そしてTIME_WAITステートにとどまっている時間は、そのポート番号が使えなくなる(使えなくする)というのがTCPの仕様にあるとのこと。そうだったのか、知らなかった・・・。

で、なぜ今回この状態に陥ったのか?httpサーバ側の実装の問題だった。サーバー側からTCPコネクションをアクティブcloseしてはいけない。アクティブcloseすると、上記のWAIT_TIMEステートに入ってしまう。あくまでもブラウザ側からのcloseを待つべし。パッシブcloseであれば、WAIT_TIMEステートを経由せずにソケットはCLOSEステートに戻ることができる。

と思ったけれど、これも事情によるようだ。今回の場合はリソースが限られている組み込み系TCP/IPの話。先日から苦しんでいる(?)TINETの話だ。
GByteサイズのメモリを搭載するPCなら気にする必要もないけれど、組み込み系では扱えるソケットの数を5個とか10個とか極端に制限せざるを得ないことがある。今回の件も「アクティブcloseがいけない」と書いたけれど、実際にはhttpサーバ側からアクティブクローズした場合、それ以降はブラウザは別のポート番号を使って接続してこようとするから手続き上は問題ないと思われる。問題は、やはり制限されたソケットしか取り合え使えない組み込み機器側のTCPスタックの実装によると思われる。

今回の場合、何回もhttpリクエストを実行してその都度ポート番号を使い捨てにしていると、なけなしのソケットすべてがWAIT_TIMEステートの状態になってしまう。この状態で新しい別ポート番号で接続しようとしてももう使えるソケットが残っていないのだ。少なくとも2MSL期間が過ぎるまでは・・・。
その点で限られたリソースの中で動作し、かつ、短時間に次々とコネクションの確立と切断を繰り返す環境の中では、少なくともアクティブcloseは貴重なソケットリソースを長時間占有してしまう。これを回避する方法は・・・・、これから考えます。

2011年7月26日火曜日

toppers/tinetの不具合(と思われる)現象…

症状:tcp_rcv_buf()で受信待ち状態にあるとき、通信相手が切断(FIN)してもtcp_rcv_buf()から戻ってこない。

基本的にtinetの実装では、このような受信待ちのときの相手からの切断にはキチンと対応しようとしているようだ。つまり、tcp_***_***()API呼び出しでブロッキングされているときFINが来たときは、そのブロックを解除して0を返すような配慮がなされている。しかし、うまく機能していない場合があるようだ。

問題のtcp_rcv_buf()呼び出しだけれど、デバッガで追いかけると最終的にはtcp_wait_rwbuf()関数内のtwai_flg(cep->rcv_flgid, TCP_CEP_EVT_RWBUF_READY, ...)でいったんブロックされる。受信データがあるか、FINを受信するとフラグがシグナル状態になってtwai_flg()から抜けてくるのだけれど、その後この関するから抜けるための条件(tinet/netinet/tcp_subr.cの957行目)を満たさないのでreturnしないで、再び上のtwai_flg()で待ちに入ってしまう。さて、これをどうやって修正するか。

整理すると、tcp_wait_rwbuf()関数から抜けられずにループしてしまうのが問題。
修正方針としては、tcp_subr.cの957行目にある条件式に新しい条件を追加、つまり、FINを受信したと思われるとき「も」条件を成立させる式を追加することによって関数から0をreturnするように変更する方法もあるが、条件式に意味が100%完全に把握できているわけではないので、安易な変更はデグレの可能性もある。例えば、追加した(とする)条件によって、FINを受信していないのに0をreturnするようになると、アプリ側は接続が切断されたと勘違いしてしまいかねない。

デバッグで動作を追ってみると、プロトコルスタックはその後tcp_input.cにあるclose_connection()と関数を呼び出していることが分かった。その関数内で、受信端のステートマシンをhalf-closedの状態に遷移させている。このタイミング利用して、twai_flg()で待ちになっているフラグをもう一度set_flg()することにしてはどうだろうか?

具体的には、tcp_input.cの
*********************
*** 1367,5 ****
--- 1367,6 ----
   switch (cep->fsm_state) {

   case TCP_FSM_SYN_RECVD: /* SYN を受信し、SYN 送信済み */
   case TCP_FSM_ESTABLISHED: /* コネクション開設完了 */
      cep->fsm_state = TCP_FSM_CLOSE_WAIT;
+    syscall(set_flg(cep->rcv_flgid, TCP_CEP_EVT_RWBUF_READY));
      break;
*********************

と、やってはどうかと。

とりあえずは期待通りの動作になったっぽいので、これでしばらく様子を見る。

2011年7月20日水曜日

価格.comからなくなったモノ

最近、価格.comのレビュー欄についていた「このレビューが参考になった」というところから「いいえ」のボタンが消えたなぁ。今は「はい」ボタンしか押せない。

確かに「参考にならなかった」という情報は余計なお世話かも知れないけど、レビューの中にはホントに酷いレビューもあるのでそういう人にはダメなレビューであることを教えてあげたい(>というのが、余計なお世話)。

例えば、自己満足をひけらかすだけのレビューなんかは、これからその製品を検討しようと思う人にはあまり参考にならないと思うから、できるだけ中立の立場での発言を期待したいところ(とはいってもある程度のバイアスのかかった意見・レビューになるのは仕方ないが・・・)。
本当によく分からないレビューは、各評価項目にはどれも「すごくイイ」「すばらしい」とかベタ褒めだけどどういうところがいいのか書いてないし、なのに総合評価は「4」になっているとか。そのマイナス1ポイントとなったところが何なのか、読者はソコが知りたいはずなんだけどな~。

2011年7月19日火曜日

ゲド戦記、見た・・・

先日、地上波で放送してたので、ゲド戦記を録画して連休中に見てみた。宮崎吾郎氏の初監督作品で非常に酷評が多いと知りつつ、「腐っても鯛」という言葉があるように、かの宮崎DNAを引いた人だし、そもそも映画は一人で作るものじゃないので周りのスタッフの協力の結集でもあるはずなので、それなりに「見れる」映画になっていると期待していたのだけれど・・・

確かにこりゃ酷いな。「映画」という娯楽というよりは、三流のRPGをプレイしたような感じだった。

ジブリ作品の特徴でもある丁寧に作り込まれた画風というのをさしおいても、ストーリーの構成そのものがなってなくて、感情移入とか没入感がまったくなかった。まあ「ヒマツブシ」くらいにはなったか。

その後、ネットで批評を調べてみると、かの押井守氏が「初監督作品でここまでできたならいいんじゃないか?」的な擁護意見を述べられたようだけど、それはちょっと違う気がする。あれほどの制作費と広告費をかけたプロ作品であり、視聴者からお金を得ているという意味ではその対価に見合った作品でなければ批評・批判が出るのは当然のこと。「初監督だから・・・」という言い訳まったくのお門違いに思える。これが医者なら、初手術だからといって酷い手術をされたんじゃあ、たまったもんじゃない。

2011年7月15日金曜日

また散財・・・

また余計なものを買ってしまった。AS501V2-128GM-C

これまで使っていたOEM版X25-Mの80Gでは容量が残り6GByteと心許なくなっていたので、ここ最近128Gくらいを物色していた。新しいどころではcrutialのm4とか、最新のSF-2281を使ったAS511S3-120GMとかあるのだけれど、値段がAS501V2とは2000円くらい高めだし、そもそもSATA3(6.0G)に対応したハードは持っておらず500MByte/sec超の性能があっても使い切れないので、CrutialのC300のOEM品であるAS501V2にした。

で、使っていたX25-Mの内容を新しいSSDにコピーしてちょっと使ってみたところでは、プラシーボ効果も手伝ってか速くなったなぁ(←つまり「速くなった気がするがあんまり変わってない」の意味)。
そりゃそうだろう、X25-Mだってそこそこ速いし、このレベルではベンチマークに現れるような速度差は現実の使用状態においてはほとんど見えてこないものだし。

とかいいながら、まだパーティションのアライメント調整ができていないので、これをやってみたいと思う。ベンチマークを取ってみると、Write系はネットで見られるようなC300のベンチ結果より少し低いのが気に入らない(やっぱり、ベンチマーク至上主義かな)。
この状態だと、むしろX25-Mよりも落ちているような気もするが、とりあえずは容量が増えたのでヨシとするか。

(元のX25-Mのベンチ結果)



(AS501V2のベンチ結果。ただしアライメント調整はまだ)

2011年7月14日木曜日

toppers/tinet 苦戦中・・・

未だにtoppers/tinetに苦戦中。
とりあえずサンプルはmakeできるんだけど、自分で.cfgを書き換えてmakeすると
  "SEM_xxx_xxx is duplicated"
とか
"TSK_xxx_xxx is duplicated"
とかのエラーが頻発して出る。
makeのどこでエラーが出ているかを調べると、コンフィグレータcfgを呼び出す中でエラーが発生していた。個人的な意見だけれど、どうもこのコンフィグレータの存在がちょっと鬱陶しく感じる。何をやっているかがよく分からないからだ。とにかく、cfgがエラーを出すならcfgのソースを拾ってきて追っかけるしかない。

う~ん、なかなか難しい。最終的に理解したのは以下の通り。


  • 指定された.cfg定義ファイルを、cfg1_out.cというCソースコードに変換する。
  • INCLUDEディレクティブ(Cプリプロセッサの#includeとは関係ない)を処理して、インクルードされた.cfgを連鎖的に読み込む。
  • .cfgファイルにある「キーワード」を引っかけて、uITRONで使用される可能性のあるすべてのオブジェクト名を内部に記憶するとともに、オブジェクトIDの定義をCソースコードとして吐き出す。
  • キーワードに引っかからない行は、そのままcfg1_out.cというソースコードに落とす。特に重要なのは#ifdefや#endifなどのCプリプロセッサディレクティブで、それらはそのままcfg1_out.cに出力する。
  • 「キーワード」は.csvファイルで定義されていて、その定義に従って静的APIとオブジェクト名を区別するのであって、静的APIの名前自体がコンフィグレータ内にハードコーディングされているわけではない。
  • こうして出力されたcfg1_out.cには.cfgファイルで定義されていて使用される可能性のあるすべてのオブジェクトIDが含まれている。
  • cfg1_out.cはGCCでコンパイルされ、その出力からシンボルだけを取り出す。ここで重要なのは、コンパイラのプリプロセッサ機能を借りることで#ifdef~#else~#endifブロックを処理させて、実際に必要とされるオブジェクトIDだけをふるいに掛けることにある。
  • cfg1_out.cをコンパイルして得られたシンボル情報を処理して、target_cfg.hにオブジェクトIDを#defineしたものを書き込んでいく。
だいたいこんな感じかな(勘違いがあればご指摘お願いします>誰か)

この調査の課程で分かったのは、前述の"xxx is duplicated"というエラーが発生する原因は、.cfgファイル(INCLUDEされたものを含む)をスキャンして得られたオブジェクト名のリストと、cfg1_out.cから得られたオブジェクト名のシンボルとに矛盾が生じているからのようだ。それは何故かというと・・・

.cfgファイルを書き換えてmakeを実行しても、cfg1_out.cやシンボルを更新してくれないから!

依存関係を調べて必要なファイルを自動的に更新してくれないのなら、いったい何のためのmakefileなの?と思ってしまう(ちょっと、怒)。

とりあえずの回避策は、.cfgファイルを変更したら、make clean; makeとすること。
こんなしょうもないことで少なくとも丸2日は潰れたな(再び、怒)

2011年7月13日水曜日

それって必要・・・かな?

いつも思うんだけど、
Vista/7でUAC制御の確認ダイアログが表示されるとき、
いちいち画面が一瞬暗くなるのはどうしても必要なんだろうか?
普通にダイアログが表示されるだけではダメ?

BSODかとちょっとビックリすることがよくある。

全然関係ないけれど、Windows95が初めて出たときのジョークを思い出した。

「Windows95で最大のバグは、PCを終了させようとしているのに”スタート”ボタンを押さなければならないこと。」

2011年7月11日月曜日

大相撲中継・・・

久しぶりに大相撲中継をon-timeで観戦した。八百長問題や朝青龍問題でゴタゴタするずっと以前から全然見ていなかった大相撲だけれど、実はその昔、昭和の四横綱時代、千代の富士・北勝海・旭富士・大乃国時代はいまよりもずっと面白くてよく見ていたことがある。相撲=地味というイメージがあるけれど、いまよりももっと個性派が揃っていたように思うのは私だけだろうか?思い当たるだけでも・・・、小錦・霧島・北天佑・寺尾・逆鉾・安芸乃島・大寿山・三杉里・隆三杉などなど。

本題に戻って、久しぶりに大相撲中継を見た感想を。

見ていて何となく「懐かしい」という感覚だけでなく、別の不思議な感覚がよぎった。しばらくはそれが何であるか分からなかったのだが、その感覚というのは「ゆったりした時間の流れ」だったのだろうと思う。
昔よく見ていた頃は、”立ち会いまでの時間がなんでこんなに長いのだろう” ”さっさとやればいいのに”と思ったものだけれど、十数年経ったいま、日々仕事や子育てに追われて過ごす中で忘れかけていたのは「ゆったりした時間の流れを感じる贅沢感」なのだろう。
確かに時間は有限、しかも、かなり早く過ぎていくのを感じずにはいられないのだけれど、ゆったりと時間を過ごすことも大事で、そして大相撲の立ち会いまでの一つ一つの動作や流れはそのゆったりとした時間を長い歴史の中で見事に体現したものなのではないかと思った。そして、勝負の一瞬だけ一気に集中力を高める、そういう静と動の切り替えは、あくせくなりがちな現代社会での生活においても、ゆとりのある贅沢な時間を追求するためにも有用なことなんじゃないかと改めて思った。

だからといって大相撲の一連の不祥事や理事会のあり方を擁護するつもりはないのだけれど、それなりの歴史があり続いてきたものにはそれなりの理由や意義があるように思えた一瞬でした。

2011年7月6日水曜日

TOPPERS/ASP on Stellaris その2・・・

あとから気づいたのだけど、toppersプロジェクトにあるCortex-M3依存部の内容はInterface誌2008年12月の記事と同様のもののようだ。

で、再びおかしな所を発見してしまった!(というか嵌った!)

非タスクコンテキスト用スタックの割り当てがおかしいようだ。場合によっては、他で使っている領域の上にSPが割り当てられるので、カーネル自体の実行や非タスクコンテキストの実行中にメモリをブチ壊すことがあるので要注意だ。

問題の箇所は、arch/arm_m_gcc/prc_config.h内でマクロTOPPERS_ISTKPT#defineしているところだ。


(誤)#define TOPPERS_ISTKPT(istk, istksz) ((STK_T *)((istk) + (istksz)))

(正)#define TOPPERS_ISTKPT(istk, istksz) ((STK_T *)((char_t*)(istk) + (istksz)))

ここは上のように(char_t*)へのキャストが必要だ。
引数istkに渡されるポインタ(スタック領域の先頭アドレス)はSTK_T*型を持つので、そのままスタックサイズ(=istksz:バイト単位)を足すと32bit CPUであるCortex-M3では計算が4倍違ってくる。
このTOPPERS_ISTKPTマクロはシステム起動時のSPの初期設定に使われるから、立ち上がった時点から本来アクセスしてはいけない部分をSPとして使って起動することになる。

ついでに、もひとつ。

target/cq_starm_gcc/target_config.hで定義されているスタックサイズDEFAULT_ISTKSZの#define部分、

(誤)#define DEFAULT_ISTKSZ (0x1000/8U) /* 4KByte */



は、8Uで割る必要はない。ここで指定するのはバイト単位。

 (正)#define DEFAULT_ISTKSZ (0x1000) /* 4KByte */

直前の行で「 デフォルトの非タスクコンテキスト用のスタック領域の定義。8byte単位で取得される」というコメントが入っているが、これも微妙。Cortex-M3では8バイト境界(ダブルワード境界)でSPを設定したほうがよいとなっているので、もう少し厳密にコメントするなら「8byte単位で取得される」ではなく、「8の倍数を設定する」とでもコメントすべきではないか?

ああ、いろんなトラップを仕掛けてくれなぁ・・・。もうヤダ。

TOPPERS/ASP on Stellarisやっと動いた・・・

かなり手こずりました。

結論としては、toppersプロジェクトサイトに置いてあるCortex-M3依存部のコードの問題だった(と思う)。プロジェクトに報告した方が良いのかも知れないけれど、120%の自信がないので自身のブログでゴニョゴニョ・・・と書き連ねておいて、誰かの参考になればと思う。

問題のコードは、Cortex-M3依存部として公開されているarch/arm_m_gcc/prc_support.Sというアセンブラコード。もともとこのコードはカーネルバージョン1.3.*用に作られたもので、今回ポーティングを行ったtoppers/asp バージョン1.7.0とは互換性がないのが原因なのかと思っていたが、そうではなかったようだ。
元のコードで、svc_handlerとラベルのある部分は次のようにコーディングされていた(435行目あたり)。

0435: svc_handler:


0440:    cpsid f                       /* 割込みロック状態へ */
0441:    mrs   r0, psp
0442:    add   r0, #EXC_FRAME_SIZE     /* スタックを捨てる   */
0443:    msr   psp, r0
0444:    mov   r0, #0


このコードは、SVCサービスコール命令によってThreadモードからHandlerモードへ移行したあと、スタックに入れられたレジスタ値を強制的に捨てることを意図したものだけれど、この部分が場合によってはよろしくない。
場合によっては」というその条件は、

  • Cortex-M3の”構成制御レジスタ”にあるSTKALIGNビットが1である
  • SVCサービスコール命令を呼び出すときのSPの値が8バイト境界に並んでいない

というものだった。
もし上記の2条件が成立しているときにSVC命令を実行すると、スタックに保存されるのは通常の[R0-R3,R12,LR,PC,xPSR]という8レジスタの前に1ワードのパッドデータがスタックされるので、都合9ワードがスタックに入ることになる。しかし、上に示したsupport.Sのコードは8ワード固定量のスタックを破棄するだけなのでスタックポインタがずれてしまい、結果として(多くの場合)Usage Faultで落ちる、ということになる。
この問題を回避するには、SVC呼び出しによってスタックに積まれたのが8ワードなのか、それともパッドを含む9ワードなのかを調べて(8バイト境界への調整が行われたかどうかを調べて)、正しい量をスタックから捨てなければならない。
幸いなことに(というか当然だけど)スタックに積まれたxPSRのビット[9]とみると、8バイト境界調整が行われたかどうかが分かるようになっているので、これを利用することにする。というわけで、修正後のコードは、

svc_handler:
cpsid f                       /* 割込みロック状態へ */
mrs   r0, psp
--- add   r0, #EXC_FRAME_SIZE     /* スタックを捨てる   */
+++ add   r0, #(EXC_FRAME_SIZE-4) /* スタックから[R0-R3,R12,LR,PC]を捨てる */
+++ ldmfd r0!, {r1}               /* スタックからxPSRを取り出す            */
+++ tst   r1,#0x200               /* 8byte境界に調整されたか? */
+++ it    ne
+++ addne r0,#4                   /* そうであれば更に1ワード調整する */
msr   psp, r0


とした。

上記のSTKALIGNビットはCortex-M3のコアリセット時には'1'に設定されると言うことなので、この問題に引っかかる可能性は純粋に1/2の確率になると思うんだけれど、世の中の人はこの地雷を踏んでいないのかなぁ。


(2011 7/6 AM11:30 追記)

CQ出版から出ている「ARM Cortex-M3システム開発ガイド」によると、Cortex-M3コアのリビジョンが1の場合は、問題の8ワードの”例外スタックフレーム”はワード境界にも、ダブルワード境界にも配置することができ、その切り替えにSTKALIGNビットがあると書いてある、Cortex-M3コアのリビジョンが2になると、例外スタックフレームはダブルワード境界にしか配置できないようになっているそうなので、今後toppersのこの問題の可能性は1/2よりも大きくなってくるのかも知れないな。
(というか、これまで問題視されてきた経緯がなさそうなのは、toppers+Cortex-M3という組み合わせでの採用実績が少ないのかな?)

2011年7月4日月曜日

JTAG接続不可からの修復成功

Setellaris関連で開発を行うときは、CodeSourcery G++(ARM)OLIMEXのJTAGエミュレータARM-USB-OCDOpenOCDを組み合わせて使っているわけだれど、これまで何機種も開発してきて初めておかしな現象に出くわしたので、ここに記録しておく。

おかしな現象とは、JTAGエミュレータがStellarisにまったく接続できなくなった、ということ。
OpenOCDを起動すると、次のようなメッセージが出た。
Open On-Chip Debugger 0.2.0 (2009-09-02-13:49) Release
$URL: http://svn.berlios.de/svnroot/repos/openocd/tags/openocd-0.2.0/src/openocd
.c $
For bug reports, read http://svn.berlios.de/svnroot/repos/openocd/trunk/BUGS
100 kHz
jtag_nsrst_delay: 100
jtag_ntrst_delay: 100
     TapName            | Enabled |   IdCode      Expected    IrLen IrCap  IrMask Instr
---|--------------------|---------|------------|------------|------|------|------|---------
 0 | sterralis.cpu      |    Y    | 0x00000000 | 0x4ba00477 | 0x04 | 0x01 | 0x0f | 0x0f
    TargetName         Type       Endian TapName            State
--  ------------------ ---------- ------ ------------------ ------------
 0* sterralis.cpu      cortex_m3  little sterralis.cpu      unknown
Info : device: 4
Info : deviceID: 67353818
Info : SerialNumber: 0B010030A
Info : Description: Luminary Micro ICDI Board A
Info : JTAG tap: sterralis.cpu tap/device found: 0x4ba00477 (mfg: 0x23b, part: 0
xba00, ver: 0x4)
Info : JTAG Tap/device matched
Warn : Timeout (1000ms) waiting for ACK = OK/FAULT in SWJDP transaction
Warn : Timeout (1000ms) waiting for ACK = OK/FAULT in SWJDP transaction
Warn : Timeout (1000ms) waiting for ACK = OK/FAULT in SWJDP transaction
Warn : Timeout (1000ms) waiting for ACK = OK/FAULT in SWJDP transaction
Warn : Block read error address 0xe000ed00, count 0x1
Warn : Timeout (1000ms) waiting for ACK = OK/FAULT in SWJDP transaction
Warn : Timeout (1000ms) waiting for ACK = OK/FAULT in SWJDP transaction
Warn : Timeout (1000ms) waiting for ACK = OK/FAULT in SWJDP transaction
Warn : Timeout (1000ms) waiting for ACK = OK/FAULT in SWJDP transaction
"Warn : timeout(1000ms) …"と延々と出続けて、何の操作もできなくなってしまっていた。
でもだいたい察しはついていた。というのも、最初はちゃんとJTAGでこのCPUを認識していて、この現象が出始めたのは新規に開発したコードを書き込んでからだったからだ。おそらくJTAG関連のピンがGPIOモードに変更されたか、CPUがスリープモードに落ちてJTAG自体も機能しなくなってしまったかどちらかだろう。

Stellarisの"困ったちゃん"なところは、ハードウェアリセットピンをアサートしているとJTAG機能まで停止していることだ。今回のように間違ったソフトウェアを書き込んでしまうと、リセット解除直後にその間違ったコードを実行してしまいJTAG接続ができなくなる。リセット解除からJTAG機能が落ちてしまう数~数十us以内に強制ブレークさせることができればよいのだが、それは至難の業。困った。

Stellarisのデータシートを読んでみると、"Recovering from a locked microcontroller"という章があるのを発見!更に、最新のOpenOCDには"stellaris recover"というコマンドが追加されていることも知る。これを使えば回復できるかも!と期待して、わざわざOpenOCDの最新ソースをgitリポジトリからDL&コンパイルしてみたが、やはり動かない。というのも、OpenOCDの"stellatis recover"コマンドは"init"コマンド以降でしか使えないようで、現状ではその"init"コマンドの実行中に例のWarningが表示されて止まってしまうのだ。つまり、せっかく「カギ」を見つけたのにそのカギはカギのかかった箱の中にあった、というようなもんだ。

仕方がないので、最終手段としてデータシートで見つけた"Recovering from a locked microcontroller"に書いてある手順を自分でコーディングしてみることにした。幸いにもJTAGデバッガはFT2232MPSSEを使用するようになっているので、簡単なライブラリ呼び出しで実行できるはず。で、サクッと作ってみたら・・・直った!再度、JTAGデバッガ+gdbから書き込みができるようになった。

しかし、ここまでで何時間をムダにしただろう。JTAGデバッグ機能って、デバッグ時の重要な砦なのにそれが使えなくなるようなマイコンの仕様っていったい・・・ブツブツ