HIDasp高速化
From:2008-09
From:HIDasp
このページは、瓶詰堂さんのHIDaspで実装されているHID Reportの転送速度向上について考察したものです
- 時間軸が逆になっていて、上の情報のほうが新しいです。
- 最新版アーカイブと、制作に関する説明は、HIDaspのページをご覧ください。
HIDasp速度比較†
- HIDasp速度比較のページをご覧ください。
AVRUSB FLOW_CONTROLの追加†
AMDマザーで計測.(SiSではこれより遅いです.)
8kB | -d0 | read | 1.453 sec (5.637kB/s) |
8kB | -d0 | write & verify | 3.157 sec (2.594kB/s) |
bash-3.2$ time ./hidspx.exe -ph -d0 8kB.hex Detected device is ATmega88. Erase Flash memory. Write Flash: 8192/8192 B Verify Flash: 8192/8192 B Passed. real 0m3.157s user 0m0.015s sys 0m0.015s
bash-3.2$ time ./hidspx.exe -ph -d0 -rp >rom.hex Detected device is ATmega88. Read Flash: 8192/8192 B Passed. real 0m1.453s user 0m0.047s sys 0m0.000s
HID Report送信の遅延評価†
- HID Reportのパケットを受け取った後、isp書き込み時間がどの程度許されるのかを評価してみた。
- 結果
- bench2コマンドは第一引数が試行回数、第二引数が遅延係数(単位は10μ秒)
- HIDパケットサイズは39バイト固定。送信(ホストからデバイス宛)のみ。
- Low Speed USBパケットを8バイト受け取る毎に待ちループを呼び出している。
X:UHCI(intel i815e)>hidmon -i script AVR> bench2 100 1 hid delay write start hid delay write end, 3900 bytes/801 ms, 4868 bytes/s AVR> bench2 100 2 hid delay write start hid delay write end, 3900 bytes/791 ms, 4930 bytes/s AVR> bench2 100 3 hid delay write start hid delay write end, 3900 bytes/801 ms, 4868 bytes/s AVR> bench2 100 4 hid delay write start hid delay write end, 3900 bytes/811 ms, 4808 bytes/s AVR> bench2 100 5 hid delay write start hid delay write end, 3900 bytes/801 ms, 4868 bytes/s AVR> bench2 100 6 hid delay write start hid delay write end, 3900 bytes/801 ms, 4868 bytes/s AVR> bench2 100 7 hid delay write start hid delay write end, 3900 bytes/801 ms, 4868 bytes/s AVR> bench2 100 8 hid delay write start hid delay write end, 3900 bytes/801 ms, 4868 bytes/s AVR> bench2 100 9 hid delay write start hid delay write end, 3900 bytes/791 ms, 4930 bytes/s AVR> bench2 100 10 hid delay write start hid delay write end, 3900 bytes/802 ms, 4862 bytes/s AVR> bench2 100 20 hid delay write start hid delay write end, 3900 bytes/801 ms, 4868 bytes/s AVR> bench2 100 30 hid delay write start hid delay write end, 3900 bytes/801 ms, 4868 bytes/s AVR> bench2 100 40 hid delay write start hid delay write end, 3900 bytes/801 ms, 4868 bytes/s AVR> bench2 100 50 hid delay write start hid delay write end, 3900 bytes/801 ms, 4868 bytes/s AVR> bench2 100 60 hid delay write start hid delay write end, 3900 bytes/801 ms, 4868 bytes/s AVR> bench2 100 70 hid delay write start hid delay write end, 3900 bytes/802 ms, 4862 bytes/s AVR> bench2 100 80 hid delay write start hid delay write end, 3900 bytes/801 ms, 4868 bytes/s AVR> bench2 100 90 hid delay write start hid delay write end, 3900 bytes/1302 ms, 2995 bytes/s AVR> bench2 100 110 hid delay write start hid delay write end, 3900 bytes/1302 ms, 2995 bytes/s AVR> bench2 100 120 hid delay write start hid delay write end, 3900 bytes/1301 ms, 2997 bytes/s AVR> bench2 100 130 hid delay write start hid delay write end, 3900 bytes/1301 ms, 2997 bytes/s AVR> bench2 100 140 hid delay write start hid delay write end, 3900 bytes/1302 ms, 2995 bytes/s AVR> bench2 100 150 hid delay write start hid delay write end, 3900 bytes/1292 ms, 3018 bytes/s AVR> bench2 100 160 hid delay write start hid delay write end, 3900 bytes/1402 ms, 2781 bytes/s AVR> bench2 100 170 hid delay write start hid delay write end, 3900 bytes/1803 ms, 2163 bytes/s AVR> bench2 100 180 hid delay write start hid delay write end, 3900 bytes/1792 ms, 2176 bytes/s AVR> bench2 100 190 hid delay write start hid delay write end, 3900 bytes/1803 ms, 2163 bytes/s AVR> q Bye.
X:OHCI(SiS M671T)>hidmon -i script AVR> bench2 100 1 hid delay write start hid delay write end, 3900 bytes/203 ms, 19211 bytes/s AVR> bench2 100 2 hid delay write start hid delay write end, 3900 bytes/297 ms, 13131 bytes/s AVR> bench2 100 3 hid delay write start hid delay write end, 3900 bytes/296 ms, 13175 bytes/s AVR> bench2 100 4 hid delay write start hid delay write end, 3900 bytes/329 ms, 11854 bytes/s AVR> bench2 100 5 hid delay write start hid delay write end, 3900 bytes/391 ms, 9974 bytes/s AVR> bench2 100 6 hid delay write start hid delay write end, 3900 bytes/406 ms, 9605 bytes/s AVR> bench2 100 7 hid delay write start hid delay write end, 3900 bytes/453 ms, 8609 bytes/s AVR> bench2 100 8 hid delay write start hid delay write end, 3900 bytes/485 ms, 8041 bytes/s AVR> bench2 100 9 hid delay write start hid delay write end, 3900 bytes/500 ms, 7800 bytes/s AVR> bench2 100 10 hid delay write start hid delay write end, 3900 bytes/500 ms, 7800 bytes/s AVR> bench2 100 20 hid delay write start hid delay write end, 3900 bytes/797 ms, 4893 bytes/s AVR> bench2 100 30 hid delay write start hid delay write end, 3900 bytes/1188 ms, 3282 bytes/s AVR> bench2 100 40 hid delay write start hid delay write end, 3900 bytes/1563 ms, 2495 bytes/s AVR> bench2 100 50 hid delay write start hid delay write end, 3900 bytes/1828 ms, 2133 bytes/s AVR> bench2 100 60 hid delay write start hid delay write end, 3900 bytes/2203 ms, 1770 bytes/s AVR> bench2 100 70 hid delay write start hid delay write end, 3900 bytes/2515 ms, 1550 bytes/s AVR> bench2 100 80 hid delay write start hid delay write end, 3900 bytes/2844 ms, 1371 bytes/s AVR> bench2 100 90 hid delay write start hid delay write end, 3900 bytes/3203 ms, 1217 bytes/s AVR> bench2 100 110 hid delay write start hid delay write end, 3900 bytes/3875 ms, 1006 bytes/s AVR> bench2 100 120 hid delay write start hid delay write end, 3900 bytes/4172 ms, 934 bytes/s AVR> bench2 100 130 hid delay write start hid delay write end, 3900 bytes/4500 ms, 866 bytes/s AVR> bench2 100 140 hid delay write start hid delay write end, 3900 bytes/4796 ms, 813 bytes/s AVR> bench2 100 150 hid delay write start hid delay write end, 3900 bytes/5188 ms, 751 bytes/s AVR> bench2 100 160 hid delay write start hid delay write end, 3900 bytes/5562 ms, 701 bytes/s AVR> bench2 100 170 hid delay write start hid delay write end, 3900 bytes/5828 ms, 669 bytes/s AVR> bench2 100 180 hid delay write start hid delay write end, 3900 bytes/6188 ms, 630 bytes/s AVR> bench2 100 190 hid delay write start hid delay write end, 3900 bytes/6531 ms, 597 bytes/s AVR> q Bye.
- 結果、なんとUHCIでは1パケット毎に直後800μ秒のISPコマンド処理時間があったとしても、コンスタントに4.8kB/秒の転送速度を保っている!
- つまり、HIDでもインターリーブの効果はあるということだ。
- 逆に、OHCIでは800μ秒のISPコマンド処理時間があった場合、1.3kB/秒にまで転送速度が落ちている。
- これは謎だ。
ちなみに '-d3'オプションを指定した場合のSCLKは375kHzなので、
- 8ビットのSPIを送るのに必要な時間は21.33μ秒。
- 8バイトのファームウェアをページバッファにセットアップする時間はその32倍の683μ秒あれば良い。
- (SPIコマンドは常に4バイト単位になっていて、1コマンドで正味データ1バイト分しか転送できない)
ファームウェアの容量削減†
- senshuさんにより取り纏め頂いたhidspx-0928b.zipに対して、firmware容量の削減を 行いました。
- 機能やコンフィギュレーションは同一です。
avr-objcopy -j .text -j .data -O ihex main.elf main.hex avr-size --mcu=attiny2313 main.elf text data bss dec hex filename 2014 4 88 2106 83a main.elf
- 1988バイトは気の迷いでした。(とあるコーディングミスで最適化され機能削除されていました。)
- WinAVRのバージョンは2006-0421でビルドしていますので、最新のWinAVRではサイズが変わる(増える)かもしれません。
おまけソフト
SCK、MOSIのHi−Z化改良†
- senshuさんにより取り纏め頂いたhidspx-0928.zipに対して、SCK、MOSIのHi−Z化を 行いました。
- ライターが書き込み動作を行っていないときはSCK、MOSIをHi−Zにします。
高速化改良その6†
- address_set , page_write , isp_command を全部含んだ融合コマンドを実装しました。
- tiny2313では、かなり有効かと思われます。
- それに伴って命令セット体系に少し変更が生じました。
ソースは現在整理中です。乞うご期待。任務完了!
おまけソフト
注意
HIDmonを使用される場合は命令Fusionが使えませんので、--使えるようにしました。#define INCLUDE_FUSION 0 #define INCLUDE_MONITOR_CMD 1
でファームを作成しなおしてください。- ポートの方向初期値を適切に設定してあげてください。
たぶん、ここらで打ち止めです。
- 残りはHIDmonの若干の機能強化と、汎用USB I/O DLLもどきの作成。
高速化改良その5†
変更内容(わりと堅実路線)
- '-d<delay>' オプションのクロックをUSBaspに近づけるように努力しました。
- 詳細は firmware/main.c にあります。
- hidasp.c を少しリライトしました。
- デバッグ文が多くて見づらかったためです。
- メモリーを減らしました。
- -d<delay> で思いのほかメモリー使用量が増えたので、ダイエットです。
- タイマー0によるUSIクロック生成は諦めました。
- うまくいく方法が見つかったらこっそり教えてください。
高速化改良その4†
- 紆余曲折の末、8バイト単位でのインターリーブ転送を実施することに決定しました。
- つまり、図で書くとこんな感じ
時間軸 0mS 1mS 2mS +--------------------------+-----------------------------+------------------ ... |USB転送| |USB転送| |USB転送| +--------------------------+-----------------------------+------------------ ... |<=ISP書き込み===>| |<=ISP書き込み======>| |<=ISP書き込み
- 目標では5kB/S(但しSCLK1MHz弱程度を想定)
- SCLKはタイマー0で与える。
- タイマー0のプリスケーラと分周比のペアを専用のコマンドで与える。
- ディレイオプション -d<delay> からペア値への変換表はホストPC側が担当する。
さて、うまくいきますやら・・・
結論
- 駄目でした。(テストマシンはintel UHCI)
8kB -d0 read 1.862 sec (4.4kB/s) 8kB -d0 write & verify 5.368 sec (1.5kB/s)
ちなみにfirmのサイズは2048きっかりでした。
- LED,MONITORの両方削除
- アンロール削除
- vendor,productIDを1字に。
- HID Reportディスクリプタは最小限の3個(6,38,70)
そもそも5kB/Sは読みか書きのどちらかの速度です。
- 転送ベンチが5kだったので、書き&ベリファイで5kも出るわけないです。
- あと、現在の実装は書き込みパケットにかなり無駄があります。(page_writeの前後の2パケットは内包可能)
コードエリアが足りません。(これは深刻・・・)
avr-size --mcu=attiny2313 main.elf text data bss dec hex filename 2034 4 59 2097 831 main.elf
- 100mSのディレイが残っていたので、差し引くと1.762 sec
- 書き込み時には無駄パケットが少し多いので、パケットをうまく統合するとreadの倍の3.6 sec 程度まで行くかもしれません。
- でも、どう頑張っても5Kの半分(2.5k/s)よりは出ないでしょう。
- だったら、今の最速(W&Vで2K弱)をキープして、コード保守するほうが堅実なのかもしれません。
実計測結果
テストアーカイブ:hidspx-test-0925.zip
- マシン=Athlon64 USBホスト=VIAチップPCIカード(UHCI)
- delayループ取り払い状態(1.5MHz SCLK)
- ATmega88へ8192バイトのHEXを書き込み&ベリファイ
bash-3.2$ time ./hidspx.exe -ph -d0 xx.hex Detected device is ATmega88. Erase Flash memory. Write Flash: 8192/8192 B Verify Flash: 8192/8192 B Passed. real 0m3.859s user 0m0.031s sys 0m0.015s
- ATmega88から8192バイトのHEXを読み込み
bash-3.2$ time ./hidspx.exe -ph -d0 -rp >a.hex Detected device is ATmega88. Read Flash: 8192/8192 B Passed. real 0m1.438s user 0m0.015s sys 0m0.000s bash-3.2$
- まとめ(テストマシンはAMD + UHCI)
- delay()ループ完全取り払い(SCLK=1.5MHz)
8kB -d0 read 1.438 sec (5.696kB/s) 8kB -d0 write & verify 3.859 sec (2.122kB/s) - 書き込みパケット数を減量(統合)すれば、write & verifyはもうすこし速くなりますので、2.5kB/sも夢ではないかもしれませんが、そのまえにコードサイズのスリム化が必要です。(どなたか挑戦しませんか、アーカイブは上記のhidspx-test-0925.zipです)
とりあえず、いい夢を見させてくれました。ありがとう>USBasp
AVRbench†
usbFunctionWrite()の性能テスト.
- usbFunctionWrite()内に遅延関数の呼び出しを入れる。
- どのくらい遅延すると、ホスト側の速度に影響するかのテスト.
- 0060 番地が遅延係数で 1 増えるごとに100uS
- 使い方は win32/ で
term -iscript
高速化改良その3†
- たいした変更ではありませんので、ここに差分を書きます。
static uint8_t usi_trans(uint8_t data){ USIDR=data; USISR=(1<<USIOIF); + if(wait==0) { + uchar CR0=(1<<USIWM0)|(1<<USICS1)|(1<<USITC); + uchar CR1=(1<<USIWM0)|(1<<USICS1)|(1<<USITC)|(1<<USICLK); + { + USICR=CR0; asm("nop"); USICR=CR1; asm("nop"); + USICR=CR0; asm("nop"); USICR=CR1; asm("nop"); + USICR=CR0; asm("nop"); USICR=CR1; asm("nop"); + USICR=CR0; asm("nop"); USICR=CR1; asm("nop"); + USICR=CR0; asm("nop"); USICR=CR1; asm("nop"); + USICR=CR0; asm("nop"); USICR=CR1; asm("nop"); + USICR=CR0; asm("nop"); USICR=CR1; asm("nop"); + USICR=CR0; asm("nop"); USICR=CR1; asm("nop"); + } + return USIDR; + }else{ do{ delay(wait); USICR=(1<<USIWM0)|(1<<USICS1)|(1<<USICLK)|(1<<USITC); } while(!(USISR&(1<<USIOIF))); + } return USIDR; }
bash-2.02$ time ./hidspx.exe -rp >1 Detected device is ATmega88. Read Flash: 8192/8192 B Passed. real 0m1.915s user 0m0.015s sys 0m0.000s bash-2.02$ time ./hidspx.exe 8K.hex Detected device is ATmega88. Erase Flash memory. Write Flash: 8192/8192 B Verify Flash: 8192/8192 B Passed. real 0m4.247s user 0m0.015s sys 0m0.000s
高速化改良(案のみ)†
- 書き込みのみですが、32バイトのHID Reportを送りつけられている間もSPI転送するような ソリューションが考えられます。
- 具体的には、usbFunctionWrite()で全部貯めてからSPI書き込みではなくて、8バイト貯まったHEXをそのつどSPIで送るといった方法です。
- 読み出しは今のところAVRUSB側にポインタと長さを渡してそれっきり、という方法でやってますのでこれも、usbFunctionReadに引っ掛けて、ちまちま読み出す、というところでしょうか。
- ただし、delayオプションが長い場合はUSB転送の足を思いっきり引っ張るような気もしています。
- readに対してだけ実際に試してみましたが、8Kのreadに1.4秒が限界でした.
高速化改良その2†
- たいした変更ではありませんので、ここに差分を書きます。
static uint8_t usi_trans(uint8_t data){ USIDR=data; USISR=(1<<USIOIF); + if(wait==0) { + do{ + USICR=(1<<USIWM0)|(1<<USICS1)|(1<<USICLK)|(1<<USITC); + } while(!(USISR&(1<<USIOIF))); + return USIDR; + }else{ do{ delay(wait); USICR=(1<<USIWM0)|(1<<USICS1)|(1<<USICLK)|(1<<USITC); } while(!(USISR&(1<<USIOIF))); + } return USIDR; }
avr-objcopy -j .text -j .data -O ihex main.elf main.hex bash checksize main.elf 2048 128 ROM: 2010 bytes (data=4) RAM: 93 bytes
残りあと38バイトとなりました。
6KB書き込み&ベリファイ時間計測†
HIDspx -ph -d<Delay> test.hex
Delay | Time |
-d0 | 4秒 |
-d1 | 5秒 |
-d4 | 8秒 |
- 計測に使用したマザーボードはSiS製です。
- マザーとHIDaspの間にはELECOM製のUSB1.1ハブが挟まっています。
ToDo:
- 時間計測コマンド(unixのtime相当)をちゃんと作る。
- 今使っているのは自作ツールで 16bit MSDOSのコード。
1993/07/09 02:33 11,682 WATCH.EXE
- 今使っているのは自作ツールで 16bit MSDOSのコード。
- そろそろATmega88では限界なのでATmega644のボードを(書き込み時間計測のためだけに)制作する。
- Snoopy−Proを使ってUSB転送の様子を観察し、パケット送信間隔等を評価する。
なんかこう、AVRに高速に書き込むことが目的化してしまいました。笑っちゃいます。
高速化改良その1†
内容
- パケットサイズのバリエーションをさらに増やしてみました。
- usbHidReportDescriptorを6種類用意して、サイズをそれぞれ、6,14,22,30,38,46 にしました。
- 但し、読み込みパケットサイズは38に留めています。(現在のところ固定)
- waitのループを瓶詰堂さんのオリジナルに戻しています(nopを消してしまいました:実は書き込み速度向上にはこれ+オプション「-d0」が一番効きます。)
- さらに速くするには、-d0のときはdelay()を外したusi_trans()を用意するか、あるいはHIDaspを20MHz動作させる等が考えられますが、ターゲットデバイスが遅い場合は意味がありません。
ダウンロードはこちらです:hidspx-src-0920.zip
- 書き込み速度の実測値ですが、ATmega88に6kBの書き込み&ベリファイで約5秒に短縮しました。
- CMD_PEEKとCMD_POKEを追加してあります。(未デバッグ)
- また、サイズは以下の通りです。
avr-objcopy -j .text -j .data -O ihex main.elf main.hex bash checksize main.elf 2048 128 ROM: 1992 bytes (data=4) RAM: 93 bytes
追加:
- HIDsphの '-d4'オプションのほうが、こちらの '-d0'書き込みより速いのではないか疑惑
- 上記調査中です。
HIDasp高速化完了†
senshu様から頂いたソースと、瓶詰堂さんのHIDaspソースをもとに 作成しました。
ディレクトリ構成
| hidspx-src/ HIDspx.exe とそのソースです。 | firmware/ AVR側のファームウェアHEXとそのソースです。
変更内容:
- HID Reportの転送をHidD_GetFeature()/HidD_SetFeature()で行うようにしました。
- usbHidReportDescriptorを4種類用意して、サイズをそれぞれ、6,14,22,30にしました。
- 変更点はたったそれだけです。
- 上位プロトコルは瓶詰堂さんのHIDaspと同じままです。
- 配線はUSBのD+,D-だけを PORTD,3,2 に変えて、他は瓶詰堂さんのHIDaspと同じです。
- usbHidReportDescriptorが異なりますので、上記exeとファームはペアでないと動作しません。
ダウンロードはこちらです:hidspx-src-0919.zip
- 期待したほど速くはなりませんでした。
- ATmega88に6KBのHEXを書き込み&ベリファイにて、所要時間6秒(AMDマザーボード)
- (後でPentium4マシンで追試しましたところ9秒でしたので、実は遅くなっただけかも・・・)
- USBの挿抜に対しては安定です。
- コードサイズは以下のとおりです。特に縮める作業はやっていません。
avr-objcopy -j .text -j .data -O ihex main.elf main.hex bash checksize main.elf 8192 1024 ROM: 1962 bytes (data=4) RAM: 86 bytes
考察†
- HID Report30バイトの書き込みと読み出しを交互に1000回実行してみます。
- 実行方法は、hidasp.cのソースにて、最初に4回testパケットを送る部分を改造して、30バイトのHID Reportを送るようにします。
- ループ回数を1000に増やします。
- hidspx.exe -ph -r を実行します。(書き込みデバイスは無くてよい)
- OHCIのUSB付きマザーで試したところ、1000回の試行に6秒掛かりましたが、UHCIではその倍の12秒でした。
- すなわち、30バイトのHID Reportを送るのに3フレーム(OHCI)もしくは6フレーム(UHCI)掛かる計算になります。
- より正確な時間の推移を知りたい場合はSnoopy-proというWindows上のUSBスニッファーを入れて、パケットをキャプチャーすると良いです。
- 30バイト単位でただひたすら読むだけなら、10kB/s もしくは 5kB/s くらいの速度が出るはずなのに、実際にSPI転送が入るとその1/10あるいは1/5になるのは、なにか要因があるのだと思いますが、まだ追求できていません。
落穂拾い†
- 配線は森芳電子さんの方法が洗練されているので、それに合わせたい。
- クロック出力をターゲットに与えることが可能になっている。
- LEDをPB2,PB3に移してあるので、TxD,RxDを使用可能になっている。(実際tiny2313ではコードを入れる空きがないけれど、同じ基板を別の用途に転用しやすい)
- 但し、D+,D-の配置がさらに変わるので、usbdrv/以下のいくつかのソースにまで手を入れなければならない。
- さらに、INT0がINT1に変わるので、最小限必要な割り込みベクタが2バイト増加する。
- AVRmonitの一部の機能(RAMやI/Oに対するPEEK/POKE命令)を組み込んで、代わりにLED制御はそっちでやる。
- すると、余ったポートにPWMを設定して昇圧回路をドライブするとか、変な付加機能をPC側から好きなように実装できる。
- AVRを焼かないときでも汎用IO代わりに流用できるようになる。
- AVRを焼いた直後にターゲットをリセット起動させたり、ターゲットとSPIクロス接続になっているので通信(printfデバッグ)したり出来るようになる(かも)
- 高速化したいけれど・・・。(無理かなぁ)
- すzさんの考察されているように、HIDデバイスに見せかけておいて、libusb経由でバルク転送とか。
- ファーム容量的に無理っぽいのと、けっきょくそうういったことは別のAVRライターでやり尽くされているような気もする
- 自分はATtiny2313しか知らないので、そんな世界も知らない。でも見てみたいかも。
こうやって、AVRライターの種類だけが増えていくのは、なんだかむなしいなぁ
HIDasp高速化検討中†
光が見えてきたので、作業記録を書いてみる。
現状
- HIDaspはWindowsAPIのReadFile()/WriteFile()によってHID Reportを転送している。
- HID Reportというのは、たとえばマウスならボタン情報、座標などを含む、固定サイズのデータだ。
- そのReportの1パケットは8バイトになっている。ReadFile()/WriteFile()に与える転送長は+1した9を与える。
- Report_IDは0になっている。ReadFile()/WriteFile()のバッファ先頭にReport_IDを置く。
- 他の例(AVR-DoperやHIDsph)を見るとReportIDは1〜のようだ。
問題点
- Windows2000では、起動時のハンドシェークでやりとりがうまく行かず、ハングする。
- WindowsXPではUSB挿入直後だけハンドシェークをミスるが、一応無視して継続する。
- 転送速度は約1kB/秒なので、ATmega644では1分弱掛かり実用的でない。
- ATtiny2313では4秒程度なので問題なし。
改善策(案)
- まず、HID Reportの転送単位を変更する(32バイト程度にすると効果あり)
- HIDaspのusbHidReportDescriptorをAVR-Doperベースのものに差し替える。
- これは、HID Report ID 1〜5までが定義されていて、転送サイズ(REPORT_COUNT)はそれぞれ
- (16-2),(32-2),(64-2),(128-2),(64-2) のようになっている。
- なぜ2のべき-2なのかというと、パケットの先頭にReport ID(1〜5のどれか)を入れる必要があるからだ。
- (でもそれは-1である理由にしかなってないんだけど)
- 実はキリの良い値でなければならないという理由はないがLowSpeed USBのパケット長上限は8バイトなので、総転送サイズが8の倍数になっているほうが効率が良い。
- 最後のやつだけ数列から外れているが、これはデバッグパケットらしい。
そして、HID Reportの転送にはHidD_GetFeature()/HidD_SetFeature() を使う。
- 転送サイズはREPORT_COUNT+1を与え、バッファの先頭にはReport_IDを書き込んで使う。
今日やったこと
- AVR-DoperのHidReportDescriptorを移植したAVR-USBのフレームワークを用意して、 32バイトパケットを単純にエコーバックするだけのファームを書く。
- そして、ホストPC側から、接続を試みる。
- (senshuさんのHIDspx-srcをありがたく使わせて頂いております)
- 31バイトのHID Reportを適当にでっちあげて Report_ID=2で送信し、そのエコーが戻ってくるのを確認。<===今日はここまで
とりあえず現状報告
avr-objcopy -j .text -j .data -O ihex main.elf main.hex bash checksize main.elf 8192 1024 ROM: 1968 bytes (data=4) RAM: 87 bytes
- 一応isp_commandまで入れた。
- AVRmonitは入れていない。
明日以降の予定
- AVRmonitをHIDベースにして、デバイスドライバ不要のやつを作ってみる。
- ベンチマーク機能があるので、ベンチマークしてみる。
- 予想では4kB/s程度。根拠は32バイトまとめて送るので。
コードサイズが余れば瓶詰さんのプロトコルを乗せてみる。すでに入っているつもり
下記の記述はHIDクラスの制約を無視した考察ですので、多分に間違いを含んでおります。 (libusbを使用する場合はOKかもしれません。)
現在再検討中です。
千秋さんのサイトでの話題
可能性を探ってみた。
- まず、LowSpeedの転送速度は、理論値1.5Mbpsあるように見えるけれどこれは気の迷い。
- 基本、コントロール転送を使うと仮定。
- USBでは1フレーム(1mS)に8バイトのパケットが1回送れる(あるいは受け取れる)だけなのだ。
- じゃあ8kB/秒かというと微妙なところで、コントロール転送を用いて8バイトのベンダーコマンドを送り、デバイスから8バイトのリターンを返してもらうという1回のトランザクションの時間を計測してみると、
- OHCIでは1mSで完結するがUHCIでは4mS掛かる。
- つまり、OHCIでは1秒に8kB送って8kBのリターンが得られるが、
- UHCIではその1/4の速度(2kB/秒)まで落ちる。
- もうひとつやっかいなのがコントロール転送では8バイトの内容のうち、先頭1バイトがbmRequestTypeであり、お尻の2バイトがwLength(後続データのサイズ指定子)となっていて自由に使えない。
- つまり送出できる正味データ量は8kB/Sではなく5kB/Sになってしまうわけだ。(UHCIではさらにその1/4)
- HIDaspに限った話をすると、5バイトのうち最初の1バイトがコマンドバイトとして使われていて、正味のSPIデータ送出は4バイト/フレームである。
- 但し、AVR書き込みターゲットに対するページリードがサポートされていて、4バイトのファームウェアデータを1トランザクションで転送しているようなので、書き込み速度としては4バイト/4mS=毎秒1kBとなる。
- これを打破する手としては、1トランザクションに後続データを16〜32バイト付加してやって、1回のコントロール転送で16〜32バイト分のファームウェアデータを送りつけてやる方法だ。
- 仮に32バイト送るとするとUHCIでは4+4=8フレームでおそらく完結するので、
- 32バイト/8mS=4kB/秒になる計算だ。
- 問題はそれらの処理を含めて2kBに入るかどうかなんだな。
- かなり難しいと思う。GCC4ではバイナリコードが肥大化する傾向があるのでGCC3ベースのWinAVRを使うしかないかも。
- むしろ、千秋さんのサイトで指摘されているとおり、tiny2313に固執するのをやめて、ATmega88あたりでゆったりとコードを組んだほうが正解なのかもしれない。
- でも、当サイトでは無理やりコードを縮めて2313に詰め込む方向にむしろ快感を感じるので、mega88は使わないだろうと思う。(嘘。手持ちのmega88が少なくて、2313ばかりが余っているので、2313を使い切る方向で考えている。)