当前位置:网站首页>【USB设备设计】--复合设备,双HID高速(64Byte 和 1024Byte)
【USB设备设计】--复合设备,双HID高速(64Byte 和 1024Byte)
2022-07-25 10:51:00 【L_17】
前言
工作项目中,某些项目对数据吞吐量有很高要求(比如需要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 iInterface
HID Descriptor:
------------------------------
0x09 bLength
0x21 bDescriptorType
0x0110 bcdHID
0x21 bCountryCode
0x01 bNumDescriptors
0x22 bDescriptorType (Report descriptor)
0x001B bDescriptorLength
Endpoint 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 iInterface
HID Descriptor:
------------------------------
0x09 bLength
0x21 bDescriptorType
0x0110 bcdHID
0x21 bCountryCode
0x01 bNumDescriptors
0x22 bDescriptorType (Report descriptor)
0x001B bDescriptorLength
Endpoint 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_list
2.遍历所有设备的描述符信息,通过PID VID等信息找到我们指定的设备
libusb_get_device_descriptor
3.打开指定设备
libusb_open
4.查询接口0,查询接口1
获取该接口端点IN OUT
5.端点上通信(hid 是中断传输,所以调用中断传输sdk)
libusb_interrupt_transfer
可参考笔者之前的文章:HID高速设备1024byte------上下位机搭建
收发测试

边栏推荐
- 大话DevOps监控,团队如何选择监控工具?
- Layout management ==pyqt5
- SQL language (V)
- 矩阵的特征值和特征向量
- LVS负载均衡之LVS-NAT与LVS-DR模式原理详解
- Multiply Floyd "suggestions collection"
- SQL language (I)
- The most complete detailed tutorial on importing ad into lichuanyuan device packaging Library in history (always white and always cool)
- Oracle parsing XML with the same name
- 圆角大杀器,使用滤镜构建圆角及波浪效果!
猜你喜欢

How does the whole network display IP ownership?

世界上最高效的笔记方法(改变你那老版的记笔记方法吧)

SQL language (4)

Filter过滤器解决request请求参数乱码的原理解析
![[IJCAI 2022] parameter efficient large model sparse training method, which greatly reduces the resources required for sparse training](/img/c8/fe18308ddad5cb2fbccb79d2d8a2b6.png)
[IJCAI 2022] parameter efficient large model sparse training method, which greatly reduces the resources required for sparse training

Emmet syntax quick query syntax basic syntax part

基于W5500实现的考勤系统

Wiznet embedded Ethernet technology training open class (free!!!)

varest蓝图设置json

SQL注入 Less23(过滤注释符)
随机推荐
Let sports happen naturally, and fire creates a new lifestyle
W5500通过上位机控制实现调节LED灯带的亮度
贪心问题01_活动安排问题
Hacker introductory tutorial (very detailed) from zero basic introduction to proficiency, it is enough to read this one.
Flinksql client connection Kafka select * from table has no data error, how to solve it?
Job interviews are always a second kill? After reading the seckill system notes secretly stored by JD T8, I have given my knees
DICOM medical image viewing and browsing function based on cornerstone.js
Dynamic planning question 05_ Missile interception
Shell fourth day homework
Stm32cubemx learning record -- installation, configuration and use
[leetcode brush questions]
Talking about Devops monitoring, how does the team choose monitoring tools?
Reptile foundation I
SQL注入 Less23(过滤注释符)
Only know that the preform is used to generate objects? See how I use unity to generate UI prefabs
Information management system for typical works of urban sculpture (picture sharing system SSM)
教你如何通过MCU配置S2E为TCP Client的工作模式
Smart cloud IOT platform STM32 esp8266-01s simple wireless light control
WIZnet嵌入式以太网技术培训公开课(免费!!!)
JVM性能调优方法