USB通信格式
USB接口最少有四根線連接,其中有兩根是數據線,而所有的USB數據傳輸都是通過這兩根線完成的,那麼它是怎麼做到的?
我們知道,串口為了實現通信,規定了起始位、停止位,有時候也可能增加奇偶校驗位,如果你知道了串口的波特率,那麼你就可以正確的接收到發送方發來的數據。那麼USB應該也有相應的通信格式要求才對,那它的格式是怎麼樣的?
串口中高電平代表1,低電平代表0,並且是全雙工通信,即可以同時發送和接收數據。而 USB 有所不同,它雖然也有兩根數據線,但它們卻是採用差分傳輸,即需要兩根數據線配合才能傳輸一個bit,因此是半雙工通信,同一時間只能發送或者接收。
首先我們需要了解一下差分 0 和差分 1 這兩種狀態:差分1:數據線 D+ 為高電平, D- 為低電平時為差分 1;差分0:數據線 D+ 為低電平, D- 為高電平時為差分 0。
但是要注意的是,這裡的差分0、差分1可不是代表數據0和1,而僅僅只是數據線表現的狀態,和真正的數據還有距離。USB 規定,如果電壓電平不變,代表邏輯1;如果電壓電平變化,則代表邏輯0,這就是 NRZI 。
看下圖進行理解:
USB不通信時,數據線處於閒置狀態(類似於串口的高電平閒置),一旦需要開始通信,首先切換到K狀態(類似串口的起始位),再進行實際的數據傳輸,在這裡傳輸的數據為 000011,實際的數據線狀態為差分101000,傳輸完畢後需要發送結束信號EOP:2位的 SE0,再加 1 位的J狀態(類似串口的停止位)。
這裡只是簡單的說明,實際上的數據傳輸比這個還要複雜一些,但大體是一致的。並且需要注意的是,上述描述的閒置狀態和J、K等狀態和設備類型有關,即全速設備和低速設備這些狀態的定義不同(這個可能和設備數據線的上拉電阻位置相關)。
AN57294採用 NRZI 編碼的好處是可以不需要時鐘線進行同步,但是為了實現準確的採樣,需要兩個條件:
1、 數據傳輸前需要發送同步域(SYNC),這個域固定為 0000 0001,通過NRZI編碼後就是一串方波信號,接收者可以通過方波信號確定採樣率(可以認為是串口的波特率)。
2、 因為數據中有大量的0,可以讓接收者通過信號的變化不斷調整採樣頻率,但是如果剛好數據中沒有0怎麼辦?
一旦有大量的1存在於數據線上,那麼數據線的電平將長時間不會發生變化,也就無法進行速率的同步,一旦接收者和發送者各自的時鐘頻率存在誤差,那麼很可能因為長時間沒有電平變化而導致採樣失敗(誤差長時間累積),所以 bit-stuffing 出現了,即所謂的強制插 0。USB規定,如果有7個連續的邏輯 1 ,需要在第 6 個 1 之後插入一個邏輯0來實現位填充,這樣D+和D-就會發生變化,從而讓接收者實現時鐘同步。在接收時,只要將6個邏輯1後的0刪除就可以恢復數據。
可以看到,6個連續的1之後強制插入了一個0進去,這樣即使接收方和發送方各自的時鐘存在誤差,也可以通過信號的變化實時同步,從而準確的進行採樣。以上內容就是 USB 為什麼只需要兩根線就能進行快速進行數據傳輸的關鍵。
USB 數據包
下面再來聊聊數據包:
前面這張圖介紹了如何通過 USB 數據線傳輸000011 數據,事實上在 USB 中,所有的數據都是以包(Packet)的形式進行傳輸的,而數據包是有一定的格式,也就是說,為了傳輸00011,需要按照包的格式才能正確傳輸。數據包有如下組成部分:
首先是 SOP(即從閒置狀態到K狀態),然後是 SYNC,即前面提到的同步域,用於接收方的時鐘同步,其次才是我們需要傳輸的數據內容,最後是 EOP(2位 SE0,1位J狀態)。如此,你的數據(PacketContent)才能被接收方正確接收。
數據包分為四大類:
令牌 (Token) Packet
幀首 (Start of Frame) Packet
數據 (Data) Packet
握手 (Handshake) Packet
每一類又可能分為多種具體的數據包,比如令牌包分為OUT、IN、SETUP等數據包,每一類中的 Packet Content 內容可能是不一樣的,比如:
令牌 (Token) Packet
(灰色部分代表不存在)
幀首 (Start of Frame) Packet
數據(Data)Packet
握手(Handshake) Packet
(灰色部分代表不存在)