分享到plurk 分享到twitter 分享到facebook

版本 ac2cf06dd936cf3443b9aae2b8f870a40aaa3b4a

embedded/USB

Changes from ac2cf06dd936cf3443b9aae2b8f870a40aaa3b4a to 8a13d6ced689a7572bfd38ac1889a0365f27d8e1

---
title: usb
...

.. image:: http://upload.wikimedia.org/wikipedia/commons/thumb/f/fd/USB_Icon.svg/200px-USB_Icon.svg.png


標準 USB 2.0 介面
^^^^^^^^^^^^^^^^

.. image:: /271px-Types-usb_new.svg.png
.. image:: /embedded/USB/2.png


USB 訊號使用標記為D+ 和D- 的雙絞線(twisted pair)傳輸,以抵消長導線的電磁干擾。

.. image:: /400px-USB_Twisted_Pair.svg.png

它們各自使用半雙工的差動訊號(Differential signal), 並利用NRZI(non-return-to-zero Inverted)的編碼方式來傳送。

* 差動訊號:訊號傳輸在兩根不同的線上,這兩個信號的振幅相等,相位相反。

.. image:: /embedded/USB/6.png

.. image:: /DiffSig.png

* NRZI Code: NRZI(Non Return to Zero Invert,不歸零就反向)的編碼方式,無需同步的時脈信號也能產生同步的資料存取。NRZI的編碼規則是,當資料位元為 “1” 時不轉換,為 “0” 時再作轉換。

.. image:: /embedded/USB/3.png

* J state:Idle state(閒置)

* K state:Resume state(恢復)

在NRZI編碼下,邏輯0 會造成轉換,所以接受者在接受數據的同時,根據接收到的翻轉信號不斷調整同步頻率,保證數據傳輸正確。

但是,這樣還是會有一個問題,就是雖然接受者可以主動和發送者的頻率匹配,但是兩者之間總會有誤差。

假如數據信號是1000 個邏輯1,資料就會造成長時間無法轉換,在這種情況下,即使接受者的頻率和發送者相差千分之一,就會造成把數據採樣成1001 個或者999 個1了。

USB 對這個問題的解決辦法,就是強制插0,也就是bit-stuffing,如果要傳輸的數據中有7 個連續的1,發送前就會在第6 個1 後面強制插入一個0,讓發送的信號強制出現翻轉,從而強制接受者進行頻率調整。


* Bit-stuffing : 如下圖所示,若是原始的串列資料中含有連續6個 “1” 位元的話,就需執行位元填塞的工作。此工作如(b)所示,就在其後填塞一個 “0” 位元。但相對的在NRZI編碼的過程中,對這連續的6個 “1” 執行如圖(c)轉換過程。因此在發送端在作資料傳輸之前,需先執行位元填塞以及NRZI編碼的工作。相對的,接收端在作資料接收之前,就必需先執行NRZI解碼,然後再作位元反填塞(unBit-Stuffing)的工作。

.. image:: /embedded/USB/4.png

USB 封包簡介
^^^^^^^^^^^

封包是組成USB傳輸的最小單位。一個 Transaction 通常由三個封包組成,但依傳輸型態而定,一個 Transaction 可能包含一個、兩個、三個封包。

.. image:: /embedded/USB/7.png

.. image:: /embedded/USB/PID types.jpg

Token 封包
==========

每個Transaction以Token封包做起始。Token封包定義裝置、Endpoint數量,傳輸的方向。用PID來識別OUT、IN、SOF與SETUP處理。對於OUT和SETUP處理,位址與端點欄位用來選擇接收資料的端點;對於IN處理,位址與端點欄位用來選擇傳送資料的端點。

.. image:: /Token Format.jpg
SOF(Start-of-Frame)為一個特別的Token封包類型,包含目前的frame數量,主機每隔一段很小的間隔就會發出一次SOF封包,所有裝置以及hub都會收到SOF封包。對只需要時間資訊的裝置而言,只需要知道PID為SOF即可,剩餘的frame number以及CRC的資訊皆可忽略。

.. image:: /SOF Packet.jpg

PID: Packet Identifier

ADDR: Address 

ENDP: Endpoint 

CRC: Cyclic Redundancy Checks 



Data 封包
=========

Data封包包含處理此動作的資料。在low-speed裝置中,Data封包最大的資料量為8 bytes;在full-speed裝置中,Data封包最大的資料量為1023 bytes;在high-speed裝置中,Data封包最大的資料量為1024 bytes。其中 Data0 及 Data1 是兩個基本的資料封包,使用這些資料封包以提供一個機制來確定將傳送端和接收端之間的資料切換同步(data toggle synchronization)。另外在 USB2.0 當中更增加了 Data2 及 MData 資料封包,用於執行高速的即時傳輸(Isochronous Transfers)。

.. image:: /embedded/USB/Data Packets.jpg

Handshake 封包
==============

Handshake封包由一個PID所組成,用來表示資料傳輸的狀態,部分Handshake封包說明如下。

* ACK表示資料封包沒有bit stuff或是CRC錯誤,也就是PID欄位以及Data欄位沒有出現錯誤。

* NAK表示裝置無法從主機接收資料或是無資料可以傳輸到主機。NAK也被當作流量控制的用途來使用,表示裝置暫時無資料傳送或無法接收資料。

* STALL表示裝置無法傳送或接收資料,需要主機介入來清除延遲狀況。

.. image:: /embedded/USB/Handshake Packet.jpg

USB Descriptors
^^^^^^^^^^^^^^^

* Device Descriptors : 提供裝置基本資訊,例如:USB 版本、最大的 packet 大小、廠商與型號資訊。每個 USB 裝置只能 device descriptors 只能有一個。

* Configuration Descriptors : 指出 USB 裝置的供電方式、interface 數量。每個 USB 裝置可以擁有不只一個 Configure Descriptor,可視為 interface descriptor 之 header。

* Interface Descriptors : 提供介面資訊,可視為 endpint descriptor 之 header。在 configuration descriptor 中會指定該 configuration 所擁有的 interface 數量,因此 interface descriptor 可以擁有一個以上。

* Endpoint Descriptors : 描述 endpoint 之行為與頻寬。

* String Descriptors : 提供人類可讀的資訊。



USB Device Class
^^^^^^^^^^^^^^^^
USB 依照裝置的不同,定義許多不同的 class code ,用來聯絡 host 端與 device 端該做出什麼適當的反應,以下為幾個常見分類:


HID Class
=========

Human Interface Device class,HID 設備屬於人機交互操作的設備,用於操作電腦,如 USB 滑鼠,USB 鍵盤,USB 觸控版,USB 軌跡球等等設備。HID 設備不一定非要是這些人機交互設備,只要符合HID設備級定義規範要求的都可以認為是 HID 設備。

使用 HID 設備的一個好處就是,操作系統自帶了 HID 類的驅動程序,而用戶無需去開發很麻煩的驅動程序,只要直接使用 API 調用即可完成通信。所以很多簡單的 USB 設備,喜歡枚舉成 HID 設備,這樣就可以不用安裝驅動而直接使用。

CDC Class
=========

Communications Device Class,CDC 類是 USB 通信設備類的簡稱。CDC 類是 USB 組織定義的一類專門給各種通信設備(電信通信設備和中速網絡通信設備)使用的 USB 子類。大部分的作業系統都帶有支持 CDC 類的設備驅動程序,可以自動識別 CDC 類的設備,這樣不僅免去了寫專用設備驅動的負擔,同時簡化了設備驅動的安裝。

MSC Class
=========

Mass Storage device Class,大容量存儲裝置類別。一種電腦和行動裝置之間的傳輸協議,它允許一個通用串行總線(USB)裝置來訪問主機的計算裝置,使兩者之間進行文件傳輸。

MSC 支持目前大多數的主流操作系統,許多舊版本的操作系統經過版本升級或者係統補丁也能實現對 MSC 的支持。MSC 的通用性和操作簡單使他成為行動裝置上最常見的文件系統,USB MSC 並不需要任何特定的文件系統, 它提供了一個簡單的界面來讀寫接口用於訪問任何硬碟驅動。

USB host and device
^^^^^^^^^^^^^^^^^^^^^^
.. image:: /embedded/usb host:device .png
  
 1. SIE(SERIAL INTERFACE ENGINE)


Block Diagram
^^^^^^^^^^^^^^^

.. image:: /USB_block_diagram.png

 1. ID pin 用來辨識OTG(on-the-go)裝置是主機還是週邊
 2. marco-A插頭的ID pin接地 vs marco-B插頭的ID pin懸空,用來區別主機和週邊 (marco-A插主機,marco-B插週邊) 
 3. DP/DM description -- in reference manual 30.3.2
 4. AHB -- Advanced High-performance Bus  
 5. UTMI -- USB 2.0 transceiver macrocell interface

USB OTG(on-the-go)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
原先USB裝置的角色都是固定的(主機或週邊)。
USB OTG讓原本只能為週邊的裝置也能成為主機,例如讓手機接上鍵盤。

傳輸型態
^^^^^^^^

USB 定義了四種傳輸型態:

 - 控制傳輸(Control Transfers) :用於控制傳輸命令及狀態操作。像是設定裝置、取得裝置資訊、發送指令到裝置等。每個USB裝置都有一個'端點0'(Endpoint, EP0),USB Core就是使用他在裝置插入後進行設定。
 - 中斷傳輸(Interrupt Transfers) :與一般常見的中斷不同(名詞有點誤導),需要 host 端先詢問才會執行。用一個固定速傳輸少量資料,像是USB鍵盤和滑鼠就是屬於這種方式。
 - 批次傳輸(Bulk Transfers):用於大量資料傳輸且需要確保資料無誤(如傳給印表機或隨身碟),沒有速度限制,若傳輸失敗就會重傳以確保正確。
 - 同時傳輸(Isochronous Transfers) :同樣用於大量資料傳輸,但不確保資料是否到達。例如例如USB視訊裝置,使用者會期望傳輸聲音或影像的速率是穩定的,若有幾張frame遺失,沒有通過CRC資料也不會重傳。

每種型態有不同的工作流程(stage),每個 stage 會需要不同的封包類型(packet)來實現,如同下表:

+---------------+--------------------+-----------+
| Transfer Type | Stages             | Phases    |
|               | (Transactions)     | (Packets) |
+===============+====================+===========+
| Control       | Setup              | Token     |
+---------------+--------------------+-----------+
|               |                    | Data      |
+---------------+--------------------+-----------+
|               |                    | Handshake |
+---------------+--------------------+-----------+
|               |====================|===========|
+---------------+--------------------+-----------+
|               | Data (IN or Out)   | Token     |
+---------------+--------------------+-----------+
|               |                    | Data      |
+---------------+--------------------+-----------+
|               |                    | Handshake |
+---------------+--------------------+-----------+
|               |====================|===========|
+---------------+--------------------+-----------+
|               | Status (IN or Out) | Token     |  
+---------------+--------------------+-----------+
|               |                    | Data      |
+---------------+--------------------+-----------+
|               |                    | Handshake |
+---------------+--------------------+-----------+
|===============|====================|===========|
+---------------+--------------------+-----------+
| Bulk          | Data (IN or Out)   | Token     |
+---------------+--------------------+-----------+
|               |                    | Data      |
+---------------+--------------------+-----------+
|               |                    | Handshake |
+---------------+--------------------+-----------+
|===============|====================|===========|
+---------------+--------------------+-----------+
| Interrupt     | Data (IN or Out)   | Token     |
+---------------+--------------------+-----------+
|               |                    | Data      |
+---------------+--------------------+-----------+
|               |                    | Handshake |
+---------------+--------------------+-----------+
|===============|====================|===========|
+---------------+--------------------+-----------+
| Isochronous   | Data (IN or Out)   | Token     |
+---------------+--------------------+-----------+
|               |                    | Data      |
+---------------+--------------------+-----------+

Demo 程式
^^^^^^^^^

::

  git clone https://github.com/kvzhao/USB-Demo

目的
========
把STM32F4作為Host,當插入隨身碟後在裡面寫入一份文件。

步驟與現象
========
.. image:: /usb.png
* 紅燈亮起:偵測到隨身碟
* 綠燈亮起:file system mount完成
* 橘燈亮起:已打開隨身碟中的目錄
* 藍燈亮起:完成寫入簽名,並且關閉file
* 當隨身碟拔出後,所有LED燈會熄滅,結束實驗,並且在隨身碟中留下文件。

.. image:: /usb_hacking.png

程式說明
========

Q & A
^^^^^ 
 Q: 如何推導出 USB 3種速度(low speed:1.5 Mb/s、full speed 12 Mb/s、high speed 480 Mb/s)的理論值?

 A: 這是原本定義的各種傳輸速度主頻率。

======

 Q: packet ID 實際上只使用到前四個 bits,為什麼後四個 bits(check field)是採用前四個 bits 的補數?

 A: USB 採用的是 NRZI 編碼,此作法方便執行,更可避免出現 bit-stuffing。

=============
 
 Q: smart phone 接上 PC 後封包傳遞順序?

 A: 主機端的 USB 集線器監視著它的每個端口的信號線的電壓,當USB設備插入主機時,信號線的電壓會發生變化,此時主機知道有新設備插入了。

 當主機檢測到設備的插入後會首選重啟這個設備,接著主機發出 Get_Port_Status 請求來驗證設備是否已經重啟,設備重啟後主機通過檢測根信號線的電壓狀態判斷設備的速度。主機發送第一次 Get_Descriptor(wValue 字段的高字節為 0x01,表示設備描述符)請求取得設備描述符,設備描述符提供了設備的多種信息,包括:設備通訊終端 0 的最大封包的大小、設備支持的配置號以及有關這個設備的其它信息、主機通過對這些信息的分析以確定接下來的通信動作。

 device descriptor 裡規定了設備一個或多個 configuration descriptor,主機再次或多次發出 Get_Descriptor(wValue 字段的高字節為 0x02,表示 configuration)指令來讀取這些 configuration descriptor,第一次只讀出 configuration descriptor 的前 9 個字節,其中包含了 configuration descriptor 和它的所有從屬描述符(interface descriptor、endpoint descriptor)的總長度,然後主機根據這個長度讀出設備的所有 configuration descriptor(當然包括其所有從屬描述符)。

 讀取完 configuration descriptor 後,若之間讀取的 configuration descriptor 中指定了相關 string descriptor(用來描述廠商、產品和設備序列號信息的)的索引,主機將發出若干次 Get_Descriptor(wValue 字段的高字節為 0x03,表示string descriptor)命令來獲得這些string descriptor,此時主機將會彈出窗口,展示發現新設備的信息,產商、產品描述、型號等。在主機已經從它的 descriptor 中知道了能夠知道的所有信息後,便開始為這個設備安裝驅動程序。加載了 USB 設備驅動以後,主機發送 Set_Configuration 命令請求為該設備選擇一個合適的配置。

==========

 Q: CRC的長度如何得知?

 A: token packet using 5bit CRC

      data packet using 16bit CRC

===========

參考資料
^^^^^^^

http://www.zeroplus.com.tw/E-paper/201112/images/201112-USB20ProtocolAnalyzer.pdf

http://www.baiheee.com/Documents/090522/090522165226.htm

http://csuftp.csu.edu.tw/~k0478/981/USB/USB_02_new.pdf

`USB Audio Class <http://baike.baidu.com/view/7879812.htm>`_

`MSC <http://baike.baidu.com/view/66940.htm>`_

http://chamberplus.myweb.hinet.net/usb.htm

`USB Specification <http://www.usb.org/developers/docs>`_

`STM32F407xx Reference Manual<http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/REFERENCE_MANUAL/DM00031020.pdf>`_

`USB On The Go <http://www.mem.com.tw/article_content.asp?sn=1101280010>`_

`USB in a NutShell <http://www.beyondlogic.org/usbnutshell/usb1.shtml>`_

`USB 設備的插入檢測 <http://jienyuan.blogspot.tw>`_