USB CDC虚拟串口复合设备

CDC包含一个控制接口和一个数据接口

1、控制接口

        必要的有CM功能描述符和接口绑定描述符(IAD/Union)

在我电脑上测试控制接口的中断端点也可以不需要,及控制接口端点数量可以为0

1.1、ACM功能描述符:

        在虚拟串口中,控制接口需要处理ACM 功能描述符。如下是一个ACM描述符,描述了虚拟串口的一些类特定请求,比如可以设置和获取的串口的波特率、停止位等等。

 参考:STM32 之 USB 虚拟串口_rannar的博客-CSDN博客_stm32 虚拟串口

bFunctionLength          : 0x04 (4 bytes)
bDescriptorType          : 0x24 (Interface)
bDescriptorSubType       : 0x02 (Abstract Control Management Functional Descriptor)
bmCapabilities           : 0x0F
 D7..4:                  : 0x00 (Reserved)
 D3   :                  : 0x01 (supports the notification Network_Connection)
 D2   :                  : 0x01 (supports the request Send_Break)
 D1   :                  : 0x01 (supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State)
 D0   :                  : 0x01 (supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature)
Data (HexDump)           : 04 24 02 0F                                       .$..

 1.2、IAD和Union描述符

IAD 与 Union 类似,Union 是旧版本下实现多个接口对应一个功能的功能描述符,而 IAD 是 USB 协会后来针对多个接口对应 一个功能的情况而扩展的,旧的主机可能只支持 Union 方式,但 IAD 并不会影响旧版本主机对设备的识别,因为旧版本主机 会通过 Union 来识别哪些接口是联合在一起的,对于 IAD 则跳过忽略;而新版主机则可以通过 IAD 来识别,跳过忽略老的 Union,因此两者可以完美兼容,互不影响。因而主机端可以精确地装载对应的驱动。

 两者功能相似,互不影响,分别针对新老协议。在我电脑上配置成多个CDC虚拟串口时,需要给定IAD才能正常出现多个串口(有Union并无区别)。

      bFirstInterface  第一个接口的序号,CDC的控制接口编号     
      bInterfaceCount 本CDC的接口数量,固定为2 (控制接口+数据接口)。数据接口必须紧跟控制接口。

        bMasterInterface        Communication class interface 控制接口的编号
        bSlaveInterface0        Data Class Interface  数据接口的编号  (对比IAD 可以接口可以不连续)

2、 数据接口

        简单的就包括一个接口描述符+两个断点描述符即可。

​
  //数据接口
        /*Data class interface descriptor*/
        0x09,                          /* bLength: Endpoint Descriptor size */
        USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */
        0x01,                          /* bInterfaceNumber: Number of Interface */
        0x00,                          /* bAlternateSetting: Alternate setting */
        0x02,                          /* bNumEndpoints: Two endpoints used */
        0x0A,                          /* bInterfaceClass: CDC */
        0x00,                          /* bInterfaceSubClass: */
        0x00,                          /* bInterfaceProtocol: */
        0x00,                          /* iInterface: */
        /*Endpoint 1 Descriptor*/
        0x07,                         /* bLength: Endpoint Descriptor size */
        USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
        0x01,                         /* bEndpointAddress: (OUT1) */
        0x02,                         /* bmAttributes: Bulk */
        VIRTUAL_COM_PORT_DATA_SIZE,   /* wMaxPacketSize: */
        0x00,
        0x00, /* bInterval: ignore for Bulk transfer */
        /*Endpoint 1 Descriptor*/
        0x07,                         /* bLength: Endpoint Descriptor size */
        USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
        0x81,                         /* bEndpointAddress: (IN1) */
        0x02,                         /* bmAttributes: Bulk */
        VIRTUAL_COM_PORT_DATA_SIZE,   /* wMaxPacketSize: */
        0x00,
        0x00, /* bInterval */

​

3、多虚拟串口

3.1、设备描述符说明

设备描述附中就描述了设备类型,但作为复合设备,显然一个设备描述符肯定是不可以的。

  • bDeviceClass : 类型代码(由USB指定)。当它的值是0时,表示所有接口在配置描述符里,并且所有接口是独立的。当它的值是1到FEH时,表示不同的接口关联的。当它的值是FFH时,它是厂商自己定义的.

针对符合设备,bDeviceClass默认给0即可。

0x12,                       /*bLength */
USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/
0x00,                       /*bcdUSB */
0x02,
0x00, // 0x00, /*bDeviceClass*/
0x0,  // 0x00, /*bDeviceSubClass*/
0x0,  // 0x00, /*bDeviceProtocol*/
0x40, /*bMaxPacketSize40*/
0x77, /*idVendor ( )*/
0x86,
0x50, /*idProduct =  */
0x58,
0x00, /*bcdDevice rel. 2.00*/
0x02,
1,   /*Index of string descriptor describing manufacturer */
2,   /*Index of string descriptor describing  product*/
3,   /*Index of string descriptor describing the device serial number */
0x01 /*bNumConfigurations*/

3.2、配置描述符

知道了控制接口的功能后,就知道增加CDC设备需要修改的内容了,为了增加兼容性,IAD和Union描述符都加上吧。

uint8_t Custom_ConfigDescriptor[] = // 
    {
        0x09,                              /* bLength: Configuration Descriptor size */
        USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
        0,                                 // sizeof(CustomHID_ConfigDescriptor), 动态设置
        /* wTotalLength: Bytes returned */
        0x00,
        4,    /* bNumInterfaces: 1 interface 总的接口数量*/
        0x01, /* bConfigurationValue: Configuration value */
        0x00, /* iConfiguration: Index of string descriptor describing
                                         the configuration*/
        0xC0, /* bmAttributes: Self powered */
        0x32, /* MaxPower 100 mA: this current is used for detecting Vbus */

#if 1         //虚拟串口 1
              //  IAD  Interface Association Descriptor //IAD描述符需要添加
        0x08, // bLength: Interface Descriptor size
        0x0B, // bDescriptorType: IAD
        0x00, // bFirstInterface                      //第一个控制接口的序号 控制接口0
        0x02, // bInterfaceCount                      //本IDA的接口数量 默认2
        0x02, // bFunctionClass: CDC                  //表明该IAD是一个CDC设备
        0x02, // bFunctionSubClass                    //默认
        0x01, // bFunctionProtocol                    //控制协议等其他我也不懂,默认就行
        0x02, // iFunction
        /*Interface Descriptor 控制接口*/
        0x09,                          /* bLength: Interface Descriptor size */
        USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */
        /* Interface descriptor type */
        0x00, /* bInterfaceNumber: Number of Interface  */
        0x00, /* bAlternateSetting: Alternate setting */
        0x00, /* bNumEndpoints: One endpoints used */
        0x02, /* bInterfaceClass: Communication Interface Class */
        0x02, /* bInterfaceSubClass: Abstract Control Model */
        0x01, /* bInterfaceProtocol: Common AT commands */
        0x00, /* iInterface: */
              //    /*Header Functional Descriptor 非必须项*/
              //    0x05,   /* bLength: Endpoint Descriptor size */
              //    0x24,   /* bDescriptorType: CS_INTERFACE */
              //    0x00,   /* bDescriptorSubtype: Header Func Desc */
              //    0x10,   /* bcdCDC: spec release number */
              //    0x01,
              //    /*Call Management Functional Descriptor*/
              //    0x05,   /* bFunctionLength */
              //    0x24,   /* bDescriptorType: CS_INTERFACE */
              //    0x01,   /* bDescriptorSubtype: Call Management Func Desc */
              //    0x00,   /* bmCapabilities: D0+D1 */
              //    0x01,   /* bDataInterface: 1 */
        /*ACM Functional Descriptor 必须项*/
        0x04, /* bFunctionLength */
        0x24, /* bDescriptorType: CS_INTERFACE */
        0x02, /* bDescriptorSubtype: Abstract Control Management desc */
        0x0F, /* bmCapabilities  */
        /*Union Functional Descriptor 建议加上*/
        0x05, /* bFunctionLength */
        0x24, /* bDescriptorType: CS_INTERFACE */
        0x06, /* bDescriptorSubtype: Union func desc */
        0x00, /* bMasterInterface: Communication class interface 控制接口0*/
        0x01, /* bSlaveInterface0: Data Class Interface 数据接口1*/
              //    /*Endpoint 2 Descriptor 非必须项目 当前接口端点数量设置为0*/
              //    0x07,   /* bLength: Endpoint Descriptor size */
              //    USB_ENDPOINT_DESCRIPTOR_TYPE,   /* bDescriptorType: Endpoint */
              //    0x8A,   /* bEndpointAddress: (INx)  无效端口*/
              //    0x03,   /* bmAttributes: Interrupt */
              //    8,      /* wMaxPacketSize: */
              //    0x00,
              //    0xFF,   /* bInterval: */

        /*Data class interface descriptor  数据接口*/
        0x09,                          /* bLength: Endpoint Descriptor size */
        USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */
        0x01,                          /* bInterfaceNumber: Number of Interface */
        0x00,                          /* bAlternateSetting: Alternate setting */
        0x02,                          /* bNumEndpoints: Two endpoints used */
        0x0A,                          /* bInterfaceClass: CDC */
        0x00,                          /* bInterfaceSubClass: */
        0x00,                          /* bInterfaceProtocol: */
        0x00,                          /* iInterface: */
        /*Endpoint 3 Descriptor*/
        0x07,                         /* bLength: Endpoint Descriptor size */
        USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
        0x01,                         /* bEndpointAddress: (OUT1) */
        0x02,                         /* bmAttributes: Bulk */
        VIRTUAL_COM_PORT_DATA_SIZE,   /* wMaxPacketSize: */
        0x00,
        0x00, /* bInterval: ignore for Bulk transfer */
        /*Endpoint 1 Descriptor*/
        0x07,                         /* bLength: Endpoint Descriptor size */
        USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
        0x81,                         /* bEndpointAddress: (IN1) */
        0x02,                         /* bmAttributes: Bulk */
        VIRTUAL_COM_PORT_DATA_SIZE,   /* wMaxPacketSize: */
        0x00,
        0x00, /* bInterval */
#endif

#if 1 虚拟串口 2

        /*---------------------------------------------------------------------------*/
        // IAD  Interface Association Descriptor
        0x08, // bLength: Interface Descriptor size
        0x0B, // bDescriptorType: IAD
        0x02, // bFirstInterface    控制接口2
        0x02, // bInterfaceCount    默认2
        0x02, // bFunctionClass: CDC
        0x02, // bFunctionSubClass
        0x01, // bFunctionProtocol
        0x02, // iFunction

        /*Interface Descriptor*/
        0x09,                          /* bLength: Interface Descriptor size */
        USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: Interface */
        /* Interface descriptor type */
        0x02, /* bInterfaceNumber: Number of Interface */
        0x00, /* bAlternateSetting: Alternate setting */
        0x00, /* bNumEndpoints: One endpoints used */
        0x02, /* bInterfaceClass: Communication Interface Class */
        0x02, /* bInterfaceSubClass: Abstract Control Model */
        0x01, /* bInterfaceProtocol: Common AT commands */
        0x00, /* iInterface: */
              //    /*Header Functional Descriptor*/
              //    0x05,   /* bLength: Endpoint Descriptor size */
              //    0x24,   /* bDescriptorType: CS_INTERFACE */
              //    0x00,   /* bDescriptorSubtype: Header Func Desc */
              //    0x10,   /* bcdCDC: spec release number */
              //    0x01,
              //    /*Call Management Functional Descriptor*/
              //    0x05,   /* bFunctionLength */
              //    0x24,   /* bDescriptorType: CS_INTERFACE */
              //    0x01,   /* bDescriptorSubtype: Call Management Func Desc */
              //    0x00,   /* bmCapabilities: D0+D1 */
              //    0x01,   /* bDataInterface: 1 */
        /*ACM Functional Descriptor*/
        0x04, /* bFunctionLength */
        0x24, /* bDescriptorType: CS_INTERFACE */
        0x02, /* bDescriptorSubtype: Abstract Control Management desc */
        0x0F, /* bmCapabilities */
        /*Union Functional Descriptor*/
        0x05, /* bFunctionLength */
        0x24, /* bDescriptorType: CS_INTERFACE */
        0x06, /* bDescriptorSubtype: Union func desc */
        0x02, /* bMasterInterface: Communication class interface 控制接口2*/
        0x03, /* bSlaveInterface0: Data Class Interface 数据接口3 */
              //    /*Endpoint 2 Descriptor*/
              //    0x07,   /* bLength: Endpoint Descriptor size */
              //    USB_ENDPOINT_DESCRIPTOR_TYPE,   /* bDescriptorType: Endpoint */
              //    0x8B,   /* bEndpointAddress: (INx)  无效端口*/
              //    0x03,   /* bmAttributes: Interrupt */
              //    8,      /* wMaxPacketSize: */
              //    0x00,
              //    0xFF,   /* bInterval: */

        //数据接口
        /*Data class interface descriptor*/
        0x09,                          /* bLength: Endpoint Descriptor size */
        USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType: */
        0x03,                          /* bInterfaceNumber: Number of Interface */
        0x00,                          /* bAlternateSetting: Alternate setting */
        0x02,                          /* bNumEndpoints: Two endpoints used */
        0x0A,                          /* bInterfaceClass: CDC */
        0x00,                          /* bInterfaceSubClass: */
        0x00,                          /* bInterfaceProtocol: */
        0x00,                          /* iInterface: */
        /*Endpoint 3 Descriptor*/
        0x07,                         /* bLength: Endpoint Descriptor size */
        USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
        0x02,                         /* bEndpointAddress: (OUT1) */
        0x02,                         /* bmAttributes: Bulk */
        VIRTUAL_COM_PORT_DATA_SIZE,   /* wMaxPacketSize: */
        0x00,
        0x00, /* bInterval: ignore for Bulk transfer */
        /*Endpoint 1 Descriptor*/
        0x07,                         /* bLength: Endpoint Descriptor size */
        USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: Endpoint */
        0x82,                         /* bEndpointAddress: (IN1) */
        0x02,                         /* bmAttributes: Bulk */
        VIRTUAL_COM_PORT_DATA_SIZE,   /* wMaxPacketSize: */
        0x00,
        0x00, /* bInterval */
#endif
};     /* CustomHID_ConfigDescriptor */

另外还需实现虚拟串口类特定请求

        case GET_LINE_CODING://虚拟串口专用 获取串口通讯参数
            CopyRoutine = Virtual_Com_Port_GetLineCoding;
            break;
        case SET_LINE_CODING://虚拟串口专用 设置串口通讯参数
            CopyRoutine = Virtual_Com_Port_SetLineCoding;
            Request = SET_LINE_CODING;
            break;
        case SET_COMM_FEATURE://虚拟串口专用 
        {
            return USB_SUCCESS;
        }
        case SET_CONTROL_LINE_STATE://虚拟串口专用
        {
            return USB_SUCCESS;
        }

然后设备就出现了

 当然,还可以更多。。。

所以就可以自己做一个USB转6路TTL,大数据量压力测试,就放在后面做吧。

STM32-CDC6路串口.zip-嵌入式文档类资源-CSDN下载枚举6路虚拟串口,端口打开关闭正常,未实现串口部分更多下载资源、学习资料请访问CSDN下载频道.https://download.csdn.net/download/ai5945fei/46935702

4、端口存储和占用问题

WIn10系统会记录每次分配给设备的端口,保证下一次设备接入还是同样的端口。这个功能在自助终端设备上很重要。

 但是也会过多的占用我们经常用的靠前的编号,只需要在注册表 

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\COM Name Arbiter

把 ComDB 键删,系统会根据实际情况,重新生成这个键的。

  • 5
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值