深入了解STM32 USB HID类设备的使用(后篇)

文章目录

  • 目的
  • 基础说明
  • 项目构建与代码调整
  • 接收发送代码与测试
  • 示例链接
  • 报告描述符
  • 总结
  • 目的

    接上篇: 《STM32 USB使用记录:HID类设备(前篇)》

    USB HID 类的设备有个比较大的好处是大部分时候接入主机中都是可以免驱使用的。这篇文章将介绍下 STM32 中实现 USB HID 双向透传功能,结合免驱的特点,这在实际工作中是比较常用的。

    基础说明

    在上一篇文章中简单了解接触了下HID设备,了解了USB设备的各种描述符概念。在这篇文章追中我们要制作一个自定义的HID设备,实现双向透传功能,主要就是要调整配置描述符、端口、报告描述符等内容。

    项目构建与代码调整

    首先使用Cube工具来生成基础的项目,其它内容和上一篇文章一样,唯一不同的是 USB_DEVICE 这里选用 Custom Human Interface Device Class(HID) :

    生成的项目和上篇文章中差不多:

    因为是自定义的HID设备,所以报告描述符需要自己准备,这里修改 usbd_custom_hid_if.c 中的报告描述符实现双向透传功能:

    /** Usb HID report descriptor. */
    __ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
    {
    0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined 0xFF00)
    0x09, 0x00,        // Usage (0x00)
    0xA1, 0x01,        // Collection (Application)
    0x09, 0x01,        //   Usage (0x01)
    0x15, 0x00,        //   Logical Minimum (0)
    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
    0x75, 0x08,        //   Report Size (8)
    0x95, 0x40,        //   Report Count (64)
    0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0x02,        //   Usage (0x02)
    0x15, 0x00,        //   Logical Minimum (0)
    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
    0x75, 0x08,        //   Report Size (8)
    0x95, 0x40,        //   Report Count (64)
    0x91, 0x00,        //   Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
    0xC0,              // End Collection
    // 34 bytes
    };
    

    然后需要修改 usbd_conf.h 中一些定义值:

    /*---------- 接收缓冲区大小 -----------*/
    /*---------- 对于全速设备收和发一个包最大都为64字节 -----------*/
    #define USBD_CUSTOMHID_OUTREPORT_BUF_SIZE     64U
    /*---------- 报告描述符长度 -----------*/
    #define USBD_CUSTOM_HID_REPORT_DESC_SIZE     34U
    /*---------- 端电查询时间间隔 -----------*/
    /*---------- 对于全速设备该值为1表示最快可以每1ms通讯一次 -----------*/
    #define CUSTOM_HID_FS_BINTERVAL     0x5U
    /*---------- -----------*/
    

    还需要修改 usbd_customhid.h 中的定义值:

    // 接收一个包最大为64字节
    #define CUSTOM_HID_EPIN_SIZE        0x40U
    // 发送一个包最大为64字节
    #define CUSTOM_HID_EPOUT_SIZE        0x40U
    

    上面的定义值的调整也可以在Cube工具中直接进行配置。

    接收发送代码与测试

    usbd_custom_hid_if.c 文件中修改接收事件( OutEvent )部分代码:

    uint32_t size = 0;
    uint8_t buff[64];
    
    // 收到来自主机的数据时会触发该事件
    static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state)
    {
      UNUSED(event_idx);
      UNUSED(state);
    
      size = USBD_LL_GetRxDataSize(&hUsbDeviceFS, CUSTOM_HID_EPOUT_ADDR); // 获取收到的数据长度
    
      USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)(hUsbDeviceFS.pClassData);
      for(int i=0; i<size; i++)
      {
    	  buff[i]=hhid->Report_buf[i]; // 读取接收到的数据
      }
      
      USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, buff, size);
      
      // 开启下一次接收
      if (USBD_CUSTOM_HID_ReceivePacket(&hUsbDeviceFS) != (uint8_t)USBD_OK)
      {
    	  return -1;
      }
    
      return (USBD_OK);
    }
    

    至此就可以进行测试了,这里用的工具下载地址如下:
    https://pan.baidu.com/s/1i5QVmrN

    测试时依据设备的VID和PID来分辨设备,这两个值定义在 usbd_desc.c 文件中(注意十进制和十六进制的差别):

    #define USBD_VID     1155
    #define USBD_PID_FS     22352
    

    上面演示中接收部分代码有拷贝动作,这在高性能需求下其实是不太合适的,可以使用下面方式来处理:

    uint32_t size = 0;
    uint8_t buff[64]; // 接收缓冲区
    static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state)
    {
      size = USBD_LL_GetRxDataSize(&hUsbDeviceFS, CUSTOM_HID_EPOUT_ADDR); // 获取收到的数据长度
      USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, buff, size); // 发送数据
    
      // 开启下一次接收,设置接收缓冲区(默认的USBD_CUSTOM_HID_ReceivePacket方法中调用的其实也是这个)
      USBD_LL_PrepareReceive(&hUsbDeviceFS, CUSTOM_HID_EPOUT_ADDR, buff, USBD_CUSTOMHID_OUTREPORT_BUF_SIZE);
    
      return (USBD_OK);
    }
    

    需要注意的是上面方式第一次接到数据是用的还是默认设置的缓冲区。

    示例链接

    仓库地址: https://github.com/NaisuXu/STM32_MCU_Examples

    本示例为仓库中 USBD_HID_FS_H750

    报告描述符

    上面演示中用的是 USB FS ,该规范下HID一包数据最大为64Bytes,如果使用 USB HS ,那么每包最大为1024Bytes,报告描述符可以使用下这个:

    0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined 0xFF00)
    0x09, 0x00,        // Usage (0x00)
    0xA1, 0x01,        // Collection (Application)
    0x09, 0x01,        //   Usage (0x01)
    0x15, 0x00,        //   Logical Minimum (0)
    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
    0x75, 0x08,        //   Report Size (8)
    0x96, 0x00, 0x04,  //   Report Count (1024)
    0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0x02,        //   Usage (0x02)
    0x15, 0x00,        //   Logical Minimum (0)
    0x26, 0xFF, 0x00,  //   Logical Maximum (255)
    0x75, 0x08,        //   Report Size (8)
    0x96, 0x00, 0x04,  //   Report Count (1024)
    0x91, 0x00,        //   Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
    0xC0,              // End Collection
    // 36 bytes
    

    HID设备的报告描述符可以使用 HID Descriptor Tool 工具配置生成:
    https://www.usb.org/document-library/hid-descriptor-tool

    HS下一包1024字节数据用上面的测试工具好像无法满足了,可以使用 HIDTool 工具:
    https://www.usbzh.com/article/detail-1191.html
    不过该工具好像也有问题,发出去的第一个字节有问题。

    总结

    总体来说 STM32 中实现 USB HID 双向透传功能并不复杂。

    物联沃分享整理
    物联沃-IOTWORD物联网 » 深入了解STM32 USB HID类设备的使用(后篇)

    发表评论