参考资料:韦东山usb驱动
usb手册
在软件开发过程中,我们可以忽略Hub的存在,硬件拓扑图简化如下:
一个物理设备里面可能有多个逻辑设备,Hos可以外接多个逻辑设备,硬件拓扑图如下:
要理解协议层、理解数据如何传输,带着这几个问题去看文档、看视频:
提前罗列出来:
先传输最低位(LSB)。
Host发出SOP信号后,就会发出SYNC信号:它是一系列的、最大传输频率的脉冲,接收方使用它来同步数据。对于低速/全速设备,SYNC信号是8位数据(从做到右是00000001);对于高速设备,SYNC信号是32位数据(从左到右是00000000000000000000000000000001)。使用NRZI编码时,前面每个"0"都对应一个跳变。
在很多文档里,把SOP和SYNC统一称为"SYNC",它的意思是"SYNC"中含有"SOP"。
USB总线上传输的数据以包为单位。USB包里含有哪些内容(“域”)?
发起一次完整的传输,可能涉及多个包。那么,第1个包里含有设备地址、端点号,后续的包就没必要包含设备地址、端点号。
注意:所有的USB文档提到的"输入"、“输出”,都是基于Host的角度,"输出"表示从Host输出到设备,"输入"表示Host从设备得到数据。
有哪些USB包?根据包数据里的PID的bit1, bit0可以分为4类:
PID有4位,使用bit1,bit0确定分类,使用bit3,bit2进一步细分。如下表(来自《圈圈教你玩USB》)所示:
在USB包中,PID域使用8位来表示,格式如下:
前4位表示PID,后4位是对应位的取反。接收方发现后4位不是前4位的取反的话,就认为发生了错误。
令牌类的PID,起"通知作用",通知谁?SOF令牌包被用来通知所有设备,OUT/IN/SETUP令牌包被用来通知某个设备。
对于OUT、IN、SETUP令牌包,它们都是要通知到具体的设备,格式如下:
USB设备的地址有7位,格式如下:
USB设备的端点号有4位,格式如下:
对于SOF包,英文名为"Start-of-Frame marker and frame number"。对于USB全速设备,Host每1ms产生一个帧;对于高速设备,每125us产生一个微帧,1帧里有8个微帧。Host会对当前帧号进行累加计数,在每帧或每微帧开始时,通过SOF令牌包发送帧号。对于高速设备,每1毫秒里有8个微帧,这8个微帧的帧号是一样的,每125us发送一个SOF令牌包。
SOF令牌包格式如下:
Host使用OUT、IN、SETUP来通知设备:我要传输数据了。数据通过"数据包"进行传输。
数据包也有4种类型:DATA0、DATA1、DATA2、MDATA。其中DATA2、MDATA在高速设备中使用。对软件开发人员来说,我们暂时仅需了解DATA0、DATA1。
为什么要引入DATA0、DATA1这些不同类型的数据包?为了纠错。
Host和设备都会维护自己的数据包切换机制,当数据包成功发送或者接收时,数据包类型切换。当检测到对方使用的数据包类型不对时,USB系统认为发生了错误。
比如:
数据包格式如下:
对于全速设备,数据包中的数据做大是1023字节;对于全速设备,数据包中的数据做大是1024字节。
握手包有4类:ACK、NAK、STALL、NYET
USB传输的基本单位是包(Packet),包的类型由PID表示。一个单纯的包,是无法传输完整的数据。
为什么?比如想输出数据,可以发出OUT令牌包,OUT令牌包可以指定目的地。但是数据如何传输呢?还需要发出DATA0或DATA1数据包。设备收到数据后,还要回复一个ACK握手包。
所以,完整的数据传输,需要涉及多个包:令牌包、数据包、握手包。这个完整的数据传输过程,被称为事务(Transaction)。
有些事务需要握手包,有些事务不需要握手包,有些事务可以传输很大的数据,有些事务只能传输小量数据。
有四类事务:
有四类传输(Transfer):
暂时记住这个关系:
事务由多个包组成,比如Host要发送数据给设备,这就会涉及很多个包:
这个完整的事务涉及3个包(Packet),分为3个阶段(Phase):
事务由包组成,这些包分别处于3个阶段(phase):令牌阶段,数据阶段,握手阶段。
对于批量传输、中断传输、实时传输,它们分别由一个事务组成,不再细分为若干个过程。
但是控制传输由多个事务组成,这些事务分别处于3个过程:建立过程(stage)、数据过程(stage)、状态过程(stage)。
总结起来就是:
批量传输用批量事务来实现,用于传输大量的数据,数据的正确性有保证,时效没有保证。
批量事务由3个阶段(phase)组成:令牌阶段、数据阶段、握手阶段。每个阶段都是一个完整的包,含有SOP、SYNC、PID、EOP。
下图中各个矩形框就对应一个完整的包。
《圈圈教你玩USB》中有详细的示例:
中断传输用中断事务来实现,用于传输小量的、周期性的数据,数据的正确性和时效都有保证。
中断事务由3个阶段(phase)组成:令牌阶段、数据阶段、握手阶段。每个阶段都是一个完整的包,含有SOP、SYNC、PID、EOP。
下图中各个矩形框就对应一个完整的包。
中断事务跟批量事务非常类似,Host使用它来周期性地读数据、写数据。
以鼠标为例,我们需要及时获得鼠标的数据,不及时的话你会感觉鼠标很迟钝。但是USB协议中并没有中断功能,它使用"周期性的读、写"来实现及时性。具体过程如下:
中断事务的优先级比批量事务更高,它要求实时性,而批量事务不要求实时性。
实时传输用实时事务来实现,用于传输实时数据,对数据的正确性没有要求。
实时事务由2个阶段(phase)组成:令牌阶段、数据阶段。每个阶段都是一个完整的包,含有SOP、SYNC、PID、EOP。
实时事务不需要握手阶段,一个示例的场景是:为了传输摄像头的实时数据,偶尔的数据错误是可以忍受的,大不了出现短暂的花屏。如果为了解决花屏而重传数据,那就会导致后续画面被推迟,实时性无法得到保证。
下图中各个矩形框就对应一个完整的包。
实时事务跟中断事务非常类似,Host也会周期性的发起实时事务,主要区别在于:
在使用批量传输时,使用IN令牌包或OUT令牌包表示数据传输方向。
控制传输的令牌包永远是SETUP,怎么分辨是读数据,还是写数据?发出SETUP令牌包后,还要发出DATA0数据包,根据数据的内容来确定后续是读数据,还是写数据。这个过程称为"建立事务"(SETUP Transaction)
但是控制传输由多个事务组成,这些事务分别处于3个过程:建立过程(stage)、数据过程(stage)、状态过程(stage)。
上图中的每一个方框,都是一个完整的事务,含有:Token Packet、Data Packet、Handshake Packet。