AVRライタ高速化(4)

.17 2010 AVR-USB comment(0) trackback(0)
久々の高速化プロジェクトです^^;
以前書いたコードがデバッグメッセージだらけでカオスになっていたのでかなりの部分を書き直しました。
ついでにAVR用のプログラムも大幅に書き直してコードサイズも100%前後だったのを90%程度まで削減できました。

せっかく書き直したのでこの際SPIバスのコマンド仕様も変更しました。

で、前回までの状況を再現。
  • single read --OK
  • single write --OK
  • burst read --OK
  • burst write --NG
でした。

singleってのはUSB経由でSPIに流すデータをすべて送るモード。
例えばsingle readってのはAVRのserial programmingの仕様を見ると
0x20 0x0H 0x0L XX (H: AdrH, L: AdrL, XX: 何でもよい)
の順に送ればよいのでUSB経由でこの4byteすべてを書き込みます。

一方、burstってのはSUB経由で「こっからここまで順次実行してね」という指定だけしてあとはAVR側でよろしくやってくれるというモードです。
例えばburst readでは最初に「BURST_READモードで0x0000から0x0400までのデータをもってこい」とだけUSB経由で送ればあとはAVRからそのデータが8byteずつ勝手に送られてきます。

こうすることでUSBでの通信にかかる時間を大幅に削減できるので高速化できるわけです。


さて、以前から問題になっていたburst writeです。
まず、どういうバグかを簡潔に書いておきます。

「各ページの前半が書き込まれない」
「たまに全く書き込まれないページが存在する」


burst writeのほうもアセンブリで書き直してだいぶ原因が分かってきました。
まず、PCから「BURST_WRITEでこっからここまで」と指定します。
次に指定したアドレスに対して書き込むデータを順次8byteずつ(USB LowSpeedは1packet = 8byte)送信します。
今回はATtiny2313なので1page = 32 byteで、4 packetに分割して送られることになります。

AVR側のバッファは8byte * 2にしているので、2 packet目の処理が終わる前に3 packet目が到着するとNAKを返します。
本来NAKが来るとホスト側は同じデータを再送しますが、現象を見る限り、これが行われていないと推測できます。

確かにNAKをひたすら送り続けるとホスト側も諦めるはずなのでタイムアウトしている可能性が考えられるわけです。

そこで…

Linux用のlibusbの関数を見るとusb_control_msg関数はtimeout値を指定できることが分かりました。

で、早速実験。


タイムアウト値を小さくすると今までと全く同じ現象が再現されました。
で、タイムアウト値を大きくすると見事完璧に書き込まれましたとさ。


結論:原因はSPI側の処理にかかる時間がUSB再送のタイムアウト値を超えていたことだった。


さて、原因がはっきりしたのであとはどう解決するかです。

タイムアウト値を大きくするのは確かに一つの解法なのですが、あまりいい方法とはいえません。
というのはタイムアウトするまでホストは何度もパケットを送ってくるわけで、いらないパケットを処理している時間、SPI側の処理が止まってしまうからです。
最終的にはSPI通信にかかる時間を正確に見積もって適切な間隔でAVRに8byteずつパケットを送るようにするのが最善策ということになるのでしょうか…

# AVR側のbufferを大きくするのは最善ではなさそう(デバイスが違えば必要なバッファサイズも異なるので汎用性を失う)。


あと一つ気になるのはLinuxでusbを使うとき、はじめに初期化とデバイスの検索をするのですが、これにかかる時間がやたらと長いです。
burst modeの書き込みと同じがそれ以上に時間がかかってしまいます。
Linuxで書き込むときはここがネックになってしまいます…
関連記事

  • comment
  • secret
  • 管理者にだけ表示を許可する

trackbackURL:http://yuranos.blog11.fc2.com/tb.php/80-49a0c20c