組み込み開発者から見るUSBの仕組み(2)


[こちら](https://qiita.com/tom_S/items/d7a7f0d9a8ebf0bf1c1d)の記事の続きとなります。
前回はUSBの概要とクラスに関して説明しました。今回の記事では接続されたデバイスのクラスや設定などを認識するための、USBエニュメレーションやUSBディスクリプタに関して説明し、USBの転送方式に関しても説明いたします。

# USBエニュメレーション

　[前回の記事](https://qiita.com/tom_S/items/d7a7f0d9a8ebf0bf1c1d)にて説明させていただいたUSBエニュメレーションについて、もう少し掘り下げて説明します。
　USBエニュメレーションは、USB HOSTとUSB DEVICEが接続された際に必ず行われる通信のことを言います。この通信の主な目的はUSB DEVICEがどんなUSBクラスのデバイスなのか、どのような設定でどのようなインターフェースを持つかをUSB HOSTが認識するために行われます。また、デバイスドライバはUSBエニュメレーションによって認識した情報を基に、接続されたUSB DEVICEとの通信を行いますので、必ず必要なものです。
　そして、このUSBエニュメレーションで取得するUSB DEVICEの情報を、USBディスクリプタといいます。これに関してを下記で説明いたします。


# USBディスクリプタ

さきほどUSBエニュメレーションで使用すると説明したUSBディスクリプタに関してここで説明いたします。USBディスクリプタにはいくつかの種類が存在し、USB DEVICEのあらゆる情報が記載されています。例えば、PCにUSBメモリを接続した際、メーカー情報まで表示される場合等があるかと思いますが、これもUSBディスクリプタからメーカー名を取得しているためです。
ただ、USBディスクリプタを毎回全部取得するということは組み込み開発では稀かと思います。というのも、USBディスクリプタには通信をする上で必ず必要なものと、そうでないものがあるからです。以下に必ず必要なディスクリプタを挙げます。下記で示したものがわかっていれば通信自体は可能です。

| ディスクリプタ| 概要 | 
 | ---- | ---- |
| Device Descriptor | デバイスの概要を示すもの。一番初めに取得するディスクリプタ。クラスの情報も含む | 
| Configuration Descriptor | 消費電力と電力供給の設定や、デバイスにいくつインターフェイスがあるかを示すもの。インターフェイスの数だけ下記のinterface descriptorがある。 | 
| Intarface Descriptor | デバイスが持つインターフェースの仕様を示すもの。Configuration Descriptor一つにつき、必ず一つ以上のInterface descriptorが存在する。| 
| Endpoint Descriptor| 通信する際のエンドポイントの仕様を示す。Interface Descriptor一つにつき、必ず一つ以上のEndpoint Descriptorが存在する。| 


USBディスクリプタの取得に関しては、USB HOSTがUSB DEVICEに送ってほしいディスクリプタの種類を通知し、USB DEVICEは通知された種類のUSBディスクリプタをUSB HOSTへ送ることで、USBディスクリプタを認識します。

![USBディスクリプタ取得フロー図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266944/3c0e94b5-8373-e1e6-1628-fb84ef8fbd21.png)



また、上記の表にて示したConfiguration Descriptor,  Interface Descriptor,  Endpoint Descriptorの三つは、一つのデータとしてまとめてUSB HOSTに送られてきます。これは複数の設定可能なインターフェースを持つUSB DEVICEも存在する(現状そのようなデバイスの方が多いかもしれません)ため、このようになっています。
ここで示したもの以外にもディスクリプタは存在しますが、必ずしも認識する必要はありません。簡易的なシステムではあえて認識しないようにしているものもあります。よってここでは割愛させていただきます。
# USBの転送方式

先ほどのエニュメレーションの話のようにUSBの通信には様々な用途があり、用途に合わせていくつかの転送方式を使い分けています。
　USBの転送方式は、コントロール転送、バルク転送、アイソクロナス転送、インタラプト転送の四つがあります。簡単に下記に説明します
| 転送方式| 使用目的 | 使用用途 |  
| ---- | ---- | ---- |
| コントロール転送 | デバイスドライバとのやり取りをするため | USBエニュメレーションや、デバイス設定の変更 | 
| バルク転送 | データ欠けを許容しないデータ通信を行うため | アプリケーションとのデータの送受信 | 
| アイソクロナス転送 | データ欠けを許容するストリームデータの通信を行うため | オーディオや動画データの転送 | 
| インタラプト転送 | USB DEVICEからUSB HOSTへ特化した通信を行うため | マウスやキーボードの入力 | 

それぞれの通信に関してを下記で詳しく説明していきます。

## コントロール転送
 
　エニュメレーションや、デバイスドライバが行うようなデバイスの設定を行うのに使用される転送方式です。コントロール転送は一度に転送できるデータ量がバルク転送や、アイソクロナス転送より小さいです。基本的にはデバイスドライバのみが扱うことが多く、アプリケーションでは使用しません。

## バルク転送
 
　データ欠けがあった際にエラーと判断して認識して再転送を行う転送方式です。データを転送する際にデータ欠けを許容できない場合に扱います。ストレージにおけるデータ転送や、アプリケーションでUSBの通信を行う際はこのバルク転送を使いますので、開発者としては一番使われている転送方式かと思います。

## アイソクロナス転送
 
　通信時にデータ欠けがあったとしても、それを無視したまま通信を続ける転送方式です。主にオーディオデータのストリーミング再生や、映像出力を行う際など、データ欠けを許容できるもので使われます。ただ、データ欠けを許容するといってもあくまで仕様上のものです。製品を作るメーカーとしてはアイソクロナス転送といえど、データ欠けは極力ゼロにした状態で製品を作りたいので、実際の現場ではデータ欠けが起きないようにデバッグを行うこともあります。

## インタラプト転送
 
　USB DEVICEからUSB HOSTへ通信を行うのに特化した転送方式で、マウスやキーボード、ゲームパッドなどをUSB DEVICEとして接続した際に使用されています。USBはUSB HOSTからUSB DEVICEへデータを送ることで通信を開始するため、USB DEVICEからUSB HOSTへデータを送る場合、ポーリング(受信データがないか定期的に確認する通信)を行う形で通信をしなければいけません。マウスやキーボードの入力を受信する際にも変わりません、マウスやキーボードの入力はいつも発生しないので、これはとても効率が悪いです。よって、この効率の悪さを補うために、USB DEVICE→USB HOSTに特化したインタラプト転送があります