
USB HID Device on STM32
An Introduction to USB-HID
A Descriptor is a complete data structure that can be implemented through programming languages such as C, and stored in a USB device. It is used to describe all the attributes of a USB device, and the USB host requests this information through a series of commands. There are 5 standard descriptors for USB: device descriptor, configuration descriptor, string descriptor, interface descriptor, and endpoint descriptor.


The HID descriptor is associated with an interface (not an endpoint), so the device does not need to provide a HID descriptor for each endpoint.
Device descriptor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | struct _DEVICE_DEscriptOR_STRUCT { BYTE bLength; //設備描述符的字節數大小 BYTE bDescriptorType; //描述符類型編號,爲0x01 WORD bcdUSB; //USB版本號 BYTE bDeviceClass; //USB分配的設備類代碼,0x01~0xfe爲標準設備類,0xff爲廠商自定義類型,0x00不是在設備描述符中定義的,如HID BYTE bDeviceSubClass; //usb分配的子類代碼,同上,值由USB規定和分配的,HID設備此值爲0 BYTE bDeviceProtocl; //USB分配的設備協議代碼,同上HID設備此值爲0 BYTE bMaxPacketSize0; //端點0的最大包的大小 WORD idVendor; //廠商編號 WORD idProduct; //產品編號 WORD bcdDevice; //設備出廠編號 BYTE iManufacturer; //描述廠商字符串的索引 BYTE iProduct; //描述產品字符串的索引 BYTE iSerialNumber; //描述設備序列號字符串的索引 BYTE bNumConfiguration; //可能的配置數量 } |
Configuration descriptor
1 2 3 4 5 6 7 8 9 10 11 12 13 | struct _CONFIGURATION_DEscriptOR_STRUCT { BYTE bLength; //配置描述符的字節數大小 BYTE bDescriptorType; //描述符類型編號,爲0x02 WORD wTotalLength; //配置所返回的所有數量的大小 BYTE bNumInterface; //此配置所支持的接口數量 BYTE bConfigurationVale; //Set_Configuration命令需要的參數值 BYTE iConfiguration; //描述該配置的字符串的索引值 BYTE bmAttribute; //供電模式的選擇 BYTE MaxPower; //設備從總線提取的最大電流 } |
String descriptor
1 2 3 4 5 6 7 8 9 | struct _STRING_DEscriptOR_STRUCT { BYTE bLength; //字符串描述符的字節數大小 BYTE bDescriptorType; //描述符類型編號,爲0x03 BYTE SomeDescriptor[36]; //UNICODE編碼的字符串 } |
Interface descriptor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | struct _INTERFACE_DEscriptOR_STRUCT { BYTE bLength; //接口描述符的字節數大小 BYTE bDescriptorType; //描述符類型編號,爲0x04 BYTE bInterfaceNunber; //接口的編號 BYTE bAlternateSetting; //備用的接口描述符編號 BYTE bNumEndpoints; //該接口使用端點數,不包括端點0 BYTE bInterfaceClass; //接口類型 HID設備此值爲0x03 BYTE bInterfaceSubClass; //接口子類型 HID設備此值爲0或者1 BYTE bInterfaceProtocol; //接口所遵循的協議 BYTE iInterface; //描述該接口的字符串索引值 } |
Endpoint descriptor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | struct _ENDPOIN_DEscriptOR_STRUCT { BYTE bLength; //端點描述符的字節數大小 BYTE bDescriptorType; //描述符類型編號,爲0x05 BYTE bEndpointAddress; //端點地址及輸入輸出屬性 BYTE bmAttribute; //端點的傳輸類型屬性 WORD wMaxPacketSize; //端點收、發的最大包的大小 BYTE bInterval; //主機查詢端點的時間間隔 } |
HID read/write devices.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | INT CHidUsb::WriteDevice(HANDLE hUsbDevice, const CHAR *lpszBuf, INT nSize, BOOL bNeedRead) { DWORD dwSizeWritten; OVERLAPPED OverLapped; DWORD dwErrCode; INT nWriteSize; INT nNeedWriteSize; CHAR szHidBuf[HID_PACKAGE_SIZE + 1]; nNeedWriteSize = nSize; nWriteSize = 0; // 只能已HID包的格式發送 memset(&OverLapped, 0, sizeof (OverLapped)); OverLapped.hEvent = m_hWriteEvent; while (1) { if (nSize < 0) { break ; } nNeedWriteSize = HID_PACKAGE_SIZE; if (nNeedWriteSize > nSize) { nNeedWriteSize = nSize; } nSize -= nNeedWriteSize; memset(szHidBuf, 0xff, HID_PACKAGE_SIZE + 1); <span style= "color:#ff0000;" >szHidBuf[0] = 0</span>; // 這裏一定不要忘記,這個是ID,定義爲0,所以加上64個字節,所以一次操作爲65個字節 memcpy(szHidBuf + 1, lpszBuf, nNeedWriteSize); lpszBuf += nNeedWriteSize; <span style= "color:#ff0000;" > if (!::WriteFile(m_hUsbDevice, szHidBuf, HID_PACKAGE_SIZE + 1, &dwSizeWritten, &OverLapped))</span> { dwErrCode = GetLastError(); break ; } assert(dwSizeWritten == HID_PACKAGE_SIZE + 1); nWriteSize += dwSizeWritten; } if (bNeedRead) { SetEvent(m_hWaitEvent); } return nWriteSize; } |