【USB设备设计】--复合设备,双HID高速(64Byte 和 1024Byte)
前言
工作项目中,某些项目对数据吞吐量有很高要求(比如需要5M/s左右的带宽),于是笔者设计了高速HID,端点大小:1024Byte设备,但是公司之前产品使用的是端点大小:64Byte的全速设备,为了保证USB设备的兼容性,于是笔者设计成两个接口的HID设备(Interface0:64Byte HID、Interface1:1024Byte HID)。好了,接下来介绍双HID复合设备是如何开发的。
前期准备
1.带USB 2.0高速功能的MCU (笔者使用的NXP RT1052)
2.libusb 1.x 版本(开发上位机可使用该库)
3.VS2015 keil (IDE环境选择很多,因人而异)
HID描述符基本结构
- 配置描述符:主要设置接口数量为:2
- 接口描述符:接口0,端点描述符设置为:64Byte;接口1,端点描述符设置为:1024Byte
-------------------------
Configuration Descriptor:
-------------------------
0x09 bLength
0x02 bDescriptorType
0x0049 wTotalLength (73 bytes)
0x02 bNumInterfaces
0x01 bConfigurationValue
0x00 iConfiguration
0xC0 bmAttributes (Self-powered Device)
0x32 bMaxPower (100 mA)Interface Descriptor:
------------------------------
0x09 bLength
0x04 bDescriptorType
0x00 bInterfaceNumber
0x00 bAlternateSetting
0x02 bNumEndPoints
0x03 bInterfaceClass (Human Interface Device Class)
0x00 bInterfaceSubClass
0x00 bInterfaceProtocol
0x00 iInterfaceHID Descriptor:
------------------------------
0x09 bLength
0x21 bDescriptorType
0x0110 bcdHID
0x21 bCountryCode
0x01 bNumDescriptors
0x22 bDescriptorType (Report descriptor)
0x001B bDescriptorLengthEndpoint Descriptor:
------------------------------
0x07 bLength
0x05 bDescriptorType
0x81 bEndpointAddress (IN endpoint 1)
0x03 bmAttributes (Transfer: Interrupt / Synch: None / Usage: Data)
0x0040 wMaxPacketSize (1 x 64 bytes)
0x01 bInterval (1 microframes)Endpoint Descriptor:
------------------------------
0x07 bLength
0x05 bDescriptorType
0x02 bEndpointAddress (OUT endpoint 2)
0x03 bmAttributes (Transfer: Interrupt / Synch: None / Usage: Data)
0x0040 wMaxPacketSize (1 x 64 bytes)
0x01 bInterval (1 microframes)Interface Descriptor:
------------------------------
0x09 bLength
0x04 bDescriptorType
0x01 bInterfaceNumber
0x00 bAlternateSetting
0x02 bNumEndPoints
0x03 bInterfaceClass (Human Interface Device Class)
0x00 bInterfaceSubClass
0x00 bInterfaceProtocol
0x00 iInterfaceHID Descriptor:
------------------------------
0x09 bLength
0x21 bDescriptorType
0x0110 bcdHID
0x21 bCountryCode
0x01 bNumDescriptors
0x22 bDescriptorType (Report descriptor)
0x001B bDescriptorLengthEndpoint Descriptor:
------------------------------
0x07 bLength
0x05 bDescriptorType
0x83 bEndpointAddress (IN endpoint 3)
0x03 bmAttributes (Transfer: Interrupt / Synch: None / Usage: Data)
0x0400 wMaxPacketSize (1 x 1024 bytes)
0x01 bInterval (1 microframes)Endpoint Descriptor:
------------------------------
0x07 bLength
0x05 bDescriptorType
0x03 bEndpointAddress (OUT endpoint 3)
0x03 bmAttributes (Transfer: Interrupt / Synch: None / Usage: Data)
0x0400 wMaxPacketSize (1 x 1024 bytes)
0x01 bInterval (1 microframes)
接口0,HID报告描述符 64byte
uint8_t g_UsbDeviceHid64ByteReportDescriptor[] =
{0x05, 0x01,0x09, 0x00,0xa1, 0x01,0x15, 0x00,0x25, 0xff,0x19, 0x01,0x29, 0x08,0x95, 0x40,0x75, 0x08,0x81, 0x02,0x19, 0x01,0x29, 0x08,0x91, 0x02,0xc0
};
接口1:HID报告描述符 1024byte
uint8_t g_UsbDeviceHid1024ByteReportDescriptor[] =
{0x05, 0x01,0x09, 0x00,0xa1, 0x01,0x15, 0x00,0x25, 0xff,0x19, 0x01,0x29, 0x08,0x95, 0x80,0x75, 0x40,0x81, 0x02,0x19, 0x01,0x29, 0x08,0x91, 0x02,0xc0
};
实现USB标准请求
USB标准请求,无非就是:总线复位,设置接口,获取接口,获取设备描述符,获取配置描述符,获取字符串描述符等等。反正主机请求啥,设备提供啥就行。
usb_status_t USB_DeviceCallback(usb_device_handle handle, uint32_t event, void *param)
{usb_status_t error = kStatus_USB_Success;uint8_t *temp8 = (uint8_t *)param;uint16_t *temp16 = (uint16_t *)param;switch (event){case kUSB_DeviceEventBusReset:{/* USB bus reset signal detected */g_UsbDeviceHidGeneric.attach = 0U;if (kStatus_USB_Success == USB_DeviceClassGetSpeed(CONTROLLER_ID, &g_UsbDeviceHidGeneric.speed)){USB_DeviceSetSpeed(handle, g_UsbDeviceHidGeneric.speed);} }break;case kUSB_DeviceEventSetConfiguration:if(param){/* Set device configuration request */g_UsbDeviceHidGeneric.attach = 1U;g_UsbDeviceHidGeneric.currentConfiguration = *temp8;if (USB_HID_GENERIC_CONFIGURE_INDEX == (*temp8)){error = USB_DeviceHidRecv(g_UsbDeviceHidGeneric.hidHandle, USB_HID_GENERIC_ENDPOINT_OUT,(uint8_t *)g_UsbDeviceHidGeneric.buffer, USB_HID_GENERIC_OUT_BUFFER_LENGTH);error = USB_DeviceHidRecv(g_UsbDeviceHidGeneric.hid1024ByteHandle, USB_HID_1024BYTE_ENDPOINT_OUT,(uint8_t *)g_UsbDeviceHidGeneric.buffer1024byte, USB_HID_1024BYTE_OUT_BUFFER_LENGTH); } }break;case kUSB_DeviceEventSetInterface:if (g_UsbDeviceHidGeneric.attach){/* Set device interface request */uint8_t interface = (uint8_t)((*temp16 & 0xFF00U) >> 0x08U);uint8_t alternateSetting = (uint8_t)(*temp16 & 0x00FFU);if (interface == USB_HID_64BYTE_INTERFACE_INDEX) {g_UsbDeviceHidGeneric.currentInterfaceAlternateSetting[interface] = alternateSetting;if (alternateSetting == 0U){error = USB_DeviceHidRecv(g_UsbDeviceHidGeneric.hidHandle, USB_HID_GENERIC_ENDPOINT_OUT,(uint8_t *)g_UsbDeviceHidGeneric.buffer,USB_HID_GENERIC_OUT_BUFFER_LENGTH);}}else if (interface == USB_HID_1024BYTE_INTERFACE_INDEX){g_UsbDeviceHidGeneric.currentInterfaceAlternateSetting[interface] = alternateSetting;if (alternateSetting == 0U){error = USB_DeviceHidRecv(g_UsbDeviceHidGeneric.hid1024ByteHandle, USB_HID_1024BYTE_ENDPOINT_OUT,(uint8_t *)g_UsbDeviceHidGeneric.buffer1024byte, USB_HID_1024BYTE_OUT_BUFFER_LENGTH); }}}break;case kUSB_DeviceEventGetConfiguration:if (param){/* Get current configuration request */*temp8 = g_UsbDeviceHidGeneric.currentConfiguration;error = kStatus_USB_Success;}break;case kUSB_DeviceEventGetInterface:if (param){/* Get current alternate setting of the interface request */uint8_t interface = (uint8_t)((*temp16 & 0xFF00U) >> 0x08U);if (interface < USB_DEVICE_INTERFACE_COUNT){*temp16 = (*temp16 & 0xFF00U) | g_UsbDeviceHidGeneric.currentInterfaceAlternateSetting[interface];error = kStatus_USB_Success;}else{error = kStatus_USB_InvalidRequest;}}break;case kUSB_DeviceEventGetDeviceDescriptor:if (param){/* Get device descriptor request */error = USB_DeviceGetDeviceDescriptor(handle, (usb_device_get_device_descriptor_struct_t *)param);}break;case kUSB_DeviceEventGetConfigurationDescriptor:if (param){/* Get device configuration descriptor request */error = USB_DeviceGetConfigurationDescriptor(handle,(usb_device_get_configuration_descriptor_struct_t *)param);}break;case kUSB_DeviceEventGetStringDescriptor:if (param){/* Get device string descriptor request */error = USB_DeviceGetStringDescriptor(handle, (usb_device_get_string_descriptor_struct_t *)param);}break;case kUSB_DeviceEventGetHidDescriptor:if (param){/* Get hid descriptor request */error = USB_DeviceGetHidDescriptor(handle, (usb_device_get_hid_descriptor_struct_t *)param);}break;case kUSB_DeviceEventGetHidReportDescriptor:if (param){/* Get hid report descriptor request */error =USB_DeviceGetHidReportDescriptor(handle, (usb_device_get_hid_report_descriptor_struct_t *)param);}break;case kUSB_DeviceEventGetHidPhysicalDescriptor:if (param){/* Get hid physical descriptor request */error = USB_DeviceGetHidPhysicalDescriptor(handle,(usb_device_get_hid_physical_descriptor_struct_t *)param);}break;default:break;}return error;
}
HID报告描述符请求函数修改:
usb_status_t USB_DeviceGetHidReportDescriptor(usb_device_handle handle,usb_device_get_hid_report_descriptor_struct_t *hidReportDescriptor)
{if (USB_HID_64BYTE_INTERFACE_INDEX== hidReportDescriptor->interfaceNumber){hidReportDescriptor->buffer = g_UsbDeviceHidGenericReportDescriptor;hidReportDescriptor->length = USB_DESCRIPTOR_LENGTH_HID_GENERIC_REPORT;}else if(USB_HID_1024BYTE_INTERFACE_INDEX == hidReportDescriptor->interfaceNumber){hidReportDescriptor->buffer = g_UsbDeviceHid1024ByteReportDescriptor;hidReportDescriptor->length = USB_DESCRIPTOR_LENGTH_HID_GENERIC_REPORT;}else{return kStatus_USB_InvalidRequest;}return kStatus_USB_Success;
}
将设备接上主机看枚举状况
枚举过程
通过Bus Hound可以抓包看到枚举过程,如下图:
上位机设计思路
1.遍历Windows端口所有usb设备,获取设备数量
libusb_get_device_list2.遍历所有设备的描述符信息,通过PID VID等信息找到我们指定的设备
libusb_get_device_descriptor3.打开指定设备
libusb_open4.查询接口0,查询接口1
获取该接口端点IN OUT5.端点上通信(hid 是中断传输,所以调用中断传输sdk)
libusb_interrupt_transfer
实例化成功USB HID设备后,如下识别2个Interface和对应的四个端点地址
可参考笔者之前的文章:HID高速设备1024byte------上下位机搭建
收发测试
端点1024Byte占用窗口比较大,这里就部分展示下
【USB设备设计】--复合设备,双HID高速(64Byte 和 1024Byte)相关推荐
- STM32CubeMX学习笔记(44)——USB接口使用(HID按键)
一.USB简介 USB(Universal Serial BUS)通用串行总线,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯.是应用在 PC 领域的接口技术.USB 接口支持设备的即插即用和 ...
- USB 协议分析之 HID 设备(转)
USB 协议分析之 HID 设备 转载于:https://www.cnblogs.com/LittleTiger/p/10764891.html
- Android usb otg通讯总结 HiD通讯直接来取吧
最近在搞一个Android的通过otg与设备进行usb通讯的功能HID. 过程中遇到了一个大坑,就是usb发数据的时候,第一次显示发送成功(返回值大于1),但是设备并没有收到实际的数据,把usb重新拔 ...
- 双路高速 AD 实验
目录 双路高速 AD 实验 1.简介 3PA1030 芯片 2.实验任务 3.程序设计 3.1.hs_dual_ad 模块代码 clk_wiz IP 核 的添加方法 ILA IP 核(集成逻辑分析器: ...
- 【正点原子FPGA连载】 第二十八章 双路高速DA实验-摘自【正点原子】领航者ZYNQ之FPGA开发指南_V2.0
1)实验平台:正点原子领航者ZYNQ开发板 2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761 3)全套实验源码+手册+视频下 ...
- Usb Composite Device (audio+hid) Descriptor
近期开发USB Composite Device 撰写的USB 描述符 ,支持 USB speaker + USB Mic,同时支持USB HID 自定义设备.可以作为 开发设备的参考.(此描述符已经 ...
- usb中cdc dfu hid msc的区别
cdc : communication device class,CDC是通信设备级方案,是USB 转其他的接口的一类设备,比如USB转RS232,USB转Ethernet等 dfu : Device ...
- USB 协议分析之 HID 设备
1. 简述 USB HID类是USB设备的一个标准设备类,包括的设备非常多.HID类设备定义它属于人机交互操作的设备,用于控制计算机操作的一些方面,如USB鼠标.USB键盘.USB游戏操纵杆等.但HI ...
- usb的device模式hid配置错误点
将usb做从机,hid通信操作(模拟串口,模拟u盘,hid通信...) 内核设定 1-模拟u盘 2.模拟串口 3.hid通信 1.报错: # insmod libcomposite.ko [ 88 ...
- QCC3040 USB Composite Device: Audio+HID+CDC/虚拟串口
笔记一下USB IAD的用途, 真实体验到了什么叫概念不清,误入歧途. 首先声明一下,笔者没有系统性了解过USB协议,只是按照实际情况,提出需求,发现问题,解决问题. 笔者记录一下在高通QCC3040 ...
最新文章
- 技术一般,却被破格提拔!肯定有黑幕......
- python中的ideavim有什么作用_Pycharm和Idea支持的vim插件的方法
- 《机器学习导论》和《统计机器学习》学习资料:张志华教授
- python enumeration_python模块之enum_上
- 泰勒及洛朗展开学习笔记
- Vue3 高级语法(一)—— h函数、jsx
- LeetCode 1291. 顺次数(模拟)
- java 多个数字_java 输入多个数字
- python爬虫入库到帝国cms_帝国小说连载系统合理利用第三方云爬虫缓存章节内容...
- Java从零开始(4)——入门项目
- 强化学习读书笔记 - 03 - 有限马尔科夫决策过程
- vmware虚拟机安装jdk
- 《 郝斌 java自学视频 完结 》_郝斌Java自学视频 全107讲视频教程下载 完整版
- 串口转usb驱动c语言程序,usb serial驱动下载-usb serial converter驱动下载 官方版usb转串口驱动程序-win7/8/10/xp32/64位-IT猫扑网...
- 软件设计的七大原则——超详细
- 01 官网下载各种CentOS教程(超详细版)
- 【源码分析】Spring Boot中Relaxed Binding机制的不同实现
- [差分 上下界最大流] SRM 694 div1 SRMDiv0Easy
- DOS之bat启动Exe脚本
- 企业BI工具实现库存周转率分析