USBエニュメレーション(USB Enumeration)



本稿では、実際にロジックアナライザを使って記録したUSB通信データを用い、USBエニュメレーションの仕組みを説明します。



Index







はじめに

USBは最も実用的で幅広く普及しているコンピューターインターフェースです。以前のコンピューターにはCOMポート、プリンタポート、IEEE 1394、PS/2、D-SUBなど、多くのインターフェースがありましたが、今はこれら全てがUSBで代用できます。PCだけでなく、携帯電話・タブレット・組込みシステムもUSBインターフェースがあります。エレクトロニクスエンジニアにとって、USBについて学ぶことは非常に重要であると言えるでしょう。

本稿ではUSB関連の技術的知識を紹介しますが、すべての技術を完全に紹介するわけではなく(全てを紹介すれば、分厚い本が一冊書けるでしょう)、USBエニュメレーション(Enumeration)に関する技術的知識に焦点を当てて説明します。USBエニュメレーションは、USBがホストに挿入されてからホストと通信するフローを指します。



USBエニュメレーションを紹介する理由

USBエニュメレーションを特に紹介する理由は二つあります。まず、USBエニュメレーションはUSBの最も重要な技術の一つであり、エニュメレーションのフローを完了しなければUSBデバイスがホストと連結できないからです。もしあなたがUSB製品開発のエンジニアなら、USBエニュメレーションの仕組みを理解しなければUSBのファームウェアをデザインすることはできません。

次に、USBエニュメレーションは本では理解しにくいことが挙げられます。USBに関する書籍のほとんどは、USBエニュメレーションの説明にたくさんの表を用いています。これらの表は重要ですが、USBの開発をしたことのない初心者にとって、これらの表だけでUSBエニュメレーションの仕組み全体を理解するのは困難です。

本稿は本だけでは理解しづらい部分を補い、ユーザーにUSBエニュメレーションの仕組みをより分かりやすく示すことを目的としています。従って実際にロジックアナライザで得たUSB通信データを分析し、USBエニュメレーションのフローを説明します。実際の信号とパケットを提示することで、書籍や文献の表よりも容易に且つ明確に仕組みを理解することができます。

USBエニュメレーションに焦点を当てているのは、他の部分を重視しないということではありません。すでに多くの書籍や文献でUSBが紹介されているため、重複を避けるため、本稿ではUSBの一部の基礎知識を省略しています。そのため、USBの技術に詳しくない方は、やはり書籍や詳細な文献をお読みになることをお勧めします。その中で、USBエニュメレーションが分かりにくいと思われた場合は、本稿が理解の助けになることでしょう。



USBエニュメレーションとは?

USBエニュメレーションは、USBデバイスがホストに挿入されてから、ホストと通信するフローを指します。例として、ホテルのフロントを想像してみてください。フロントでは宿泊客にとって最適な部屋を用意するため、いくつか質問をする必要があります。

フロント:「ご宿泊は何名様ですか」
客:「一人です」
フロント:「お部屋は海側と山側どちらがお好みですか」
客:「海側がいいです」
フロント:「シャワーとバスタブどちらがお好みですか」
客:「シャワーがいいです」
......
......

こうして全ての質問をすることで、フロントは宿泊客に最適な部屋を用意することができます。USBエニュメレーションはこの例のようなフローであるとお考えください。USBデバイスがホストと接続しようとする時、ホストはデバイスのタイプやニーズを知る必要があります。そこでホストはデバイスにいくつか質問をし、接続可能であると判断した場合、デバイスにドライバインストールのプログラムを与え、USBエニュメレーションが完了します。



ロジックアナライザでUSBの通信を測定するには?

USBにはD+とD-の2本の信号線があり、USBを測定するには、D+、D-、Gndをロジックアナライザに接続する必要があります。USBのカバーを外してみると、下図のように赤・黒・緑・白の4本の信号線があるのが分かります。赤は電源、黒はGnd、緑はD+、白はD-です。USBカバーを外して黒・緑・白の線(切断しないこと)をロジックアナライザにつなぎます。


もしくは、下図のようなPerytechのUSB信号アダプタボードを購入して使用することもできます。このPCBの機能はシンプルで、USBの信号をピンヘッダに送るだけで測定ができます。ご自分で作成することも可能です。



ここで測定するデバイスはUSBキーボードです。まず信号線を接続します。下図のように、ロジックアナライザのチャンネルA0にD+を、A1にD-をつなぎます。



USBエニュメレーションはUSBがホストに挿入されるとすぐに始まるため、まずロジックアナライザのソフト設定を行ってから、USBキーボードをホストに挿入します。こうすることで、USBキーボードが挿入されてすぐの通信を測定することができるのです。まずロジックアナライザの「圧縮モード」(Compress Mode)を起動します。USBエニュメレーションには少し時間がかかるため(このUSBキーボードのテストでは約1秒)、長いデータを測定するには、ロジックアナライザを圧縮モードにする必要があります。続いてサンプリングレートを200MS/sに設定します。さらにトリガ条件を設定します。ここではチャンネルA0の立ち上がりエッジ(Rising Edge)のトリガを設定します。

設定ができたらRunを押します。このとき、USBデバイスはまだホストに接続されていないため、D+とD-は信号がなく、ロジックアナライザはトリガを待っている状態になります。USBデバイスをホストに挿入すると、USBが通信を開始し、ロジックアナライザのトリガがかかり、データを記録し始めます。

下図は記録したUSB信号です。約1.3秒のデータ内容が示されています。圧縮モードでなければ、200MS/sのサンプリングレートで1.3秒間記録するためには、チャンネルごとに260Mビットのメモリが必要です。



画面を拡大すると、信号の開始部分にD+とD-の信号がどちらも低電圧の状態になっている所が2か所あり、時間は10ms以上あります。これはUSBハブがUSBデバイスに送った2回のリセット信号です。もしUSB 2.0 High Speedデバイスであれば、リセット信号は1回だけ送られます。



さらに大きく拡大すると、下図の黄色の枠内がSOF(Start-of-Frame packet)で、各フレームが始まる時に送出されます。USB 1.1の各フレームの時間は1msです。下図の信号の間隔は約998.66us、さらにSOFパケット自体の幅が約1.34usなので、1msとなります。



さらにもっと拡大すると、下図のようにパケットの内容を見ることができます。信号とパケットを同時に観察することで、USB信号をより深く理解することができますが、一般的には時間の節約のためにパケットリスト機能によりパケットを検査します。Tool → Packet listを実行すると、パケットリストを開くことができます。



下図はパケットリスト機能を開いた画面です。パケットリスト機能はパケットのデータを一つずつリストアップするので、ユーザーはパケットのデータをより容易に検査できます。



USBパケットを分析するには?

これらのUSBパケットはUSBエニュメレーションの情報です。それではこれらのデータをどのように解読すればよいでしょうか。これにはUSB仕様書を参考にする必要があります。本稿で参考とするデータはUSB 2.0仕様書(USB 2.0 Specification)のもので、usb.orgからダウンロードできます。

ここでUSB通信のフォーマットを簡単に説明します。ホストがUSBデバイスを読み書きする時(例えばUSBハードディスク読み取りなど)、USBドライバーはこのリクエストを1つまたは複数のトランザクションに分けます。トランザクションはUSBのデータ転送の単位であり、各トランザクションは2~3つのUSBパケットで構成されます。トランザクションの1つ目のパケットはトークンパケットで、このトランザクションの形態を表します。このトランザクションにデータ転送のリクエストがある場合、2つ目のパケットがデータパケットになります。データは、ホストからUSBデバイス、またはUSBデバイスからホストの方向に転送することができます。全てのトランザクションにデータパケットがあるわけではなく、データパケットの有無、及びデータ転送の方向は、トークンによって決まります。最後のパケットはハンドシェイクパケットで、データ受信側がこのパケットを使って正確なデータを受信したかどうかを応答します。ホストまたはUSBデバイスどちらもデータ受信側になれます。

下図は1つ目から3つ目のUSBパケットを示したものですが、これら3つのパケットが1つのトランザクションを構成します。一番左の黄色い枠で示した部分がパケットのシリアルナンバーです。これはユーザーがパケットを検査しやすいようにロジックアナライザのソフトが設定したもので、USBの伝送データではありません。No.1のパケットの緑色の枠で示したものがトークンで、このトークンはセットアップです。USBデバイスがホストに接続されてすぐはアドレスとエンドポイントが設定されていないため、このセットアップパケットの後ろに続くアドレスとエンドポイントの数値は0になります。



2つめのパケットはデータパケットで、このトークンをセットアップするにはUSBデバイスのデータを送信します。このデータパケットのデータを分析する方法は、USB 2.0仕様書の「Format of Setup Data」を参考にします。この資料は下表のようにUSB Specification 2.0のTable 9-2にあり、それぞれのByteの意味を説明するものです。

Offset Field Size Value Description
0 bmRequestType 1 Bitmap Characteristics of request:

D7: Data transfer direction
  0 = Host-to-device
  1 = Device-to-host

D6...5: Type
  0 = Standard
  1 = Class
  2 = Vendor
  3 = Reserved

D4...0: Recipient
  0 = Device
  1 = Interface
  2 = Endpoint
  3 = Other
  4...31 = Reserved
1 bRequest 1 Value Specific request
2 wValue 2 Value Word-sized field that
varies according to request
4 wIndex 2 Index or Offset Word-sized field that varies
according to request; typically
used to pass an index or offset
6 wLength 2 Count Number of bytes to transfer
if there is a Data stage

Format of Setup Data,Source:USB 2.0 Specification Table 9-2



Byte 0はbmRequestTypeで、数値はこのリクエストの属性を表します。このByteはRecipient、Type、Data transfer directionの3つの部分に分かれます。ロジックアナライザのソフトは自動的にこのByteを3つのフィールドに分けており、Recipientの数値は0で、これはDeviceを意味します。Typeの数値0はStandardを表します。Data transfer direction(Dir)のソフトはすでにD→Hと表示しているので、データ伝送の方向はDeviceからHostです。

Byte 1はbRequestで、ここでの数値は0x06です。これが何を意味するのかは、下図に示すUSB仕様書のTable 9-4、Standard Request Codesを参照してください。この表の内容から、0x06はGET_DESCRIPTOR、つまりこのリクエストがGET_DESCRIPTORであることが分かります。

bRequest Value
GET_STATUS 0
CLEAR_FEATURE 1
Reserved for future use 2
SET_FEATURE 3
Reserved for future use 4
SET_ADDRESS 5
GET_DESCRIPTOR 6
SET_DESCRIPTOR 7
GET_CONFIGURATION 8
SET_CONFIGURATION 9
GET_INTERFACE 10
SET_INTERFACE 11
SYNCH_FRAME 12

Standard Request Codes,Source:USB 2.0 Specification Table 9-4



Byte 2~7はそれぞれwValue、wIndex、wLengthのフィールドで、それぞれのフィールドの幅は2 byteです。この3つのフィールドの意味はリクエストによって異なります。このリクエストはGET_DESCRIPTORで、USB仕様書の9.4.3節のGet Descriptorでは、リクエストがGET_DESCRIPTORである時の3つのフィールドが表す意味を、以下のように説明しています。

bmRequestType bRequest wValue wIndex wLength Data
10000000B GET_DESCRIPTOR Descriptor Type
and
Descriptor Index
Zero or
Language ID
Descriptor
Length
Descriptor

Get Descriptor,Source:USB 2.0 Specification



この内、wValueのHigh Byteはdescriptor typeを表し、ここでの数値は0x01です。USB仕様書9.4.3節から分かるように、この数値の意味は以下のTable 9-5を参考にします。表9-5から、数値1はDEVICEを意味すること、つまりこのdescriptorのタイプはDEVICEであることが分かります。

Descriptor Types Value
DEVICE 1
CONFIGURATION 2
STRING 3
INTERFACE 4
ENDPOINT 5
DEVICE_QUALIFIER 6
OTHER_SPEED_CONFIGURATION 7
INTERFACE_POWER 8

Descriptor Type,Source:USB 2.0 Specification



No.3のパケットはACKです。これはUSBデバイスが応答したもので、データを正確に受信したことを意味します。

No.4、5のパケットは、下図のようにそれぞれInとNAKで、この2つのパケットで1つのトランザクションになります。このトランザクションはデータを伝送しないため、パケットは2つだけです。USBのINとOUTはどちらもホスト側を主体としているため、INはホストがUSBデバイスからデータを読み取ることを意味します。ここでUSBデバイスがNAKの応答をしたのは、データが間違っているのではなく、伝送できるデータがないことを表します。伝送できるデータがない場合でも、USBデバイスは応答する必要があり、一定時間応答がない場合、ホストはUSBデバイスがオフラインであると判断します。このようなNAKパケットはデータを伝送しないので、ほとんどの場合は検査する必要はありません。本稿の他の部分でもNAKパケットについては省略しています。



ホストが絶えずInパケットを送信している場合はデータを受信することを意味し、USBデバイスがNo.9のパケットでやっと応答を始めました。この部分の応答は合計で18 Byteです。この伝送モードでは各パケットのデータは最高8 Byteなので、この部分のデータは3つのデータパケットに分けて応答されます。下の図では3つのパケットの内容を抜粋しています。



ではこれらのデータは何を表すのでしょうか。前のパケットからこのリクエストはGET_DESCRIPTOR、タイプはDeviceであるため、ホストが要求するデータはDevice Descriptorであることが分かります。Device Descriptorのデータフォーマットの内容は下のTable 9-8の通りです。Table 9-8と照らし合わせれば、これらのデータの各Byteの意味が分かります。

Offset Field Size Value Description
0 bLength 1 Number Size of this descriptor in bytes
1 bDescriptorType 1 Constant DEVICE Descriptor Type
2 bcdUSB 2 BCD USB Specification Release Number in Binary-Coded Decimal.
4 bDeviceClass Class 1 Class code (assigned by the USB-IF).
5 bDeviceSubClass 1 SubClass Subclass code (assigned by the USB-IF).
6 bDeviceProtocol 1 Protocol Protocol code (assigned by the USB-IF).
7 bMaxPacketSize0 1 Number Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid)
8 idVendor 2 ID Vendor ID (assigned by the USB-IF)
10 idProduct 2 ID Product ID (assigned by the manufacturer)
12 bcdDevice 2 BCD Device release number in binary-coded decimal
14 iManufacturer 1 Index Index of string descriptor describing manufacturer
15 iProduct 1 Index Index of string descriptor describing product
16 iSerialNumber 1 Index Index of string descriptor describing the device’s serial number
17 bNumConfigurations 1 Number Number of possible configurations

Standard Descriptor Type,Source:USB 2.0 Specification



ホストがUSBデバイスのDevice Descriptorを読み取るフローは以上の通りです。しかしこれで完了するわけではなく、完全なUSBエニュメレーションは少なくとも以下の5つのステップが必要です。

1.ホストがUSBデバイスのDevice Descriptorを読み取る
2.ホストが1つのアドレスをUSBデバイスに割り当てる
3.ホストがUSBデバイスのConfiguration Descriptorを読み取る
4.ホストがUSBデバイスのInterface Descriptorを読み取る
5.ホストがUSBデバイスのEndpoint Descriptorを読み取る

上で述べたUSBパケットの分析は、この1つ目のステップになります。他のステップの内容は異なりますが、分析方法は似ているため、ここでは説明を省略します。エニュメレーションの命令の順序は決まっておらず、USBデバイスはいかなる命令にも常に応答しなければなりません。ホストがDescriptorを重複して読み取ることもあります。

特筆すべきこととしては、1つのUSBデバイスはデバイスデスクリプタが1つしかありませんが、複数のコンフィギュレーションを有することができ、デバイスデスクリプタでコンフィギュレーションの数を定義します。また各コンフィギュレーションは複数のインターフェースを有することができ、コンフィギュレーションデスクリプタでインターフェースの数を定義します。さらに各インターフェースは複数のエンドポイントを有することができ、インターフェースデスクリプタでエンドポイントの数を定義します。このようにUSBエニュメレーション全体のデータアーキテクチャは階層化され、樹形図のようになっています。最上層がデバイスデスクリプタ、次にコンフィギュレーションデスクリプタ、そしてインターフェースデスクリプタ、最後がエンドポイントデスクリプタです。

本稿で分析したUSB通信データは、下のリンクからダウンロードすることができます。ロジックアナライザまたはMSOソフト(フリーダウンロード)をインストールし、このファイルをダウンロードすれば、USBキーボードのエニュメレーションフローを確認することができ、ハードウェアは必要ありません。またUSB 2.0仕様書を参考にすれば、USBエニュメレーションの仕組みを理解することができるでしょう。

Download



USBエニュメレーションのプログラミング方法

USBエニュメレーションの仕組みは理解できました。では、USBエニュメレーションはどうやってプログラミングすればよいでしょうか。一般的に、USBエニュメレーションのプログラムはUSBデータの表に記入するのに似ています。USBインターフェースを持つCPUはUSBコントローラーを有しており、USBコントローラーはエニュメレーションのフローにおいてこれらの表のデータをホストにフィードバックし、エニュメレーションの作業を完了します。

各USBコントローラーのエニュメレーションデータ表のパターンは同じというわけではなく、C言語のものもあれば、アセンブリ言語のものもあります。USBのICを扱う多くの会社は、コーディングの範例を提供しています。以下はあるUSBコントローラーのデバイスデスクリプタのコーディングです。

code uint8 DeviceDescriptor[0x12] =
{
/* bLength */
0x12,
/* bDescriptorType */
0x01,
/* bcdUSB */
0x10,
0x01,
/* bDeviceClass */
0x00,
/* bDeviceSubClass */
0x00,
/* bDeviceProtocol */
0x00,
/* bMaxPacketSize0, the pdiusbd12 chip has a maximize size of 16 */
0x10,
/* idVender, just for test, for commercial use, you should apply for it from the usb association */
0xF3,
0x04,
/* idProduct */
0x03,
0x01,
/* bcdDevice, version number of product */
0x07,
0x01,
/* iManufacturer */
0x00,
/* iProduct */
0x00,
/* iSerialNumber */
0x00,
/* bNumConfigurations, the number of configurations of a device, most device have only one configuration */
0x01
};



USB測定に対する圧縮モードの重要性

ロジックアナライザの圧縮機能は、USB測定の重要なポイントです。圧縮モードの有無を比較してみましょう。下図は、圧縮モードを使用せずに測定したUSB信号です。メモリは64k、サンプリングレートは200MS/sで、記録時間は約327.67usです。



パケットリストを見ると、4つのパケットしか記録していません。



次に、他社のロジックアナライザをテストしてみます。このロジックアナライザの最大圧縮倍率は256倍で、テスト条件は変えずに行います。下図から分かるように、記録時間は約40.478msです。



パケットリストを見ると20のパケットしか記録がなく、この記録時間では全く足りないことが分かります。USBキーボードを例とすると、完全なUSBエニュメレーションは400以上のパケットが必要で、20のパケットでは必要量の1/20にも届きません。



最後にPerytechロジックアナライザで圧縮モードをテストします。記録時間は約3.36秒です。



パケットリストを見ると、1680のパケットが記録されています。Perytechロジックアナライザの圧縮モードの最大圧縮倍率は100万倍で、このテストから圧縮モードで記録時間が大幅に増えることが分かります。



USB1.1がUSBの入門に最適である理由とは?

今回テストしたUSB信号はUSB 1.1です。今はUSB 3.1まで出ているのに、なぜUSB 1.1を例とするのかと思われるでしょう。私たちがUSB 1.1を入門用とするのは、いくつかの理由があります。まず、USB 1.1は全てのUSB仕様の基礎で、USB 2.0はUSB 1.1の延長で共に類似のアーキテクチャを有しています。そのためUSB 1.1を熟知していれば、USB 2.0もすぐに理解できます。USB 3.0は機能が追加されていますが、USB 2.0、USB 1.1と互換性があります。USB 3.0について学ぶには、USB 2.0、1.1も理解する必要があるのです。

次に、USB 1.1のチップはUSB 2.0よりも選択範囲が広く、価格も安く、下位8 bitのプロセッサの多くにはUSB 1.1が内蔵されています。USB 2.0であれば選択範囲が狭まり、価格も高くなります。またUSB 2.0以上は高速のため、PCBと配線材に厳格なインピーダンスマッチングが要求され、開発により多くのコストと時間がかかります。それに比べてUSB 1.1はかなりシンプルで、手半田のブレッドボードでも使えます。

またスピードについて言えば、大量のデータ伝送にはもちろんUSB 3.0が適していますが、実はほとんどの制御は少量のデータ伝送にのみ必要なのです。Baud Rate 19200 (19.2k bit)のRS232通信は産業用制御システムで今でもよく見られ、スピードが12MのUSB 1.1でも十分に余裕があります。

最後に最も重要なこととしては、USB 2.0の分析機器は非常に高価で、数万元のものから100万元に上る機器もあり、アマチュアの愛好家やメイカーにとってはなかなか手が出ません。USB 1.1の分析であれば、Perytechロジックアナライザで十分ですし、価格も1台数千元で済みます。またPerytechロジックアナライザの機能は幅広く、USBの分析はその内の1つの機能でしかありません。