なんちゃってシリアル
ATtiny2313でUSBtoシリアル変換器を作ろうと思う。†
- プロトコルはいろいろ考えたが、コントロール転送(ベンダーリクエスト)のみを使うやり方で落ち着いた。
- これだとエンドポイントを用意しなくて良いので、コードサイズ、SRAMサイズを最小に出来る。
- 8バイトのコマンドパケットを送って、必要なら8バイトのリターンパケットを受け取る。
- コマンドパケットの内容(ベンダーリクエスト)
0 1 2 3 4 5 6 7 +------+------+---------------------------+-------------+ | req | cmd | 送信データ(最大4バイト)| wlength | +------+------+---------------------------+-------------+
- reqはbmRequestTypeである。
- wlengthは8固定(の予定)これはデバイスからホストへの受信パケットが後続する意味。
- cmdは送信バイト数(0〜4)
- cmdが5以上になった場合は、特殊コマンドとして解釈(ボーレート設定等)
- 受信パケット
0 1 2 3 4 5 6 7 +------+------------------------------------------------+ | size | 受信データ(最大7バイト) | +------+------------------------------------------------+
- sizeは0〜7
- sizeのMSBが1になるときは送信が拒否された。(TxBuf FULL)
- その場合PC側は同じデータを再送する。
- ターミナルソフト
- AVR_Monitを改造して作る。
- オプションで仮想エコーバックポートに対応したい。
- ファーム
- RS232C受信はUSART割り込み駆動。
- 送信はメインループ内のPoll()のループ内に仕掛ける(1ループで1文字)
- ベンダーリクエストのパケットが来たら、送信バッファにとりあえず4文字をためておいて
- USART受信したバッファをホストに送る。
- 送信バッファが空になっていない場合は再送フラグを立てて、送信データを捨てる。
- この一連のパケットのやり取りは普通のUHCIなら4フレーム(4mS)掛かる。
- SiSのOHCI(EHCI)では1フレーム(1mS)でいける。
- 普通のEHCI(intel含む)でも、間にHiSpeedハブを挟むことによって だいたい1フレームで応答が帰ってくるようだ。
ということは
- 送信スループットは最大4kB/秒(32Kbps相当)
- 受信スループットは最大7kB/秒(56Kbps相当)
- ハブを挟むとか、SiSのチップセットを使うとかの工夫をしない状態だと、この1/4。
- 送信は手入力のときなどは1回に1バイトになり、アップロードのときは4バイトまでいける。(と思う・・・)
- これで手を打とうではないか。
- かろうじてMIDI速度だ。
なぜLowSpeedのBulkを使わない?
- VistaやLinuxに対応できない。
- 残念だが、HiSpeedハブに濾過される。
- 最高速のSiSのEHCIでもバルクパケットの往復だと2フレーム掛かってしまう。
- だったら、1フレームで送受が完結するコントロール転送のほうがましだ。
なぜCDCクラスにしないのか?
- これもたぶんHiSpeedハブに濾過される。
- ATtiny2313では逆立ちしても無理(コードサイズが256バイト以上オーバーする)
なんちゃって方式ではあるが、うまくいけば仮想COMポートのエコーバックを利用してteratermからも使えるようになる(といいなぁ・・・)
LowSpeed AVRUSBの挙動に関するまとめ†
転送モードの種類†
どのみちUSBにはこれだけしか転送モードは存在しない。
転送モード | 特徴 | 所要フレーム数 | 速度 |
コントロール転送 | 各種セットアップに使われるほか、ベンダー独自のコマンドも追加できる。 | 一回のトランザクションで1〜4フレーム程度(注1、2) | 8kB/秒〜2kB/秒(注1、2) |
インタラプト転送 | 一定期間おきに起こるような転送に使う | LowSpeedの規格では、10フレームに1回よりも短く出来ないと定められている。実際それ以下には出来ない | 1kB/秒以下 |
バルク転送 | 空いているUSB帯域を使ってフルに大量のデータを転送するのに向いている。(注3) | 1フレームに1〜4パケット程度(注4) | 8kB/秒〜32kB/秒(注4) |
アイソクロナス転送 | 主にUSBオーディオなどでストリームデータを一定の帯域で送るのに使われる | LowSpeedでは非対応 | LowSpeedでは非対応 |
- USBにおける1フレームとは1mSのことで、USBドライバーは1フレームを単位としてスケジューリングや同期処理を行っているようだ。このため、アプリケーションから同期(完了復帰型)read/writeを行なうと必ず1mSの整数倍の時間だけ待たされる。
- USB2.0で定義された480Mbpsモード(HighSpeed)においては、1フレームの1/8にあたる125μ秒を単位とするマイクロフレームが定義されたので、1mSというレイテンシーをその1/8に短縮することが出来る。
- 注1)intelを含む多くのホストコントローラで実測すると4フレーム掛かるので2kB/秒。
- これはコントロール転送8バイトを送り、リザルト8バイトを受信した場合。
- 注2)SiSのコントローラを使用した場合、コントロール転送は1フレームで完結し、8kB/秒になる。
- SiSコントローラを使用しない場合でも、HighSpeedハブを挟めば、ほぼ8kB/秒の速度が出せるようだ。
- これは、ホストから見てLowSpeedのデバイスがHighSpeedとみなされることで、トランザクションの時間単位が1mSから1/8mSに短縮される効果のようだ。
- 注3)規格上、LowSpeedでのバルク転送はサポートされていない
- はずだが、WindowsXPでは何故か使用できる。
- Vistaでははじかれる(たぶん)
- HighSpeed(480Mbps)ハブを挟んだ場合も濾過されて無視される(現在ハブのサンプル数が1個なので、まだ断言は出来ない)
- 注4)1フレーム(1mS)に4パケットを送るためにはusb_bulk_write()で一度に32バイトのデータを渡す等の工夫が必要。そうでないときはusb_bulk_write()が常に1mS待つので結局1フレームに1パケット(8バイト)となる。
結論から言って、LowSpeedではどの転送モードが使えるのか?†
- LowSpeedで正式にサポートされている転送モードはコントロール転送とインタラプト転送の2種類だけだ。
- インタラプト転送はポーリング間隔が10mS単位になるので、とても遅くて使えない。
結局LowSpeedにおいてはコントロール転送しか使いものにならないということだ
UHCIは遅い
- intel製のUSBホストコントローラのこと。
- 遅いの意味は、1回のコントロール転送(リザルト8バイト受信を入れて)に4フレーム(4mS)も掛かるという意味。
- 1フレームで済ませてくれと言いたい。
SiSのOHCIは速い
- SiS製のUSBホストコントローラのこと。
- 速いというのは語弊があるが、ほぼ理論上のレイテンシーで駆動できている。
EHCIで速くしたければHiSpeedハブを挟め
- USB1.1までのホストコントローラは歴史的事情でインテル(UHCI)とそれ以外(OHCI)という風に実装が別々になってしまった。
- その反省を踏まえてUSB2.0のホストコントローラの設計(ハードウェアのインターフェース)はEHCIに統一された。
- つまり、現在USB2.0をサポートしているホストコントローラは全てEHCI規格なはず。(パソコンに内蔵されるチップセットの話として)
- 但し、ホストから見てFullSpeed,LowSpeedでの接続時はUHCIもしくはOHCIとしての動作になる。
参考
上記の資料によれば、VIAはUHCIに属するので、やっぱり遅いわけだ。
OHCI>NEC、SiS、Opti 等の Chip に使用されています。
- ということなので、不幸にもマザーボードがインテルとVIAの人はNECのUSBカードを買ってくればいいわけだ。
- SiSチップが乗っているUSBカードって、見たこと無いなぁ・・・。
- Optiって、まだ生きてるの?
LowSpeedバルク転送というのは裏技になってしまったが、どんなときに有効か?†
- USB経由のRS232Cシリアルデバイスを作る場合。例:
(AVR-CDC)
- CDC(通信デバイスクラス)のRxD、TxDストリームはBulkタイプのエンドポイントで実装されているので、必然的にバルク転送を使うことになる。
- コントロール転送は常にエンドポイント0が使われるので、それとは独立したエンドポイントを用意したいとき。
- コントロール転送よりも速度(帯域)が欲しいとき。
制限事項
- ただし、上記の通りWindowsXPに限定される。
- デバイスとの間にHighSpeedハブを挟むことが出来ない。
目次