目录
1、USB是什么
USB(Universal Serial Bus)全称通用串口总线,USB为解决即插即用需求而诞生,支持热插拔。USB协议版本有USB1.0、USB1.1、USB2.0、USB3.1等,USB2.0目前比较常用,以下以2.0为主介绍。由于USB是主从模式的结构,设备与设备之间、主机与主机之间不能互连,为解决这个问题,扩大USB的应用范围,出现了USB OTG,全拼 ON The Go。USB OTG 同一个设备,在不同的场合下可行在主机和从机之间切换。
1.1 USB特点:
USB1.0和USB1.1支持1.5Mb/s的低速模式和12Mb/bs的全速模式。在USB2.0以上支持480Mb/s的高速模式。应用如下:
1.2 USB设备供电方式:
USB设备有两种供电方式
- 自供电设备:设备从外部电源获取工作电压
- 总线供电设备:设备从VBUS(5v) 取电
- 对总线供电设备,区分低功耗和高功耗USB设备
- 低功耗总线供电设备:最大功耗不超过100mA
- 高功耗总线供电设备: 枚举时最大功耗不超过100mA,枚举完成配置结束后功耗不超过500mA
- 对总线供电设备,区分低功耗和高功耗USB设备
设备在枚举过程中,通过设备的配置描述符向主机报告它的供电配置(自供电/总线供电)以及它的功耗要求
如下 USB 配置描述符(以Joystick为例),后面具体介绍:
1.3 USB总线信号:
USB使用的是差分传输模式,两个数据线D+和D-
- 差分信号1:D+ > VOH(min) (2.8V) 且D- < VOL(max)(0.3V)
- 差分信号0:D- > VOH and D+ < VOL
- J状态(高电平):D+ 高,D- 低
- K状态(低电平):D+低,D- 高
- SEO状态:D+ 低,D- 高
- Reset信号:D+ and D- < VOL for >= 10ms ,主机在要和设备通信之前会发送Reset信号来把设备设置到默认的未配置状态。即主机拉低两根信号线(SE0状态)并保持10ms
- Idle状态:J状态数据发、送前后总线的状态
- Suspend状态:3ms以上的J状态
- SYNC: 3个KJ状态切换,后跟随2位时间的K状态(看到的波形变化是总线上发送0000 0001经过NRZI编码后的波形)
- Resume信号:20ms的K状态+低速EOP 主机在挂起设备后可通过翻转数据线上的极性并保持20ms来唤醒设备,并以低速EOP信号结尾带远程唤醒功能的设备还可自己发起该唤醒信号;前提是设备已进入idle状态至少5ms,然后发出唤醒K信号,维持1ms到15ms并由主机在1ms内接管来继续驱动唤醒信号
- SOP:从IDLE状态切换到K状态
- EOP:持续2位时间的SE0信号,后跟随1位时间的J状态
- Keep alive即低速EOP信号
1.4 USB插入检测和速度检测
主机通过设备在D+或D-上的1.5K上拉来检测设备的连接和断开事件,并由此判别设备的速度
主机先把高速设备检测为全速设备,然后再通过“Chirp序列”的总线握手机制来识别高速和全速设备
- USB连接和断开连接:
设备连上主机时(连接)
- 当主机检测到某一个数据线电平拉高并保持了一段时间,就认为有设备连上来了,主机必需在驱动SE0状态以复位设备之前,立刻采样总线状态来判断设备的速度
没有设备连上主机时(断开)
- D+和D-数据线上的下拉电阻起作用,使得二者都在低电平;主机端看来就是个SE0状态;同样地,当数据线上的SE0状态持续一段时间了,就被主机认为是断开状态
1.5 数据编解码和位填充
USB采用NRZI(非归零编码)对发送的数据包进行编码
- 输入数据0, 编码成“电平翻转”
- 输入数据1, 编码成“电平不变”
编码出来的序列,高电平:J状态;低电平:K状态
位填充是为了保证发送的数据序列中有足够多的电平变化,填充的对象是(输入数据),即先填充再编码 ,数据流中每6个连续的“1”,就要插入1个“0”,从而保证编码,数据出现电平变化,接收方赋值解码NRZI码流,然后识别出填充位,并丢弃它们
2. USB传输
一个transfer(传输)由一个或多个transaction(事务)构成,一个transaction(事务)由一个或多个packet(包)构成,一个packet(包)由一个或多个sync(域)构成。
1.传输数据通信
- USB的数据通讯首先是基于传输(transfer)的,传输的类型有:中断传输、批量传输、同步传输、控制传输。
2.事务数据通讯
- 一次传输由一个或多个事务(transaction)构成,事务可以分为:in事务、out事务、setup事务。
3.包数据通讯
- 一个事务由一个或多个包(packet)构成,包可分为:令牌包(setup)、数据包(data)、握手包(ack)、特殊包。
4.域数据通讯
- 一个包由多个域构成,域可分为:同步域(sync)、标识域(pid)、地址域(addr)、端点域(endp)、帧号域(fram)、数据域(data)、校验域(crc)。
注意:USB传输数据先发数据低位再发高位数据
以下对其具体进行分析
因为传输涉及事务,而事务又涉及包,包又涉及域,所以我们先分析包和域,再分析事件和传输
2、1包
2.1.1 包的组成:
2.1.2 包的内容:
Packet分四大类: 命令 (Token) 、Packet 帧首 (Start of Frame) 、Packet 数据 (Data) 、Packet 握手 (Handshake) Packet
不同类型包,以上的组成部件有所不同
- PID:
这里只用(PID0~4),PID4~7是PID0~4的取反,用来校验PID
PID1~0:01 令牌包、11 数据包、10 握手包、00 特殊包
- 地址:
- 帧号:
- 数据:
- CRC:
Packet分四大类:
- 命令 (Token)
- Packet 帧首 (Start of Frame)
- Packet 数据 (Data)
- Packet 握手 (Handshake) Packet
不同类型包,以上的组成部件有所不同
- 四种Packet类型之令牌包(Token Packet):
令牌包用来启动一次USB传输。
- 输出(OUT)令牌包:用来通知设备将要输出一个数据包
- 输入(IN)令牌包:用来通知设备返回一个数据包
- 建立(SETUP)令牌包:只用在控制传输中,和输出令牌包作用一样,也是通知设备将要输出一个数据包,两者区别在于:SETUP令牌包后只使用DATA0数据包,且只能发送到设备的控制端点,并且设备必须要接收,而OUT令牌包没有这些限制
- Packet类型之SOF Packet
帧起始包:在每帧(或微帧)开始时发送,以广播的形式发送,所有USB全速设备和高速设备都可以接收到SOF包。
0xA5:1010 0101:对应上面PID表可知是帧起始包
- Packet类型之Data Packet
- Packet类型之Handshake Packet
2、2 事件
Transaction可以分成三类
- Setup transaction:主机用来向设备发送控制命令
- Data IN transaction:主机用来从设备读取数据
- Data OUT transaction:主机用来向设备发送数据
Transaction的packet组成
- Token packet:总是由主机发出
- Data packet:包含此次transaction的数据负载
- 可选的Handshake packet
例子:
2、3 传输
USB协议定义了四种传输类型:
- 批量(大容量数据)传输(Bulk Transfers): 非周期性,突发
- 大容量数据的通信,数据可以占用任意带宽,并容忍延迟 。如USB打印机、扫描仪、大容量储存设备等
- 中断传输(Interrupt Transfers): 周期性,低频率
- 允许有限延迟的通信 如人机接口设备(HID)中的鼠标、键盘、轨迹球等
- 等时(同步)传输(Isochronous Transfers): 周期性
- 持续性的传输,用于传输与时效相关的信息,并且在数据中保存时间戳的信息 ,如音频视频设备
- 控制传输(Control Transfers): 非周期性,突发
- 用于命令和状态的传输
2.3.1 批量传输
批量输出事务:
- (1)主机先发出一个OUT令牌包(包含设备地址,端点号)
- (2)然后再发送一个DATA包,这时地址和端点匹配的设备就会收下这个数据包,主机切换到接收模式,等待设备返回握手包
- (3)设备解码令牌包,数据包都准确无误,并且有足够的缓冲区来保存数据后就会使用ACK/NYET握手包来应答主机(只有高速模式才有NYET握手包,他表示本次数据成功接收,但是没有能力接收下一次传输),如果没有足够的缓冲区来保存数据,就返回NAC,告诉主机目前没有缓冲区可用,主机会在稍后时间重新该批量传输事务。如果设备检查到数据正确,但端点处于挂起状态,返回STALL。如果检测到有错误(如校验错误,位填充错误),则不做任何响应,让主机等待超时。
批量输入事务:
- (1)主机首先发送一个IN令牌包(包含设备地址,端点号)
- (2)主机切换到接收数据状态等待设备返回数据。如果设备检测到错误,不做任何响应,主机等待超时。如果此时有地址和端点匹配的设备,并且没有检测到错误,则该设备作出反应:设备有数据需要返回,就将一个数据包放在总线上;如果没有数据需要返回,设备返回NAK响应主机;如果该端点处于挂起状态,设备返回STALL。如果主机收到设备发送的数据包并解码正确后,使用ACK握手包应答设备。如果主机检测到错误,则不做任何响应,设备会检测到超时。注意:USB协议规定,不允许主机使用NAK来拒绝接收数据包。主机收到NAK,知道设备暂时没有数据返回,主机会在稍后时间重新该批量输入事务。
PING令牌包,它不发送数据,直到等待设备的握手包。
2.3.2 中断传输
中断传输是一种保证查询频率的传输。中断端点在端点描述符中要报告它的查询间隔,主机会保证在小于
这个时间间隔的范围内安排一次传输。
2.3.3 等时传输
等时(同步)传输用在数据量大、对实时性要求高的场合,如音频设备,视频设备等,这些设备对数据的延迟很敏感。对于音频或视频设备数据的100%正确性要求不高,少量的数据错误是可以容忍的,主要是保证数据不能停顿,所以等时传输是不保证数据100%正确的。当数据错误时,不再重传操作。因此等时传输没有应答包,数据是否正确,由数据的CRC校验来确认。
2.3.4 控制传输
控制传输可分为三个过程:
- (1)建立过程
- (2)数据过程(可选)
- (3)状态过程
特性:
每个USB设备都必须有控制端点,支持控制传输来进行命令和状态的传输。USB主机驱动将通过控制传输与USB设备的控制端点通信,完成USB设备的枚举和配置
方向:
控制传输是双向的传输,必须有IN和OUT两个方向上的特定端点号的控制端点来完成两个方向上的控制传输
数据的拆分和数据传输完毕的判定 :
以高速设备的最大数据包长度64字节为例 ,要传输250字节,拆分成4个packet
要传输正好256字节,通过最后一个0字节包告诉设备传输完成
各种传输特性比较
3、USB标准请求
3.1 USB标准请求的数据结构
3.2 USB 设备枚举及描述符介绍
当一个USB设备插入主机后,会有以下活动:
在USB设备的逻辑组织中,包含设备、配置、接口和端点4个层次。设备通常有一个或多个配置,配置通常有一个或多个接口,接口通常有零个或多个端点。
include/uapi/linux/usb/ch9.h
/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 bcdUSB;
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
__u8 bMaxPacketSize0;
__le16 idVendor;
__le16 idProduct;
__le16 bcdDevice;
__u8 iManufacturer;
__u8 iProduct;
__u8 iSerialNumber;
__u8 bNumConfigurations;
} __attribute__ ((packed));
#define USB_DT_DEVICE_SIZE 18
struct usb_config_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wTotalLength;
__u8 bNumInterfaces;
__u8 bConfigurationValue;
__u8 iConfiguration;
__u8 bmAttributes;
__u8 bMaxPower;
} __attribute__ ((packed));
#define USB_DT_CONFIG_SIZE 9
/* USB_DT_INTERFACE: Interface descriptor */
struct usb_interface_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bInterfaceNumber;
__u8 bAlternateSetting;
__u8 bNumEndpoints;
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
__u8 iInterface;
} __attribute__ ((packed));
#define USB_DT_INTERFACE_SIZE 9
/* USB_DT_ENDPOINT: Endpoint descriptor */
struct usb_endpoint_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bEndpointAddress;
__u8 bmAttributes;
__le16 wMaxPacketSize;
__u8 bInterval;
/* NOTE: these two are _only_ in audio endpoints. */
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
#define USB_DT_ENDPOINT_SIZE 7
#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
/* USB_DT_STRING: String descriptor */
struct usb_string_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wData[1]; /* UTF-16LE encoded */
} __attribute__ ((packed));
/* note that "string" zero is special, it holds language codes that
* the device supports, not Unicode characters.
*/
例程分析
我们插上鼠标后后出现如下的信息,我们先来分析第一个传输:
我们看到第一个是控制传输,它包含了4个事物,分别是:1个setup事务,3个in事务,1个out事务,我们先打开setup事务: 我们看到这个事务里包含了3个包
- 第一个包是令牌包,它由主控制器发送给目标设备的0号端口,用于设置目标设备的地址和端口号,我们看到后面两个包都缺省了地址与端口号。在usb系统中,所有的通信都是由主机发出相应的令牌所引起的。
- 第二个是数据包,由主控器发送给目标设备,其中数据的内容表示:
- 80:表示要求设备向主机发送信息
- 06:表示GET_DESCRIPTOR,即设备向主机发送设备描述符
- 00与01:Word-sized field that varies according to request
- 00与40:Word-sized field that varies according to request; typically used to pass an index or offset
- 00:Number of bytes to transfer if there is a:Data stage
- 总结一下第二个包就是向默认地址0 发送GET_DESCRIPTOR 指令包,请求设备发送设备描述符
- 第三个是应答包:设备接收到主机发送的数据后会给出应答
接着我们看第一个in事务
我们看到这个事务里也有三个包
- 第一个是in包:由主机发送给设备,表示要设备向主机发送上面请求的设备描述符
- 第二个是数据包:由设备发送给主机,当然是发送设备描述符,我们来分析一下:
- 12:表示接下来要求主机向设备发送信息
- 01:CLEAR_FEATURE、
- 第三个是应答包,由主机发送给设备
接着我们来看第二个in事务
这个事务里依旧是3个包
- 第一个是in包:由主机发送给设备,表示需要输入
- 第二个是数据包:由设备发送给主机,我们来解析一下:
- 6D:表示要求主机发给设备数据
- 04:Reserved for future use
- 第三个是主机给设备的应答包
最后来看out事务
- 第一个是out包:由主机发给设备
- 第二个是数据包:由主机发给设备,无数据
- 第三个包是设备给主机的应答包