CubeMX USB HID修改为WinUSB
Reference
本文基本参考自 WinUSB communication with STM32 round 2 (Part 1: Firmware) (参考代码在文章第一句话中) 和 Microsoft - WinUSB 设备
本文非完全翻译,可能会出现参考链接代码跟本文对不上的情况。如果你想完全弄清WinUSB的枚举流程,建议直接看微软的文档。
本文有一定历史,这里仅记录当时的实现。我自己重写了一套新的winusb实现,不需要修改usbd等usb核心文件,请查看:Flasher24/App
注意,如果使用这段程序,CubeMX 中 USBD_MAX_NUM_INTERFACES 必须大于等于5,否则winusb配置程序收不到OS描述符请求
0x00 关于如何对WINUSB进行DEBUG
请注意,Windows仅查询OS字符串描述符
一次,在开发过程中会造成麻烦。OS描述符存储在注册表中HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\UsbFlags\VVVVPPPPRRRR
(VVVV - VID; PPPP - PID; RRRR - 版本号)
请删除你USB设备对应的注册表项,然后使用USBDeview卸载设备,以便始终获得新的设备插入行为。
Src/usbd_desc.c
第128行,USBD_SUPPORT_USER_STRING_DESC
后添加
#if (USBD_SUPPORT_WINUSB==1)
uint8_t *USBD_WinUSBOSStrDescriptor(uint16_t *length);
uint8_t *USBD_WinUSBOSFeatureDescriptor(uint16_t *length);
uint8_t *USBD_WinUSBOSPropertyDescriptor(uint16_t *length);
#endif // (USBD_SUPPORT_WINUSB==1)
在USBD_DescriptorsTypeDef FS_Desc
中,最后的地方添加
#if (USBD_SUPPORT_WINUSB == 1)
, USBD_WinUSBOSFeatureDescriptor
, USBD_WinUSBOSPropertyDescriptor
#endif // (USBD_SUPPORT_WINUSB==1)
在/* USB_DeviceDescriptor */
后添加
#define USB_LEN_OS_FEATURE_DESC 0x28
#if defined ( __ICCARM__ ) /* IAR Compiler */
#pragma data_alignment=4
#endif /* defined ( __ICCARM__ ) */
__ALIGN_BEGIN uint8_t USBD_WINUSB_OSFeatureDesc[USB_LEN_OS_FEATURE_DESC] __ALIGN_END =
{
0x28, 0, 0, 0, // length
0, 1, // bcd version 1.0
4, 0, // windex: extended compat ID descritor
1, // no of function
0, 0, 0, 0, 0, 0, 0, // reserve 7 bytes
// function
0, // interface no
0, // reserved
'W', 'I', 'N', 'U', 'S', 'B', 0, 0, // first ID
0, 0, 0, 0, 0, 0, 0, 0, // second ID
0, 0, 0, 0, 0, 0 // reserved 6 bytes
};
#define USB_LEN_OS_PROPERTY_DESC 0x8E
#if defined ( __ICCARM__ ) /* IAR Compiler */
#pragma data_alignment=4
#endif /* defined ( __ICCARM__ ) */
__ALIGN_BEGIN uint8_t USBD_WINUSB_OSPropertyDesc[USB_LEN_OS_PROPERTY_DESC] __ALIGN_END =
{
0x8E, 0, 0, 0, // length 246 byte
0x00, 0x01, // BCD version 1.0
0x05, 0x00, // Extended Property Descriptor Index(5)
0x01, 0x00, // number of section (1)
//; property section
0x84, 0x00, 0x00, 0x00, // size of property section
0x1, 0, 0, 0, //; property data type (1)
0x28, 0, //; property name length (42)
'D', 0,
'e', 0,
'v', 0,
'i', 0,
'c', 0,
'e', 0,
'I', 0,
'n', 0,
't', 0,
'e', 0,
'r', 0,
'f', 0,
'a', 0,
'c', 0,
'e', 0,
'G', 0,
'U', 0,
'I', 0,
'D', 0,
0, 0,
// D6805E56-0447-4049-9848-46D6B2AC5D28
0x4E, 0, 0, 0, // ; property data length
'{', 0,
'1', 0,
'3', 0,
'E', 0,
'B', 0,
'3', 0,
'6', 0,
'0', 0,
'B', 0,
'-', 0,
'B', 0,
'C', 0,
'1', 0,
'E', 0,
'-', 0,
'4', 0,
'6', 0,
'C', 0,
'B', 0,
'-', 0,
'A', 0,
'C', 0,
'8', 0,
'B', 0,
'-', 0,
'E', 0,
'F', 0,
'3', 0,
'D', 0,
'A', 0,
'4', 0,
'7', 0,
'B', 0,
'4', 0,
'0', 0,
'6', 0,
'2', 0,
'}', 0,
0, 0,
};
在文件末尾添加
#if (USBD_SUPPORT_WINUSB==1)
const uint8_t USBD_OS_STRING[8] = {
'M',
'S',
'F',
'T',
'1',
'0',
'0',
USB_REQ_MS_VENDOR_CODE,
};
uint8_t *USBD_WinUSBOSStrDescriptor(uint16_t *length)
{
USBD_GetString((uint8_t *)USBD_OS_STRING, USBD_StrDesc, length);
return USBD_StrDesc;
}
uint8_t *USBD_WinUSBOSFeatureDescriptor(uint16_t *length)
{
*length = USB_LEN_OS_FEATURE_DESC;
return USBD_WINUSB_OSFeatureDesc;
}
uint8_t *USBD_WinUSBOSPropertyDescriptor(uint16_t *length)
{
*length = USB_LEN_OS_PROPERTY_DESC;
return USBD_WINUSB_OSPropertyDesc;
}
#endif // (USBD_SUPPORT_WINUSB==1)
Inc/usbd_conf.h
在文件中添加
#define USBD_SUPPORT_WINUSB 1
Middlewares/ST/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c
在static uint8_t USBD_GetLen(uint8_t *buf);
后添加
#if (USBD_SUPPORT_WINUSB==1)
static void USBD_WinUSBGetDescriptor(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
#endif // (USBD_SUPPORT_WINUSB==1)
在USBD_StdDevReq
函数中,case USB_REQ_CLEAR_FEATURE:
分支后面添加
#if (USBD_SUPPORT_WINUSB==1)
case USB_REQ_MS_VENDOR_CODE:
USBD_WinUSBGetDescriptor( pdev, req );
break;
#endif // (USBD_SUPPORT_WINUSB==1)
在USBD_StdItfReq
函数中,switch的default
分支中添加
#if (USBD_SUPPORT_WINUSB==1)
if ( req->bmRequest == 0xC1 ) {
USBD_WinUSBGetDescriptor( pdev, req );
break;
}
#endif // (USBD_SUPPORT_WINUSB==1)
在USBD_GetDescriptor
函数中,第一个switch的case USB_DESC_TYPE_STRING:
分支中的USBD_IDX_INTERFACE_STR
子分支后添加
#if (USBD_SUPPORT_WINUSB==1)
case 0xEE: // OS String
pbuf = (uint8_t *) pdev->pClass->GetWinUSBOSDescriptor(&len);
break;
#endif // (USBD_SUPPORT_WINUSB==1)
在该文件最后添加
#if (USBD_SUPPORT_WINUSB==1)
static void USBD_WinUSBGetDescriptor(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
{
uint16_t len;
uint8_t *pbuf;
switch (req->wIndex)
{
case 0x04: // compat ID
pbuf = pdev->pDesc->GetWinUSBOSFeatureDescriptor(&len);
break;
case 0x05:
pbuf = pdev->pDesc->GetWinUSBOSPropertyDescriptor(&len);
break;
default:
USBD_CtlError(pdev , req);
return;
}
if((len != 0)&& (req->wLength != 0))
{
len = MIN(len , req->wLength);
USBD_CtlSendData (pdev,
pbuf,
len);
}
}
#endif // (USBD_SUPPORT_WINUSB==1)
Middlewares/ST/STM32_USB_Device_Library/Core/Inc/usbd_def.h
在#define USB_REQ_SYNCH_FRAME
后添加
// WinUSB MS Vendor Code
#define USB_REQ_MS_VENDOR_CODE 0xA0
在typedef struct _Device_cb USBD_ClassTypeDef
中,末尾添加
#if (USBD_SUPPORT_WINUSB == 1)
uint8_t *(*GetWinUSBOSDescriptor)(uint16_t *length);
#endif
在typedef struct USBD_DescriptorsTypeDef
中,末尾添加
#if (USBD_SUPPORT_WINUSB==1)
uint8_t *(*GetWinUSBOSFeatureDescriptor)(uint16_t *length);
uint8_t *(*GetWinUSBOSPropertyDescriptor)(uint16_t *length);
#endif
Middlewares/ST/STM32_USB_Device_Library/HID/inc/usbd_hid.c
在static uint8_t USBD_HID_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);
后添加
#if (USBD_SUPPORT_WINUSB==1)
uint8_t* USBD_WinUSBOSStrDescriptor(uint16_t *length);
#endif //(USBD_SUPPORT_WINUSB==1)
在USBD_ClassTypeDef USBD_HID
中,末尾添加
#if (USBD_SUPPORT_WINUSB==1)
USBD_WinUSBOSStrDescriptor
#endif // (USBD_SUPPORT_WINUSB==1)
已有 6 条评论
2019年06月03日
写的很好,支持一下
2019年06月12日
asdasdasd
2021年02月03日
Please state the original document you are copying from.
请注明翻译原本文章出处.
2021年02月03日
Reference link added.
2021年02月04日
You didn't state where is the origin of source code.
2021年02月04日
Hi,
The code link is in the first sentence of the first reference.
I referenced its code, but it was not a complete copy. If you are looking for stm32 winusb code, I suggest you look at the Microsoft documentation, it is very comprehensive.