USB是串行总线,所以数据是一位一位地在数据线上传送的。既然是一位一位传送的,就存在着一个数据位的先后问题。
USB采用的是LSB在前的方式,即现出来的是最低位的数据,接下来是次低位....最后是最高位(MSB)。一个包有被分成很多个域(field),而LSB、MSB就是以域来为单位划分的。
这里还有一个数据传输方向的问题,因为在USB系统中,主机处于主导地位,所以把设备到主机的数据叫做输入,从主机到设备的数据叫做输出。
USB总线上的数据传输是以包为基本单位的。一个包被分成不同的域。根据不同类型的包,所包含的域是不一样的。但是不同的包有一个共同的特点。就是都要以同步域开始,紧跟着一个包标识符PID(Packet Identifiter),最后以包结束符EOP(End Of Pactet)来结束这个包。
同步域:所有数据包都以同步(SYNC)字段开始,该字段是生成最大边缘过渡密度的编码序列。 输入电路使用它将输入数据与本地时钟对齐。 全速/低速设备SYNC被定义长度为8位(0000 0001),高速长度定义为32位(0000 0000 0000 0000 0000 0000 0000 0001)。 注意,这个长度是对发送端的要求,收到端的SYNC字段可可以少于这个数。下图是一个全速/低速设备,经过NRZI编码后的波形。SYNC字段中的最后两位是一个标记(电平未翻转,即受到数据1),用于标识SYNC字段的结束,并通过推断来标识PID的开始。
下图为USB1.1设备的同步域数据包
起始包SOP(Start Of Packet):通过将D +和D-线从空闲状态驱动到相反的逻辑电平(K状态),由始发端口发信号通知分组的开始(SOP)。 此开关级别表示SYNC字段的第一位。 当重新传输到小于±5 ns时,集线器必须限制SOP第一位宽度的变化。 通过将通过集线器的标称数据延迟与集线器的输出使能延迟相匹配,可以最小化失真。
结束包EOP(End of Packet):
全速或低速设备的结束包:SE0状态用于发信号通知分组结束(EOP)。 通过将D +和D-驱动到SE0状态两位时间,然后将线路驱动到J状态一位时间来发信号通知EOP。 从SE0到J状态的转换定义了接收器处的分组的结束。 J状态被置位一个位时间,然后D +和D-输出驱动器都处于高阻态。 总线终端电阻将总线保持在空闲状态。
SE0的意思是D+和D-都表示为低电平。
高速设备的EOP:在高速信令中,以从EOP之前的最后一个符号到相反符号的转换开始。这个相反的符号是EOP模式中的第一个符号对于SOF以外的高速数据包。故意生成比特填充错误以指示EOP。需要接收器将任何位错误解释为EOP。发送的EOP定界符必须是没有位填充的NRZ字节01111111。例如,如果EOP字段之前的最后一个符号是J,则这将导致EOP为KKKKKKKK。对于高速SOF,传输的EOP分隔符需要5个NRZ字节而不需要填充比特,由01111111 11111111 11111111 11111111 11111111组成。因此,如果EOP字段之前的最后一位是J,这将导致线路上有40 K,线路必须返回到高速空闲状态。额外的EOP长度对接收器没有意义;它用于断开检测。
数据包标识符(packet identifier PID)紧跟在每个USB数据包的SYNC字段之后。 PID由一个四位数据包类型字段和一个四位校验字段组成,如图8-1所示。 PID指示数据包的类型,并通过推断,数据包的格式和应用于数据包的错误检测类型包。 PID的四位校验字段确保PID的可靠解码,以便正确解释分组的其余部分。 通过执行分组类型字段的一个补码来生成PID校验字段。 如果四个PID校验位不是它们各自的分组标识符位的补码,则存在PID错误。
主机和所有功能必须对所有接收的PID字段执行完整解码。 使用失败的检查字段接收的任何PID或解码为未定义的值的PID被假定为已损坏,并且数据包接收器将忽略它以及数据包的其余部分。 如果函数接收到其不支持的事务类型或方向的其他有效PID,则该函数不得响应。
例如,仅IN端点必须忽略OUT令牌。 表8-1中列出了PID类型,编码和描述。
*注意:PID位以MSb顺序显示。 当通过USB发送时,将首先发送最右边的位(位0)。
中文的借用圈圈大神的翻译。
PID分为四个编码组:令牌(01),数据(11),握手(10)和特殊(00),前两个传输PID位(PID <0:1>)表示哪个组。 这解释了PID代码的分布。
如果上面的没看明白,下面我贴出了令牌包的IN和握手包的NAK。
只要知道NRZI编码,看下面的就非常容易了。
IN包的PID是9H(低四位),取反是6H(高四位)。因为正常解析为0x69,因为是先发LSB,所以下面PID包的高低四位显示都调换了顺序显示。(为了看起来和波形移一致)
使用两个字段来处理功能端点:功能地址域和端点域。 函数需要完全解码地址和端点域。 不允许地址或端点别名,并且任一字段上的不匹配都必须导致忽略令牌。 访问非初始化端点也会导致令牌被忽略。
设备地址
功能地址(ADDR)字段通过其地址指定功能,该功能是数据包的源或目标,具体取决于令牌PID的值。 如图8-2所示,总共128个地址被指定为ADDR <6:0>。 ADDR字段指定用于IN,SETUP和OUT令牌以及PING和SPLIT特殊令牌。 根据定义,每个ADDR值定义单个函数。 复位和上电时,函数的地址默认值为零,并且必须在枚举过程中由主机编程。 函数地址零保留为默认地址(根hub使用),不能分配给任何其他用途。
端点地址
如图8-3所示,附加的四位端点(ENDP)字段允许更灵活地寻址需要多个端点的功能。 除端点地址为零外,端点号是特定于功能的。 端点字段定义为IN,SETUP和OUT令牌以及PING特殊令牌。 所有函数必须支持端点号为零的控制管道(默认控制管道)。 低速设备每个功能最多支持三个管道:端点号为零的控制管道加上两个额外的管道(两个控制管道,一个控制管道和一个中断端点,或两个中断端点)。 全速和高速功能最多可支持16个IN和OUT端点。
总结:地址是由两个地址构成,设备地址+端点地址
帧号域是11比特字段,其由主机在每帧的基础上递增。 帧号字段在达到其最大值7FFH时翻转,并且仅在每个(微)开始时以SOF令牌发送。
如下图,在帧号达到2047时翻转,又从0开始。
同时比对99537个包,它的帧号是0,占11位。(D+和D-只显示为NRZI编码,没显示强制插0)
总结:
数据域的范围可以是0到1,024字节,并且必须是整数个字节。 图8-4显示了多个字节的格式。 每个字节内的数据位首先从LSb移出。
根据不同的传输类型,定义如下一次最大传输量
数据域包分为以下四种。
在USB1.1中只定义了DATA0和DATA1。在USB2.0中增加了DATA2和MDATA,主要用在告诉分裂事物和高速带宽同步传输中。
而之所以使用不同类型的数据包,主要是用在握手包出错时纠错。下面以DATA0和DATA1包的切换为例来解释。
主机和从机都会维护自己的数据包切换机制,当数据包发送/接收成功时,数据包类型切换。当检测到对方使用的数据包不对时,USB系统认为发生了一个错误,并试图从错误中恢复。
数据包类型不匹配,主要发生在握手包被损坏的情形。当一端已经正确接收到数据并返回确认信号,确认信号却在传输中被损坏。这时另一端就无法知道刚发送的数据是否已经成功,这时它只好保持自己的数据包的类型不变。如果对方下一次使用的数据包类型跟自己的不一致,则说明他刚刚已经成功接收到数据包了。相反。如果对方下一次使用的数据包没有切换包类型,也就是说,刚刚的数据包没发送成功,这是上一次的重试操作。
下面给出了,发送成功情况下的四次数据包。
循环冗余校验(CRC)用于保护令牌和数据包中的所有非PID字段。PID不包含在包含CRC的分组的CRC校验中。 在执行比特填充之前,在发送器中的各个字段上生成所有CRC。 类似地,在去除填充位之后,在接收器中对CRC进行解码。令牌和数据包CRC为所有单比特和双比特错误提供100%的覆盖。 CRC失败被认为表示一个或多个受保护字段已损坏并导致接收器忽略这些字段,并且在大多数情况下,忽略整个数据包。
对于CRC生成和检查,生成器和检查器中的移位寄存器以全1模式播种。 对于发送或接收的每个数据位,当前余数的高阶位与数据位进行异或,然后剩余部分向左移位一位,低阶位设置为零。 如果该XOR的结果为1,则余数与生成多项式进行异或运算。 当发送被检查字段的最后一位时,发生器中的CRC被反转并首先被发送到检查器MSb。 当检查器接收到CRC的最后一位并且没有发生错误时,余数将等于多项式残差。
如果在分组接收结束时计算的校验和余数与残差不匹配,则存在CRC错误。
CRC必须满足比特填充要求,这包括如果前面的6比特都是1,则需要在CRC结束时插入零。
令牌CRC
为令牌提供五位CRC字段,并覆盖IN,SETUP和OUT令牌的ADDR和ENDP字段或SOF令牌的时间戳字段。 PING和SPLIT特殊令牌还包括一个五位CRC字段。
生成多项式为: G(X)= X^5 + X^2 + 1
如果一个多项式的二进制位模式是00101B。 如果接收到所有令牌位而没有错误,则接收器处的五位校验和将为01100B。
数据CRC
数据CRC是应用于数据分组的数据字段的16位多项式。
生成多项式是:G(X)= X^16 + X^15 + X^2 + 1
表示该多项式的二进制位模式是1000000000000101B。 如果没有错误地接收到所有数据和CRC位,则16位校验和将为1000000000001101B。