1. USB协议基础:USB总线架构、USB物理层与电气特性、USB数据包格式
大家好,我是你们的老朋友。今天咱们来聊聊USB协议的基础。说实话,很多做驱动的兄弟一上来就扎进代码里,结果遇到热插拔问题就抓瞎。我个人习惯是,先把底层的这些概念吃透,后面写代码才心里有底。
1.1 USB总线架构:从拓扑到角色
USB的总线架构,说白了就是一颗星形拓扑。你想想看,一个主机(Host)下面挂着一堆设备(Device),中间通过集线器(Hub)来扩展。这个结构其实挺像咱们公司的组织架构——老板(Host)发号施令,员工(Device)只能乖乖听话。
这里有个关键点:USB是主从架构。所有通信都由Host发起,Device永远不能主动说话。我在项目中遇到过新手写驱动,试图让设备主动上报数据,结果发现根本发不出去——嗯,这就是没搞懂架构。
核心角色:
- Host(主机):唯一的主控者,负责调度所有传输
- Device(设备):被动响应,不能主动发起事务
- Hub(集线器):负责扩展端口,检测设备插拔
我建议你记住一个数字:USB 2.0最多支持127个设备(包括Hub在内)。为什么是127?因为地址字段只有7位,0被保留给未配置的设备。这个细节在枚举过程中特别重要。
1.2 USB物理层与电气特性
物理层这块,说白了就是两根差分信号线(D+和D-)加上Vbus和GND。USB 2.0用半双工差分传输,速度最高480Mbps。我刚开始做驱动时,总觉得电气特性是硬件工程师的事,直到有一次设备在长线缆上频繁掉线——查了半天,原来是D+和D-的阻抗没匹配好。
避坑指南:我曾经在调试一个USB摄像头时,发现插上后主机能识别,但一传数据就断连。最后用示波器一看,D+信号线上的上升沿太缓了——线缆超过了5米。记住:USB 2.0的线缆建议不超过5米,否则信号完整性会出问题。
电气特性上,有几个关键参数你得记住:
| 参数 | USB 1.0/1.1 | USB 2.0 | 说明 |
|---|---|---|---|
| 速度 | 1.5 Mbps (Low) / 12 Mbps (Full) | 480 Mbps (High) | High Speed需要额外握手 |
| 信号电平 | 0~3.3V | 0~3.3V (HS: 400mV差分) | HS模式下摆幅更小 |
| 终端电阻 | D+或D-上拉1.5kΩ | D+和D-各接45Ω到地 | 用于速度识别 |
| 线缆最大长度 | 3m (Low) / 5m (Full) | 5m | 超过需加Hub中继 |
为什么会这样?因为USB用D+和D-上的上拉电阻来识别设备速度。Full Speed设备在D+上拉,Low Speed在D-上拉。High Speed设备先以Full Speed握手,再切换到HS模式。我记得第一次看这个协议时,觉得这个设计挺巧妙的——不用额外引脚就能区分速度。
1.3 USB数据包格式:从字节到事务
USB的数据传输,说白了就是包(Packet)的交换。每个包由同步字段(SYNC)、包标识符(PID)、数据字段和CRC组成。我建议你把这个结构刻在脑子里,因为后面写驱动时,所有错误排查都要回到包级别。
USB包的基本结构:
+--------+--------+--------+--------+--------+
| SYNC | PID | DATA | CRC | EOP |
| (8位) | (8位) | (0-1024字节)| (5/16位)| |
+--------+--------+--------+--------+--------+
PID(Packet Identifier)是包的类型标识,一共4位,但为了可靠性,会取反后重复4位。嗯,这里要注意:PID决定了包的类型和传输方向。常见的PID有:
- 令牌包(Token):OUT (0xE1)、IN (0x69)、SETUP (0x2D) —— 主机发起的传输方向
- 数据包(Data):DATA0 (0xC3)、DATA1 (0x4B) —— 数据交替翻转,用于错误检测
- 握手包(Handshake):ACK (0xD2)、NAK (0x5A)、STALL (0x1E) —— 设备响应状态
- 特殊包(Special):PRE (0x3C)、ERR (0x3C) —— 用于低速设备通信
我个人习惯把USB传输分成三个层次:
- 包(Packet):最底层的数据单元,上面已经讲了
- 事务(Transaction):由令牌包+数据包+握手包组成,完成一次数据交换
- 传输(Transfer):由多个事务组成,实现一次完整的读写操作
举个例子,你往U盘里写一个文件,底层其实是无数个OUT事务在跑。每个OUT事务包含:主机发OUT令牌包 → 主机发DATA0/DATA1数据包 → 设备回ACK/NAK握手包。如果设备回了NAK,说明它忙,主机得重试。
注意:我曾经在调试一个USB打印机驱动时,发现打印到一半就卡住了。抓包一看,设备连续回了3个NAK,然后主机就放弃了。原因是打印机缓存满了,但驱动没做重试逻辑。记住:NAK不是错误,是设备在说“我还没准备好”,驱动应该重试而不是放弃。
数据包里的DATA0和DATA1交替机制,是USB保证数据可靠性的关键。每次成功的事务后,主机和设备都会翻转数据包PID。如果收到重复的PID,说明上一包没被确认,需要丢弃。这个机制在USB 2.0的High Speed模式下尤其重要,因为480Mbps的速率下,噪声干扰的概率更高。
好了,USB协议基础就聊到这儿。这些概念虽然基础,但后面讲热插拔、枚举流程、驱动开发时,全都要用到。你想想看,如果连包格式都搞不清,怎么排查设备枚举失败的问题?
我的建议:刚开始学USB驱动时,别急着写代码。先拿一个USB分析仪(比如Beagle USB 480)抓抓包,看看真实的USB通信长什么样。我当年就是这么干的——看了一周的抓包数据,后面写驱动基本没出过大错。
公众号:蓝海资料掘金营,微信deep3321