macOSからPi Picoを使う - その18 [Pi Pico]
TinyUSBを読んでいる。前回はUSBのdevice descriptorをTinyUSBではどう扱っているかをみた。基本的にはUSBの規格に準拠した単なる構造体として定義されて、それをコールバックで返すようになっている。今日は残りのdescriptorを見てみる....
bEndpointAddressは
endpoint番号用には4ビットしか与えられていない。デバイス内でendpoint番号は重複できないので、defaultを含めて最大16個になる。
またbmAttributesはビット0..1で転送タイプ
ビット2..3でSynchronizationタイプ
ビット4..5でUsageタイプ
となっている。めんどくさい。詳細はUSB規格を参照のこと。
wMaxPacketSizeはビット0..10で最大パケットサイズをバイト数で表す。ビット11..12はhigh-speed isochronous とinterrupt endpointでは特別な意味がある。ビット13..15は0に予約。
bIntervalはフレーム単位のポーリング間隔を指定する。これもいっぱい場合分けがある。詳細はUSB規格を参照のこと。
descriptorを作るためのヘルパ関数として
なんかが定義されている。すごく便利、というわけではない。
string descriptorのbDescriptorTypeはTUSB_DESC_STRING=0x03。
USBのstring descriptorはローカライズされていることになっている。従って1つの文字列を読むときはそのindex番号と言語コードの両方を指定する。index番号0を読むとそのデバイスがサポートしている言語コードのリストを返すことになっている。従って、他のdescriptorにある文字列のindex値は1以上でないといけない。
TinyUSBではindex=0の場合のstructは定義されていないけどたとえば
のようなものを返す。wLANGIDは言語コードの配列で、USBの規格にリストになっている。例えばUS英語は0x0409で、日本語は0x0411など。
まじめに規格に対応しようとするとこの文字列のエンコードはUTF-16LEでないといけない。汎用のデバイス、たとえばHID、CDC、Audioデバイスとかなら真面目に則らないといけないのでちゃんとエンコードする必要がある。C文字列からdescriptor structへの変換や、言語の選択なんかはTinyUSBがやってくれればいいと思うんだけど、そうなっていなくて、exampleを見るとどれもほぼ同じ関数が書いてある。ASCII文字列のバイトごとに0x00を頭にくっつけて出力するようになっていて、かなり原始的なASCII→UTF-16LE変換になっている。
vendor specificなデバイスではそれほど拘る必要もないし、そもそもstring descriptorも必要はないと言える。
15.3.3 interface descriptorとendpoint descriptor
あとinterface descriptorとendpoint descriptorも備忘録を残しておく。Table 3: Interface descriptorの意味
bLength | descriptorのバイト数 |
bDescriptorType | interface descriptorはTUSB_DESC_INTERFACE=0x04 |
bInterfaceNumber | interface番号。configuration内で0から |
bAlternateSetting | 代替interfaceの指定 |
bNumEndpoints | interfaceが使うendpointの個数 |
bInterfaceClass | device descriptor参照 |
bInterfaceSubClass | 同上 |
bInterfaceProtocol | 同上 |
iInterface | string descriptorへのindex |
Table 4: endpoint descriptorの意味
bLength | descriptorのバイト数 |
bDescriptorType | endpoint descriptorはTUSB_DESC_ENDPOINT=0x05 |
bEndpointAddress | ビットフィールド |
bmAttributes | ビットフィールド |
wMaxPacketSize | endpointの最大パケットサイズ |
bInterval | ポーリング間隔 |
bEndpointAddressは
7: | ホストから見たデータ方向。0はOUT、1はIN |
6..4: | 0に予約 |
3..0: | endpoint番号 |
endpoint番号用には4ビットしか与えられていない。デバイス内でendpoint番号は重複できないので、defaultを含めて最大16個になる。
またbmAttributesはビット0..1で転送タイプ
00: | control |
01: | isochronous |
10: | bulk |
11: | interrupt |
ビット2..3でSynchronizationタイプ
00: | Synchronizationなし |
01: | Asynchronous |
10: | Adaptive |
11: | Synchronous |
ビット4..5でUsageタイプ
00: | Data endpoint |
01: | Feedback endpoint |
10: | Implicit feedback Data endpoint |
11: | 予約 |
となっている。めんどくさい。詳細はUSB規格を参照のこと。
wMaxPacketSizeはビット0..10で最大パケットサイズをバイト数で表す。ビット11..12はhigh-speed isochronous とinterrupt endpointでは特別な意味がある。ビット13..15は0に予約。
bIntervalはフレーム単位のポーリング間隔を指定する。これもいっぱい場合分けがある。詳細はUSB規格を参照のこと。
descriptorを作るためのヘルパ関数として
static inline uint8_t const * tu_desc_next(void const* desc); static inline uint8_t tu_desc_type(void const* desc); static inline uint8_t tu_desc_len(void const* desc); // Get direction from Endpoint address static inline tusb_dir_t tu_edpt_dir(uint8_t addr); // Get Endpoint number from address static inline uint8_t tu_edpt_number(uint8_t addr); static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir);
15.3.4 string descriptor
ついでにstring descriptor。// USB String Descriptor typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< Descriptor Type uint16_t unicode_string[]; } tusb_desc_string_t;
USBのstring descriptorはローカライズされていることになっている。従って1つの文字列を読むときはそのindex番号と言語コードの両方を指定する。index番号0を読むとそのデバイスがサポートしている言語コードのリストを返すことになっている。従って、他のdescriptorにある文字列のindex値は1以上でないといけない。
TinyUSBではindex=0の場合のstructは定義されていないけどたとえば
struct stringDescriptorAtIndex0 { uint8_t bLength; uint8_t bDescriptorType; // 0x03 for string descriptor uint16_t wLANGID[]; };
まじめに規格に対応しようとするとこの文字列のエンコードはUTF-16LEでないといけない。汎用のデバイス、たとえばHID、CDC、Audioデバイスとかなら真面目に則らないといけないのでちゃんとエンコードする必要がある。C文字列からdescriptor structへの変換や、言語の選択なんかはTinyUSBがやってくれればいいと思うんだけど、そうなっていなくて、exampleを見るとどれもほぼ同じ関数が書いてある。ASCII文字列のバイトごとに0x00を頭にくっつけて出力するようになっていて、かなり原始的なASCII→UTF-16LE変換になっている。
vendor specificなデバイスではそれほど拘る必要もないし、そもそもstring descriptorも必要はないと言える。
2021-07-15 20:40
nice!(0)
コメント(0)
コメント 0