4. USB枚举过程详解:复位、获取描述符、地址分配、配置选择

USB枚举是主机(Host)识别并配置新接入设备的核心协议过程。枚举由主机软件(USB驱动程序栈)发起,设备被动响应。整个过程涉及总线状态变化、控制传输(默认管道)以及设备固件的正确描述符返回。本章深入解析枚举的四个关键阶段:总线复位、获取描述符、地址分配和配置选择。

4.1 枚举全流程概览

从设备插入根集线器端口到设备就绪,主机侧依次执行以下步骤。下表总结了各阶段的核心动作与协议特征:

阶段 触发条件 主机动作 设备响应 传输类型
1. 复位 集线器检测到端口状态变化(D+/D-信号) 发送复位信号(SE0状态持续≥10ms) 复位内部状态机,默认地址0就绪 总线状态(非数据包)
2. 获取描述符 复位完成后主机收到设备连接确认 发送Get_Descriptor(Device)请求 返回设备描述符(前8字节或完整18字节) 控制传输(默认管道)
3. 地址分配 主机解析设备描述符后 发送Set_Address请求 保存新地址,返回ACK后切换地址 控制传输(默认管道)
4. 配置选择 地址分配完成,主机获取完整配置信息 发送Set_Configuration请求 按配置值初始化功能单元 控制传输(默认管道)
关键提示: 枚举过程中,设备在收到Set_Address之前始终使用默认地址0x00通信。地址分配后,主机必须等待设备完成内部地址切换(通常为2ms)才能使用新地址发起后续传输。

4.2 总线复位:枚举的起点

当根集线器检测到新设备插入(D+线被拉高,全速/高速设备)或D-线被拉高(低速设备)时,主机首先通过集线器端口发送复位信号。复位信号将D+和D-同时拉低(SE0状态)并维持至少10ms。设备检测到SE0后,执行以下内部操作:

  • 清空所有端点状态和缓冲区。
  • 将USB设备地址重置为0x00。
  • 将端点0(默认控制端点)配置为最大包长度(全速设备为64字节,低速设备为8字节)。
  • 进入默认状态(Default State),等待主机发送Setup包。

复位完成后,主机通过读取集线器端口状态寄存器确认设备已处于“已连接且复位完成”状态,随后开始第一次控制传输。

硬件视角: 复位期间,DMA引擎应暂停与USB控制器相关的所有数据传输,避免在总线状态不稳定时搬运无效数据。复位结束后,DMA通道需重新初始化描述符指针。
USB总线复位信号与设备状态转换 D+/D- SE0 (复位) ≥ 10ms 连接状态 复位中 默认状态 (地址0) 复位后设备 等待主机Setup包

4.3 获取描述符:主机识别设备身份

复位完成后,主机通过默认地址0x00向设备的端点0发送Get_Descriptor(Device)请求。这是一个标准控制传输,包含Setup阶段、数据阶段(可选)和状态阶段。主机通常先请求设备描述符的前8个字节,以获取端点0的最大包长度(bMaxPacketSize0),然后根据该长度重新调整后续传输的包大小。

设备描述符的关键字段如下:

偏移 字段 大小 说明
0 bLength 1字节 描述符长度(固定为18)
1 bDescriptorType 1字节 设备描述符类型码(0x01)
2-3 bcdUSB 2字节 USB规范版本号(BCD码,如0x0200表示USB 2.0)
4 bDeviceClass 1字节 设备类代码(0x00表示在接口描述符中定义)
7 bMaxPacketSize0 1字节 端点0最大包长度(8/16/32/64)
8-9 idVendor 2字节 厂商ID(由USB-IF分配)
10-11 idProduct 2字节 产品ID(厂商自定义)
常见问题: 如果设备在Get_Descriptor阶段返回的数据包长度小于请求长度,主机不会重试,而是直接使用已接收的数据。因此设备固件必须确保前8字节的bMaxPacketSize0字段正确,否则后续所有控制传输都可能因包长度不匹配而失败。
Get_Descriptor(Device) 控制传输流程 主机 (Host) 设备 (Device) Setup包 bmRequestType=0x80, bRequest=0x06 数据 (18字节) 设备描述符内容 ACK 主机解析bMaxPacketSize0

4.4 地址分配:设备获得唯一身份

主机解析设备描述符后,通过Set_Address请求为设备分配一个唯一的USB地址(范围1~127)。该请求同样通过默认地址0x00发送。设备收到请求后,必须:

  1. 立即返回ACK(在控制传输的状态阶段)。
  2. 在状态阶段完成后,在2ms内切换到新地址。
  3. 切换完成后,所有后续通信使用新地址。

主机在发送Set_Address后,会等待至少2ms(USB规范要求),然后使用新地址发送下一个请求。如果主机过早使用新地址,设备可能尚未完成切换,导致传输超时。

DMA协同要点: 地址分配阶段,DMA控制器应避免在设备地址切换窗口(2ms)内发起针对该设备的传输请求。建议在Set_Address的状态阶段完成后,由USB控制器硬件自动插入一个2ms的DMA暂停窗口,或由软件在DMA描述符链中插入一个等待标记。
Set_Address 请求与地址切换窗口 t 主机发Set_Address 设备返回ACK 设备切换地址 (≤2ms) 新地址就绪 ⚠ 主机必须等待至少2ms才能使用新地址发起传输 DMA引擎在此期间应暂停该设备的数据通道

4.5 配置选择:设备功能激活

地址分配完成后,主机继续获取设备的配置描述符、接口描述符和端点描述符。主机通过多次Get_Descriptor请求获取完整配置信息(配置描述符的总长度由wTotalLength字段指示)。

获取所有描述符后,主机根据设备类、接口数量和端点能力,选择一个合适的配置值(bConfigurationValue),发送Set_Configuration请求。设备收到该请求后:

  • 根据配置值初始化对应的功能单元(如启用端点、分配缓冲区)。
  • 将设备状态从“地址状态”(Address State)切换到“配置状态”(Configured State)。
  • 此时设备可以开始正常的数据传输(中断、批量、同步)。

如果主机发送的配置值等于0,设备将进入“未配置”状态,所有非控制端点被禁用。

性能建议: 在Set_Configuration完成后,主机应重新评估DMA通道的配置。例如,如果设备配置了批量输出端点,DMA应准备好对应的接收描述符链;如果配置了中断输入端点,DMA应周期性轮询该端点。建议在配置选择阶段由USB控制器触发一个DMA重配置中断。
配置选择后的设备状态与DMA通道映射 USB设备 (配置后) 端点0 (控制) 端点1 IN (中断) 端点2 OUT (批量) DMA通道映射 DMA通道0 → 端点0 (控制) DMA通道1 → 端点1 IN (中断) DMA通道2 → 端点2 OUT (批量) 配置选择完成后,DMA通道与端点绑定

4.6 枚举过程中的DMA协同策略

在枚举的每个阶段,DMA引擎的行为需要与USB控制器的状态机同步。以下是各阶段的DMA协同建议:

枚举阶段 DMA状态 操作建议
复位 暂停 清空所有与USB相关的DMA描述符链,等待复位完成中断
获取描述符 仅允许控制传输DMA DMA通道0(控制)预置描述符接收缓冲区,其他通道禁用
地址分配 暂停(2ms窗口) Set_Address状态阶段后,DMA插入2ms等待,不发起新传输
配置选择 重配置 根据Set_Configuration的值,动态分配DMA通道到对应端点
最佳实践: 在嵌入式系统中,建议将枚举阶段的DMA控制权交给一个专用的“枚举状态机”模块。该模块根据USB控制器的中断事件(复位完成、控制传输完成、地址切换完成)自动调整DMA通道的使能状态和描述符指针,避免CPU在枚举关键路径上频繁干预。