枚举波形
setup 00 00
data: 80 06 00 01 00 00 40 00
1.获取设备描述符
IN 00 00
data 12 01 00 02 02 02 00 40 83 04 40 57 00 02 01 02 03 01
即这段内容:
OUT 00 00
状态阶段:表示获取成功;
reset阶段
SETUP :00 00
data0:00 05 16 00 00 00 00 00 主机向设备表示设置地址为0x16
状态阶段:
从机回复主机ACK
SETUP:16 00
DATA0:80 06 00 01 00 00 12 00
主机向设备获取设备描述符长度为0x12
IN 16 00
DATA1:12 01 00 02 02 02 00 40 83 04 40 57 00 02 01 02 03 01
设备向主机发送设备描述符 0x12 长度
OUT :16 00
状态阶段主机向从机表示ACK
SET UP:16 00
DATA0: 80 06 00 02 00 00 FF 00
主机向从机发送 获取配置描述符,长度不超过0xFF
IN 16 00
DATA1:09 02 43 00 02 01 00 C0 32 09 04 00 00 01 02 02 01 00 05 24 00 10 01 05 24 01 00 01 04 24 06 00 01 07 05 82 03 08 00 10 09 04 01 00 02 0a 00 00 00 07 05 01 02 40 00 07 05 81 02
数据内容含义如下:
1.配置描述符
0x09, // bLength: 描述符长度9字节(固定值) USB_DESC_TYPE_CONFIGURATION, // 类型标识0x02(配置描述符)[4,5](@ref) USB_CDC_CONFIG_DESC_SIZ, // wTotalLength: 配置描述符集合总字节数(包含接口、端点等所有描述符) 0x00, 0x02, // bNumInterfaces: 包含2个接口(控制接口+数据接口)[2](@ref) 0x01, // bConfigurationValue: 配置标识符(主机通过此值激活配置) 0x00, // iConfiguration: 配置字符串索引(0表示无字符串描述) 0xC0, // bmAttributes: D7=1(保留位必须为1),D6=1(自供电)[4](@ref) 0x32 // MaxPower: 0x32 * 2mA=100mA(设备最大功耗)[4](@ref)
作用:定义设备供电方式及接口数量,声明配置整体属性
2.控制接口描述符
0x09, // bLength: 接口描述符长度9字节(固定值) USB_DESC_TYPE_INTERFACE, // 类型标识0x04(接口描述符) 0x00, // bInterfaceNumber: 接口编号0(控制接口) 0x00, // bAlternateSetting: 备用接口编号(0表示无备用) 0x01, // bNumEndpoints: 使用1个端点(中断端点) 0x02, 0x02, 0x01, // 接口类/子类/协议:0x02(CDC类)、0x02(ACM子类)、0x01(AT命令协议)[2,6](@ref) 0x00 // iInterface: 接口字符串索引(0表示无描述)
作用:声明控制接口为CDC-ACM模型,支持AT指令集
3.类特定功能描述符
3.1 1. Header Functional Descriptor
0x05, 0x24, 0x00, // 类特定接口描述符(类型0x24),子类型0x00(Header) 0x10, 0x01 // bcdCDC=0x0110(CDC协议版本1.1)[2](@ref)
作用:声明CDC协议版本号
3.22. Call Management Functional Descriptor
0x05, 0x24, 0x01, // 子类型0x01(呼叫管理) 0x00, 0x01 // bmCapabilities=0x00(不处理呼叫管理),bDataInterface=0x01(关联数据接口)[2](@ref)
作用:关联控制接口与数据接口
3.33. ACM Functional Descriptor
0x04, 0x24, 0x02, // 子类型0x02(抽象控制模型) 0x02 // bmCapabilities=0x02(支持SET_LINE_CODING等串口控制指令)[2](@ref)
作用:声明ACM功能支持的特性
3.4 控制接口端点(Interrupt Endpoint)
0x07, USB_DESC_TYPE_ENDPOINT, // 端点描述符(类型0x05) CDC_CMD_EP, 0x03, // 端点地址(IN方向),传输类型0x03(中断传输) CDC_CMD_PACKET_SIZE, // 最大包大小(如64字节) CDC_HS_BINTERVAL // 轮询间隔(如16ms)[2](@ref)
作用:用于传输控制指令(如波特率设置请求)
3.5 数据接口描述符
0x09, USB_DESC_TYPE_INTERFACE, 0x01, 0x00, 0x02, // 接口编号1,2个端点(Bulk IN/OUT) 0x0A, 0x00, 0x00 // 接口类0x0A(CDC数据类)[6](@ref)
作用:定义数据传输接口,与控制接口分离以实现高速通信
3.6数据接口端点
1.Bulk out 端点
0x07, USB_DESC_TYPE_ENDPOINT, CDC_OUT_EP, 0x02, // 端点地址(OUT方向),传输类型0x02(批量传输) CDC_DATA_HS_MAX_PACKET_SIZE // 最大包大小(如512字节)
- Bulk In 端点
0x07, USB_DESC_TYPE_ENDPOINT, CDC_IN_EP, 0x02, // 端点地址(IN方向) CDC_DATA_HS_MAX_PACKET_SIZE
OUT 16 00
状态 ACK
SETUP 16 00
DATA0 80 06 03 03 09 04 FF 00
获取字符串描述符
IN 16 00
DATA1 1A 03 35 00 43 00 45 00 30 00 36 00 36 00 37 00 41 00 33 00 38 00 33 00 33 00
USB设备的序列号字符串描述符
长度 1A 序列号 03 读取内部唯一的设备ID 寄存器地址,通常指向芯片出厂时烧录的96位唯一标识符
__ALIGN_BEGIN uint8_t USBD_StringSerial[USB_SIZ_STRING_SERIAL] __ALIGN_END = { USB_SIZ_STRING_SERIAL, USB_DESC_TYPE_STRING, }; static void Get_SerialNum(void) { uint32_t deviceserial0; uint32_t deviceserial1; uint32_t deviceserial2; deviceserial0 = *(uint32_t *) DEVICE_ID1; deviceserial1 = *(uint32_t *) DEVICE_ID2; deviceserial2 = *(uint32_t *) DEVICE_ID3; deviceserial0 += deviceserial2; if (deviceserial0 != 0) { IntToUnicode(deviceserial0, &USBD_StringSerial[2], 8); IntToUnicode(deviceserial1, &USBD_StringSerial[18], 4); } }
OUT 状态ACK
SET UP 16 00
DATA0 80 06 00 03 00 00 FF 00
获取字符串描述符 序列0
DATA 04 03 09 04
__ALIGN_BEGIN uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = { USB_LEN_LANGID_STR_DESC, USB_DESC_TYPE_STRING, LOBYTE(USBD_LANGID_STRING), HIBYTE(USBD_LANGID_STRING) };
LANG ID 作用:定义字符串的语言编码标准 英语0409 主机必须先获取该描述符,才能正确解码其他字符串描述符中的Unicode字符
状态 ack
SETUP 16 00
DATA0 80 06 02 03 09 04 ff 00
主机向设备请求产品描述符
void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len) { uint8_t idx = 0U; if (desc != NULL) { *len = (uint16_t)USBD_GetLen(desc) * 2U + 2U; unicode[idx++] = *(uint8_t *)(void *)len; unicode[idx++] = USB_DESC_TYPE_STRING; while (*desc != '\0') { unicode[idx++] = *desc++; unicode[idx++] = 0U; } } }
DATA1 2C 03 53 00 54 00 4D 00 33 00 32 00 20 00 56 00 69 00 72 00 74 00 75 00 61 00 6C 00 20 00 43 00 6F 00 72 00 74 00
"STM32 Virtual ComPort"
状态握手 ack
由于设备异常重新抓取了波形,每次枚举会重新分配地址新的地址是0x1C,枚举过程不会改变分配之后的地址,除非和主机断开连接接下去以0x1C地址枚举过程进行解释。
DATA 80 06 00 02 00 00 09 00
DATA1: 09 02 43 00 02 01 00 C0 32 USB设置配置/* Set configuration and Start the Class*/
主机向设备开启配置启动CDC 类
USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { USBD_StatusTypeDef ret = USBD_FAIL; if (pdev->pClass != NULL) { /* Set configuration and Start the Class*/ if (pdev->pClass->Init(pdev, cfgidx) == 0U) { ret = USBD_OK; } } return ret; }
状态ACK
接口请求:
bmRequest=0xA1 的协议分解
- 二进制格式:1010 0001
- 方向(bit7):→ IN传输(设备到主机)。
- 请求类型(bit6-5):→ 类特定请求(Class-Specific Request)。
- 接收者(bit4-0):→ 接口(Interface)。
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
/*---------------------------------------------------------------------*/ /* CDC definitions */ /*---------------------------------------------------------------------*/ #define CDC_SEND_ENCAPSULATED_COMMAND 0x00U #define CDC_GET_ENCAPSULATED_RESPONSE 0x01U #define CDC_SET_COMM_FEATURE 0x02U #define CDC_GET_COMM_FEATURE 0x03U #define CDC_CLEAR_COMM_FEATURE 0x04U #define CDC_SET_LINE_CODING 0x20U #define CDC_GET_LINE_CODING 0x21U #define CDC_SET_CONTROL_LINE_STATE 0x22U #define CDC_SEND_BREAK 0x23U
基础通信控制类请求
1. CDC_SEND_ENCAPSULATED_COMMAND (0x00)
- 功能此请求用于向设备发送封装命令,通常是传输某些自定义协议的命令帧。设备需要具备相应的解析逻辑来处理这些命令。
- 应用场景在嵌入式系统与PC之间的通信中,可能需要传输不符合标准协议的特殊数据或命令。STM32可以通过USB设备的控制回调函数接收该请求,并解析命令帧,根据需要执行特定操作(如传感器初始化、自定义协议切换等)。
2. CDC_GET_ENCAPSULATED_RESPONSE (0x01)
- 功能:该请求用于获取设备对封装命令的响应数据。通常,它与0x00请求结合使用,完成双向自定义协议通信。
- 应用场景:例如,在STM32应用中,当PC端通过CDC_SEND_ENCAPSULATED_COMMAND请求发送特定命令时,STM32设备可以通过此请求返回命令执行的结果或状态信息。
特性配置类请求
3. CDC_SET_COMM_FEATURE (0x02)
- 功能:用于设置通信接口的特性。例如,可以配置流控、数据格式等高级功能。这个请求允许用户根据应用需求定制通信的行为。
- 应用场景:在STM32的USB虚拟串口应用中,可以通过此请求来设置流控参数(如RTS/CTS流控)或配置数据格式(如奇偶校验位的设置),这对于高效且可靠的数据传输至关重要。
4. CDC_GET_COMM_FEATURE (0x03)
- 功能:该请求用于查询当前通信特性的配置状态。它通常在驱动程序初始化时使用,以便同步通信参数。
- 应用场景:在STM32的USB虚拟串口应用中,可以通过此请求查询当前的通信配置,确保主机和设备之间的一致性。例如,主机可以查询设备是否启用了流控功能,或者当前的通信数据格式。
串口参数控制类请求
5. CDC_SET_LINE_CODING (0x20)
- 功能:这是一个核心的配置请求,用于设置串口的基本通信参数,如波特率、数据位、停止位和奇偶校验位等。这是设置串口通信行为的关键步骤。
- 应用场景:在STM32的USB CDC应用中,通常需要在设备端通过CDC_Control_FS回调函数解析此请求。设备端通过解析传入的line_coding结构体,设置对应的通信参数。例如,在STM32中,通常会在USB CDC类驱动中接收到此请求后,更新串口硬件的配置,以确保数据能够按照指定的格式进行传输。
bmRequest=0x21 的协议分解
- 二进制格式:0010 0001
- 方向(bit7):→ OUT传输(设备到主机)。
- 请求类型(bit6-5):→ 类特定请求(Class-Specific Request)。
- 接收者(bit4-0):→ 接口(Interface)。
SETUP 1C 00
DATA 80 06 00 03 00 00 FF 00
请求 longin 之前提到过 语言类型
IN 1C 00
04 03 09 04 英语
状态ACK
SET UP :1C 00 获取厂商描述符
data0 80 06 01 03 09 04 FF 00
uint8_t * USBD_FS_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
UNUSED(speed);
USBD_GetString((uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
return USBD_StrDesc;
}
IN 1C 00
DATA1: 26 03 53 00 54 00 4D 00 69 00 63 00 72 00 6F 00 6C 00 65 00 63 00 74 00 6E 00 69 00 63 00 73 00
#define USBD_MANUFACTURER_STRING "STMicroelectronics"
状态ACK 握手