2. USB包结构与传输:深入理解USB通信的基石
大家好,我是你们的讲师。今天我们来聊聊USB协议里最核心的部分——包结构与传输。说实话,很多工程师做了好几年USB开发,对这块的理解还是模模糊糊的。我个人觉得,搞懂USB包结构,就像拿到了USB世界的钥匙。你想想看,USB设备之间怎么交流?就是靠这些包。
2.1 USB包的组成:从SOP到EOP
一个完整的USB包,说白了就是一段有头有尾的数据。我习惯把它拆成六个部分来看:
- SOP(Start of Packet):包的起始标志。硬件检测到这个信号,就知道“哦,来活了”。
- PID(Packet Identifier):包的类型标识。这是包的“身份证”,告诉接收方这是个什么包。
- 地址(Address):目标设备的地址。USB总线上挂着那么多设备,总得知道发给谁吧。
- 端点(Endpoint):设备内部的“端口号”。一个设备可以有多个端点,就像你家有多个房间。
- CRC(Cyclic Redundancy Check):循环冗余校验。用来检查数据在传输过程中有没有出错。
- EOP(End of Packet):包的结束标志。告诉接收方“我说完了”。
重点提醒:PID字段只有4位,但实际传输时会复制一份取反,总共8位。这样做是为了提高可靠性。我在项目中遇到过PID被干扰导致误判的情况,后来加了硬件校验才解决。
嗯,这里要注意:SOP和EOP是物理层的东西,我们做软件开发的通常不直接操作它们。但理解它们的存在很重要,因为时序问题往往出在这里。
2.2 四种传输类型:各司其职
USB定义了四种传输类型,每种都有自己的脾气。我刚开始学的时候也觉得有点乱,后来发现其实很好理解——就看你的应用场景需要什么。
| 传输类型 | 特点 | 典型应用 | 带宽保证 |
|---|---|---|---|
| 控制传输 | 双向、可靠、有保证 | 设备枚举、配置 | 10%保留 |
| 批量传输 | 可靠、无带宽保证 | U盘读写、打印机 | 无 |
| 中断传输 | 可靠、有延迟保证 | 鼠标、键盘 | 有(轮询间隔) |
| 同步传输 | 不可靠、实时性高 | 音频、视频 | 有 |
2.2.1 控制传输
这是USB的“老大哥”。每个USB设备都必须支持控制传输。它分三个阶段:建立阶段、数据阶段(可选)、状态阶段。我曾经调试一个设备枚举失败的问题,查了两天才发现是控制传输的状态阶段没处理好。说白了,控制传输就像两个人握手——不仅要握上,还要确认握好了。
2.2.2 批量传输
批量传输的特点是“尽力而为”。它不保证带宽,但保证数据正确。你想想看,U盘拷贝文件时,快一点慢一点无所谓,但数据绝对不能错。这就是批量传输的用武之地。我建议在批量传输中一定要处理好错误重试机制,因为USB总线上的错误是不可避免的。
2.2.3 中断传输
名字叫“中断”,其实不是真的中断。它是主机定期轮询设备,看看有没有数据要传。鼠标、键盘都用这个。轮询间隔可以设置,从1ms到255ms不等。嗯,这里有个坑:如果你把轮询间隔设得太短,会占用大量总线带宽,影响其他设备。
2.2.4 同步传输
同步传输追求的是“准时”,而不是“准确”。音频数据丢一两个包,人耳听不出来;但要是延迟了,那声音就卡顿了。所以同步传输没有重试机制,也不保证数据正确。我记得有一次做USB麦克风,就是用了同步传输,效果还不错。
2.3 事务处理:Token、Data、Handshake
USB的事务处理,说白了就是一次完整的“对话”。每次对话包含三个阶段:
- Token包:主机发起,告诉设备“我要干嘛”。
- Data包:传输实际数据。
- Handshake包:确认收到或拒绝。
实战技巧:调试USB通信时,我习惯用逻辑分析仪抓Token包。看PID就能知道当前在做什么操作。比如OUT Token后面跟着DATA0/DATA1,IN Token后面等着设备发数据。
举个例子,主机要从设备读数据:
主机发送:IN Token(告诉设备我要读)
设备发送:DATA0/DATA1(设备把数据发出来)
主机发送:ACK(主机说收到了,没问题)
如果数据出错,设备会发NAK或者STALL。NAK表示“我还没准备好”,STALL表示“这个操作我不支持”。我在项目中遇到过设备一直发NAK的情况,后来发现是端点配置错了。
注意:同步传输没有Handshake阶段。因为它不需要确认,丢了就丢了。这也是为什么同步传输不适合传重要数据的原因。
最后说一句,USB协议看起来复杂,但只要你把包结构和事务处理搞清楚了,剩下的就是细节问题。我当年也是从一头雾水开始,慢慢摸索出来的。记住:多动手、多抓包、多分析,没有搞不定的USB问题。