历史上的今天
返回首页

历史上的今天

今天是:2024年09月20日(星期五)

正在发生

2018年09月20日 | STM32 USB HID 自定义设备 bulk 传输

2018-09-20 来源:eefocus

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

1

配置描述符中的接口描述符也要做相应的调整,将端点数目 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 设备。


推荐阅读

史海拾趣

EG & G Inc公司的发展小趣事

随着市场竞争的加剧,EG & G Inc公司意识到通过并购和整合来提升自身竞争力的重要性。公司先后收购了多家具有技术优势和市场潜力的企业,将其纳入自己的业务体系。这些并购不仅增强了公司的技术实力和市场地位,也为其未来的发展奠定了坚实的基础。

ACL staticide公司的发展小趣事

为了进一步扩大市场份额,EG & G Inc公司积极开展市场拓展和国际合作。公司在中国、欧洲等多个国家和地区设立了分支机构,与当地企业建立了紧密的合作关系。同时,公司还积极参与国际展览和交流活动,展示了其先进的技术和产品。这些努力使得EG & G Inc公司在国际市场上获得了更多的机会和认可。

Advanced Monolythic Ceramics公司的发展小趣事

随着市场竞争的加剧,EG & G Inc公司意识到通过并购和整合来提升自身竞争力的重要性。公司先后收购了多家具有技术优势和市场潜力的企业,将其纳入自己的业务体系。这些并购不仅增强了公司的技术实力和市场地位,也为其未来的发展奠定了坚实的基础。

Coiltronics公司的发展小趣事

随着市场的不断扩大,Coiltronics公司意识到单凭自身的力量难以满足日益增长的市场需求。于是,公司开始积极寻求与其他企业的战略合作。通过与知名电子设备制造商建立合作关系,Coiltronics成功将其线圈技术应用于更广泛的领域,进一步提升了市场份额。同时,这种合作也带来了双方在技术研发、市场推广等方面的深入交流,为公司的长远发展奠定了坚实基础。

GardTec Inc公司的发展小趣事

背景:GardTec Inc公司,成立于1987年(也有资料显示为1985年),自创立之初便确立了成为全球风扇配件产品第一供应商的目标。这一明确的定位为公司后续的发展奠定了坚实的基础。

发展:在创立初期,GardTec专注于风扇配件的研发与生产,通过技术创新和品质提升,逐渐在行业内崭露头角。公司利用现代化的制造和工程设施,不断突破设计与材料的限制,推出了一系列具有创新性的风扇配件产品。

影响:随着产品质量的提升和市场份额的扩大,GardTec逐渐在电子行业中建立了良好的口碑,为后续的快速发展奠定了基础。

Habia Cable公司的发展小趣事

背景:GardTec始终致力于产品创新和技术研发,不断推出符合市场需求的新产品。

发展:公司积极与风扇制造商密切合作,联合推出了一系列具有创新性的风扇配件产品。同时,GardTec还投入大量资源用于研发工作,不断提升产品的技术含量和附加值。

影响:通过持续的创新与合作,GardTec不仅巩固了其在风扇配件市场的领先地位,还推动了整个行业的技术进步和产业升级。

问答坊 | AI 解惑

请各位高手帮帮忙 关于超声波驱动电源

最近即将毕业  老师给了个题目是关于2KW超声波驱动电源的设计与制作  要求功率可以 吸起眼镜就足够了 不需要2KW那么大功率 . ..各位好手 能提供一些参考资料吗?急  如果可以发去我邮箱或者QQ邮箱麻烦各位了.邮箱edis ...…

查看全部问答>

电子元件教程1

能够产生自感、互感作用的器件均称为电感器件.电感器件是无线电设备中重要元件之一,它与电阻、电容、晶体二极管、晶体三极管等电子器件进行适当的配合,可构成各种功能的电子线路. 由于电感器一般由线圈构成,所以又称为电感线圈.为了增加Q值、缩小 ...…

查看全部问答>

AVR mega16中的T/C1 ctc模式问题

请教一下,T/C1工作在ctc模式时,当允许比较匹配A中断时,是把TCON1和OCR1A比较,那当允许比较匹配B中断时是不是TCON1和ICR1比较啊?当允许比较匹配B中断时是不是OCR1B的内容就是ICR1的内容啊? 谢谢 …

查看全部问答>

alsa soc音频驱动的架构问题

急需ALS SOC音频驱动的一些信息,如主要数据结构,主要函数功能,…

查看全部问答>

讨论:短信猫并发问题解决方案

短信猫并发问题解决方案,这方面有吗? …

查看全部问答>

数码管没反应啊,怎么问题啊,位选段选都很正确啊

我要实现的功能:利用定时器A(定时1秒)做一个时钟 问题描述:编译没错误,烧进板子后,数码管没反应(数码管是共阳的,送0位选,送0段选) 检查了很长时间了,也没检查问题出在哪里?让一个写程序高手的同学帮我检查,他也不知道问题在啊。谁能 ...…

查看全部问答>

吉时利讲堂:2602型数字源表数模转换器测试实例

为了说明2602型数字源表在多通道、多功能测试应用中的源表能力和灵活性,让我们看一下8-位乘法数模转换器(DAC) 的测试序列。图1给出这个应用的测试设置。通过TSP-Link连接的每个仪器都被分配一个唯一的节点编号,类似于GPIB地址。DAC实例使用两个 ...…

查看全部问答>

msp430 f149交流

谁有    MSP430  F149  开发板         3.2TFT 彩色液晶屏和触摸屏驱动程序         (1)并行连接方式驱动程序         (2 )SPI 连接方式驱动 ...…

查看全部问答>

STM32及STM8_2012年6月最新版选型手册

STM32及STM8_2012年6月最新版选型手册发布了, 包括了如下几种系列: STM32F1XX、 STM32F2xx、STM32F3xx、STM32F4xx、STM8S、STM8L系列 …

查看全部问答>