--- tags: I/O, System Software --- # USB(1): 基礎篇 :::info 本文主要是以系統軟體開發的角度出發整理相關資料,因此對於硬體特徵不會有過多著墨! 若對硬體細節有興趣可參考 [USB Made Simple](https://www.usbmadesimple.co.uk/index.html) 和 [USB in a NutShell](https://www.beyondlogic.org/usbnutshell/usb1.shtml) 等材料。 ::: ## Overview [USB(Universal Serial Bus)](https://zh.wikipedia.org/zh-tw/USB) 是連接電腦與裝置的一種序列匯流排標準,也是用於電子裝置之間通訊的一種協定。 在 USB 被制定以前,外接式裝置的傳輸介面各不相同,如印表機只能接 Parrel Port、數據機只能接 RS232、滑鼠鍵盤只能接 PS/2 等。繁雜的介面系統,加上必須安裝驅動程式並重新開機才能使用的限制,都會造成使用者的困擾。因此,創造出一個統一且支援易插拔的外接式傳輸介面,便成為無可避免的趨勢,USB 應運而生。 ![image](https://hackmd.io/_uploads/SktNi8Coa.png) > [Parrel Port](https://zh.wikipedia.org/wiki/%E5%B9%B6%E8%A1%8C%E7%AB%AF%E5%8F%A3) ![image](https://hackmd.io/_uploads/HyUuoUAjp.png) > [RS-232](https://zh.wikipedia.org/wiki/RS-232) ![image](https://hackmd.io/_uploads/S1V5iU0oa.png) > [PS/2介面](https://zh.wikipedia.org/wiki/PS/2%E6%8E%A5%E5%8F%A3) ### USB 版本演進 USB 規範多年來一直在不斷更新,最主要的來自對更快通訊速度的需求。如下表總結了 USB 標準版本的演進與可提供的最快速度。 ![image](https://hackmd.io/_uploads/SkNt9IRsp.png) > [An Introduction to USB Communication](https://open4tech.com/an-introduction-to-usb-communication-part-1/) :::info 筆者撰文當下 USB 已發展至 USB4.0,傳輸速度為 40Gbit/s ::: ## Connector Types USB 之物理接口演進則如下圖。從號稱第一次一定會差錯的 Type-A,到至今在行動裝置上常見、正反皆可的 Type-C。並且各自可能又有 mini/micro 之分。 ![image](https://hackmd.io/_uploads/ryfgewAi6.png) > [USB(Universal Serial Bus)](https://zh.wikipedia.org/zh-tw/USB) > 延伸閱讀: > [USB 種類比較|一篇文章搞懂 USB Type A、B、C 的差異!](https://online.senao.com.tw/Article/detail/1696) ## Cables and Signals 標準 USB 線(USB 2.x)的內部結構,可以看到裡面有紅、白、綠、黑四根小的導線。分別對應的訊號功能為: | 訊號 | 顏色 | 功能 | |:--- | ------ |:---- | | VBUS | ==<font color=red>紅</font><br>== | 對連接的裝置供電(4.40 – 5.25 V) | | D- | ==<font color=white>白</font><br>== | 搭配 D+ 各自使用[半雙工](https://zh.wikipedia.org/wiki/%E9%9B%99%E5%B7%A5#%E5%8D%8A%E9%9B%99%E5%B7%A5)的[差分訊號](https://zh.wikipedia.org/wiki/%E5%B7%AE%E5%88%86%E4%BF%A1%E5%8F%B7)協同工作,以抵消長導線的電磁干擾,傳遞 NRZI 編碼的資料信號 | | D+ | ==<font color=green>綠</font><br>== | - - | | GND | ==<font color=black>黑</font><br>== | 接地 | ![image](https://hackmd.io/_uploads/rkzYlvCoT.png) ## USB Topology USB Bus 實體上是 tiered star 拓撲架構,在一個 USB Bus 上,可以容納一個 host 以及最多 127 個 devices (這是因為封包中的 address field 長度是 7 bits,而 address 0 不使用,因為它有特殊的用途)。 在 bus 上除了具有實際功能的 USB 裝置外,另一個重要的元件是 USB hub。它允許使用 1 個 upstream port 和最多 7 個 downstream port 傳遞訊息。由於延遲考量,最多只可以將五個 hub 依序連結。 這導致 USB 網路中只多只能有七層。 包含 host 所在的第 1 層,以及 hub 可以從第 2 層連結到第 6 層。 ![image](https://hackmd.io/_uploads/H1AJPvCs6.png) 留意到 USB hub 也佔用定址。因此舉例來說,如果我們有 20 個 hub,那麼最終實際裝置的最大可能數量為 127 – 20 = 107。 ![image](https://hackmd.io/_uploads/HJDvHwRs6.png) > [USB Topology](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc939107(v=technet.10)?redirectedfrom=MSDN) ![image](https://hackmd.io/_uploads/rJcQJL0sa.png) > [Universal Serial Bus Device(ScienceDirect)](https://www.sciencedirect.com/topics/engineering/universal-serial-bus-device) ## USB Protocol USB 是一種 polled bus,意思是由 host 發起所有傳輸開頭。則為了讓 host 從 USB 裝置接收訊息,它必須向裝置做 polling。此 polling 會組織成 frame 的方式定期執行,每 1ms 啟動一個新的 frame,另外還可以有 micro frame(每 125μs 啟動一次)。 ![image](https://hackmd.io/_uploads/B1ic4Ky36.png) 之前曾經提過,USB bus 上的每個裝置都分配一個唯一的 7 位元位址(實際上會是 1 到 127)。而 USB bus 上發送的所有內容都被建構為 **packet**。 ## Endpoints 在 USB 協定下,對 USB 的資料傳輸透過 Endpoint 進行。一個裝置可以擁有至多 16 個 OUT 和 16 個 IN 的 Endpoints。 * OUT : 從 device 輸出 * IN : 輸入至 device ![image](https://hackmd.io/_uploads/rJiQ2dQ3a.png) 每個 Endpoint 只能有一個傳輸方向,除 Endpoint 0 是例外。Endpoint 0 用於控制傳輸命令及狀態操作。像是設定裝置、取得裝置資訊、發送指令到裝置等,可以有 IN 和 OUT 的雙向傳輸。 在 USB 中的 endpoint 根據類型可分四種: * Control: 即 endpoint 0,用於裝置控制和詢問狀態。一個裝置只能有一個,而且一定要支援 * Bulk: 用於大量資料傳輸,如傳給印表機或隨身碟 * 有重送機制 * 無 bandwidth/latency 的保證 * Interrupt: 定期傳輸,裝置端需要聲明這個期間是多久。適合事件驅動的裝置,像是 USB 鍵盤和滑鼠 * 保證裝置提供服務的最大週期 * 如果發送失敗,重送也會在下一個周期進行 * Isochronous: 需要及時資料更新時使用,可大量傳。適合例如 USB 視訊裝置、喇叭、麥克風等重視即時性且可接受少量遺失資料的應用 * 資料如果錯誤無法修正或丟失,不會重送 * 有 bandwidth/latency 的保證 ## USB Packet Packet 是 USB 交換訊息的最小元素,是用幾個 field 建構而成的。Field 分別有以下幾種: * SYNC – packets 總是以此 field 為開頭,用來同步 transmitter 和 receiver 之間的傳輸 * PID – 標示 packet 的種類 * ADDR – packet 之目標 USB 裝置的地址 * ENDP – 標示 USB device 中目標的 endpoint * DATA – 傳輸的資料 * CRC – 錯誤檢測用的 CRC * CRC5(5bits) 用於 token packets * CRC16(16bits) 用於 data packets * EOP – packets 結尾 ![image](https://hackmd.io/_uploads/SkKpit7hp.png) 如上表,每個 PID 對應到四種 packet 類型的其中,並根據實際功能可再細分。 ### Token Packet Token packets 只能由 host 發出,每個類型是特定的一種 transaction type。 * OUT: Host 將會從 USB 裝置獲得資料 * IN: Host 將會傳送資料給 USB 裝置 * SETUP: Host 接著要做 control transfer ![image](https://hackmd.io/_uploads/BJiMaKXhT.png) * SOF: 此 packet 將 USB bus 上的傳輸切分成數個 time frame,如下圖。 在 full-speed 下,SOF 每 1 ms 發送一次。 在 high-speed 下,每個 1ms frame 被分成 8 個 micro frame。frame 號碼每 1 ms 會增加一次 ![image](https://hackmd.io/_uploads/ByU_aKm3a.png) ![image](https://hackmd.io/_uploads/BkA9aFXna.png) ### Data Packet 顧名思義用於資料傳輸,又分為 DATA0、DATA1、DATA2、DATAM 類型。這種 packet 的來源可以是 host 或 device。 ![image](https://hackmd.io/_uploads/SJVWzcQnT.png) Data Packet 的 DATA 大小可為零,而其最大值則受 endpoint descriptor 中的 wMaxPacketSize 限制。 ### Handshake Packet 用於確認 packet 的收發狀態(ACK, NACK 等)。 ![image](https://hackmd.io/_uploads/r19-fqX36.png) ## Linux USB Device Driver 關於 USB device driver 的撰寫可參考 Linux 中的 [Writing USB Device Drivers](https://docs.kernel.org/driver-api/usb/writing_usb_driver.html)。 ## USB Descriptor > * [USB Made Simple - Protocal](https://www.usbmadesimple.co.uk/ums_4.htm) > * [USB in a NutShell - USB Descriptors](https://www.beyondlogic.org/usbnutshell/usb5.shtml) USB 裝置中包含許多 descriptor,如下圖。這讓 host 可以有辨別並設定裝置的資訊。 ![image](https://hackmd.io/_uploads/HkAMDvFaT.png) > [USB Made Simple - Protocal](https://www.usbmadesimple.co.uk/ums_4.htm) Device descriptor 代表整個裝置。因此,一個 USB 裝置只能有一個。它包含有關裝置的一些基本信息,例如支援的 USB 版本、最大 packet 尺寸、供應商和產品 ID 以及裝置可以具有的可能 configuration 數量等資訊。 Configuration descriptor 提供裝置的供電方式、最大功耗以及其具有的 interface 數量等資訊。一台裝置可以有多個 configuration descriptor,但同時間只能啟用其中一個。如果要更改,整個裝置必須暫時停止運作。它也描述了其包含的 interface 數量。 一台裝置可以有一個或多個 **interface**,由 interface descriptor 去描述。Interface descriptor 可以被視為裝置特定功能之 **endpoint 的群組**。而 [endpoints](#Endpoints) 固然是由 endpoint descriptor 描述,前面我們已經介紹過 endpoint 代表每個資料輸入或輸出的單元。 ![image](https://hackmd.io/_uploads/Hkeey5HxR.png) > [A tour of USB Device Controller (UDC) in Linux](https://bootlin.com/pub/conferences/2023/eoss/codina-a-tour-of-usb-device-controller/codina-a-tour-of-usb-device-controller.pdf) ## Reference * [成大資工 Wiki - USB (Universal Serial Bus)](https://wiki.csie.ncku.edu.tw/embedded/USB) * [An Introduction to USB Communication (Part 1)](https://open4tech.com/an-introduction-to-usb-communication-part-1/) * [An Introduction to USB Communication (Part 2)]() * [Writing USB Device Drivers](https://docs.kernel.org/driver-api/usb/writing_usb_driver.html) * [USB Made Simple](https://www.usbmadesimple.co.uk/index.html) * [USB in a NutShell](https://www.beyondlogic.org/usbnutshell/usb1.shtml) * [Linux: Where the USB related kernel files are](https://billauer.co.il/blog/2017/05/linux-usb-files/) * [USB 3.1 Gen 1、Gen 2 及 USB 3.2 的差異為何?](https://www.kingston.com/tw/usb-flash-drives/usb-30) * [A Tour of USB Device Controller (UDC) in Linux - Hervé Codina, Bootlin](https://youtu.be/LJuE2RhfgnA?si=zZikgUcjOe-5gZEb) * [A tour of USB Device Controller (UDC) in Linux/ppt](https://bootlin.com/pub/conferences/2023/eoss/codina-a-tour-of-usb-device-controller/codina-a-tour-of-usb-device-controller.pdf) * [USB Host 簡介](https://pollos-blog.blogspot.com/2015/08/usb-host.html)