美文网首页
5. USB协议

5. USB协议

作者: 郑行_aover | 来源:发表于2019-01-08 18:30 被阅读0次

    https://blog.csdn.net/songze_lee/article/details/77658094

    1. USB概述

    USB总线属于一种轮询式总线,主机控制端口初始化所有的数据传输。每一总线动作最多传送三个数据包,包括令牌(Token)、数据(Data)、联络(HandShake)。

    按照传输前制定好的原则,在每次传送开始时,主机送一个描述传输动作的种类、方向、USB设备地址和终端号的USB数据包,这个数据包通常被称为令牌包(TokenPacket)。USB设备从解码后的数据包的适当位置取出属于自己的数据。数据传输方向不是从主机到设备就是从设备到主机。

    在传输开始时,由标志包来标志数据的传输方向,然后发送端开始发送包含信息的数据包或表明没有数据传送。接收端也要相应发送一个握手的数据包表明是否传送成功。发送端和接收端之间的USB数据传输,在主机和设备的端口之间,可视为一个通道。USB中有一个特殊的通道一缺省控制通道,它属于消息通道,设备一启动即存在,从而为设备的设置、状态查询和输入控制信息提供一个入口。

    2. USB基本知识普及

    1. 端点: 位于USB设备或主机上的一个数据缓冲区,用来存放和发送USB的各种数据,每一个端点都有惟一的确定地址,有不同的传输特性(如输入端点、输出端点、配置端点、批量传输端点) 

    2. 帧: 时间概念,在USB中,一帧就是1MS,它是一个独立的单元,包含了一系列总线动作,USB将1帧分为好几份,每一份中是一个USB的传输动作。 

    3. upstream、downstream(上行、下行):设备到主机为上行,主机到设备为下行

    4. USB传输线:vcc、gnd、D+、D- 差分线。3.3V电压

    5. 传送方式: 数据在usb线里由地位到高位传送

    6. USB的数据格式:USB数据是由二进制数字串构成的,首先数字串构成(有七种),域再构成包,包再构成事务(IN、OUT、SETUP),事务最后构成传输(中断传输、并行传输、批量传输和控制传输)

    3. USB的域

    7种域

    1、同步域(SYNC),八位,值固定为0000 0001,用于本地时钟与输入同步

    2、标识域(PID),由四位标识符+四位标识符反码构成,表明包的类型和格式,这是一个很重要的部分,这里可以计算出,USB的标识码有16种,具体分类请看问题五。

    3、地址域(ADDR):七位地址,代表了设备在主机上的地址,地址000 0000被命名为零地址,是任何一个设备第一次连接到主机时,在被主机配置、枚举前的默认地址,由此可以知道为什么一个USB主机只能接127个设备的原因。

    4、端点域(ENDP),四位,由此可知一个USB设备有的端点数量最大为16个。

    5、帧号域(FRAM),11位,每一个帧都有一个特定的帧号,帧号域最大容量0x800,对于同步传输有重要意义(同步传输为四种传输类型之一,请看下面)。

    6、数据域(DATA):长度为0~1023字节,在不同的传输类型中,数据域的长度各不相同,但必须为整数个字节的长度

    7、校验域(CRC):对令牌包和数据包(对于包的分类请看下面)中非PID域进行校验的一种方法,CRC校验在通讯中应用很泛,是一种很好的校验方法,至于具体的校验方法这里就不多说,请查阅相关资料,只须注意CRC码的除法是模2运算,不同于10进制中的除法。

    关于PID标识域名

            令牌包

            0x01:输出(OUT)启动一个方向为主机到设备的传输,并包含了设备地址和标号。

            0x09:输入(IN) 启动一个方向为设备到主机的传输,并包含了设备地址和标号。

            0x05:帧起始(SOF)表示一个帧的开始,并且包含了相应的帧号。

            0x0d:设置(SETUP)启动一个控制传输,用于主机对设备的初始化。

            数据包 :

            0x03:偶数据包(DATA0)。

            0x0b:奇数据包(DATA1)。

            握手包:

            0x02:确认接收到无误的数据包(ACK)。

            0x0a:无效,接收(发送)端正在忙而无法接收(发送)信息。

            0x0e:错误,端点被禁止或不支持控制管道请求。

            特殊包0x0C前导,用于启动下行端口的低速设备的数据传输。

    4. USB的包

    包:由域构成的包有四种类型,分别是令牌包、数据包、握手包和特殊包,前面三种是重要的包,不同的包的域结构不同,介绍如下

    1、令牌包:可分为输入包、输出包、设置包和帧起始包(注意这里的输入包是用于设置输入命令的,输出包是用来设置输出命令的,而不是放据数的)其中输入包、输出包和设置包的格式都是一样的:

    SYNC+PID+ADDR+ENDP+CRC5(五位的校验码)

    帧起始包的格式:

    SYNC+PID+11位FRAM+CRC5(五位的校验码)

    2、数据包:分为DATA0包和DATA1包,当USB发送数据的时候,当一次发送的数据长度大于相应端点的容量时,就需要把数据包分为好几个包,分批发送,DATA0包和DATA1包交替发送,即如果第一个数据包是 DATA0,那第二个数据包就是DATA1。但也有例外情况,在同步传输中(四类传输类型中之一),所有的数据包都是为DATA0,格式如下:

    SYNC+PID+0~1023字节+CRC16

    3、握手包:结构最为简单的包,格式如下

    SYNC+PID

    5. USB的事物

            分别有IN、OUT和SETUP三大事务,每一种事务都由令牌包、数据包、握手包三个阶段构成,这里用阶段的意思是因为这些包的发送是有一定的时间先后顺序的,事务的三个阶段如下:

            1、令牌包阶段:启动一个输入、输出或设置的事务。

            2、数据包阶段:按输入、输出发送相应的数据。

            3、握手包阶段:返回数据接收情况,在同步传输的IN和OUT事务中没有这个阶段,这是比较特殊的。

            事务的三种类型如下(以下按三个阶段来说明一个事务):

           5. 1、 IN事务:

            令牌包阶段——主机发送一个PID为IN的输入包给设备,通知设备要往主机发送数据;

            数据包阶段——设备根据情况会作出三种反应(要注意:数据包阶段也不总是传送数据的,根据传输情况还会提前进入握手包阶段)。

            1) 设备端点正常:设备往主机里面发出数据包(DATA0与DATA1交替);

            2) 设备正在忙:无法往主机发出数据包就发送NAK无效包,IN事务提前结束,到了下一个IN事务才继续;

            3) 相应设备端点被禁止:发送错误包STALL包,事务也就提前结束了,总线进入空闲状态。

            握手包阶段——主机正确接收到数据之后就会向设备发送ACK包。

            5.2、 OUT事务:

            令牌包阶段——主机发送一个PID为OUT的输出包给设备,通知设备要接收数据;

            数据包阶段——比较简单,就是主机会往设备送数据,DATA0与DATA1交替

            握手包阶段——设备根据情况会作出三种反应

            1) 设备端点接收正确,设备给主机返回ACK,通知主机可以发送新的数据,如果数据包发生了CRC校验错误,将不返回任何握手信息;

            2) 设备正在忙,无法给主机返回ACK,就发送NAK无效包,通知主机再次发送数据;

            3) 相应设备端点被禁止,发送错误包STALL包,事务提前结束,总线直接进入空闲状态。

           5.3、SETUT事务:

            令牌包阶段——主机发送一个PID为SETUP的输出包给设备,通知设备要接收数据;

            数据包阶段——比较简单,就是主机往设备送数据,注意,这里只有一个固定为8个字节的DATA0包,这8个字节的内容就是标准的USB设备请求命令,详见2.4。

            握手包阶段——设备接收到主机的命令信息后,返回ACK,此后总线进入空闲状态,并准备下一个传输(在SETUP事务后通常是一个IN或OUT事务构成的传输)。

    6. USB的四种传输

            USB系统中的数据传输,宏观看是在HOST和USB功能设备之间进行。微观看是在应用软件的Buffer和USB功能设备的端点之间进行。一般来说端点都有Buffer,可以认为USB通讯就是应用软件Buffer和设备端点Buffer之间的数据交换,交换的通道称为管道。应用软件通过和设备之间的数据交换来完成设备控制和数据传输。通常需要多个管道来完成数据交换,因为同一管道只支持一种类型的数据传输。用在一起来对设备进行控制的若干管道称为设备的接口,这就是端点、管道和接口的关系。

            USB 采用“令牌包”-“数据包”-“握手包”的传输机制,在令牌包中指定数据包去向或者来源的设备地址和端点(Endpoint),从而保证了只有一个设备对被广播的数据包/令牌包作出响应。握手包表示了传输的成功与否。

            USB 采用轮询的广播机制传输数据,所有的传输都由主机发起,任何时刻整个 USB 体系内仅允许一个数据包的传输,即不同物理传输线上看到的数据包都是同一被广播的数据包。

            传输由OUT、IN和SETUP事务构成,传输有四种类型,中断传输、批量传输、同步传输、控制传输,其中中断传输和批量传输的结构一样,同步传输有最简单的结构,而控制传输是最重要的也是最复杂的传输。

    6. 1.  控制传输:

            控制传输是一种可靠的双向传输,一次控制传输可分为三个阶段。

            第一阶段为从HOST到Device的SETUP事务传输,这个阶段指定了此次控制传输的请求类型;

            第二阶段为数据阶段,也有些请求没有数据阶段;第三阶段为状态阶段,通过一次IN/OUT 传输表明请求是否成功完成。

            控制传输通过控制管道在应用软件和 Device 的控制端点之间进行,控制传输过程中传输的数据是有格式定义的,USB 设备或主机可根据格式定义解析获得的数据含义。

             其他三种传输类型都没有格式定义。

             控制传输对于最大包长度有固定的要求。对于高速设备该值为 64Byte;对于低速设备该值为 8;全速设备可以是 8或 16或 32或 64。

             最大包长度 表征了一个端点单次接收/发送数据的能力,实际上反应的是该端点对应的Buffer 的大小。Buffer 越大,单次可接收/发送的数据包越大,反之亦反。

             当通过一个端点进行数据传输时,  若数据的大小超过该端点的最大包长度时,需要将数据分成若干个数据包传输,并且要求除最后一个包外,所有的包长度均等于该最大包长度。

              这也就是说如果一个端点收到/发送了一个长度小于最大包长度的包,即意味着数据传输结束。

          控制传输在访问总线时也受到一些限制,如:

    a. 高速端点的控制传输不能占用超过 20%的微帧,全速和低速的则不能超过 10%。 

    b. 在一帧内如果有多余的未用时间,并且没有同步和中断传输,可以用来进行控制传输。

    6. 2.  中断传输:

            中断传输是一种轮询的传输方式,是一种单向的传输HOST通过固定的间隔对中断端点进行查询,若有数据传输或可以接收数据则返回数据或发送数据,否则返回NAK,表示尚未准备好。

            中断传输的延迟有保证,但并非实时传输,它是一种延迟有限的可靠传输,支持错误重传

            对于高速/全速/低速端点,最大包长度分别可以达到1024/64/8 Bytes。

            高速中断传输不得占用超过 80%的微帧时间,全速和低速不得超过 90%。

            中断端点的轮询间隔由在端点描述符中定义,全速端点的轮询间隔可以是1~255mS,低速端点为10~255mS,高速端点为(2interval-1)*125uS,其中 interval取 1到 16之间的值。

             除高速高带宽中断端点外,一个微帧内仅允许一次中断事务传输,高速高带宽端点最多可以在一个微帧内进行三次中断事务传输,传输高达 3072 字节的数据。

          所谓单向传输,并不是说该传输只支持一个方向的传输,而是指在某个端点上该传输仅支持一个方向,或输出,或输入。如果需要在两个方向上进行某种单向传输,需要占用两个端点,

          分别配置成不同的方向,可以拥有相同的端点编号。

    6. 3.  批量传输:

          批量传输是一种可靠的单向传输,但延迟没有保证它尽量利用可以利用的带宽来完成传输,适合数据量比较大的传输。

          低速 USB 设备不支持批量传输,高速批量端点的最大包长度为 512,全速批量端点的最大包长度可以为 8、16、32、64。

          批量传输在访问 USB 总线时,相对其他传输类型具有最低的优先级,USB HOST 总是优先安排其他类型的传输,当总线带宽有富余时才安排批量传输。

          高速的批量端点必须支持PING 操作,向主机报告端点的状态,NYET 表示否定应答,没有准备好接收下一个数据包,ACK 表示肯定应答,已经准备好接收下一个数据包。

    6. 4.  同步传输:

              同步传输是一种实时的、不可靠的传输,不支持错误重发机制。只有高速和全速端点支持同步传输,高速同步端点的最大包长度为 1024,低速的为 1023。

              除高速高带宽同步端点外,一个微帧内仅允许一次同步事务传输,高速高带宽端点最多可以在一个微帧内进行三次同步事务传输,传输高达 3072 字节的数据。

              全速同步传输不得占用超过 80%的帧时间,高速同步传输不得占用超过 90%的微帧时间。 同步端点的访问也和中断端点一样,有固定的时间间隔限制。

               在主机控制器和 USB  HUB 之间还有另外一种传输——分离传输(Split  Transaction),它仅在主机控制器和 HUB之间执行,通过分离传输,可以允许全速/低速设备连接到高速主机。

              分离传输对于USB 设备来说是透明的、不可见的。

              分离传输:顾名思义就是把一次完整的事务传输分成两个事务传输来完成。其出发点是高速传输和全速/低速传输的速度不相等,如果使用一次完整的事务来传输,势必会造成比较长的等待时间,

              从而降低了高速 USB 总线的利用率。通过将一次传输分成两此,将令牌(和数据)的传输与响应数据(和握手)的传输分开,这样就可以在中间插入其他高速传输,从而提高总线的利用率。

    USB的最小单元是“域”,由“域”构成了“包”,在由“包”构成了“事务”,最后由“事务”构成了“传输”,在应用层面,我们看到的只是传输,所以USB协议栈就需要完成传输以下的所有事情。这对标准的USB协议栈提出了最基本的要求。 

    8.枚举

    8.1 枚举时USB的状态

    当USB设备插上主机时,主机就通过一系列的动作来对设备进行枚举配置(配置是属于枚举的一个态,态表示暂时的状态),这些态如下:

    1、接入态(Attached):设备接入主机后,主机通过检测信号线上的电平变化来发现设备的接入;

    2、供电态(Powered):就是给设备供电,分为设备接入时的默认供电值,配置阶段后的供电值(按数据中要求的最大值,可通过编程设置);

    3、缺省态(Default):USB在被配置之前,通过缺省地址0与主机进行通信;

    4、地址态(Address):经过了配置,USB设备被复位后,就可以按主机分配给它的唯一地址来与主机通信,这种状态就是地址态;

    5、配置态(Configured):通过各种标准的USB请求命令来获取设备的各种信息,并对设备的某些信息进行改变或设置。

    6、挂起态(Suspended):总线供电设备在3ms内没有总线操作,即USB总线处于空闲状态的话,该设备就要自动进入挂起状态,在进入挂起状态后,总的电流功耗不超过280uA。

    8.2 枚举过程

    1、用户将一个USB设备插入USB端口,主机为端口供电,设备此时处于上电状态。主机检测设备。集线器使用中断通道将事件报告给主机。

    2、主机发送Get_Port_Status(读端口状态)请求,以获取更多的设备信息。返回的消息告诉主机该设备是什么时候连接的。集线器检测设备是低速运行还是高速运行,并将此信息送给主机,这是对Get_Port_Status请求的响应。

    3、主机发送Set_Port_Feature(写端口状态)请求给集线器,要求它复位端口,请求集线器来重新设置端口。集线器使设备的USB数据线处于重启(RESET)状态至少10ms。

    4、主机使用Chirp K信号来了解全速设备是否支持高速运行。

    5、主机发送另一个Get_Port_Status请求,确定设备是否已经从复位状态退出。返回的数据有一位表示设备仍然处于重启状态。当集线器释放了重启状态,设备此时处于缺省状态,且已准备好在零端点通过缺省通道响应主机控制传输。缺省地址为00h,设备能从总线获取高达100mA的电流。

    6、集线器检测设备速度

            集线器通过测定哪根信号线(D+或D-)在空闲时有更高的电压来检测设备是低速设备还是全速设备。全速和高速设备D+有上拉电阻,低速设备D-有上拉电阻。

    7、获取最大数据包长度

    主机向address 0发送Get_Device_Deor(读设备描述符)报文,以取得缺省控制管道所支持的最大数据包长度。并在有限的时间内等待USB设备的响应。该长度包含在设备描述符的bMaxPacketSize0字段中,其地址偏移量为7,所以这时主机只需读取该描述符的前8个字节。注意,主机一次只能枚举一个USB设备,所以同一时刻只能有一个USB设备使用缺省地址0。

    例:主机向设备发送一个八字节请求:80 06 00 01 00 00 40 00,设备接收到请求后产生一个中断,我们可以通过读中断寄存器知道中断源,并且可以加读最后状态寄存器来确定第一个接到的包是否为一个Setup包。当控制器处理程序判断出它是一个Get_descriptor请求时,把设备描述符的前16个字节发送到端点0缓冲区中。剩下的2个字节描述符第一次请求时不再发送。

    8、主机分配一个新的地址给设备

            主机通过发送一个Set_Address请求来分配一个唯一的地址给设备。设备读取这个请求,返回一个确认,并保存新的地址。从此开始所有通信都使用这个新地址。

            例:当主机收到正确的前16字节描述符后,会给设备分配一个地址,我的PC分配的地址为:0x03(这个要看你的机子当时的USB接口设备数目而定) Set_Address 请求所发送的数据为:00 05 03 00 00 00 00 00,其中的03就表示主机为设备分配的地址为0x03,在以后的通信里设备就只对0x03地址作出应答。当设备产生一个接收中断后,根据所分配的地址设置设备的地址寄存器相应位。

    9、主机向新地址重新发送Get_Device_Deor命令,此次读取其设备描述符的全部字段,以了解该设备的总体信息,如VID,PID。

    例:主机发送设备描述符标准请求Get_descriptor:80 06 00 01 00 00 12 00,此次将要求把18个字节全部发送完。所以主机要分两次来读取。第一次读取16个字节,第二次读取两个字节,最后主机发送0表示发送完毕的应答。

    10、主机向设备循环发送Get_Device_Configuration命令,要求USB设备回答,以读取全部配置信息。

    11、主机发送Get_Device_String命令,获得字符集描述(unicode),比如产商、产品描述、型号等等。此时主机将会弹出窗口,展示发现新设备的信息,产商、产品描述、型号等。

            根据Device_Deor和Device_Configuration应答,PC判断是否能够提供USB的Driver,一般win2k能提供几大类的设备,如游戏操作杆、存储、打印机、扫描仪等,操作就在后台运行。但是Win98却不可以,所以在此时将会弹出对话框,索要USB的Driver。

    12、主机分配并加载设备驱动程序,这时就可能作应用中的数据传输了。

    13、主机发送Set_Configuration(x)(写配置)命令请求为该设备选择一个合适的配置(x代表非0的配置值)。如果配置成功,USB设备进入“配置”状态,并可以和客户软件进行数据传输。此时,常规的USB完成了其必须进行的配置和连接工作,至此设备应当可以开始使用。不过,USB协议还提供了一些用户可选的协议,设备如果不应答,也不会出错,但是会影响到系统的功能。

    14、主机为复合设备接口分配驱动程序。如果集线器检测到有过流现象,或者主机要求集线器关闭电源,则USB总线切断设备供电电源。在这种情况下,设备与主机无法通信,但设备处于连接状态。  

    8. USB的描述符

    Descriptor是一个完整的数据结构,可以通过C语言等编程实现,并存储在USB设备中,用于描述一个USB设备的所有属性,USB主机是通过一系列命令来要求设备发送这些信息的。它的作用就是给主机传递信息,从而让主机知道设备具有什么功能、属于哪一类设备、要占用多少带宽、使用哪类传输方式及数据量的大小,只有主机确定了这些信息之后,设备才能真正开始工作,所以描述符也是十分重要的部分,标准的描述符有5种,USB为这些描述符定义了编号:

            1——设备描述符

            2——配置描述符

            3——字符描述符

            4——接口描述符

            5——端点描述符

            上面的描述符之间有一定的关系,一个设备只有一个设备描述符,而一个设备描述符可以包含多个配置描述符,而一个配置描述符可以包含多个接口描述符,一个接口使用了几个端点,就有几个端点描述符。这些描述符是用一定的字段构成的,分别如下说明:

       1、设备描述符

    struct _DEVICE_DEscriptOR_STRUCT{

        BYTE bLength;                          //设备描述符的字节数大小,为0x12

        BYTE bDescriptorType;          //描述符类型编号,为0x01

        WORD bcdUSB;                       //USB版本号

        BYTE bDeviceClass;  //USB分配的设备类代码,0x01~0xfe为标准设备类,0xff为厂商自定义类型

                                                //0x00不是在设备描述符中定义的,如HID

        BYTE bDeviceSubClass;   //usb分配的子类代码,同上,值由USB规定和分配的

        BYTE bDeviceProtocl;             //USB分配的设备协议代码,同上

        BYTE bMaxPacketSize0;        //端点0的最大包的大小

        WORD idVendor;                      //厂商编号

        WORD idProduct;                     //产品编号

        WORD bcdDevice;                   //设备出厂编号

        BYTE iManufacturer;             //描述厂商字符串的索引

        BYTE iProduct;                      //描述产品字符串的索引

        BYTE iSerialNumber;          //描述设备序列号字符串的索引

        BYTE bNumConfiguration; //可能的配置数量

    }

      2、配置描述符

    struct _CONFIGURATION_DEscriptOR_STRUCT{

        BYTE bLength;                      //设备描述符的字节数大小,为0x12

        BYTE bDescriptorType;       //描述符类型编号,为0x01

        WORD wTotalLength;          //配置所返回的所有数量的大小

        BYTE bNumInterface;          //此配置所支持的接口数量

        BYTE bConfigurationVale;  //Set_Configuration命令需要的参数值

        BYTE iConfiguration;           //描述该配置的字符串的索引值

        BYTE bmAttribute;                  //供电模式的选择

        BYTE MaxPower;                   //设备从总线提取的最大电流

    }

    3、字符描述符

    struct _STRING_DEscriptOR_STRUCT{

        BYTE bLength;                              //设备描述符的字节数大小,为0x12

        BYTE bDescriptorType;               //描述符类型编号,为0x01

        BYTE SomeDescriptor[36];         //UNICODE编码的字符串

    }

            4、接口描述符

    struct _INTERFACE_DEscriptOR_STRUCT{

        BYTE bLength;                      //设备描述符的字节数大小,为0x12

        BYTE bDescriptorType;      //描述符类型编号,为0x01

        BYTE bInterfaceNunber;     //接口的编号

        BYTE bAlternateSetting;        //备用的接口描述符编号

        BYTE bNumEndpoints;        //该接口使用端点数,不包括端点0

        BYTE bInterfaceClass;          //接口类型

        BYTE bInterfaceSubClass;    //接口子类型

        BYTE bInterfaceProtocol;    //接口所遵循的协议

        BYTE iInterface;                    //描述该接口的字符串索引值

    }

            5、端点描述符

    struct _ENDPOIN_DEscriptOR_STRUCT{

        BYTE bLength;                        //设备描述符的字节数大小,为0x12

        BYTE bDescriptorType;          //描述符类型编号,为0x01

        BYTE bEndpointAddress;      //端点地址及输入输出属性

        BYTE bmAttribute;                   //端点的传输类型属性

        WORD wMaxPacketSize;       //端点收、发最大包的大小

        BYTE bInterval;                        //主机查询端点的时间间隔

    }

    相关文章

      网友评论

          本文标题:5. USB协议

          本文链接:https://www.haomeiwen.com/subject/fujbrqtx.html