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的事务处理,说白了就是一次完整的“对话”。每次对话包含三个阶段:

  1. Token包:主机发起,告诉设备“我要干嘛”。
  2. Data包:传输实际数据。
  3. Handshake包:确认收到或拒绝。

实战技巧:调试USB通信时,我习惯用逻辑分析仪抓Token包。看PID就能知道当前在做什么操作。比如OUT Token后面跟着DATA0/DATA1,IN Token后面等着设备发数据。

举个例子,主机要从设备读数据:

主机发送:IN Token(告诉设备我要读)
设备发送:DATA0/DATA1(设备把数据发出来)
主机发送:ACK(主机说收到了,没问题)

如果数据出错,设备会发NAK或者STALL。NAK表示“我还没准备好”,STALL表示“这个操作我不支持”。我在项目中遇到过设备一直发NAK的情况,后来发现是端点配置错了。

注意:同步传输没有Handshake阶段。因为它不需要确认,丢了就丢了。这也是为什么同步传输不适合传重要数据的原因。

最后说一句,USB协议看起来复杂,但只要你把包结构和事务处理搞清楚了,剩下的就是细节问题。我当年也是从一头雾水开始,慢慢摸索出来的。记住:多动手、多抓包、多分析,没有搞不定的USB问题。