USB 列舉(USB Enumeration)



本文配合實際使用邏輯分析儀記錄到的USB通訊資料,來說明USB列舉的機制。



Index







前言

USB是最成功也最普遍的電腦介面。早期電腦有非常多種介面:COM Port、Printer Port、IEEE 1394、PS/2、D-SUB...,現在這些介面都可以USB取代。除了PC之外,手機、平板及嵌入式系統也有USB介面。如果你是一位電子工程師,USB是非常值得學習的一種傳輸介面。

本文的內容是要介紹USB相關的技術知識,不過並不是鉅細靡遺的完整介紹所有USB相關的技術,那內容將會是一本厚厚的書。我們將專注在說明USB列舉(Enumeration)或稱枚舉的相關技術知識。USB列舉是USB裝置插入主機後,與主機溝通的流程。



我們為什麼要介紹USB列舉?

為什麼特別介紹USB列舉呢?原因有兩個,一是USB列舉是所有USB知識中最重要的技術之一,USB裝置必須完成列舉的流程才能與主機連接。如果你是一位USB產品開發工程師,你必須要了解USB列舉的機制才有辦法設計USB的韌體。

另一個原因是,USB列舉比較難從書本上理解。幾乎所有的USB書籍在介紹USB列舉時,都是說明一堆的表格,雖然這些表格是USB列舉的重要資料,不過對於從沒接觸過USB開發的新手來說,只靠這些表格要去理解整個USB列舉的機制是很困難的。

本文的目的就是補充書本在這部份的不足,讓使用者更容易的了解USB列舉的機制。我們會分析實際由邏輯分析儀所抓取到的USB通訊資料,來說明USB列舉的流程。相較於書本或文件上的表格,看到實際的訊號與封包會讓您更容易且深刻的理解USB列舉的機制。

我們專注於說明USB列舉並不是表示其他的部份不重要,只是介紹USB的書籍或文件已經很多了,不需要我們多餘的重複。為了縮短篇幅,本文省略了部份USB的基礎知識,如果您對於USB的技術並不熟悉的話,還是很建議您找一本書或詳細的文件來閱讀。當您讀到USB列舉時覺得難以理解的時候,本文就是您最好的朋友。



USB列舉是什麼?

USB列舉是USB裝置插入主機後,與主機溝通的流程。想像一位旅客要入住一間飯店,飯店為了確保能為旅客安排合適的房間,在旅客入住前服務人員必須詢問旅客一些問題,才能安排合適的房間給旅客。

服務生:「請問幾個人入住呢?」
客人:「一位」
服務生:「請問喜歡海景還是山景呢?」
客人:「海景」
服務生:「請問喜歡淋浴還是浴缸呢?」
客人:「淋浴」
......
......

相關問題全部問完後,服務生就能選擇適合的房間給客人。USB列舉就是類似這樣的一個過程。USB裝置要跟主機連接,主機必須知道裝置的類型與需求,所以需要詢問裝置一些的問題。經過一段問答的過程後,如果主機判斷裝置可以連接,就會給裝置安裝驅動程式,完成USB列舉。



如何使用邏輯分析儀量測USB通訊?

USB有兩條資料線,D+與D-,要量測USB就必須把USB的D+、D-還有Gnd連接到邏輯分析儀。把USB線的外皮剝開後您會看到四條線,顏色分別是紅、黑、綠、白,如下圖。其中紅色是電源,黑色是Gnd,綠色是D+,白色是D-。把黑色、綠色、白色剝開外皮後(不要剪斷)連接到邏輯分析儀即可。


或者您可以跟沛瑞科技購買USB訊號轉接板,如下圖。這個PCB的功能很單純,就是把USB的訊號拉出來。您也可以自行DIY一個。



我們測試的裝置是USB鍵盤,先把線接好。這裡我們把邏輯分析儀的通道A0接到D+、A1接到D-,如下圖。



USB列舉在USB插入主機後就會開始進行,所以要先把邏輯分析儀軟體設定好後,再把USB鍵盤插入主機,這樣才可以量到USB鍵盤剛插入時的通訊。首先開啟邏輯分析儀的壓縮模式。USB列舉需要一段不短的時間(以這次測試的USB鍵盤來說,需要約1秒鐘),要量測這麼長的資料邏輯分析儀需要開啟「壓縮模式」。再來把取樣率設定為200MS/s。接著設定觸發條件,這裡我們設定通道A0上升緣觸發。

設定好後,按下Run。此時由於USB裝置還沒接上主機,D+ D- 沒有訊號所以邏輯分析儀會保持在等待觸發的狀態。接著把USB裝置插入主機,插入後USB開始通訊,邏輯分析儀就觸發了,開始記錄資料。

記錄到的USB訊號如下圖,可以看到記錄了約1.3秒的資料內容。如果沒有壓縮模式的話,200MS/s的取樣率記錄1.3秒的時間,每通道需要260M Bit的記憶體。



放大來看,訊號的開始有兩段時間D+ D-都是低電壓的狀態,時間超過10ms。這是Hub對USB裝置送出的Reset訊號。如果是USB 2.0 High Speed 裝置則只會送出一次Reset訊號。



再放大一點,下圖黃色框內的就是SOF(Start-of-Frame packet) ,在每一個frame開始時發送。USB 1.1的每個Frame時間是1ms。下圖訊號的間隔約998.66us,加上SOF封包本身的寬度約1.34us,就是1ms。



再放大一點就可以看到封包的內容,如下圖。同時觀察訊號與封包可以讓您對USB訊號有更深入的了解,不過一般來說為了節省時間,通常使用封包列表功能來檢視封包。執行Tool → Packet list 就可開啟封包列表。



開啟封包列表功能的畫面如下圖,封包列表功能會把封包的資料一個個清楚的列出,讓使用者可以更容易的檢視封包的資料。



如何分析USB封包?

這些USB封包就是USB列舉的資訊,那我們該如何解讀這些資料呢?分析這些資料,需要參考USB規格書。本文所參考的資料來源為USB 2.0規格書(USB 2.0 Specification),您可以在usb.org下載。

這裡我們簡單說明一下USB傳輸的格式。當主機需要讀寫USB裝置時(例如要讀取USB硬碟),USB Driver會把這個需求拆解成一個或多個Transaction,Transaction是USB傳輸資料的單位,每個Transaction由2~3個USB封包所組成。Transaction的第一個封包是Token封包,用來表示這個Transaction的型態。如果這個Transaction有傳輸資料的需求的話,那第二個封包就是Data封包。資料傳輸的方向可以是Host to Device或Device to Host。並非每個Transaction都有Data封包,有沒有Data封包及Data傳輸的方向,都是視token而定。最後一個封包是Handshake封包,資料接收端用這個封包回應有無收到正確資料。資料接收端可能是主機或USB裝置。

下圖是第1~3個USB封包,這三個封包就是一個Transaction。最左邊黃色框內的封包編號,這個編號是邏輯分析儀軟體了方便使用者檢視封包而設定的,並不是USB傳輸的資料。第1號封包中綠色框內的就是Token,這個Token是Setup。由於USB裝置剛插入主機還沒有設定Address與Endpoint,所以這個Setup封包後面所接的Address與Endpoint數值都是0。



第二個封包是Data封包,是Setup這個Token要傳給USB裝置的資料。要如何分析這個Data封包的資料呢?要參考 USB Specification 的「Format of Setup Data」。這個資料在USB Specification 2.0 的Table 9.2,如下表。這個表說明了每個Byte所代表的意義。

Offset Field Size Value Description
0 bmRequestType 1 Bitmap Characteristics of request:

D7: Data transfer direction
  0 = Host-to-device
  1 = Device-to-host

D6...5: Type
  0 = Standard
  1 = Class
  2 = Vendor
  3 = Reserved

D4...0: Recipient
  0 = Device
  1 = Interface
  2 = Endpoint
  3 = Other
  4...31 = Reserved
1 bRequest 1 Value Specific request
2 wValue 2 Value Word-sized field that
varies according to request
4 wIndex 2 Index or Offset Word-sized field that varies
according to request; typically
used to pass an index or offset
6 wLength 2 Count Number of bytes to transfer
if there is a Data stage

Format of Setup Data,資料來源:USB 2.0 Specification Table 9-2



Byte 0 是 bmRequestType,數值代表的意義是這個Request的屬性。這個Byte分成三個部份,分別是Recipient、Type與Data transfer direction,邏輯分析儀軟體已經自動把這個Byte拆為三個欄位了,Recipient數值是0,代表Device。Type是數值是0,代表Standard。Data transfer direction(Dir)軟體已經標明是 D→H,也就是資料傳輸的方向是Device to Host。

Byte 1是bRequest,這裡的數值是0x06,代表什麼意義呢?請參考USB Specification的 Table 9-4,Standard Request Codes,如下表。由這個表的內容可以得知0x06是GET_DESCRIPTOR,也就是這個 Request是GET_DESCRIPTOR。

bRequest Value
GET_STATUS 0
CLEAR_FEATURE 1
Reserved for future use 2
SET_FEATURE 3
Reserved for future use 4
SET_ADDRESS 5
GET_DESCRIPTOR 6
SET_DESCRIPTOR 7
GET_CONFIGURATION 8
SET_CONFIGURATION 9
GET_INTERFACE 10
SET_INTERFACE 11
SYNCH_FRAME 12

Standard Request Codes,資料來源:USB 2.0 Specification Table 9-4



Byte 2~7分別是wValue、wIndex、wLength欄位,每個欄位寬度各2 byte。這三個欄位代表的意義會隨著Request而不同,這個 Request是GET_DESCRIPTOR,在USB Specification的9.4.3節,Get Descriptor,有說明 Request是GET_DESCRIPTOR時這三個欄位所代表的意義,如下表。

bmRequestType bRequest wValue wIndex wLength Data
10000000B GET_DESCRIPTOR Descriptor Type
and
Descriptor Index
Zero or
Language ID
Descriptor
Length
Descriptor

Get Descriptor,資料來源:USB 2.0 Specification



其中wValue的High Byte表示的是descriptor type,這裡的數值是0x01,由USB Specification的9.4.3節知道這個數值的意義要參考Table 9-5,如下表。由表9-5可以知道數值1代表的是DEVICE,也就是這個descriptor 的type是DEVICE。

Descriptor Types Value
DEVICE 1
CONFIGURATION 2
STRING 3
INTERFACE 4
ENDPOINT 5
DEVICE_QUALIFIER 6
OTHER_SPEED_CONFIGURATION 7
INTERFACE_POWER 8

Descriptor Type,資料來源:USB 2.0 Specification



第三個封包是ACK,這是USB裝置回應的,代表有正確收到資料。

封包4-5分別是In與NAK,如下圖,這兩個封包合起來也是一個Transaction,由於這個Transaction沒有傳輸資料所以只有兩個封包。USB的IN與OUT都是指對主機而言,所以IN的意思就是Host要從Device讀取資料。這裡Device回應NAK,並不是代表資料錯誤,而是沒有資料可以傳送。即使沒有資料可以傳送Device還是要回應,如果一段時間沒回應,Host就會判定Device離線。這種NAK的封包由於沒有傳送資料,大部分的情況都可略過不看,這篇文章的其他部份也會略過NAK封包。



Host不斷的送出In封包表示要接收資料,Device終於在第9個封包開始有回應了,這一段的回應總共有18個Byte,由於在這個傳輸模式每個封包的資料最多只有8個Byte,所以這段資料分成三個Data封包回應,下圖是把三個封包的內容節錄下來。



這些資料代表什麼意義?由前面的封包得知這個 Request是GET_DESCRIPTOR,Type是Device,所以Host要求的資料是Device Descriptor。Device Descriptor的資料格式內容在Table 9-8,如下圖。對照Table 9-8,就可以知道這些資料每個Byte的意義。

Offset Field Size Value Description
0 bLength 1 Number Size of this descriptor in bytes
1 bDescriptorType 1 Constant DEVICE Descriptor Type
2 bcdUSB 2 BCD USB Specification Release Number in Binary-Coded Decimal.
4 bDeviceClass Class 1 Class code (assigned by the USB-IF).
5 bDeviceSubClass 1 SubClass Subclass code (assigned by the USB-IF).
6 bDeviceProtocol 1 Protocol Protocol code (assigned by the USB-IF).
7 bMaxPacketSize0 1 Number Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid)
8 idVendor 2 ID Vendor ID (assigned by the USB-IF)
10 idProduct 2 ID Product ID (assigned by the manufacturer)
12 bcdDevice 2 BCD Device release number in binary-coded decimal
14 iManufacturer 1 Index Index of string descriptor describing manufacturer
15 iProduct 1 Index Index of string descriptor describing product
16 iSerialNumber 1 Index Index of string descriptor describing the device’s serial number
17 bNumConfigurations 1 Number Number of possible configurations

Standard Descriptor Type,資料來源:USB 2.0 Specification



以上就是Host讀取USB裝置的Device Descriptor的流程。這樣就結束了嗎?當然不是。完整的USB列舉至少需要以下5個步驟:

1.主機讀取USB裝置的Device Descriptor
2.主機分配一個位址給USB裝置
3.主機讀取USB裝置的Configuration Descriptor
4.主機讀取USB裝置的Interface Descriptor
5.主機讀取USB裝置的Endpoint Descriptor

我們以上分析的這些USB封包,就是第一個步驟。其他的步驟雖然內容不同,但是分析的方法是類似的,所以不再重複敘述。列舉命令的順序並非固定的,USB裝置必須隨時能回應任何的命令。有時主機會重複讀取Descriptor。

要特別說明的是,一個USB裝置只有一個Device Descriptor,但是可以有多個Configuration。在Device Descriptor中會定義總共有幾個Configuration 。每個Configuration又可以有多個Interface,在Configuration Descriptor中會定義有幾個Interface。每個Interface又可以有多個Endpoint ,在Interface Descriptor中會定義有幾個Endpoint。整個USB列舉的資料架構就是階層式的,有點像是樹狀圖,最上層是Device Descriptor,再來是Configuration Descriptor,接著是Interface Descriptor,最後是Endpoint Descriptor。

這篇文章所分析的USB通訊資料可以在下面的連結下載。您可以安裝邏輯分析儀或MSO軟體(免費下載),再載入這個檔案,就可以檢視USB鍵盤的列舉流程,不需要硬體。對照USB 2.0 規格書,相信您就可以了解USB列舉的機制。



如何撰寫USB程式?

了解了USB列舉的機制之後,該如何撰寫USB列舉的程式呢?一般來說撰寫USB列舉的程式比較像是填寫一些USB資料的表格。有USB界面的CPU會有一個USB控制器,USB控制器會在列舉的流程中把這些表格的資料回應給主機,完成列舉的工作。

每個USB控制器的列舉資料表的樣式不一定一樣,有些是C語言,有些是組合語言,大多數的USB IC公司會提供範例的程式碼。以下是某個USB控制器的 Device Descriptor 程式碼:

code uint8 DeviceDescriptor[0x12] =
{
/* bLength */
0x12,
/* bDescriptorType */
0x01,
/* bcdUSB */
0x10,
0x01,
/* bDeviceClass */
0x00,
/* bDeviceSubClass */
0x00,
/* bDeviceProtocol */
0x00,
/* bMaxPacketSize0, the pdiusbd12 chip has a maximize size of 16 */
0x10,
/* idVender, just for test, for commercial use, you should apply for it from the usb association */
0xF3,
0x04,
/* idProduct */
0x03,
0x01,
/* bcdDevice, version number of product */
0x07,
0x01,
/* iManufacturer */
0x00,
/* iProduct */
0x00,
/* iSerialNumber */
0x00,
/* bNumConfigurations, the number of configurations of a device, most device have only one configuration */
0x01
};



壓縮模式對量測USB的重要性

邏輯分析儀的壓縮功能是USB量測的重要關鍵,我們來試試有無啟用壓縮的差異。下圖是沒有使用壓縮模式所量測的USB訊號。記憶體為64k,取樣率200MS/s,記錄的時間約327.67us。



觀察封包列表,只記錄了4個封包



接著測試其他廠牌的邏輯分析儀,此款邏輯分析儀的最大壓縮倍率256倍,測試條件不變。從下圖可以看到,記錄的時間長度約40.478ms。



觀察封包列表,記錄了20個封包。這樣的記錄時間是遠遠不夠的,以USB鍵盤為例,完整的USB列舉需要400個以上的USB封包才能完成,20個封包還不到需求量的1/20。



最後測試沛瑞科技邏輯分析儀開啟壓縮模式。記錄時間約3.36秒。



檢視封包列表,記錄了1680個封包。沛瑞科技邏輯分析儀的壓縮模式最大壓縮倍率可達100萬倍,由測試結果可以看到壓縮模式可以大幅度的增加記錄的時間。



為什麼USB 1.1是很好的USB入門?

我們測試的USB訊號是USB 1.1,您可能會覺得現在都有USB 3.1了為什麼用USB 1.1當例子。我們有幾個理由可以說明USB 1.1是很好的入門。首先,USB 1.1是所有USB規格的基礎,USB 2.0是USB 1.1的延伸,架構是很類似的。如果您熟悉了USB 1.1一定可以在很短的時間就了解USB 2.0。USB 3.0 雖然多了更多的東西,但是仍須相容USB 2.0與USB 1.1。如果你要學習USB 3.0,也必須了解USB 2.0與1.1。

第二個原因是,USB 1.1的晶片的選擇比USB 2.0多很多,也便宜很多。很多低階的8 bit處理器就有內建USB 1.1了,但如果要USB 2.0選擇就很少,且價格高許多。而且USB 2.0以上由於速度快,對PCB與線材有很嚴格的阻抗匹配要求,會增加PCB的成本與開發時間。USB 1.1就簡單很多,甚至手焊的洞洞板也可以用。

再來談到速度,如果需要傳輸很大量的資料,那當然是USB 3.0較合適,但其實大部分的控制只需傳輸少量的資料。Baud Rate 19200 (19.2k bit)的RS232通訊仍很常見於工業控制,速度12M的USB 1.1絕對綽綽有餘。

最後也是最重要的,分析USB 2.0的儀器都非常貴,數萬元到上百萬不等,業餘的玩家或創客購買起來是有困難的。如果是分析USB 1.1只需要沛瑞科技邏輯分析儀就夠了,一台只要幾千元。而且沛瑞科技邏輯分析儀功能強大,分析USB只是其中一項功能而已。