USB驱动开发-基于I.MX6ULL(底层协议)

USB框架

硬件框架

在USB系统中,有2个硬件概念:

  • USB Host:它跟处理器相连,处理器通过USB Host跟各类USB设备通信。USB Host中集成有一个root hub

  • USB Device:这分为两类设备

    • Hub:用来扩展USB接口

    • Function:就是普通的USB设备,比如U盘、声卡等

 

软件框架

                       

APP可以通过USB设备驱动程序访问USB设备, 也可以绕过USB设备驱动,直接通过USB控制器驱动访问USB设备。

USB电气信号

USB设备状态切换图

           

硬件线路

 USB连接涉及Hub Port和USB设备,硬件连接如下:

 

电子信号

        USB连接线有4条:5V、D+、D-、GND。数据线D+、D-,只能表示4种状态。USB协议中,很巧妙地使用这两条线路实现了空闲(Idle)、开始(SOP)、传输数据(Data)、结束(EOP)等功能。

设备连接与断开

连接

Hub端口的D+、D-都有15K的下拉电阻,平时为低电平。全速设备内部的D+有1.5K的上拉电阻,低速设备内部的D-有1.5K的上拉电阻,连接到Hub后会导致Hub的D+或D-电平变化,Hub根据变化的引脚分辨接进来的是全速设备还是低速设备。高速设备一开始也是作为全速设备被识别的。全速设备、高速设备连接时,D+引脚的电平由低变高:

低速设备连接时,D-引脚的电平由低变高:

断开

对于低速、全速设备,接到Hub时导致D-或D+引脚变为高电平,断开设备后,D-或D+引脚变为低电平:

对于高速设备,它先作为全速设备被识别出来,然后再被识别为高速设备。工作于高速模式时,D+的上拉电阻是断开的,所以对于工作于高速模式的USB设备,无法通过D+的引脚电平变化监测到它已经断开。工作于高速模式的设备,D+、D-两边有45欧姆的下拉电阻,用来消除反射信号:

复位

从状态切换图上看,一个USB设备连接后,它将会被供电,然后被复位。当软件出错时,我们也可以发出复位信号重新驱动设备。

那么,USB Hub端口或USB控制器端口如何发出复位信号?发出SE0信号,并维持至少10ms。

USB设备看到Reset信号后,需要准备接收"SetAddress()"请求;如果它不能回应这个请求,就是"不能识别的设备"。

设备速率识别

低速/全速

Hub端口的D+、D-都有15K的下拉电阻,平时为低电平。全速设备内部的D+有1.5K的上拉电阻,低速设备内部的D-有1.5K的上拉电阻,连接到Hub后会导致Hub的D+或D-电平变化,Hub根据变化的引脚分辨接进来的是全速设备还是低速设备。

高速

高速设备必定兼容全速模式,所以高速设备内部D+也有1.5K的上拉电阻,只不过这个电阻是可以断开的:工作于高速模式时要断开它。

高速设备首先作为全速设备被识别出来,然后Hub如何确定它是否支持高速模式?

Hub端口如何监测一个新插入的USB设备能否工作于高速模式?流程如下:

  • 对于低速设备,Hub端口不会监测它能否工作于高速模式。低速设备不能兼容高速模式。

  • Hub端口发出SE0信号,这就是复位信号

  • USB设备监测到SE0信号后,会发出"a high-speed detection handshake"信号表示自己能支持高速模式,这可以细分为一下3种情景

    • 如果USB设备原来处于"suspend"状态,它检测到SE0信号后,就发出"a high-speed detection handshake"信号

    • 如果USB设备原来处于"non-suspend"状态,并且处于全速模式,它检测到SE0信号后,就发出"a high-speed detection handshake"信号。这个情景,就是一个设备刚插到Hub端口时的情况,它一开始工作于全速模式。

    • 如果USB设备原来处于"non-suspend"状态,并且处于高速模式,它会切换回到全速模式(重新连接D+的上拉电阻),然后发出"a high-speed detection handshake"信号

"a high-speed detection handshake"信号,就是"高速设备监测握手信号",既然是握手信号,自然是有来有回:

  • USB设备维持D+的上拉电阻,发出"Chirp K "信号,表示自己能支持高速模式

  • 如果Hub没监测到"Chirp K "信号,它就知道这个设备不支持高速模式

  • 如果Hub监测到"Chirp K "信号后,如果Hub能支持高速模式,就发出一系列的"Chirp K"、"Chirp J"信号,这是用来通知USB设备:Hub也能支持高速模式。发出一系列的"Chirp K"、"Chirp J"信号后,Hub继续维持SE0信号直到10ms。

  • USB设备发出"Chirp K "信号后,就等待Hub回应一系列的"Chirp K"、"Chirp J"信号

    • 收到一系列的"Chirp K"、"Chirp J"信号:USB设备端口D+的上拉电阻,使能高速模式

    • 没有收到一系列的"Chirp K"、"Chirp J"信号:USB设备转入全速模式

 

数据信号

SOP起始包

起始包SOP(Start Of Packet),通过将D +和D-线从空闲状态驱动到相反的逻辑电平(K状态),由始发端口发信号通知分组的开始(SOP)。 此开关级别表示SYNC字段的第一位。 当重新传输到小于±5 ns时,集线器必须限制SOP第一位宽度的变化。 通过将通过集线器的标称数据延迟与集线器的输出使能延迟相匹配,可以最小化失真。

SYNC同步域

同步域(SYNC),这个域固定为 0000 0001,这个域通过 NRZI 编码之后,就是一串方波(NRZI 遇 0 翻转遇 1 不变),接受者可以用这个 SYNC 域来同步之后的数据信号。

因为在 USB 的 NRZI 编码下,逻辑 0 会造成电平翻转,所以接受者在接受数据的同时,根据接收到的翻转信号不断调整同步频率,保证数据传输正确。但是,这样还是会有一个问题,就是虽然接受者可以主动和发送者的频率匹配,但是两者之间总会有误差。假如数据信号是 1000 个逻辑 1,经过 USB的 NRZI 编码之后,就是很长一段没有变化的电平,在这种情况下,即使接受者的频率和发送者相差千分之一,就会造成把数据采样成 1001 个或者 999 个1 了。
USB 对这个问题的解决办法,就是强制插 0,也就是传说中的 bit-stuffing,如果要传输的数据中有 7 个连续的 1,发送前就会在第 6 个 1 后面强制插入一个 0,让发送的信号强制出现翻转,从而强制接受者进行频率调整。接受者只要删除 6 个连续 1 之后的 0,就可以恢复原始的数据了.

  • 低速或全速的同步域为00000001
  • 高速的同步域为31个0,后面为一个1。
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内容

包内容属于协议层,包括的内容大概为PID(包ID),地址,帧号,数据和CRC校验。

Packet内容

 

PID:
根据PID的内容,包可分为四大类:
Packet分四大类:

  • 命令 (Token) Packet
  • 帧首 (Start of Frame) Packet
  • 数据 (Data) Packet
  • 握手 (Handshake) Packet

地址:
地址包括设备地址和端点地址。其中设备地址占1字节,端点地址占4位。

地址

帧号:

  • 总共11位。主机每发出一个帧
  • 帧号都会自加1
  • 当帧号达到7FFH时,将归零重新开始计数
  • 仅在每个帧的帧首传输一次SOF

数据域
为USB传输的数据。对于不同的USB传输类型,数据域的数据长度从0到1024字节不等。

数据域

CRC校验域:
CRC校验域分为令牌校验域和数据校验域

  • 令牌Token CRC校验域
    计算地址域和帧号域的CRC:G(X) = X5 + X2 + 1

  • Data CRC
    计算数据域数据的CRC: G(X) = X16 + X15 + X2 + 1

 

NRZI与位填充

NRZI:Non Return Zero Inverted Code,反向不归零编码。NRZI的编码方位为:对于数据0,波形翻转;对于数据1,波形不变。

使用NRZI,发送端可以很巧妙地把"时钟频率"告诉接收端:只要传输连续的数据0即可。在下图中,低速/全速协议中"Sync Pattern"的原始数据是"00000001",接收端从前面的7个0波形就可以算出"时钟频率"。

 使用NRZI时,如果传输的数据总是"1",会导致波形维持不变。如果电平长时间维持不变,比如传输100位1时,如果接收方稍有偏差,就可能认为接收到了99位1、101位1。而USB中采用了Bit-Stuffing位填充处理,即在连续发送6个1后面会插入1个0,强制翻转发送信号,从而让接收方调整频率,同步接收。而接收方在接收时只要接收到连续的6个1后,直接将后面的0删除即可恢复数据的原貌。

通信协议

        我们在第二章了解了传输是通过“包格式”进行的,接下来我们详细讲解一下USB驱动和设备的通信

USB字节序:LSB先发,MSB后

组成

在USB协议中:

域组成了包,不同的域组成了不同类型的包(Token、Data、HandShake)

多个包一起组成了一个事务(SetUp事务,IN事务,OUT事务)

多个事务,进而组成了不同类型的传输(控制传输,中断传输,批量传输,同步传输)

包组成

包(Packet)是USB系统中信息传输的基本单元,所有数据都是经过打包后在总线上进行传输的。数据在总线上的传输以包为单位,包只能在帧内传输。帧起始由一个特定的包(SOF)表示,帧尾为EOF。EOF不是一个包,是一种电平状态,EOF期间不允许有数据传输。

包是USB总线传输的最小单位,不能被打断或干扰,否则会发生错误。若干个数据包组成一次事务传输,一次事务传输也不能被打断,属于一次事务传输的几个包必须连续,不能夸帧完成。一次传输由一次到多次事务传输构成,可以跨帧完成。

USB包由五部分组成,即同步字段(SYNC)、包标识符字段(PID)、数据字段、循环冗余校验字段(CRC)和包结尾字段(EOP),包格式如下图:

PID域

不同的PID标识了不同类型的USB包。由四位标识符+四位标识符反码组成

可以看出,由PID主要将USB的包分为了4类:

  • 令牌包(Token):01B

  • 数据包(Data):11B

  • 握手包(Handshake):10B

  • 特殊包(Special):00B

 

 PID 数据传输方向

IN                 Device->Host

OUT             Host ->Device

SETUP         Host->Device

PING            Device->Host

Address地址域

地址域有两部分组成:

【7bits的设备地址ADDR+4bits的端点地址ENDP】

 可以知道,USB系统最大支持链接127设备,每个设备最多32个端点。

这个ENDP只用在IN/OUT/SETUP令牌中。


Frame Number帧号域

当USB令牌包的PID为SOF时候,其数据字段为11位的帧序列号。帧号占11位,主机每发出一个帧,帧号会自加1,当帧号达到0x7FF时,将归0重新开始计数。对同步传输由重要的意义。

Data数据域

仅存在于Data信息包,根据不同的传输类型,拥有不同大小的字节(0--1023字节)

CRC域

用于进行数据的CRC校验

包类型

令牌包(Token)

  • OUT:通知设备将要输出一个数据包
  • IN:通知设备返回一个数据包
  • SETUP:只能用于控制传输中,也是通知设备将要输出一个数据包,与OUT令牌的区别是:只使用DATA0数据包,且只能发送到控制端点
  • SOF:在每帧开始时以广播的形式发送,针对USB全速设备,主机每1ms/125us产生一个帧,USB主机会对当前帧号进行统计,每次帧开始时通过SOF包发送帧号。
  • 输入包(IN)、输出包(OUT)、设置包(SETUP)的格式是一样的:       

        SYNC + PID + ADDR(7bits)+ENDP(4bits)+CRC(5bits) 

数据包(Data)

分为DATA0包和DATA1包,当USB发送数据时,如果一次发送的数据长度大于相应端点的容量时,就需要把数据包分为好几个包,分批发送,DATA0包和DATA1包交替发送,即如果第一个数据包是DATA0,那第二个数据包就是DATA1。也有特殊情况,同步传输,所有数据包都是DATA0

SYNC+PID+0~1023字节+CRC16

握手包(Handshake)

SYNC+PID

  • ACK:数据接收方用来回复发送方,表示正确接收到了数据并且有足够的空间保存数据。

  • NAK:Host发送数据给设备时,设备可以回应NAK表示"我还没准备好,没办法接收数据";Host想读取设备的数据时,设备可以回复NAK表示"我没有数据给你"。

  • STALL:表示发生了错误,比如设备无法执行这个请求(不支持该断点等待)、断点已经挂起。设备返回STALL后,需要主机进行干预才能接触STALL状态。

  • NYET:仅适用于高速设备。Host可以发出PING包用来确认设备有数据,设备可以回应NYET表示"还没呢"。Hub也可以回应NYET表示低速/全速传输还没完结。

 事务

        有以下四种事务:

  • 批量事务:用来传输大量的数据,数据的正确性有保证,时效没有保证。

  • 中断事务:用来传输周期性的、小量的数据,数据的正确性和时效都有保证。

  • 实时事务:用来传输实时数据,数据的正确性没有保证,时效有保证。

  • 建立事务:跟批量事务类似,只不过令牌包是SETUP令牌包。

事务由包组成,这些包分别处于3个阶段(phase):令牌阶段,数据阶段,握手阶段。  

 传输

  • 批量传输:就是使用批量事务实现数据传输,比如U盘。

  • 中断传输:就是使用中断事务实现数据传输,比如鼠标。

  • 实时传输:就是使用实时事务实现数据传输,比如摄像头。

  • 控制传输:由建立事务、批量事务组成,所有的USB设备都必须支持控制传输,用于"识别/枚举"

 

对于批量传输、中断传输、实时传输,它们分别由一个事务组成,不再细分为若干个过程。但是控制传输由多个事务组成,这些事务分别处于3个过程:建立过程(stage)、数据过程(stage)、状态过程(stage)。

批量传输

批量传输用批量事务来实现,用于传输大量的数据,数据的正确性有保证,时效没有保证。批量事务由3个阶段(phase)组成:令牌阶段、数据阶段、握手阶段。每个阶段都是一个完整的包,含有SOP、SYNC、PID、EOP。下图中各个矩形框就对应一个完整的包。

示例:

中断传输

中断传输用中断事务来实现,用于传输小量的、周期性的数据,数据的正确性和时效都有保证。中断事务由3个阶段(phase)组成:令牌阶段、数据阶段、握手阶段。每个阶段都是一个完整的包,含有SOP、SYNC、PID、EOP。下图中各个矩形框就对应一个完整的包。

中断事务跟批量事务非常类似,Host使用它来周期性地读数据、写数据。

以鼠标为例,我们需要及时获得鼠标的数据,不及时的话你会感觉鼠标很迟钝。但是USB协议中并没有中断功能,它使用"周期性的读、写"来实现及时性。具体过程如下:

  • Host每隔n毫秒发出一个IN令牌包

  • 鼠标有数据的话,发出DATA0或DATA1数据包给Host;鼠标没有数据的话,发出NAK给Host。

中断事务的优先级比批量事务更高,它要求实时性,而批量事务不要求实时性。

实时传输

实时传输用实时事务来实现,用于传输实时数据,对数据的正确性没有要求。

实时事务由2个阶段(phase)组成:令牌阶段、数据阶段。每个阶段都是一个完整的包,含有SOP、SYNC、PID、EOP。

实时事务不需要握手阶段,一个示例的场景是:为了传输摄像头的实时数据,偶尔的数据错误是可以忍受的,大不了出现短暂的花屏。如果为了解决花屏而重传数据,那就会导致后续画面被推迟,实时性无法得到保证。

实时事务跟中断事务非常类似,Host也会周期性的发起实时事务,主要区别在于:

  • 实时事务不要求准确性,没有握手阶段

  • 实时事务传输的数据量比较大,中断事务传输的数据量比较小

控制传输

在使用批量传输时,使用IN令牌包或OUT令牌包表示数据传输方向。

控制传输的令牌包永远是SETUP,怎么分辨是读数据,还是写数据?发出SETUP令牌包后,还要发出DATA0数据包,根据数据的内容来确定后续是读数据,还是写数据。这个过程称为"建立事务"(SETUP Transaction)

但是控制传输由多个事务组成,这些事务分别处于3个过程:建立过程(stage)、数据过程(stage)、状态过程(stage)。

  • 建立过程(stage),使用SETUP事务:Host发出SETUP令牌包、DATA0数据包、得到ACK握手包

  • 数据过程(stage),使用批量事务:

    • 对于输出:Host发出OUT令牌包,发出DATA0、DATA1数据包、得到ACK握手包

    • 对于输入:Host发出IN令牌包,读到DATA0、DATA1数据包、发出ACK握手包

  • 状态过程(stage),使用批量事务:

    • 对于输出:Host发出IN令牌包,读到DATA1数据包,发出ACK握手包

    • 对于输入:Host发出OUT令牌包,发出DATA1数据包,等待ACK握手包

 上图中的每一个方框,都是一个完整的事务,含有:Token Packet、Data Packet、Handshake Packet。

结语

本章已经结束,我们会继续更新第二章(usb枚举)、第三章(libusb的编写与使用)、第四章(手把手USB驱动编写),敬请期待

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值