SSブログ

macOSからPi Picoを使う - その18 [Pi Pico]

TinyUSBを読んでいる。前回はUSBのdevice descriptorをTinyUSBではどう扱っているかをみた。基本的にはUSBの規格に準拠した単なる構造体として定義されて、それをコールバックで返すようになっている。今日は残りの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;
string descriptorのbDescriptorTypeはTUSB_DESC_STRING=0x03。

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[];
};
のようなものを返す。wLANGIDは言語コードの配列で、USBの規格にリストになっている。例えばUS英語は0x0409で、日本語は0x0411など。

まじめに規格に対応しようとするとこの文字列のエンコードはUTF-16LEでないといけない。汎用のデバイス、たとえばHID、CDC、Audioデバイスとかなら真面目に則らないといけないのでちゃんとエンコードする必要がある。C文字列からdescriptor structへの変換や、言語の選択なんかはTinyUSBがやってくれればいいと思うんだけど、そうなっていなくて、exampleを見るとどれもほぼ同じ関数が書いてある。ASCII文字列のバイトごとに0x00を頭にくっつけて出力するようになっていて、かなり原始的なASCII→UTF-16LE変換になっている。

vendor specificなデバイスではそれほど拘る必要もないし、そもそもstring descriptorも必要はないと言える。
nice!(0)  コメント(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。