USB枚举移植适配:从Host驱动到设备识别 - 第1节

1.1 USB总线发展史:从1.0到4.0的演进

通用串行总线(Universal Serial Bus,USB)自1996年正式发布以来,已成为电子设备最通用的有线连接标准。其演进历程不仅反映了数据传输速率的飞跃,更体现了电源管理、协议架构和物理层设计的持续革新。

版本 发布年份 理论最大速率 编码方式 核心特性
USB 1.0 / 1.1 1996 / 1998 1.5 Mbps (Low-Speed)
12 Mbps (Full-Speed)
NRZI + 位填充 热插拔、即插即用、总线供电
USB 2.0 2000 480 Mbps (Hi-Speed) NRZI + 位填充 微帧调度、事务分割(Split Transaction)
USB 3.2 Gen 1×1 2008 (USB 3.0) 5 Gbps (SuperSpeed) 8b/10b 双总线架构(USB 2.0 + SuperSpeed)、全双工
USB 3.2 Gen 2×2 2017 (USB 3.2) 20 Gbps 128b/132b 双通道传输、Type-C接口强制
USB4 Gen 3×2 2019 40 Gbps 128b/132b 基于Thunderbolt 3协议、隧道化传输

关键演进节点:USB 2.0引入的微帧(Microframe)机制将帧周期从1ms缩短为125μs,为等时传输提供了更精细的调度粒度;USB 3.0的双总线架构是向后兼容性的经典设计——保留完整的USB 2.0差分对(D+/D-),同时新增SuperSpeed差分对(SSTX/SSRX)。

嵌入式移植视角:在Host驱动适配时,USB 2.0的EHCI(Enhanced Host Controller Interface)与USB 3.0的xHCI(eXtensible Host Controller Interface)寄存器模型完全不同。xHCI统一管理所有速度等级的设备,而EHCI仅处理Hi-Speed事务,Full/Low-Speed需依赖UHCI/OHCI配合。

USB 协议演进时间线 USB 1.0/1.1 12 Mbps USB 2.0 480 Mbps USB 3.0/3.1 5~10 Gbps 8b/10b USB 3.2 20 Gbps USB4 40 Gbps 说明: USB 3.0 之后命名规则多次变更,USB 3.0 / 3.1 Gen 1 / 3.2 Gen 1×1 均为 5 Gbps 速率。 USB4 强制要求 Type-C 接口,并支持 DisplayPort 和 PCIe 隧道化传输。

1.2 物理层与电气特性

1.2.1 差分信号与线缆结构

USB物理层采用差分信号传输以抑制共模噪声。USB 2.0及以下版本使用一对差分线(D+/D-)进行半双工通信;USB 3.x/4.0在此基础上增加独立的SuperSpeed发送(SSTX+/-)和接收(SSRX+/-)差分对,实现全双工传输。

信号组 线缆数量 方向 适用版本 电气特性
VBUS 1 Host → Device 所有版本 4.75~5.25 V,最大电流随版本提升(0.5A→0.9A→3A/5A)
GND 1 公共地 所有版本 参考地平面
D+/D- 2 半双工 USB 1.0/2.0 差分阻抗 90Ω ±15%,信号摆幅 0~3.3V
SSTX+/- 2 Host → Device USB 3.x/4 差分阻抗 90Ω ±15%,摆幅 0.8~1.2V
SSRX+/- 2 Device → Host USB 3.x/4 差分阻抗 90Ω ±15%,摆幅 0.8~1.2V

电气适配陷阱:在嵌入式Host移植中,USB 2.0的D+/D-上拉/下拉电阻配置是设备识别的关键。Full-Speed设备在D+线上接1.5kΩ上拉至3.3V,Low-Speed设备则在D-线上接上拉。Host端D+/D-各接15kΩ下拉电阻,检测上拉信号以识别设备插入和速度等级。

1.2.2 速度识别与终端匹配

设备插入后,Host通过检测D+/D-的电压状态判断设备速度等级。USB 2.0规范定义了三种速度的电气识别方式:

  • Low-Speed (1.5 Mbps):D-线上拉,D+线保持低电平
  • Full-Speed (12 Mbps):D+线上拉,D-线保持低电平
  • Hi-Speed (480 Mbps):先以Full-Speed上拉D+,随后在Host发起的复位信号中通过Chirp J/K序列协商切换到Hi-Speed
USB 2.0 速度识别电气模型 Host 15kΩ 下拉 D+ D- Device Full-Speed D+ 1.5kΩ 上拉 1.5k 速度协商流程: 1. Host检测D+高电平 → 识别为Full-Speed设备 → 发送复位信号 2. 设备在复位期间发送Chirp K → Host回应Chirp J/K序列 → 切换到Hi-Speed

1.3 USB拓扑结构:Host、Hub与Device

1.3.1 分层星形拓扑

USB采用分层星形(Tiered Star)拓扑结构,由Host Controller作为根节点,通过Hub扩展下游端口,最多支持7层(Tier),包括根Hub在内。每个物理设备(Function)占用一个唯一地址(0~127),地址0保留给未配置的设备。

拓扑角色 功能描述 关键约束
Host Controller 总线主控,发起所有事务,管理带宽分配和电源 每个Host最多127个设备地址
Root Hub 集成在Host Controller内部,提供物理端口 通常2~4个端口,支持过流保护
Hub 端口扩展器,转发事务、管理电源、检测设备插入/移除 最多5层级联,每端口支持不同速度
Function (Device) 实现具体功能的外设,如HID、Mass Storage、CDC 复合设备可包含多个Function

枚举路径约束:在枚举过程中,Host通过Hub的端口状态变化(Port Change)检测设备插入。每个Hub端口有独立的状态寄存器,Host轮询Hub中断端点获取状态变化。设备地址分配必须在Set Address阶段完成,且地址0在复位后必须立即释放。

1.3.2 复合设备与多功能设备

USB设备可分为两种复合形态:

  • 复合设备(Composite Device):单个物理设备包含多个Function(接口),每个Function由不同的驱动程序管理。例如USB摄像头同时包含Video和Audio接口。
  • 复合设备(Compound Device):物理上包含一个内置Hub和一个或多个Function,例如带Hub功能的键盘。
USB 分层星形拓扑结构 Host Controller Root Hub Hub 1 (Tier 2) Hub 2 (Tier 2) Device A Device B Device C 复合设备 拓扑深度限制:从Root Hub到最末端Function最多经过5个Hub(7层Tier)。超过此限制的设备无法被Host识别。

1.3.3 Host驱动与设备枚举的桥梁

在嵌入式系统中,Host驱动(xHCI/EHCI/OHCI)负责管理拓扑中的事务调度和状态机。设备枚举是Host驱动与设备逻辑之间的第一次握手,其核心步骤包括:

  1. 设备插入检测:Hub端口状态寄存器检测到信号变化(D+/D-上拉)
  2. 复位与速度协商:Host发送复位信号(SE0),设备在复位期间完成速度识别
  3. 获取设备描述符:Host通过控制传输(Setup包)读取设备描述符的前8字节(获取最大包长度)
  4. 分配地址:Host发送Set Address请求,设备切换到新地址
  5. 完整枚举:读取配置描述符、接口描述符、端点描述符,加载对应驱动程序

移植适配要点:在裸机或RTOS环境下,Host驱动需要实现完整的控制传输状态机(Setup → Data → Status)。xHCI的TRB(Transfer Request Block)环管理机制与EHCI的QH(Queue Head)/TD(Transfer Descriptor)链表差异显著,移植时需重点关注链表维护和中断处理。

/* USB 设备枚举核心流程伪代码(Host 驱动侧) */
void usb_enumerate_device(uint8_t hub_port, uint8_t hub_addr) {
    // 1. 检测端口状态变化
    port_status_t status = hub_read_port_status(hub_addr, hub_port);
    if (status.connection_change) {
        // 2. 复位端口
        hub_set_port_feature(hub_addr, hub_port, PORT_RESET);
        delay_ms(10);  // 复位持续时间至少 10ms
        hub_clear_port_feature(hub_addr, hub_port, PORT_RESET);
        
        // 3. 读取端口速度
        uint8_t speed = hub_get_port_speed(hub_addr, hub_port);
        
        // 4. 分配设备地址(地址 0 为默认)
        uint8_t device_addr = allocate_device_address();
        
        // 5. 获取设备描述符前 8 字节(获取 bMaxPacketSize0)
        device_descriptor_t desc;
        usb_control_transfer(0, 0x80, GET_DESCRIPTOR, 
                             DEVICE_DESCRIPTOR, 0, 8, &desc);
        
        // 6. 设置设备地址
        usb_control_transfer(0, 0x00, SET_ADDRESS, 
                             device_addr, 0, 0, NULL);
        delay_ms(2);  // 地址切换稳定时间
        
        // 7. 完整读取设备描述符
        usb_control_transfer(device_addr, 0x80, GET_DESCRIPTOR,
                             DEVICE_DESCRIPTOR, 0, 18, &desc);
        
        // 8. 读取配置描述符并解析接口/端点
        configuration_descriptor_t cfg_desc;
        usb_control_transfer(device_addr, 0x80, GET_DESCRIPTOR,
                             CONFIGURATION_DESCRIPTOR, 0, 9, &cfg_desc);
        
        // 9. 选择配置
        usb_control_transfer(device_addr, 0x00, SET_CONFIGURATION,
                             cfg_desc.bConfigurationValue, 0, 0, NULL);
        
        // 10. 加载驱动
        usb_driver_bind(device_addr, &desc);
    }
}

常见枚举失败场景:

  • 复位时序不足:某些Hub芯片需要更长的复位保持时间(10~20ms),过短会导致设备无法进入配置状态
  • 地址冲突:未正确释放地址0或重复分配地址,导致设备无响应
  • 最大包长度误判:设备描述符前8字节中的bMaxPacketSize0字段决定了控制传输的数据阶段大小,读取错误将导致后续传输失败
  • Hub级联深度超限:超过5层Hub级联时,Host将忽略该设备