纪国圣 发表于 2021-10-2 10:19

【华大测评】+ HC32F460 WINUSB移植、遇到的问题与解决方法

最近有空测试了一下官方的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_funcclass_cdc_cbk,添加成员变量:


5.添加extern __USB_ALIGN_BEGIN uint8_t usb_dev_strdesc __USB_ALIGN_END、__USB_ALIGN_BEGIN uint8_t USBD_WINUSB_OSFeatureDesc __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.18088Date: 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代码:

CDC代码:

INF文件:

上位机测速软件:










精灵魔仙 发表于 2021-10-3 14:43

看了下好像是OS 1.0的,何不同时移植BOS Descriptor OS 2.0的版本?

duo点 发表于 2021-10-4 14:34

讲解超详细的

纪国圣 发表于 2021-10-30 09:29

上传一份Microsoft_OS_2.0_Descriptors版本:





kiwis66 发表于 2021-11-1 10:07

学习了,比较详细,
感谢

vip3 发表于 2023-12-6 14:21

实现不了,安装驱动失败

h32446975 发表于 2024-1-24 10:25

楼主描述的很详细,非常好的分享。

biscuit2 发表于 2024-2-28 09:25

楼主你好,我下载你的 《【华大测评】+ HC32F460 WINUSB移植、遇到的问题与解决方法》里面的WINUSB源码到HC32F460PETB芯片里,电脑USB显示HDSC WINUSB有感叹号,请教一下原因,万分感谢。

biscuit2 发表于 2024-3-13 09:09

例程里有一处BUG,修改后解决问题。

小夏天的大西瓜 发表于 2024-3-27 08:30

讲解的很详细,按照这个过程能够正常配置
页: [1]
查看完整版本: 【华大测评】+ HC32F460 WINUSB移植、遇到的问题与解决方法