PIC32MX220F032B USB MIDI ホスト (9)

基本的に USB デバイス 1 個の接続のみに対応する Microchip の USB ホスト・スタックを使って、無理やり USB ハブに簡易的な対応をする方法について説明します。
まず、今回は USB ハブについての主に一般的な話です。
1 台のホストに 2 台のハブと 3 個のデバイスを接続する場合の例を下に示します。

これは、ホストによるエニュメレーションが終了して、ネットワーク・トポロジが確定した状態の図です。
ハブの上側の端子は「アップストリーム・ポート」、つまりホスト (に近い) 側と接続するポートで、ハブの下側の端子は「ダウンストリーム・ポート」、つまりデバイス (に近い) 側と接続するポートを表すものとします。
ダウンストリーム・ポートは、左から 1, 2, 3, 4 番ポートとして番号が振られているものとします。
ダウンストリーム・ポートの中にバツ印が書いてあるのは接続が有効でないポートを表します。
USB の場合には、ハブも一種のデバイスとして扱われ、デバイス・アドレスが割り振られます。
上の図では、角かっこ [] の中の数字がアドレスを表すものとします。
バイス 3 個、ハブ 2 台の計 5 個の重複しないユニークなアドレスが割り当てられます。
たとえば、1 段目のハブはアドレス「1」となっています。
ホストに直結している 1 段目のハブは、特に「ルートハブ」と呼ばれ、通常はホスト・コントローラと一体化しています。
ここでは、PIC32MX の内蔵 USB モジュールに合わせて、ルートハブが内蔵されていないイメージで表現してあります。

ホスト - ハブ間が USB 2.0 ハイスピード (HS, 480 Mbps) で接続され、ハブ - デバイス間がフルスピード (FS, 12 Mbps) で接続されている場合には、ハブでデータのバッファリング、スピード変換が行われますが、スピードが同じ場合にはハブの中では変換は行われず、単なる「リピータ・ハブ」として動作します。
リピータ・ハブ動作での、ホスト → デバイス方向 (OUT 方向) のデータの流れを左の図に示します。
ハブを通過する際の電気的な信号の遅延が数十 ns 付加されますが、データの内容としては、論理的に接続が有効となっているすべてのデバイスに対して同じものが送られます。
各デバイスでは、自分に割り当てられているアドレスと、ホストからのメッセージに含まれるアドレスを照合し、自分宛てのメッセージでなけば応答せず、無視します。
今度は、デバイス → ホスト方向 (IN 方向) のデータの流れを下の図に示します。

アドレス「4」のデバイスがホストから「指名」されて応答する場合を想定しています。
バイス[2]、デバイス[5]、ハブ[1]、ハブ[3] はアドレスが一致しないので応答せず、ポートをアイドル状態に保持しつづけます。
アクティプなデータを出力するのはデバイス[4] だけなので、各ダウンストリーム・ポートの状態を「合成」してホスト側へ送られるデータはデバイス[4] のものとなります。
ハブ側には、データの衝突を回避するメカニズムや、データの衝突を検出する機構はないので、正常な動作のためには、各デバイスにユニークなアドレスが割り振られていて、IN 方向でアクティブになるデバイスが 1 個に限られることが必要です。
次は、システムの電源が ON になって、リセット後にホストがエニュメレーションを開始する前の「初期状態」の図を下に示します。

「初期状態」では、ハブの各ポートは「閉じて」いて、ホスト側とのデータの送受はできない状態になっています。
リセット後には、各デバイス (ハブ含む) は「Default state」になって、デバイス・アドレスが「0」の状態になります。
この状態で、もし仮にハブのポートが全部開いていたとすると、ホストから見えるすべてのデバイスが同じアドレス「0」を持つことになり、ホストからのアドレス「0」に対するメッセージにすべてのデバイスが応答してしまうことになります。
そのような事態を避けるために、リセット後にはハブのすべてのポートが無効の状態になっています。
この状態では、ホスト側からは、ホストに直結されている 1 段目のハブだけが見えています。
このハブに対してエニュメレーションを行い、ユニークなアドレスを割り当て (たとえば「1」)、ハブを動作可能な状態にします。
ハブにはポートの状態を取得するコマンドや、ポートの状態を設定するコマンド、ポートの状態変化を報告するためのインタラプト IN エンドポイントなどが備わっているので、これらを活用して、ハブにつながっているデバイスのエニュメレーションを進めていきます。
まず、初期状態では、ポートのデータ・インターフェース部の「電源」すら入っていないので、電源 ON コマンドの発行から始めます。
この「電源」はデバイスへの +5 V 電源「VBUS」ではなく、ハブ側のデータ・トランシーバ回路の電源のことです。
データ線回路の電源を ON にすると、ポートにデバイスが接続されているか、またそのスピードは HS か LS かということが判明します。

バイスが接続されていることが分かると、今度はポートを「リセット」するコマンドを発行します。
このリセット状態はハブの方で自動的に 10 ms 程度の間保持され、完了するとポートが「イネーブル」された状態となり、そのポートに接続されているデバイスにアクセスできる状態となります。
この時点では、そのデバイスのアドレスは Default state の「0」ですから、そのデバイスに対してエニュメレーションを行い、ユニークなアドレス (たとえば「2」) を割り当て、動作可能な状態にします。
そこまでエニュメレーションが進んだのが左の図の状態です。
あとは、同様に進めれば、最初の図のようになります。