STM32 USB HID 自定义设备 bulk 传输

2 篇文章 1 订阅
1 篇文章 0 订阅

STM32 USB HID 自定义设备 bulk 传输


ST(意法半导体公司)为STM32系列处理器编写了外设USB的库,并提供了很好的参考例程,本文就是参考ST提供的例程,在STM32F4 discovery板子上实现usb bulk传输。Host端是在linux平台上利用libusb库函数写的读写USB应用。

本次实现在STM32 USB例程中的Device HID 鼠标例程基础上添加bulk传输端点修改而来。

usb_conf.h 文件中添加 bulk传输端点

/*
*   endpoint 0x80 and 0x00 are used for enumerating device.
*   endpoint 0x81 and 0x80 are used for control xfer.
*/
#define HID_IN_EP                    0x81
#define HID_OUT_EP                   0x01
#define HID_IN_PACKET                4
#define HID_OUT_PACKET               4

// add bulk xfer endpoint
#define HID_IN_BULK_EP               0x82 // endpoint in 
#define HID_OUT_BULK_EP              0x02 // endpoint out
// define endpoint max packet size
#define HID_IN_BULK_PACKET           64 
#define HID_OUT_BULK_PACKET          64

usb_desc.c 中修改设备描述符

把bDeviceClass值改为0xFF,表示用户自定义设备;修改VID 和 PID,例如以下程序中的值。

__ALIGN_BEGIN uint8_t USBD_DeviceDesc[USB_SIZ_DEVICE_DESC] __ALIGN_END =
  {
    // the size of device descriptor
    0x12,                       /*bLength */

    // descriptor type. device descripor type is 0x01
    USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/

    // we use usb2.0
    0x00,                       /*bcdUSB */
    0x02,

    // user defined device
    0xff,                       /*bDeviceClass*/ 
    0x00,                       /*bDeviceSubClass*/

    0x00,                       /*bDeviceProtocol*/

    // endpoint 0 max packet size
    USB_OTG_MAX_EP0_SIZE,      /*bMaxPacketSize*/

    // vendor ID
    LOBYTE(USBD_VID),           /*idVendor*/
    HIBYTE(USBD_VID),           /*idVendor*/

    // Product ID
    LOBYTE(USBD_PID),           /*idVendor*/
    HIBYTE(USBD_PID),           /*idVendor*/

    // Device version
    0x00,                       /*bcdDevice rel. 2.00*/
    0x02,
    USBD_IDX_MFC_STR,           /*Index of manufacturer  string*/
    USBD_IDX_PRODUCT_STR,       /*Index of product string*/
    USBD_IDX_SERIAL_STR,        /*Index of serial number string*/

    // the number of configurations 0x01
    USBD_CFG_MAX_NUM            /*bNumConfigurations*/
  } ; /* USB_DeviceDescriptor */

修改配置描述符

在原有的鼠标配置描述符中添加bulk xfer的两个端点描述符(IN and OUT)。最后, 记得修改配置描述符的长度,不然配置描述符传输不完整。

在usbd_hid_core.h 文件中修改配置描述符的大小 USB_HID_CONFIG_DESC_SIZ

        #define USB_HID_CONFIG_DESC_SIZ       46

配置描述符中的接口描述符也要做相应的调整,将端点数目 bNumEndpoints 改为4个,将接口子类bInterfaceSubClass改成 0x00, 将接口协议改成0x00。nInterfaceProtocol 修改成0x00。具体描述见下面代码中的注释。

__ALIGN_BEGIN static uint8_t USBD_HID_CfgDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =
{
  0x09, /* bLength: Configuration Descriptor size */
  USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
  USB_HID_CONFIG_DESC_SIZ,
  /* wTotalLength: Bytes returned */
  0x00,
  0x01,         /*bNumInterfaces: 1 interface*/
  0x01,         /*bConfigurationValue: Configuration value*/
  0x00,         /*iConfiguration: Index of string descriptor describing
  the configuration*/
  0xE0,         /*bmAttributes: bus powered and Support Remote Wake-up */
  0x32,         /*MaxPower 100 mA: this current is used for detecting Vbus*/

  /************** Descriptor of Joystick Mouse interface ****************/
  /* 09 */
  0x09,         /*bLength: Interface Descriptor size*/
  USB_INTERFACE_DESCRIPTOR_TYPE,/*bDescriptorType: Interface descriptor type*/
  0x00,         /*bInterfaceNumber: Number of Interface*/
  0x00,         /*bAlternateSetting: Alternate setting*/
  0x04,         /*bNumEndpoints*/
  0x00,         /*bInterfaceClass: HID*/
  0x00,         /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
  0x00,         /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
  0,            /*iInterface: Index of string descriptor*/
  /******************** Descriptor of Mouse endpoint ********************/
  /* 18 */
  0x07,          /*bLength: Endpoint Descriptor size*/
  USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/

  HID_IN_EP,     /*bEndpointAddress: Endpoint Address (IN)*/
  0x03,          /*bmAttributes: Interrupt endpoint*/
  HID_IN_PACKET, /*wMaxPacketSize: 4 Byte max */
  0x00,
  0x0A,          /*bInterval: Polling Interval (10 ms)*/
  /******************** Descriptor of Mouse endpoint ********************/
  /* 25 */
  0x07,          /*bLength: Endpoint Descriptor size*/
  USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/

  HID_OUT_EP,     /*bEndpointAddress: Endpoint Address (IN)*/
  0x03,          /*bmAttributes: Interrupt endpoint*/
  HID_IN_PACKET, /*wMaxPacketSize: 4 Byte max */
  0x00,
  0x0A,          /*bInterval: Polling Interval (10 ms)*/
  /******************** Descriptor of bulk xfer endpoint ********************/
  /* 32 */
  0x07,          /*bLength: Endpoint Descriptor size*/
  USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/

  HID_IN_BULK_EP,     /*bEndpointAddress: Endpoint Address (IN)*/
  0x02,          /*bmAttributes: bulk endpoint*/
  HID_IN_BULK_PACKET, /*wMaxPacketSize: 64 Byte max */
  0x00,
  0x0A,          /*bInterval: Polling Interval (10 ms)*/
  /******************** Descriptor of bulk xfer endpoint ********************/
  /* 39 */
  0x07,          /*bLength: Endpoint Descriptor size*/
  USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/

  HID_OUT_BULK_EP,     /*bEndpointAddress: Endpoint Address (OUT)*/
  0x02,          /*bmAttributes: bulk endpoint*/
  HID_OUT_BULK_PACKET, /*wMaxPacketSize: 64 Byte max */
  0x00,
  0x0A,          /*bInterval: Polling Interval (10 ms)*/
  /* 46 */
} ;

至此,描述符的修改就完成了。由于是bulk传输,所以不需要定义报告描述符,只有中断传输和控制传输需要定义报告描述符。接下来需要添加发送和接收数据的接口函数了。

初始化端点

usb_hid_core.c 中,HID 初始化函数中添加对 bulk I/O 端点的初始化,直接追加在鼠标所使用端点后面。在最后又添加了bulk xfer OUT 端口的发送初始化函数,以便让USB知道当接收到数据后数据该存储到哪儿。数组 USB_Rx_Buffer[HID_OUT_BULK_PACKET] 是用户自己定义的一个数据缓冲区,大小设为该端点的最大包长度即可。

static uint8_t  USBD_HID_Init (void  *pdev, 
                               uint8_t cfgidx)
{
  printf("%s\r\n", __FUNCTION__);
  /* Open EP IN */
  DCD_EP_Open(pdev,
              HID_IN_EP,
              HID_IN_PACKET,
              USB_OTG_EP_INT);

  /* Open EP OUT */
  DCD_EP_Open(pdev,
              HID_OUT_EP,
              HID_OUT_PACKET,
              USB_OTG_EP_INT);

  /* Open EP IN BULK */
  DCD_EP_Open(pdev,
              HID_IN_BULK_EP,
              HID_IN_BULK_PACKET,
              USB_OTG_EP_BULK);

  /* Open EP OUT BULK*/
  DCD_EP_Open(pdev,
              HID_OUT_BULK_EP,
              HID_OUT_BULK_PACKET,
              USB_OTG_EP_BULK);

   /* Prepare Out endpoint to receive next packet */
   DCD_EP_PrepareRx(pdev,
                    HID_OUT_BULK_EP,
                    (uint8_t*)(USB_Rx_Buffer),
                    HID_OUT_BULK_PACKET);

  return USBD_OK;
}

添加 OUT 端点接收HOST发出数据的回调函数。类似地,添加 IN端点回调函数发送数据到HOST

在usb_hid_core.c 中,修改USB_HID_cb 函数数组中的函数指针。

USBD_Class_cb_TypeDef  USBD_HID_cb = 
{
  USBD_HID_Init,
  USBD_HID_DeInit,
  USBD_HID_Setup,
  NULL, /*EP0_TxSent*/  
  NULL, /*EP0_RxReady*/
  USBD_HID_DataIn, /* add your IN point callback to send data to HOST */
  USBD_HID_DataOut, /* add your OUT point callback to receive data from HOST*/
  NULL, /*SOF */
  NULL,
  NULL,      
  USBD_HID_GetCfgDesc,
#ifdef USB_OTG_HS_CORE  
  USBD_HID_GetCfgDesc, /* use same config as per FS */
#endif  
};

// USB OUT endpoint callback
static uint8_t USBD_HID_DataOut (void  *pdev, uint8_t epnum)
{
    uint16_t USB_Rx_Cnt;

    USB_Rx_Cnt = ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_count;

    // add your own data to process the received data 
    /*    
    *    printf_the_received_data((char *)USB_Rx_Buffer, USB_Rx_Cnt);
    */

  /* Prepare Out endpoint to receive next packet */
    DCD_EP_PrepareRx(pdev,
                       HID_OUT_BULK_EP,
                       (uint8_t*)(USB_Rx_Buffer),
                       HID_OUT_BULK_PACKET);

  return USBD_OK;
}

static uint8_t USBD_HID_DataIn(void  *pdev, uint8_t epnum)
{
    int USB_Tx_length = HID_IN_BULK_PACKET;

      // copy your data to buffer, then send through USB IN endpoint
      /*
      *   buffer_copy(APP_Rx_Buffer, USB_Tx_length);
      */
      /* Prepare the available data buffer to be sent on IN endpoint */
      DCD_EP_Tx (pdev,
                 CDC_IN_EP,
                 (uint8_t*)&APP_Rx_Buffer[USB_Tx_ptr],
                 USB_Tx_length);

     return USBD_OK;
}

验证

将USB代码编译后下载到STM32F4Discovery 板子上运行,连接USB线到PC,windows操作系统下在设备管理器中可以看到HID设备,查看VID/PID 或者USB 显示出的Product string和你代码中设定的一致的就是我们的USB 设备。


STM32 USB 上位机软件实现

请查看 STM32 USB 上位机程序实现,利用 libusb 在 linux 平台上 使用 bulk xfer 和 STM32F4Discovery 传输数据。对应的源码在 http://download.csdn.net/detail/chengwenyang/9479835 可以下载。

  • 13
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
### 回答1: STM32 USB HID是指STM32系列单片机的一种USB设备协议,在该协议下,STM32单片机可以作为一个USB HID(Human Interface Device)设备与计算机进行数据通信,实现数据传输设备控制等功能。 在STM32 USB HID通信中,STM32单片机通常使用USB接口作为数据传输的主要通信接口,通过该接口可以实现与计算机的数据交互。在该模式下,STM32单片机作为一个USB设备,可以模拟各种不同的传感器、按键、鼠标等设备,从而实现与计算机的数据交互的目的。 可以使用ST的STM32CubeMX软件来配置STM32USB HID功能,通过配置一些参数,可以支持多种不同的USB HID设备类型,如鼠标、键盘、游戏手柄等。通过自定义USB HID协议,还可以实现更加丰富的功能,例如在游戏开发中,可以使用STM32 USB HID协议来实现游戏手柄控制等。 总之,STM32 USB HIDSTM32系列单片机的一种重要的USB设备协议,可以广泛应用于各种数据传输设备控制场景,具有易用性、可扩展性以及高效性等优点,在未来的嵌入式系统应用中具有广泛的发展前景。 ### 回答2: STM32 USBHID,是指在STM32单片机上实现USB HID(Human Interface Device)协议的技术。USB HID是一种USB设备通讯协议,它定义了如何在计算机和外设之间传输数据,并规定了外设的功能。比如键盘、鼠标、游戏手柄、触摸屏等都可以通过USB HID协议来实现数据传输。 在STM32单片机上实现USB HID协议,可以使STM32连接计算机时,被识别为一个HID设备,从而完成与计算机之间的数据传输。例如,可以通过STM32实现一个USB键盘,当STM32接入计算机时,相当于插入了一个键盘,可以通过代码控制键盘的按键输出。还可以实现一个USB鼠标,通过控制鼠标指针的坐标和点击事件,实现鼠标操作。 需要注意的是,实现USB HID协议需要使用STM32USB接口,需要进行复杂的USB协议栈和设备驱动的开发。同时,也需要掌握相关的USB HID协议知识。因此,对于初学者来说,需要认真学习STM32USB开发知识,并且根据具体的需求选择合适的开发工具和技术路线。 ### 回答3: STM32 USBHID是指基于STMicroelectronics公司生产的STM32微控制器的USB HID协议接口。USB HID(Human Interface Device)是一种用于支持人机交互的USB协议,它可以用来传输各种输入设备(如鼠标、键盘、游戏手柄等)的数据到计算机中。 STM32 USBHID具有以下特点: 1. 易于使用:STM32 USBHID提供了丰富的软件库和例程,使得开发者可以快速且方便地实现USB HID的功能。 2. 高性能:STM32微控制器具有高速的计算能力和丰富的外设接口,能够满足各种应用需求。 3. 灵活性强:STM32 USBHID支持自定义报告格式和热插拔功能,可以根据应用需求进行灵活配置。 4. 低功耗:STM32微控制器采用低功耗技术,可以实现低功耗运行,并支持强大的省电模式,可以有效延长电池寿命。 在应用方面,STM32 USBHID可以广泛应用于鼠标、键盘、游戏手柄、医疗设备等领域。比如,开发者可以使用STM32 USBHID制作一款自定义的游戏手柄,或者是一种带有安全锁的医疗设备,以实现更好的用户体验和数据安全性。总之,STM32 USBHID是一种功能强大、易于使用的USB协议接口,拥有广泛的应用前景和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值