1. 从DATA0/DATA1切换说起:USB的“暗号”与“默契”
大家好,我是你们的老朋友,一个在嵌入式USB开发里摸爬滚打了十多年的工程师。今天我们不聊那些高大上的框架,就聊一个最基础、但又最核心的机制——USB数据包的重传。你可能觉得,重传嘛,不就是发错了再发一次?听起来很简单,但USB协议的设计者却用一个极其巧妙的“暗号”系统,让主机和设备在看不见、摸不着的电信号里,达成了完美的“默契”。这个暗号,就是DATA0和DATA1。
想象一下这样一个场景:你和朋友在一条嘈杂的电话线里传递一串数字。为了防止漏听或听错,你们约定好,每说一个数字,就附带说一个“暗号”,比如第一个数字说“苹果”,第二个说“香蕉”,第三个又说“苹果”……如此交替。如果对方听到“苹果”,但收到的数字校验不对,他会回复“没听清,再说一遍”。这时,你必须重复上一个带“苹果”暗号的数字。如果对方听到“香蕉”但数字正确,他会回复“收到香蕉”,然后你们俩心里都默默地把下一个暗号切换成“苹果”。
USB的DATA0和DATA1,干的就是“苹果”和“香蕉”的活儿。它们本身不携带应用数据,而是数据包标识符(PID)的一部分,专门用来标识数据包的顺序。主机和设备各自心里都记着一个“预期暗号”(我们称之为数据切换序列位,Toggle Bit)。一次成功的通信,不仅仅是数据正确,还必须“暗号”对上。
我刚开始接触这个机制时,觉得它多此一举,直接用个计数器不就行了?后来在项目里踩过坑才明白,在高速、且没有全局时钟同步的串行总线里,这种极简的“乒乓”切换(0->1->0->1)是可靠性和实现复杂度之间最佳的平衡。它不需要维护复杂的序列号,只需要一个比特位的状态,就能实现错误检测、丢包发现和重传同步三大功能。接下来,我们就一层层剥开这个机制,看看它到底有多精妙。
2. 核心机制拆解:状态机如何同步起舞
要理解重传,必须先理解正常情况下的“完美舞步”。USB的数据传输以事务为单位,比如一个OUT事务(主机发给设备),包含令牌包、数据包、握手包三个阶段。DATA0/DATA1的切换就嵌在这个流程里。
2.1 完美流程:一次成功的“击掌”
我们假设主机和设备都从0状态开始(期待DATA0)。
- 主机行动:主机查看自己的状态位是0,于是发送一个DATA0数据包给设备。
- 设备验货:设备收到包,先做CRC校验,确保数据完好。同时,它检查数据包的PID,发现是DATA0,正好和自己期待的暗号(状态位0)匹配!
- 设备回应与翻转:设备高兴了,做两件事:一、回复一个ACK握手包,告诉主机“货已收到”;二、把自己的状态位从0翻转为1(现在期待DATA1了)。
- 主机确认与翻转:主


380

被折叠的 条评论
为什么被折叠?



