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 配置描述符(以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傳輸
一個傳輸有多個事務組成,一個事務由2/3個包組成。
傳輸又分爲四種類型:批量傳輸、等時(同步)傳輸、中斷傳輸、控制傳輸。
注意:USB傳輸數據先發數據低位再發高位數據
2.1 包
包的組成:
包的內容:
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):
令牌包用來啓動一次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設備插入主機後,會有以下活動:
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.
*/