USBフルスピード信号波形:USBプロトコル・アナライザーを自作するときに参考になればと思います。
図1はUSBフルスピードにおけるD+信号とD-信号の波形例です。波形データ:D+D-.zip
図1
USBの信号はパケットから成り立っています。つまり、USBホスト(例えば、パーソナル・コンピュータ:1つだけ)とUSBデバイス(ホストに繋ぐ機器:複数可)との間で、パケットのやり取りをすることで、USB通信が成立しています。上図ではSOFパケットとINパケットとNAKパケットが見えています。パケットは必ずSYNC(synchronisation:0x80)で始まってEOP(End of Packet)で終わります。
※1 D+信号のSOFパケットの先頭部分を拡大します。
図2
USBフルスピードは12Mbps(1秒間に12Mビット)のデータ転送速度を持ちます。この値の逆数をとると、1ビットあたり83.33...ナノ秒となります。つまり、83.33...ナノ秒間で1バイトのデータを転送できるということです。この時間を、以後、1バイト期間ということにします。図2の信号を見ると、HからL、あるいは、LからHへ、1バイト期間ごとに変化しているのが分かります。なお、Hは3.3 Vで、Lは0 Vを意味します(ただし、電圧には許容幅があります)。
※2 D+信号のSOFパケットの部分を拡大します。
図3
USB信号は、NRZI(Non Return to Zero Inversion)符号化(encode)されています。これを読み解くには、次のようにします。上記「1バイト期間」を単位として、
○ 信号がHからL、あるいはLからHへ変化したとき、0と読みます。
○ 信号がHでも、Lでも変化していない場合、1と読みます。
○ 1が連続して6回続いた場合、その後の0(スタッフビット)は読み飛ばします(destuff)。
ためしに、図3のD+信号のSOFパケットの始まりの部分を見ると、まず7つの0が続くことが読み取れます。その後の1バイト期間はLで変化がないので、これを、1と読み取ります。結局、最初の8バイトは「0000 0001」と読み取れます。これが、SYNC(synchronisation:0x80)フィールドです。ところで、USB信号はLSB(最下位ビット:Least Significant Bit)から送られますので、「0000 0001」は(一番左のビットがLSB)、ビットを逆順にして「1000 0000」(0x80)(一番右のビットがLSB)を表しています。SYNCフィールドは、USB信号を受信する機器に対する同期信号です。USB信号は、それを受信する機器にとって非同期信号なのです。
SYNCフィールドの続きは後回しにして、先にEOPについて書いておきます。EOPはパケットの終了を示すものですが、D+とD-が両者とも2ビット期間Lになる箇所です。図1で確かめられます。ハード(ウェア)面から見ると、このEOPが有ることがとても重要です。
SYNCフィールドの後の8ビットは、必ずPIDとPIDフィールドです(各4ビット)。これはパケット名(意訳しています)です。PIDは、PIDを反転したもの、すなわち、1と0を入れ替えたものです。PIDの意味は以下の表の通りです。図2からPIDを読み取ると「0101」ですから(ビットが逆順になることに注意)、SOFパケットであることが分かります。
表種別 | PID | パケット名 |
トークン | 0001 | OUT |
1001 | IN | |
0101 | SOF | |
1101 | SETPU | |
データ | 0011 | DATA0 |
1011 | DATA1 | |
ハンドシェーク | 0010 | ACK |
1010 | NAK | |
1110 | STALL | |
特殊 | 1100 | PRE |
SOFはStart of Frameの意味で、フレームの始まりを表します。1つのフレームはSOFパケットで始まり、次のSOFパケットの直前で終了します。1つのフレームの続く時間は1ミリ秒間です。SOFパケットは、1ミリ秒間隔で常時、USBホスト(たとえばパーソナル・コンピュータ)から出力されています。ただし、デバイス側(ホストに接続されているUSB機器)から見たときに、リセット時には、SOFが出力されていないように見えます。リセットについては後程説明します。図1の場合は、SOFパケットで始まる1つのフレームの中でINパケットとNAKパケットがUSBホスト・デバイス間を行き来していることになります。
PIDとPIDの後には、11ビットのフレーム番号(Frame#:#はnumberの意)が続きます。図3で、スタッフビットを抜かすことに注意して、いつもの通り、ビットを逆順で読んでゆくと、「110 0101 1111」となります。16進数で0x65fです。フレーム番号は0x000から0x7ffまで、フレームの順に1つづつ増えて行きます。0x7ffになったら、次は0x000に戻ります(11ビットなので)。ただし、デバイス側からみると、リセット時にはリセットの時間だけSOFパケットが抜けるので、フレーム番号がリセットの前後で飛んでいるように見えます。
図3を再び見ると、SOFパケットの最後の方に、5ビットのチェックサムCRC5(Cyclic Redundancy Checksums)が付いています。CRC5の5はビット数です。0x65fのチェックサムCRC5を別途算出すると、0x0aとなります。図2から読み取れるCRC5の数値と一致しています。なお、CRC5の算出にはすzのAVR研究で公開されているプログラムを使用しました。
※ D+信号のINパケットの部分を拡大します。
図4
このパケットがINパケットであることは、PIDの値から明らかです。IN、そして後程出てくるOUTは、USBホストから見ての名称で、それぞれ入力と出力を意味します。INパケットの場合、PIDとPIDの後には、7ビットのADDR(アドレス)、4ビットのENDP(エンドポイント)、5ビットのCRC5が続きます。
ADDRは、USBホストが、自分に繋がっているUSBデバイスを区別するため、各USBデバイスに設定するアドレスです。図3の場合、「001 1000」で、16進数で書くと0x18です。ADDRは7ビットですから、0x00から0x7fまでの128個の異なったアドレスを設定できます。しかし、0x00はUSBホストにUSBデバイスが接続された際に、USBホストがその接続を認識するために使用する共通のアドレスなので、各USBデバイスを区別するアドレスとしては使えません(USBデバイスの接続認識が終わった時点で、USBホストは各USBデバイスをリセットした後に0以外のアドレスをUSBデバイスに設定します)。したがって、0x01から0x7fまでの127個の異なったアドレスをUSBデバイスに設定できます。換言すれば、127個のUSBデバイスしかUSBホストに繋げないということになります。
ADDRの次はENDP(END Point:エンドポイント)です。エンドポイントは、USBホストとUSBデバイスが持っているデータを一時的に溜めておくバッファ・レジスタ・メモリです。USBホスト・デバイス間は、物理的にはD+とD-とを一纏めにすると1本の線でしか接続されていませんが、これを仮想的に複数線化します。エンドポイントの番号が同じメモリどうしを、パイプという仮想的な線で結び、そのパイプにデータを通すことによりデータ転送を行うというイメージです。パイプの終端(エンドポイント)はバッファ・レジスタ・メモリですから、バッファ・レジスタ・メモリをエンドポイントと呼ぶのだと想像します。 さて、ENDPは4ビットですから、0x0から0xfまでの最大で16個の異なるエンドポイントを用意できます(EP0からEP15まで)。そして、エンドポイントは、IN(ホストから見て、データ入力)用とOUT(ホストから見て、データ出力)用のものをそれぞれ用意しますので、最大32個のエンドポイントを用意できます。ところで、USB通信を行うためには、仮想と言えども最低1本の線(パイプ)が必要で、その終端がEP0(エンドポイント・ゼロ)です。なお、図4の場合、エンドポイントは「0001」で、16進数で書くと0x1(EP1)です。
ENDPの後はCRC5です。ADDRとCRCを合わせて数値化すると、「000 1001 1000」(16進数で0x098)となります。これのCRC5を算出すると0x06で、この数値は、図4から読み取れるCRC5の値と一致しています。
INパケットはUSBホストからUSBデバイスに向け発信されます。USBデバイスのうちADDRで指定したデバイスのENDPに対して、入力データがあるかどうかをUSBホストが問い合わせるためのパケットがINパケットです。
最後に、図1の最後に来ているのはNAKパケット(Not acknowledge)です。このパケットがNAKパケットであることはPIDの値から明らかでしょう。NAKパケットはSYNCとPIDとPIDだけで構成されています。NAKパケットは、INパケットに対して、USBデバイスが転送するデータは無いと回答するためのものです。
下図はUSBフルスピードにおけるD+信号と、これをFPGAでNRZI(Non Return to Zero Inversion)復号(decode)した信号の波形の1例です。波形データ:NRZI.zip
図5
以下の回路図のように、NRZI復号は2つのFF(フリップ・フロップ)と、それらの出力データの排他的論理和(出力は負論理)をとるExclusive-NORで構成できます。だたし、12MHzのクロック端とFFの入力変化が一致してはいけません。工夫が必要です(実際には、48MHzクロックのdigital phase locked loopでD+信号を読みとったあと、NRZI復号を行います)。最初のクロックで最初の1バイトデータを1つ目のFFに記憶させます。次のクロックで、そのデータを2つ目のFFに移動させるとともに、1つ目のFFに、次の1バイトデータを記憶させます。同時に、2つのFFに記憶させた2つの1バイトデータのExclusive-NORをとります。Exclusive-NORの出力としてNRZI復号信号が得られます。連続する2つの1バイトデータが、互いに同じならば1となり、異なれば0となる論理回路を作れば良いということです。例えば、連続する2つの1バイトデータとして、0と1を考えれば、Exclusive-NORの出力は0となります(USB信号で、LからHに変わったとき、出力がLとなる)。
NRZI復号した信号からスタッフビットを取り除き(destuff)、パーソナル・コンピュータに送れば、USBプロトコル・アナライザーが作成できます。フルスピードで簡易なものであれば、5千円程度で作成できると思います。その1例がUSBプロトコル・アナライザー(フルスピード専用簡易型)です。
下図はUSBフルスピードにおけるD+信号(IN-DATA波形)の波形例です。USBホストが出したINパケットに対して、USBデバイスがデータを送っている様子を表しています。USBホストがデータを受信するとUSBデバイスにACK(acknowledge)パケットを送ります。波形データ:IN.zip
図6
INパケットの近傍を拡大します。INパケットの後に、USBデバイスがDATA0パケットでデータをUSBホストに送っています。転送データは64バイトで、最初の1バイトは'b'で、それ以外はゼロとしています。DATA0のPIDとPIDの後に、すぐデータが続きます。なお、'b'はASCIIコードで0x62、2進数で「0110 0010」です。
図7
DATA0パケットの終わりの部分を拡大します。64バイトのデータの後に、CRC16が続いています。'b'から始まる64バイトのデータのCRC16を算出すると、0x5926となります。図8から読み取れるCRC16の値に一致しています。なお、CRC16の算出にはすzのAVR研究で公開されているプログラムを、より一般化したものを使用しました。
図8
下図はUSBフルスピードにおけるD+信号(OUT-DATA波形)の波形例です。USBホストが出したOUTパケットに、続いてUSBデバイスへデータを送っている様子を表しています。USBデバイスがデータを受信すると、USBホストにACKパケットを送ります。波形データ:OUT.zip
図9
OUTパケットの近傍を拡大します。OUTパケットの後に、USBホストがDATA1パケットでデータをUSBデバイスに送っています。データは64バイトで、最初の1バイトは'a'で、それ以外はゼロです。なお、'a'はASCIIコードで0x61、2進数で「0110 0001」です。また、これまでにDATA0とDATA1パケットが出てきましたが、これらは、おおむね交互に使用されます。
図10
DATA1パケットの終わりの部分を拡大します。64バイトのデータの後に、CRC16が続いています。'a'から始まる64バイトのデータのCRC16を算出すると、0x0866となります。図11から読み取れるCRC16の値に一致しています。
図11
下図はUSBフルスピードにおけるD+信号とD-信号(リセット波形)です。波形データ:reset.zip
図12
上図のように、システム・リセットは2回あります。USBホストはUSBデバイスが接続された後、USBデバイスに1回目のリセット(D+もD-もL状態)を掛けます。その後、USBホストは、USBデバイスにGET_DISCRIPTORを発行し、USBデバイスのデバイス・ディスクリプタの情報を最初の8バイト分を読み取ります。その後、すぐに2回目のリセットを掛けます。その後、USBホストはUSBデバイスに対して、SET_ADDRESS(アドレス設定)、GET_DISCRIPTORなどを発行してゆきます。