4. USB设备状态机
USB 设备的生命周期由一套严格定义的状态机管理。从物理连接到功能可用,设备必须依次经历 连接 (Attached)、上电 (Powered)、默认 (Default)、地址 (Address)、配置 (Configured) 五个核心状态,并可在任意时刻因总线空闲进入 挂起 (Suspended) 状态。理解这套状态机是掌握 USB 枚举流程的基石。
核心要点: 状态转换由主机发起的总线事件(复位、SETUP 事务、帧起始包)驱动,设备端被动响应。任何一步失败都会导致枚举终止或设备不被识别。
4.1 状态定义与转换条件
下表列出了 USB 2.0 规范定义的 6 个设备状态及其触发条件:
| 状态 | 触发条件 | 设备行为 | 主机视角 |
|---|---|---|---|
| 连接 (Attached) | 设备插入 USB 端口 | D+/D- 线上拉电阻生效,产生电平变化 | 检测到端口电平变化,准备供电 |
| 上电 (Powered) | 主机为端口提供 VBus (5V) | 内部电路上电,等待复位信号 | 端口已供电,等待设备稳定 |
| 默认 (Default) | 主机发送复位信号 (SE0 ≥ 10ms) | 复位结束后响应默认地址 0,等待主机请求 | 复位结束,开始枚举流程 |
| 地址 (Address) | 主机发送 SET_ADDRESS 请求 | 分配唯一地址,后续通信使用新地址 | 设备有了唯一标识,可进行配置 |
| 配置 (Configured) | 主机发送 SET_CONFIGURATION 请求 | 加载配置描述符,功能可用 | 设备功能就绪,可进行数据传输 |
| 挂起 (Suspended) | 总线空闲 ≥ 3ms | 进入低功耗模式,保留地址和配置 | 总线进入暂停状态,可唤醒 |
4.2 状态转换流程图
下图展示了 USB 设备状态机的完整转换路径,箭头上的标注为触发事件:
4.3 关键状态详解
4.3.1 默认状态与复位
设备上电后处于 上电状态,等待主机发送复位信号。主机通过将 D+ 和 D- 同时拉低至少 10ms(SE0 状态)来复位设备。复位结束后,设备进入 默认状态,此时:
- 设备地址为 0(默认地址),所有设备共享此地址进行初始通信。
- 设备响应主机在端点 0 上的控制传输请求。
- 设备的最大包长度(MaxPacketSize0)已确定(通过读取设备描述符的前 8 字节)。
常见陷阱: 复位信号持续时间不足 10ms 可能导致设备无法正确识别。部分低速设备对复位时序要求更严格,主机必须保证 SE0 信号连续且稳定。
4.3.2 地址状态与 SET_ADDRESS
主机在获取设备描述符后,通过控制传输发送 SET_ADDRESS 请求,为设备分配一个唯一的 1~127 之间的地址。设备在收到请求后:
- 在状态阶段完成后立即切换到新地址。
- 后续所有通信(包括获取配置描述符)都使用新地址。
- 地址分配后,设备进入 地址状态,但此时尚未加载功能配置。
// SET_ADDRESS 请求格式(主机到设备)
// bmRequestType: 0x00 (主机到设备,标准请求,设备接收)
// bRequest: 0x05 (SET_ADDRESS)
// wValue: 新地址 (0x01 ~ 0x7F)
// wIndex: 0x0000
// wLength: 0x0000
// 示例:分配地址 0x12
// 令牌包: 0x00 0x05 0x0012 0x0000 0x0000
// 设备在状态阶段后切换到地址 0x12
4.3.3 配置状态与 SET_CONFIGURATION
主机读取所有配置描述符后,发送 SET_CONFIGURATION 请求,选择设备的某个配置(通常为配置 1)。设备进入 配置状态 后:
- 加载所选配置下的所有接口和端点。
- 功能接口(如 HID、Mass Storage、CDC)开始工作。
- 设备可以开始进行批量、中断或同步传输。
调试技巧: 在逻辑分析仪上捕获 SET_CONFIGURATION 请求后,观察设备是否返回 ACK。如果设备返回 STALL,说明配置描述符解析失败或设备不支持该配置。
4.4 挂起与唤醒机制
当总线空闲超过 3ms 时,设备必须进入 挂起状态,以降低功耗。挂起状态下:
- 设备保留当前地址和配置信息。
- 设备电流消耗降至 500µA 以下(未配置时为 2.5mA)。
- 设备可通过远程唤醒信号(Resume)或主机发起的复位信号退出挂起。
挂起状态是 USB 电源管理的关键,尤其在电池供电设备中。主机通过周期性发送 SOF(帧起始包) 来防止总线空闲超过 3ms,从而避免设备意外挂起。
4.5 状态机与枚举流程的对应关系
下表将状态机转换与枚举流程中的具体步骤对应起来,方便实战调试时定位问题:
| 枚举步骤 | 设备状态 | 主机操作 | 常见失败原因 |
|---|---|---|---|
| 1. 检测设备插入 | 连接 → 上电 | 检测 D+/D- 电平变化,提供 VBus | 上拉电阻损坏、VBus 短路 |
| 2. 复位设备 | 上电 → 默认 | 发送 SE0 信号 ≥ 10ms | 复位时序不足、设备未响应 |
| 3. 获取设备描述符 | 默认 | 发送 GET_DESCRIPTOR 请求 | 端点 0 未配置、MaxPacketSize0 错误 |
| 4. 分配地址 | 默认 → 地址 | 发送 SET_ADDRESS 请求 | 地址冲突、设备未 ACK |
| 5. 获取配置描述符 | 地址 | 发送 GET_DESCRIPTOR (配置) | 描述符长度错误、接口描述符缺失 |
| 6. 选择配置 | 地址 → 配置 | 发送 SET_CONFIGURATION 请求 | 配置值无效、设备 STALL |
实战建议: 在调试枚举问题时,使用逻辑分析仪捕获总线上的复位信号和 SET_ADDRESS 请求。如果设备在复位后没有返回设备描述符,检查复位时序和端点 0 的最大包长度设置。如果 SET_ADDRESS 后设备无响应,检查地址分配是否与总线上的其他设备冲突。