USB电气特性与信号编码:电压、电流与NRZI的底层逻辑
说实话,很多做嵌入式开发的朋友,一开始接触USB,往往先被各种协议层、描述符搞得头大。但我个人习惯是,先搞懂最底层的电气特性和信号编码。为什么?因为你在实际项目中遇到的绝大多数硬件问题——设备不枚举、通信不稳定、线长一点就掉线——根源都在这一层。
这一章,我们就来扒一扒USB的“物理层”。电压多高?电流多大?数据是怎么在两根线上“跑”起来的?
1. USB的电压等级:不只是5V那么简单
USB总线电压,大家最熟悉的是VBUS上的5V。但这里有个细节,我当年第一次做USB HUB项目时就踩过坑——VBUS的电压范围是4.75V到5.25V,不是精确的5V。
| 参数 | USB 2.0 规范值 | 实际工程建议 |
|---|---|---|
| VBUS 标称电压 | 5.0 V | 4.75 V – 5.25 V |
| VBUS 最低允许电压(主机端) | 4.75 V | 4.4 V(考虑线损) |
| 设备端最低工作电压 | 4.4 V | 4.0 V(部分低功耗芯片) |
| D+/D- 差分信号摆幅 | 0 – 3.3 V | 实际约 0 – 3.6 V |
2. 电流限制:主机不是无限电源
USB主机对每个端口都有严格的电流限制。你想想看,如果每个设备都随便取电,主机电源早就烧了。
- USB 2.0 低功耗设备: 最大 100 mA(枚举前) / 150 mA(配置后)
- USB 2.0 高功耗设备: 最大 500 mA(需配置描述符声明)
- USB 3.0 / 3.1: 最大 900 mA / 1.5 A(需协商)
- USB BC 1.2(充电协议): 最大 1.5 A / 3 A(需专用握手)
3. NRZI编码机制:数据是怎么“跑”起来的?
USB的数据传输,用的是NRZI(Non Return to Zero Inverted)编码。说白了,就是“电平翻转表示0,电平不变表示1”。
为什么会用这种编码?因为USB只有两根数据线(D+和D-),没有独立的时钟线。NRZI编码把时钟信息“嵌入”到数据流中,接收端通过检测电平变化来恢复时钟。
举个例子:
- 发送数据:
0 1 0 0 1 1 0 - NRZI编码:电平在遇到“0”时翻转,遇到“1”时保持不变
- 起始电平假设为高,编码后:
低 低 高 低 低 低 高
你看,连续的“0”会导致电平频繁翻转,接收端很容易同步。但连续的“1”会导致电平长时间不变,接收端就可能失锁。这就是为什么需要位填充(Bit Stuffing)。
4. 位填充(Bit Stuffing):防止“死锁”的妙招
NRZI编码有个致命弱点:如果数据中出现连续6个以上的“1”,电平就会一直不变,接收端的PLL(锁相环)会失锁,导致数据错误。
解决方案很简单:发送端在连续6个“1”之后,强制插入一个“0”。这个“0”会强制电平翻转一次,让接收端重新同步。
- 发送端:每检测到连续6个“1”,就在第6个“1”之后插入一个“0”
- 接收端:每收到连续6个“1”,就自动丢弃后面的那个“0”
- 注意:这个“0”是填充位,不是有效数据
举个例子:
原始数据: 111111 0101
填充后: 1111110 0101
^ 这个0是填充的
我在调试一个USB键盘时,发现偶尔会丢包。用逻辑分析仪抓波形,发现就是位填充逻辑在FPGA实现时有个边界条件没处理好。嗯,这种问题最头疼,因为不是每次都复现。
5. 同步头(SYNC)与包尾(EOP):包的“身份证”
USB通信是以“包”为单位的。每个包都有固定的开始和结束标志。
5.1 同步头(SYNC)
SYNC字段用于让接收端与发送端时钟同步。USB 2.0的SYNC是8位的特定序列:00000001(注意,这是经过NRZI编码前的数据)。
- 前7个“0”产生7次电平翻转,让PLL锁定
- 最后一个“1”作为同步完成标志
- 接收端检测到SYNC后,开始接收后续数据
5.2 包尾(EOP)
EOP(End of Packet)标志包的结束。USB 2.0的EOP是单端0(SE0)状态,持续2个位时间。
- SE0:D+和D-同时拉低(差分“0”状态)
- 持续2个位时间后,进入空闲状态(J状态)
- 接收端检测到SE0,就知道包结束了
6. 知识结构图:USB物理层核心要素
下面这张图,把本章的核心知识点串起来了。你可以把它当作一个快速参考。
7. 实战中的几个关键点
最后,分享几个我在项目中积累的经验,希望能帮你少走弯路。
- 测量VBUS电压: 不要只测主机端,一定要在设备端USB座子处测。线损和接触电阻会让电压掉很多。
- 电流检测: 如果设备枚举失败,先检查电流是否超标。很多主机在检测到过流时会自动断开端口。
- 信号完整性: D+/D-走线要等长,阻抗控制在90Ω±15%。我见过一个项目,因为D+和D-走线长度差了2cm,导致高速模式无法工作。
- 逻辑分析仪: 调试NRZI和位填充问题时,逻辑分析仪是你的好朋友。抓一段波形,对照协议分析,问题往往一目了然。