1. USB协议基础
USB(Universal Serial Bus)自1996年诞生以来,已成为嵌入式系统中最通用的外设连接标准。理解USB协议是调试USB驱动、配置设备树时钟的前提。本节从总线拓扑、传输类型和描述符体系三个核心维度展开。
1.1 USB总线拓扑结构
USB采用星形-菊花链混合拓扑,由主机(Host)、集线器(Hub)和功能设备(Function)三层构成。主机控制器(Host Controller)位于拓扑根部,通过根集线器(Root Hub)向下扩展,最多支持7层(含根集线器),最多127个设备(含集线器)。
关键概念: 在嵌入式Linux中,主机控制器通常集成在SoC内部(如i.MX6的EHCI/OHCI控制器),通过设备树节点描述其基地址、中断号和时钟源。
1.2 USB传输类型
USB协议定义了四种传输类型,分别对应不同的带宽、延迟和可靠性需求。驱动开发者需要根据设备类型选择正确的端点(Endpoint)配置。
| 传输类型 | 带宽保证 | 错误重试 | 典型应用 | 端点类型 |
|---|---|---|---|---|
| 控制传输 | 10% 保留 | 硬件重试 | 枚举、描述符读取、命令设置 | 默认端点 (EP0) |
| 批量传输 | 无保证 | 硬件重试(CRC) | U盘、打印机、网络适配器 | Bulk端点 |
| 中断传输 | 有保证(轮询间隔) | 硬件重试 | 鼠标、键盘、游戏手柄 | Interrupt端点 |
| 同步传输 | 有保证(带宽) | 无重试 | 音频、视频、摄像头 | Isochronous端点 |
调试提示: 在Linux内核中,通过
usb_endpoint_descriptor 结构体的 bmAttributes 字段判断传输类型:0x00=控制,0x02=批量,0x03=中断,0x01=同步。使用 lsusb -v 可查看端点描述符。
1.3 USB描述符体系
USB描述符是设备向主机报告自身能力的结构化数据。主机通过控制传输(标准设备请求 GET_DESCRIPTOR)逐层获取描述符,完成枚举。描述符采用TLV(Type-Length-Value)格式,每个描述符以bLength和bDescriptorType开头。
描述符层级结构
- 设备描述符(Device Descriptor):描述USB规范版本、设备类、厂商ID(VID)、产品ID(PID)、配置数量等。每个设备只有一个。
- 配置描述符(Configuration Descriptor):描述供电模式、最大电流、接口数量。每个设备至少一个配置。
- 接口描述符(Interface Descriptor):描述功能接口、协议、备用设置。一个配置可包含多个接口。
- 端点描述符(Endpoint Descriptor):描述端点地址、方向、传输类型、最大包大小。每个接口至少一个端点(EP0除外)。
- 字符串描述符(String Descriptor):提供可读的厂商名、产品名、序列号(可选)。
关键描述符字段速查
| 描述符类型 | bDescriptorType值 | 关键字段 | 长度(字节) |
|---|---|---|---|
| 设备描述符 | 0x01 | idVendor, idProduct, bcdUSB, bNumConfigurations | 18 |
| 配置描述符 | 0x02 | bNumInterfaces, bMaxPower, bConfigurationValue | 9 |
| 接口描述符 | 0x04 | bInterfaceNumber, bInterfaceClass, bInterfaceProtocol | 9 |
| 端点描述符 | 0x05 | bEndpointAddress, bmAttributes, wMaxPacketSize | 7 |
| 字符串描述符 | 0x03 | wLANGID[0](语言ID), bString(Unicode字符串) | 可变 |
驱动调试常见问题:
- 设备树中USB时钟频率配置错误(如UTMI时钟应为60MHz)会导致枚举失败,表现为
usb 1-1: device not accepting address。 - 描述符中
wMaxPacketSize必须与硬件FIFO大小匹配,否则批量传输会丢包。 - 高速设备(HS)必须支持
SetConfiguration请求,否则主机无法完成枚举。
枚举流程简述
- 复位:主机检测到设备插入,复位总线,设备地址为0。
- 获取设备描述符:主机发送
GET_DESCRIPTOR(DEVICE),读取前8字节(含最大包大小)。 - 设置地址:主机分配唯一地址(
SET_ADDRESS),设备切换到新地址。 - 获取完整描述符:主机重新获取完整设备描述符、配置描述符、接口描述符、端点描述符。
- 选择配置:主机发送
SET_CONFIGURATION,设备进入配置状态,驱动开始绑定。
内核调试命令: 使用
usbmon 或 cat /sys/kernel/debug/usb/usbmon/0u 可实时抓取USB总线上的URB(USB Request Block)数据,分析枚举失败原因。