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 键删,系统会根据实际情况,重新生成这个键的。
|