【USB设备设计】--复合设备,双HID高速(64Byte 和 1024Byte)

7 篇文章 2 订阅
前言

​ 工作项目中,某些项目对数据吞吐量有很高要求(比如需要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

实例化成功USB HID设备后,如下识别2个Interface和对应的四个端点地址
请添加图片描述

可参考笔者之前的文章:HID高速设备1024byte------上下位机搭建

收发测试

端点1024Byte占用窗口比较大,这里就部分展示下
请添加图片描述
请添加图片描述

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值