最近有空测试了一下官方的VCP例程,使用感觉不错,将其稍微改动做了一个CDC回环测试,速率也不错,就是安装驱动有些麻烦,于是想直接将CDC改写成WINUSB不就不需要驱动了吗?于是抽空从之前写的STM32 WINUSB移植到HC32F460。一、移植的方法
修改的话主要是在CDC的基础上添加有关描述符的发送等函数。修改方法如下:
1.修改头文件usb_core_driver.h中的结构体usb_dev_class_func,添加如下成员:
2.修改usb_dev_stdreq.c中的void hd_usb_getdesc(usb_core_instance *pdev, const USB_SETUP_REQ *req),添加如下语句:
3.添加宏定义USBD_SUPPORT_USER_STRING_DESC:
4.修改usb_dev_cdc_class.c中的usb_dev_class_func class_cdc_cbk,添加成员变量:
5.添加extern __USB_ALIGN_BEGIN uint8_t usb_dev_strdesc[USB_MAX_STR_DESC_SIZ] __USB_ALIGN_END、__USB_ALIGN_BEGIN uint8_t USBD_WINUSB_OSFeatureDesc[USB_LEN_OS_FEATURE_DESC] __USB_ALIGN_END、uint8_t *USBD_WinUSBOSFeatureDescriptor(uint16_t *length):
6.修改配置描述符:
7.修改usb_dev_core.c中的void hd_usb_setup_process(usb_core_instance *pdev),添加如下语句:
8.继续在usb_dev_cdc_class.c中添加有关描述符的函数:
9.至此WINUSB修改完毕。为了测试发送速度,在做一些修改:
由于之前做STM32 WINUSB+CDC时将系统的驱动弄崩了,于是需要安装驱动。驱动安装完毕,电脑识别了USB设备:
测试USB上传速度HC32F460->PC:
速度相当不错。
二、遇到的问题
1.相比于STM32的uint8_t USBD_WinUSB_TransmitPacket(USBD_HandleTypeDef *pdev),由于HC32F460的USB发送函数void hd_usb_deveptx( usb_core_instance *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t buf_len)
是没有提供是否成功发送的状态值,因此不能保证数据因为USB总线繁忙而丢失。
可以看出很多数据并没有成功发送。
2.每次系统复位后,都会出现掉驱动的情况:
查看设备信息,发现有CM_PROB_FAILED_START问题,String Descriptors读不到:
=========================== USB Port2 ===========================
Connection Status : 0x01 (Device is connected)
Port Chain : 1-5-2
Properties : 0x01
IsUserConnectable : yes
PortIsDebugCapable : no
PortHasMultiCompanions : no
PortConnectorIsTypeC : no
======================== USB Device ========================
+++++++++++++++++ Device Information ++++++++++++++++++
Device Description : WinUSB 设备
Device ID : USB\VID_07E9&PID_07E9\00000000050C
Hardware IDs : USB\VID_07E9&PID_07E9&REV_0200 USB\VID_07E9&PID_07E9
Driver KeyName : {88bae032-5a81-49f0-bc3d-a4ff138216d6}\0008 ({88BAE032-5A81-49F0-BC3D-A4FF138216D6})
Driver : \SystemRoot\System32\drivers\WinUsb.sys (Version: 6.3.9600.18088 Date: 2015-10-11)
Driver Inf : C:\Windows\inf\winusb.inf
Legacy BusType : PNPBus
Class : USBDevice
Class GUID : {88bae032-5a81-49f0-bc3d-a4ff138216d6}
Service : WINUSB
Enumerator : USB
Location Info : Port_#0002.Hub_#0003
Location IDs : PCIROOT(0)#PCI(1400)#USBROOT(0)#USB(5)#USB(2), ACPI(_SB_)#ACPI(PCI0)#ACPI(XHC_)#ACPI(RHUB)#ACPI(HS05)#USB(2)
Container ID : {73a183c8-3781-5e8a-93bc-38be9dd6928c}
Manufacturer Info : WinUSB 设备
Capabilities : 0x14 (Removable, UniqueID)
Status : 0x01806400 (DN_HAS_PROBLEM, DN_DISABLEABLE, DN_REMOVABLE, DN_NT_ENUMERATOR, DN_NT_DRIVER)
Problem Code : 10 (CM_PROB_FAILED_START)
Power State : D3 (supported: D0, D2, D3, wake from D0, wake from D2)
+++++++++++++++++ Registry USB Flags +++++++++++++++++
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\UsbFlags\07E907E90200
osvc : REG_BINARY 01 A0
SkipContainerIdQuery : REG_BINARY 01 00
---------------- Connection Information ---------------
Connection Index : 0x02 (2)
Connection Status : 0x01 (DeviceConnected)
Current Config Value : 0x00
Device Address : 0x3E (62)
Is Hub : 0x00 (no)
Number Of Open Pipes : 0x00 (0)
Device Bus Speed : 0x01 (Full-Speed)
Data (HexDump) : 02 00 00 00 12 01 00 02 00 00 00 40 E9 07 E9 07 ...........@....
00 02 01 02 03 01 00 01 00 3E 00 00 00 00 00 01 .........>......
00 00 00 ...
--------------- Connection Information V2 -------------
Connection Index : 0x02 (2)
Length : 0x10 (16 bytes)
SupportedUsbProtocols : 0x03
Usb110 : 1 (yes)
Usb200 : 1 (yes)
Usb300 : 0 (no)
ReservedMBZ : 0x00
Flags : 0x00
DevIsOpAtSsOrHigher : 0 (Is not operating at SuperSpeed or higher)
DevIsSsCapOrHigher : 0 (Is not SuperSpeed capable or higher)
DevIsOpAtSsPlusOrHigher : 0 (Is not operating at SuperSpeedPlus or higher)
DevIsSsPlusCapOrHigher : 0 (Is not SuperSpeedPlus capable or higher)
ReservedMBZ : 0x00
Data (HexDump) : 02 00 00 00 10 00 00 00 03 00 00 00 00 00 00 00 ................
---------------------- Device Descriptor ----------------------
bLength : 0x12 (18 bytes)
bDescriptorType : 0x01 (Device Descriptor)
bcdUSB : 0x200 (USB Version 2.00)
bDeviceClass : 0x00 (defined by the interface descriptors)
bDeviceSubClass : 0x00
bDeviceProtocol : 0x00
bMaxPacketSize0 : 0x40 (64 bytes)
idVendor : 0x07E9
idProduct : 0x07E9
bcdDevice : 0x0200
iManufacturer : 0x01 (String Descriptor 1)
iProduct : 0x02 (String Descriptor 2)
iSerialNumber : 0x03 (String Descriptor 3)
bNumConfigurations : 0x01 (1 Configuration)
Data (HexDump) : 12 01 00 02 00 00 00 40 E9 07 E9 07 00 02 01 02 .......@........
03 01 ..
------------------ Configuration Descriptor -------------------
bLength : 0x09 (9 bytes)
bDescriptorType : 0x02 (Configuration Descriptor)
wTotalLength : 0x0020 (32 bytes)
bNumInterfaces : 0x01 (1 Interface)
bConfigurationValue : 0x01 (Configuration 1)
iConfiguration : 0x00 (No String Descriptor)
bmAttributes : 0xC0
D7: Reserved, set 1 : 0x01
D6: Self Powered : 0x01 (yes)
D5: Remote Wakeup : 0x00 (no)
D4..0: Reserved, set 0 : 0x00
MaxPower : 0x32 (100 mA)
Data (HexDump) : 09 02 20 00 01 01 00 C0 32 09 04 00 00 02 FF 00 .. .....2.......
00 00 07 05 01 02 40 00 00 07 05 81 02 40 00 00 ......@......@..
---------------- Interface Descriptor -----------------
bLength : 0x09 (9 bytes)
bDescriptorType : 0x04 (Interface Descriptor)
bInterfaceNumber : 0x00
bAlternateSetting : 0x00
bNumEndpoints : 0x02 (2 Endpoints)
bInterfaceClass : 0xFF (Vendor Specific)
bInterfaceSubClass : 0x00
bInterfaceProtocol : 0x00
iInterface : 0x00 (No String Descriptor)
Data (HexDump) : 09 04 00 00 02 FF 00 00 00 .........
----------------- Endpoint Descriptor -----------------
bLength : 0x07 (7 bytes)
bDescriptorType : 0x05 (Endpoint Descriptor)
bEndpointAddress : 0x01 (Direction=OUT EndpointID=1)
bmAttributes : 0x02 (TransferType=Bulk)
wMaxPacketSize : 0x0040 (64 bytes)
bInterval : 0x00 (ignored)
Data (HexDump) : 07 05 01 02 40 00 00 ....@..
----------------- Endpoint Descriptor -----------------
bLength : 0x07 (7 bytes)
bDescriptorType : 0x05 (Endpoint Descriptor)
bEndpointAddress : 0x81 (Direction=IN EndpointID=1)
bmAttributes : 0x02 (TransferType=Bulk)
wMaxPacketSize : 0x0040 (64 bytes)
bInterval : 0x00 (ignored)
Data (HexDump) : 07 05 81 02 40 00 00 ....@..
----------------- Device Qualifier Descriptor -----------------
Error : ERROR_GEN_FAILURE
-------------------- String Descriptors -------------------
String descriptors are not available (because the device has problem code CM_PROB_FAILED_START)
重新安装驱动设备工作正常。
三、解决方法
对于第一个问题,暂且希望官方能做一个修改。下面重点讲解一下解决的方法。
首先对比一下STM32与HC32F460关于USB的Setup阶段的处理方法:
STM32:
USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup)
{
USBD_StatusTypeDef ret;
USBD_ParseSetupRequest(&pdev->request, psetup);
pdev->ep0_state = USBD_EP0_SETUP;
pdev->ep0_data_len = pdev->request.wLength;
switch (pdev->request.bmRequest & 0x1FU)
{
case USB_REQ_RECIPIENT_DEVICE:
ret = USBD_StdDevReq(pdev, &pdev->request);
break;
case USB_REQ_RECIPIENT_INTERFACE:
ret = USBD_StdItfReq(pdev, &pdev->request);
break;
case USB_REQ_RECIPIENT_ENDPOINT:
ret = USBD_StdEPReq(pdev, &pdev->request);
break;
default:
ret = USBD_LL_StallEP(pdev, (pdev->request.bmRequest & 0x80U));
break;
}
return ret;
}
USBD_StatusTypeDef USBD_StdDevReq(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
{
USBD_StatusTypeDef ret = USBD_OK;
switch (req->bmRequest & USB_REQ_TYPE_MASK)
{
case USB_REQ_TYPE_CLASS:
case USB_REQ_TYPE_VENDOR:
ret = (USBD_StatusTypeDef)pdev->pClass->Setup(pdev, req);
break;
case USB_REQ_TYPE_STANDARD:
switch (req->bRequest)
{
case USB_REQ_GET_DESCRIPTOR:
USBD_GetDescriptor(pdev, req);
break;
case USB_REQ_SET_ADDRESS:
USBD_SetAddress(pdev, req);
break;
case USB_REQ_SET_CONFIGURATION:
ret = USBD_SetConfig(pdev, req);
break;
case USB_REQ_GET_CONFIGURATION:
USBD_GetConfig(pdev, req);
break;
case USB_REQ_GET_STATUS:
USBD_GetStatus(pdev, req);
break;
case USB_REQ_SET_FEATURE:
USBD_SetFeature(pdev, req);
break;
case USB_REQ_CLEAR_FEATURE:
USBD_ClrFeature(pdev, req);
break;
default:
USBD_CtlError(pdev, req);
break;
}
break;
default:
USBD_CtlError(pdev, req);
break;
}
return ret;
}
HC32F460:
void hd_usb_setup_process(usb_core_instance *pdev)
{
USB_SETUP_REQ req;
hd_usb_parsesetupreq(pdev , &req);
switch (req.bmRequest & 0x1Fu)
{
case USB_REQ_RECIPIENT_DEVICE:
hd_usb_standarddevreq (pdev, &req);
break;
case USB_REQ_RECIPIENT_INTERFACE:
hd_usb_standarditfreq(pdev, &req);
break;
case USB_REQ_RECIPIENT_ENDPOINT:
hd_usb_standardepreq(pdev, &req);
break;
default:
hd_usb_stalldevep(pdev, req.bmRequest & 0x80u);
break;
}
}
void hd_usb_standarddevreq(usb_core_instance *pdev, USB_SETUP_REQ *req)
{
if(req->bRequest == USB_REQ_GET_DESCRIPTOR)
{
hd_usb_getdesc (pdev, req) ;
}
else if(req->bRequest == USB_REQ_SET_ADDRESS)
{
hd_usb_setaddr(pdev, req);
}
else if(req->bRequest == USB_REQ_SET_CONFIGURATION)
{
hd_usb_setconfig (pdev , req);
}
else if(req->bRequest == USB_REQ_GET_CONFIGURATION)
{
hd_usb_getconfig (pdev , req);
}
else if(req->bRequest == USB_REQ_GET_STATUS)
{
hd_usb_getstatus (pdev , req);
}
else if(req->bRequest == USB_REQ_SET_FEATURE)
{
hd_usb_setfeature (pdev , req);
}
else if(req->bRequest == USB_REQ_CLEAR_FEATURE)
{
hd_usb_clrfeature (pdev , req);
}
else
{
if (pdev->dev.class_callback->ep0_setup (pdev, req))
{
hd_usb_ctrlerr(pdev);
}
}
}
可以看出STM32在USBD_StdDevReq中遍历常见情况后会直接抛出USBD_CtlError(pdev, req);,而HC32F460则是判断pdev->dev.class_callback->ep0_setup (pdev, req)才抛出hd_usb_ctrlerr(pdev)。就是这个差异导致掉驱动。实际调试可以定位到这个问题:
修改void hd_usb_setup_process(usb_core_instance *pdev)中的hd_usb_standarddevreq (pdev, &req)和hd_usb_standarditfreq(pdev, &req):
从新安装驱动之后,不再掉驱动了:
设备工作正常。
WINUSB代码:
HC32F460_WINUSB.zip
(1.06 MB)
CDC代码:
HC32F460_CDC.zip
(1.06 MB)
INF文件:
Driver Package1.zip
(11.77 KB)
上位机测速软件:
WINUSB.zip
(9.79 MB)
|