2011年5月31日火曜日

イライラするなぁ

どうもStellarisを使っているとイライラする。

○データシートに書いてある内容が不十分
○データシートに書いてある内容どおりに動かない
○StellarisWareは間違いだらけ

確かに、アプリケーションノートやサンプルあること”だけ”をやっている限りはちゃんと動くし、パフォーマンスもそこそこよいと思う。もちろん、CPU以外の機能についても豊富で充実はしている。

しかし、そのCPU以外の周辺機能は、本来想定された正常な動作から外れるともうガタガタだと言わざるを得ない。エラー時の対応・回復処理とか、処理途中でキャンセルするとか、そういうことをやろうとするととたんに不可解な動作をし始める。

例えば、uDMAのキャンセル方法。
データシートによると、DMAENCLRの該当ビットに1を書き込めばDMA動作を停止するとあるが、実際にはちゃんと止まってくれない。いや、確かに“止まっている”のだけれど、uDMAコントローラ内部では転送途中の状態をまだ記憶しているようで、新しい別の転送先/転送元アドレスを指定してDMAENSETのビットをセットしても、新しいアドレスには転送してくれない。
結局、DMAを停止させるために、まずDMAの要求トリガを発生させる機能(UARTやUSBなど)でDMA要求を出させないようにした上で、そのDMAチャンネルにソフトウェアトリガを繰り返し発行してDMA転送を“本当に”完了させる、という方法を採用するしかなかった。

他にも、USBの転送のキャンセル方法についても不具合発見。
USBデバイスとして機能させ、USBデバイス→ホスト方向への転送を途中で止めたくなったとする。つまり、ホストへ転送するためにFIFOに入れておいたパケットの内容を取り消して、ホストからIN-NAKとさせたい訳だけれど、データシートどおりにUSBTXCSRLnのFLUSHに1を書いてみてもFIFOの内容は消えていない(ホストからINトークンでパケットが取れる)し、TXRDYビットがクリアされると書いてあるけれど実際には自分で0を書いて消さなければ消えない。どうやら、FLUSHビットへに書き込みは、FIFO内部のポインタをリセットするだけでFIFOの内容を消したり、USBコントローラに送信可能(TXRDY)であることをキャンセルさせたりはしていないようだ。
しかも、FLUSHでFIFOをクリアすると(正確にはクリアするためにTXRDYに0を書き込むと)割り込みが発生する。その割り込みは要らないだろう。しかも、このデバイスは割り込みを発生させた細かい要因を教えてくれないので、「FIFOクリア直前にホストがINトークンでパケットを転送した」のか、「FLUSHによるキャンセルが要因」なのか区別がつかないじゃないか!バカヤロウ!

全体的に見て、正常な場合の動作しか想定しておらず、「もしもこういうことが起きたら・・・」という異常系での振る舞いについてはほとんど考えられていないのではないだろうか?あるいは、文化的な違いから、青い目の人は「異常が起きたら全部リセットして最初からやり直し、それでいいじゃん?」的な考えなんだろうか。

とまぁ、悪態をついてみたところで、巨大企業であるTIが動いてくれるわけでもなく、せいぜいこんないところを愚痴を書き連ねるのが関の山って所か・・・、orz

2011年5月6日金曜日

Stellarisのバグ?(その2)

UART+uDMAを使った受信において気づいたこと。

例として、10バイトのデータをuDMAを使って受信することを考える。データシートやサンプルに従って設定すれば期待通りに動作した。しかし、不測のデータ受信やエラーリカバリ処理に難儀した。

通信相手が10バイトではなく13バイト送ってきたと仮定する。
uDMAをBASICモードで設定していれば、まず最初の10バイトをDMA受信した時点で割り込みが発生した。これは期待通り。uDMAをBASICモードで設定しているので、この時点でuDMAの動作はSTOPになっている。
問題は、このあと残りの3バイトを受信したときにStellarisがどのように振る舞うかだ。
このときStellarisは残り3バイトについて、通常の(DMAを使わない)ソフトウェア+割り込みを使う方法と同じように、受信割り込みを発生させてしまう。ここで誤ってその3バイトの受信データをソフトウェアで読み出してしまうと話がややこしくなる。

UART自体は、RXDMAEフラグがセットされている以上は受信データが1バイトでも検出されると、そのUART回路内部でDMAリクエストを保持してuDMAコントローラの方に送っているようで、たとえUARTの受信FIFOの内容をすべてソフトウェアで読み取った後でもそのDMAリクエストはUART内部で残り続けている。つまり、余分な3バイトをソフトウェアで読み取ってもうFIFOには受信データが残っていなくても、次回uDMAの受信設定を行うとまだ保持され続けているUARTからのDMAリクエストによって1バイト分の受信データ転送トランザクションが発生してしまう、という誤動作につながるようだ。

これを回避する方法としては、

(A)DMAを使うときはソフトウェアで直接FIFOを読み出すようなことはしないこと。

(B)上記のような3バイトを「余分なデータ」として読み捨てる場合は、ソフトウェアでFIFOを読み出しても良いが、次回DMAを設定する前にUARTからのDMAリクエストをクリアする方法を行うこと。

の2案が考えられる。
上記の例で余分に受信された3バイト分が、本来次に受信されるべき10バイトのうちの先頭3バイトであれば(=すなわち、正常な次のパケットの一部などであれば)、この(A)を採用してそのまま次のDMA受信を設定&開始すれば問題なく(DMAで)受信される。

しかし、受信された3バイトが本来必要ではないゴミデータであればそれを読み捨てる(B)案を採用せざるを得ない。その(B)案を行う具体的な方法としては、

(B-1)Software Reset Control 1レジスタのUARTnビットを使ってUARTそのものをリセットしてしまう方法

(B-2)UART ControlレジスタのUARTENフラグにいったん0を書いて、1に戻すという方法

の2つが有効であるようだ。
(B-1)の方法は、UARTの設定そのものがリセットされてしまうので、再設定を余儀なくされる。
(B-2)の方法は、UARTの設定は保持されるがUARTENに0を設定している瞬間は受信処理が止まるのでその瞬間に受信データが来ると受信し損ねてしまう、という問題が残る。
どちらにしてもUARTの動作は一瞬でも止まるので、データを受信し損ねる可能性は排除できない。

もうちょっとうまいエラーリカバリ方法を用意してくれないものかなぁ。

2011年5月2日月曜日

Visual Studio 2008の「へぇ~」な機能

Windows VISTAや7では、システム関係のファイルの書き換えに関してちょっとした保護機能が追加されている。WINDOWSフォルダやProgram Filesフォルダは、ファイルを変更しようとするといくらadmin権限でも確認ダイアログが出てくるし、アプリケーションでProgram Files以下に自分用の設定ファイルを保存するような(お行儀の悪い)アプリケーションでは、ファイルの保存先をコッソリとすげ替えさせられている。
特にUAC関連では叩かれることの多いMSだけれども、今回はその件をとやかく言うつもりはない。

今回、Visual Studioを使ってちょっとしたインストーラを作っていて気づいたことがありました。インストーラをデバッグ実行してもデバッグできなかった。理由は上のとおりで、Visual Studioから起動されるプロセスはVisual Studio自体のユーザー特権で実行されるから、Program Filesへの書き込みが禁止されているという訳だった。これまでは、ほとんどの開発をXPでやっていたから気づかなかったし、またReleaseビルドのときは親インストーラである”setup.exe"からの子プロセスとして実行されるインストーラだったので、特権レベルが"インストーラ"レベルに昇格されていて問題なく動いていた。が、開発環境を7で、Visual Studioから直接起動するとこの特権問題が露見した、という具合だったようです。

で、回避策として、Debugフォルダにあるデバッグ対象のインストーラ.exe自体を、エクスプローラ上からプロパティ変更して「管理者として実行する」に変更してみた。すると・・・、

Visual Studioはデバッグセッション開始時に、デバッグ対象.exeが「管理者として実行する」ことを要求していることを自動的に検知してダイアログを表示し、デバッグ処理を継続させるとVisual Studio自体が「管理者」権限で再起動した。

残念ながらそのままデバッグは開始しなかったけれど、この段階ではもうVisual Studioは管理者で実行されているので、再度F5でデバッグを開始すると難なくデバッグプロセスが開始され、以降ステップ実行やら変数インスペクションができた。もちろんインストーラとしてProgram Filesフォルダへのアクセスも自由にできている。

なかなか気が利いている、と思った。
しかし、起動している子プロセス(というかexeファイル)が管理者権限での実行を要求している、ということはどうやって検知しているのだろう?