STM32 USB HID 自定义设备 bulk 传输

发布者:春林初盛最新更新时间:2018-09-20 来源: eefocus关键字: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

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 设备。


关键字:STM32  USB  HID  自定义设备  bulk  传输 引用地址:STM32 USB HID 自定义设备 bulk 传输

上一篇:stm32usb库bug及解决办法
下一篇:STM32 UVC学习笔记3

推荐阅读最新更新时间:2024-03-16 16:14

赛普拉斯和Icron宣布USB3.0控制器和有源电缆延长器实现互操作
采用Icron的ExtremeUSB®技术,成功地将赛普拉斯的EZ-USB® USB 3.0外设控制器的数据传输距离从3米延长到15米,传递5-Gbps的数据吞吐量。 USB控制器的领导者赛普拉斯半导体公司和USB及视频扩展技术领先者Icron技术公司联合宣布,成功地完成了赛普拉斯EZ-USB FX3™ USB 3.0 外设控制器、 EZ-USB CX3™ 相机控制器及 Icron USB 3.0 Spectra™ 3001-15 有源铜质延长线缆之间的互操作性测试。 USB3.0的5 Gbps带宽可实现高分辨率、高帧频的实时成像,无需会导致图像质量下降的压缩过程,因而在机器视觉和工业相机领域越来越受欢迎。但目前U
[嵌入式]
基于单片机和USB接口的数据采集系统设计
在工业生产和科学技术研究中,常利用PC或工控机对各种数据进行采集,以获得所需要的控制信息和实验数据。传统的数据采集系统多以ISA,EISA或PCI插卡的形式完成数据传输,这种方式存在安装麻烦,受计算机插槽数量、地址、中断资源限制,可扩展性差等缺点。由于通用串行总线(Universal Serial Bus.USB)具有自动被系统识别.自动安装驱动程序、自行进行系统配置,以及支持不同速率的同步和异步传输方式,支持热插拔和即插即用(Plug and Play,PNP)等优点,已逐渐成为现代数据传输的发展趋势。目前实现USB数据传送多采用专用的USB接口芯片,文献采用的PDIUSBDl2可支持USBl.1协议,文献E37采用的接口芯片
[单片机]
详解STM32堆栈
学习STM32单片机的时候,总是能遇到“堆栈”这个概念。分享本文,希望对你理解堆栈有帮助。 对于了解一点汇编编程的人,就可以知道,堆栈是内存中一段连续的存储区域,用来保存一些临时数据。堆栈操作由PUSH、POP两条指令来完成。而程序内存可以分为几个区: 栈区(stack) 堆区(Heap) 全局区(static) 文字常亮区程序代码区 程序编译之后,全局变量,静态变量已经分配好内存空间,在函数运行时,程序需要为局部变量分配栈空间,当中断来时,也需要将函数指针入栈,保护现场,以便于中断处理完之后再回到之前执行的函数。 栈是从高到低分配,堆是从低到高分配。 普通单片机与STM32单片机中堆栈的区别 普通单片机启动时,不需要用b
[单片机]
详解<font color='red'>STM32</font>堆栈
奥运前将在8城市开播地面数字电视
  在3月20日上午召开的CCBN2008主题报告会上,国家广电总局科技司司长王效杰透露,在奥运会前将在6个奥运城市,包括:北京、上海、天津、秦皇岛、青岛、沈阳,还有广州和深圳,开播地面数字电视广播。   王效杰还透露,广电总局已经部署,今年将在奥运城市,直辖市,省会城市,计划单列市,全国一共37个城市,建设地面数字电视传输与发射系统。现在已经做好了这37个城市的频率规划。   王效杰说,在频率规划方面,为每个城市都规划了两个数字电视频道,一个频道是用于播出央视的高清节目,一个频道是用于播出中央和地方的模拟节目,中央是中央电视台第一套和新闻频道,然后再加上当地省里市里的节目,同时这个频道也兼顾用于本地公交车移动电视,非国标系统
[焦点新闻]
STM32 温度传感器 探究
温度传感器可以用来测量器件周围的温度(TA)。 温度传感器在内部和ADCx_IN16输入通道相连接,此通道把传感器输出的电压转换成数字值。 温度传感器模拟输入推荐采样时间是17.1μs。 当没有被使用时,传感器可以置于关电模式。 注意: 必须设置TSVREFE位激活内部通道:ADCx_IN16(温度传感器)和ADCx_IN17(VREFINT)的转换。 主要特征 ● 支持的温度范围:-40到125度 ● 精确度:+/- 1.5° C 读温度 为使用传感器: 1. 选择ADCx_IN16输入通道 2. 选择采样时间大于2.2 μs 3. 设置ADC控制寄存器2(ADC_CR2)的TSVREFE位,以唤醒关电模式下的温度
[单片机]
聚焦AI、IoT,STM32峰会即将上演
以 “聚智慧,创未来” 为主题,2019年STM32峰会聚焦人工智能与计算、工业与安全、云技术与连接三大专题 在为期两天的峰会上,意法半导体将联合45个合作伙伴共同展出180多个原型设计,举行40场精心策划的专题分论坛和技术研讨会 预计现场参观者达到2,500人,直播观众超过3万人 半导体供应商意法半导体将于4月26-27日在深圳蛇口希尔顿南海酒店举办2019年STM32峰会。 历时三载,STM32 峰会为数千名开发者持续呈现了前沿的技术和创新,成长为备受瞩目的大型年度技术展会。2019年第四届STM32峰会将聚焦3大专题:人工智能与计算,工业与安全,云技术与连接。 人工智能与计算 AI(人工智能)正在以惊人的速度
[物联网]
STM32 DMA 应用之(一)SRAM 与flash 间数据传输
一、为什么要用DMA? DMA 全称:Direct MemoryAccess 就是可以直接内存存取; 正是它可以直接操作内存所以具备以下优点: 而无需经过CPU去操作内存的存取,这样可以解放CPU出来干其他的事情; 因为他可以进行存储器时间的数据传输,而不需经过cpu,所以大大加快了数据传输速度—是一种高速的数据传输; 二.DMA有几种传输数据方式: (1)内存到 内存之间的;即:SRAM?à SRAM (2)内存到 外设之间的; (例如:串口收到的数据 从数据寄存器 à 内存) (3) 外设到内存之间的; 三.传输的数据宽度是怎样的,数据是什么样的形式传输?DMA 能传输多大的数据量? A. 数据源地址到数据目的地址 传
[单片机]
基于串口透明传输的无线射频收发系统设计
目前市场上各类无线产品种类及应用越来越广泛,如何让广大学生、电子研发人员及一些小公司能快速在自己的产品中使用无线技术、降低无线技术的门槛,是本设计的初衷。对一些没有接触无线技术的人,从学到最后的设计应用需要比较长的时间。本文设计了一种基于无线收发芯片Si4432和单片机C8051F340的无线射频收发系统。基于串口透明传输,用户只需要了解一些串口指令即可方便实现无线收发。多种标准接口方便用户把模块嵌入到自己的产品中去。模块经过大量的试验、改进,能实现较远距离的稳定传输。 1、系统总体方案 无线射频收发系统结构框图如图1所示,由单片机C8051F340控制Si4432实现无线数据的收发。 发送模块中的C8051F340将数据
[单片机]
基于串口透明<font color='red'>传输</font>的无线射频收发系统设计
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved