USB之基本協議和數據波形1

 

=============  本系列參考  =============html

《圈圈教你玩USB》、《Linux那些事兒之我是USB》緩存

協議文檔:https://www.usb.org/document-library/usb-20-specification  usb_20_20190524/usb_20.pdf工具

調試工具:Beagle USB 480 邏輯分析儀編碼

====================================spa

前言:翻譯

  咱們先不一上來說USB大而全的協議規範文檔, 會讓人退而卻步, 只要有協議, 在數據傳輸上波形就有規律可循, 翻譯成數據, 也先無論USB1.1/2.0等版本, 由於最終的傳輸單元是同樣的3d

 

一. 最基本傳輸單位 --包(packet)

1.電氣信號:

  a. 採用D+/D-差分信號傳輸, LSB在前, NRZI編碼也就是0反轉, 1不反轉, 遇到連續6個1強插一個0調試

 

  b. 低速Lowspeed 1.5Mb/s, 全速Fullspeed 12Mb/s, 高速Highspeed 480Mb/s, USB1.1支持L/F  USB2.0支持L/F/H USB3.0也支持L/F/H 同時支持OTG功能code

  c. OTG(on the go) 就是多了根ID線, 用於判斷主控器做Host仍是device視頻

  d. L/F S採用電壓傳輸(3.3v), HS採用電流傳輸(等效電阻後示波器顯示400mv)

  e. 傳輸方向以Host爲準, 即IN表示device數據到Host, OUT表示Host數據到device

  f. 插入上電波形分析(下面單獨抽出來分析)

2. packet格式

      SYNC同步域  +  PID域  +  數據域  +  CRC  +  EOP

  a. 同步域: L/FS 固定00000001, HS前面31個0後一個1

  b. PID佔一個字節,高4bit是低4bit的反碼, 用於校驗PID自己, 而PID[3:0] 表示該packet的類型(協議文檔8.3.1):

    

    打*表示USB1.1不支持的, 而USB2.0全支持, 這裏要特別注意令牌包, 任何事務傳輸, 必須先發個令牌包說明意圖, 至於後面是否須要數據包仍是握手吧取決事務類型(下面會說)

  c. 數據域是可選的, 取決PID是否是數據包(DATA0/1/2/M) 

  d. CRC也是可選的, PID自校驗,因此只對數據域校驗,  若數據域沒有那CRC也沒有, 令牌包的數據域採用CRC5校驗, 數據包的數據域採用CRC16校驗

  e. EOP結束包, 對於L/FS是兩個數據位寬的SE0信號(D+/D-都是0),  對於HS使用故意位填充表示(待具體解釋)

  f. 空閒狀態, 在SYNC同步域前和EOP後 總線上處於空閒狀態, L/FS是一根高電平一根低電平(也就是J或K狀態, 後面會講), HS是SE0表示空閒狀態

  g. SYNC同步域、EOP、CRC是硬件發射器自動添加和硬件接收器自動解析的, 軟件看到的只有PID域和數據域

    

2. packet類型

  根據PID[3:0]能夠將包的類型分紅4類

  a. 令牌包: 一次USB傳輸必須首發令牌包, 告知意圖, 同時後面數據表示跟哪一個設備及端點通訊, 這點很重要, 設想一下一個Host接了不少外設, Host發出的信號會到達全部hub和普通外設, 如何避免串擾呢?

        那就是總線某一時刻只有一個外設與Host通訊, 外設硬件接口只響應令牌包, 由於令牌包的數據域表示設備的地址和端點地址, 外設能夠解析是否和本身匹配, 若是是則響應(使能硬件接收數據), 以及後續的數據包交互, 若是不是

        就不響應, 固然後續的數據包也會被外設硬件屏蔽, 不理會總線信號, 除非一段時間後又檢測到令牌包, 再次進行地址匹配, 符合才使能硬件接收總線上的信號

   IN OUT SETUP 包的數據域包含7bit設備地址和4bit端點地址, 因此一個Host可以最多接127個設備(0是外設剛插入時的默認地址, 握手後必須賦值非0, 否則下一個設備也是0就衝突了),  一個設備端點最多隻能16個(端點0是必須的, 因此其餘最多15個)

      

 

 

   SOF(幀起始包) 至關於心跳包, 讓全部外設知道Host還在活動(哪怕Host不是跟該設備通訊但起碼知道跟其餘設備通訊), L/FS每隔1ms發一次, 每發一次11bit幀號加1, HS把1ms分割8份即每隔125us發一次, 但這8份裏面的11bit幀號是相同的

  

    這個心跳包主要用於休眠喚醒用的, 當Host沒有發SOF超過3ms時(通常是Host本身進入休眠或者想外設休眠), 外設設置本身進入低功耗狀態(若是支持), 而後進入監聽模式若是檢測到總線有信號變化(只要跟睡眠前不同)當即喚醒,

  多是Host要召喚設備了, 固然設備也能夠喚醒Host, Host進入休眠也會設置監聽總線狀態,外設被人爲喚醒改變總線信號接着喚醒Host

 

  b. 數據包: 這沒啥好說的就是PID代表本身是數據包(DATA0仍是DATA1主要用於 確保對方收到), 後面就是字節數據了, 這裏須要注意就是沒有告知這個數據包到底多少個數據, 因此我猜測外設接收PID域後, 每接收一個字節counter計數器加1

        直到EOP, 而後減2 CRC16校驗值就是數據量, 接着對FIFO數據CRC16和最後兩個字節對比, 不一致就產生數據錯誤中斷, 一致就產生數據成功中斷並將數據量填充RX counter寄存器

     

  c. 握手包: 告知對方狀態, 好比Host發送IN令牌包, 接着設備發送數據包, 而後Host接收完發送ACK握手包告知設備成功接收

    不用數據域!

  d. 特殊包主要用於高速, 好比上面Host發完IN令牌包後, 設備應該要發數據包的, 但設備還沒準備好數據, 致使Host等待超時, Host能夠再次發IN包讓設備進入發送數據, Host切換等待接收數據狀態, 

    這裏有兩個小問題, 一是設備數據未準備好, 卻沒有有效方式告知Host, 只能啥都不作靠超時告知, 浪費Host時間, 二是IN包讓設備進入發送數據模式, 設備有數據早發了還等你吹, 還讓外設進入發送模式影響準備數據

    而PING特殊包就是當第一次超時後, Host不發IN包改發PING包詢問設備準備好沒, 設備若準備好了回覆ACK握手包, 接着Host再發IN包, 若是還沒準備好就發NAK告知, Host就知道設備還沒準備好而不用死等超時,

    其餘幾個讀者可自行查閱

 

   總結: 總線是一個一個packet傳輸的, 且信號達到全部外設, 當發送SYNC域全部外設接收並調整時鐘採樣點作好同步, 接着解析PID域,  若是是非令牌包就不理會(只有已被選中的外設才理會), 若是是令牌包就解析後面地址是否和本身匹配,

      不匹配繼續不會理, 匹配的使能硬件接收數據功能, 並根據PID是IN OUT SETUP SOF再細分, 若是是OUT,產生OUT中斷, 軟件應該清空使能FIFO準備接收數據, 若是是IN, 產生IN中斷, 軟件要填充好即將發的數據而後使能端點發送,

      若是是SETUP包(Host會接着發DATA0數據包數據域包含8個字節的標準請求), 設備要清空特殊FIFO並作好接受下一個數據, 接受完才產生SETUP中斷, 軟件就解析FIFO裏的8byte標準請求, 而後準備數據, 好比是獲取設備描述符請求

      那軟件得準備好設備描述符緩存並ACK(必須ACK不能NAK)回覆, 而後Host會發IN包, 接着設備IN中斷將剛纔準備好的設備描述符緩存丟到端點0發出去!

      若是是SOF包, 設備會重置時間計數器, 當3ms內沒有新的SOF包, 就會產生中斷, 設備知道總線如今是空閒狀態, 能夠自行決定是否休眠

 

 

 2、 事務--四種傳輸類型

  一個個packet只是人心渙散, 經過組織起來做爲一個有效傳輸咱們稱之爲事務, 因此一個事務起碼包含:

  一個令牌包, 經過地址選中具體外設

  可選的數據包, 若是是IN/OUT/SETUP包那後續有數據包, 若是是 SOF則數據包和握手吧都沒有

  可選的握手包, 像視頻聊天這種實時傳輸不須要ACK應該, 丟了就丟了, 省下帶寬不如用來發數據

  所以, 根據具體的使用場景, 事務能夠分紅四種傳輸類型:

1. 批量傳輸(Bulk transfers

  一個批量事務包含三個階段, 令牌包階段 + 數據包階段 + 握手包階段, 其中數據包階段能夠發一個或多個數據包

              

 

  以Beagle USB 480 邏輯分析儀抓U盤上電時序時爲例, 期間Host(PC機)會讀取U盤數據(bluk傳輸), 咱們能夠猜想應該發一個讀取U盤根目錄命令, 而後讀取扇區信息, 以下:    

        

  一個讀取扇區信息命令分別爲 Command + Data + Status, Command是一個寫操做, 往設備發送數據告知想幹嗎, 而後就是讀數據, 最後檢查狀態, 能夠看到這些操做都由三個packet構成 IN/OUT令牌包 + 數據包 + 握手包

  由於U盤每次操做只能512byte/block, 因此想讀取多個扇區只能分屢次IN操做(傳輸最大字節數端點描述符有說明)

 

2. 中斷傳輸(Interrupt transfers

   一箇中斷事務跟批量事務相似, 不一樣在於傳輸量比較少, 且但願Host每隔一段時間來訪問設備(不是靠硬件中斷告知系統, 而是端點描述符有個時間間隔變量, 告知Host最好小於這個時間間隔來訪問設備), 像鼠標鍵盤都是這類傳輸模式, 

   以Beagle USB 480 邏輯分析儀抓鍵盤爲例:

  

  這裏能夠看出三點, 一是Host每間隔x時間就發起一次讀取鍵盤數據操做(仍是老樣子 IN包 + DATA0包 + ACK包); 二是若是我沒敲鍵盤, 則設備NAK告知Host沒有數據; 三是間隔時間約 72/10  344/44 = 8ms

  查看鍵盤端點描述符bInterval=1, 根據datasheet表明1ms, 即鍵盤但願Host每隔1ms讀取一次數據, 但採不採納在於Host端

          

 

 3. 等時傳輸(Isochronous transfers

  等時事務跟前兩種也差很少, 不一樣在於對時間敏感, 對數據準確性不關心, 因此不須要握手包, 主要用於音頻、視頻類設備

 

4. 控制傳輸(Control transfers

   控制傳輸稍微複雜一點, 上面三個一個傳輸就是一個事務, 但控制傳輸有三個狀態, 每一個狀態對應一個事務, 因此須要三次事務

三次過程分別爲:

  創建過程:SETUP令牌包 + DATA0數據包(標準請求就在這) + ACK握手包(設備必須返回ACK, 不能NAK 若是設備連這個都不能保證的話就別玩了)

  數據過程: 可選, 如上面是獲取設備描述符這裏就是 IN令牌包 + DATA1數據包 + ACK握手包; 若是是設置地址請求, 地址在請求內部了, 不須要數據過程 

  狀態過程: 上面的數據過程必須是同一個方向的, 若是方向改變, 則就是狀態過程, 若是沒有數據過程, 則這個數據包就是狀態過程無論哪一個方向

      

  以Beagle USB 480 邏輯分析儀抓U盤爲例:

     

  從捕捉的數據可看到, 創建過程的數據包包含着標準請求 80 06 00 01 00 00 12 00 (小端排序) , 前面的C3是PID, 後面E0 F4 是CRC16, 能夠經過http://www.ip33.com/crc.html 驗證

 80 06 0100 0000 0012
struct usb_ctrlrequest {
    __u8 bRequestType; //0x80
    __u8 bRequest;    //0x06
    __le16 wValue;     //0x100   
    __le16 wIndex;    //0
    __le16 wLength;  //0x12
} __attribute__ ((packed));
具體請參考協議文檔9-4

 

  上面log還有個有趣的現象: 狀態過程發送1字節0x00數據包,  U盤居然返回NAK, 不知爲什麼,  因爲是高速模式下, 因此Host接下來會發PING包探測U盤是否ready, 直到U盤迴復ACK纔再次發送OUT包,若是是L/FS則繼續發OUT包直到接收ACK

 

剩餘數據的解析將在下一篇博文講解!

相關文章
相關標籤/搜索