文/張凡忠 公安部第一研究所
摘要:USB設(shè)備已成為當(dāng)前移動設(shè)備數(shù)據(jù)傳輸?shù)闹饕獋鬏斀涌?,即便在安防,移動存儲或擴展存儲時,也時常需要到,但USB技術(shù)如何?可怎樣設(shè)計和利用?請看本文就USB的體系結(jié)構(gòu)、USB通信技術(shù)基礎(chǔ)、USB固件程序的開發(fā)方法等是如何論述的。
前言
不管是計算機還是連接的外圍設(shè)備,在新品開發(fā)時保持兼容性是必須考慮的。即使是革命性的新外圍設(shè)備,也必須使用到連接計算機的接口。當(dāng)設(shè)計一個外圍設(shè)備的接口時,下列是該外圍設(shè)備應(yīng)該具備的特性:
穩(wěn)定性:具備自動差錯與除錯的功能,使錯誤的發(fā)生率幾乎為零;
便宜:讓大部分的用戶都有能力購買;
省電:在便攜式計算機上節(jié)省電池的消耗;
有彈性:讓許多不同種類的外圍設(shè)備,都可以使用這個接口;
快速:此接口不可以成為傳輸?shù)钠款i;
容易使用:用戶容易安裝、設(shè)置與使用;
操作系統(tǒng)的支持:如果操作系統(tǒng)支持此接口,開發(fā)者就不必要自行開發(fā)底層的驅(qū)動程序來使用此接口。
USB就是一個為符合上述所有條件而開發(fā)的最新外圍設(shè)備接口。USB是一種通用串行總線。它是由COMPAQ、INTEL、MICROSOFT和NEC等公司共同開發(fā)的一種新型、快速、雙向、同步傳輸?shù)牟⒖梢詿岵灏蔚臄?shù)據(jù)傳輸總線接口。
規(guī)范的版本
USB規(guī)范的版本變動,如表1所示。
經(jīng)過多次版本的更新后,USB1.0發(fā)表于1996年1月。USB1.1則修訂了1.0版本的問題,并且新增一個新的傳輸類型(中斷傳輸)。USB2.0在2000年4月發(fā)表,新增了高速模式。對于支持USB1.1規(guī)范的設(shè)備最高傳輸率可達(dá)12Mb/s,而支持USB2.0規(guī)范的設(shè)備最高速率可達(dá)48012Mb/s。
USB系統(tǒng)結(jié)構(gòu)
一個USB系統(tǒng)主要被定義為三個部分:
USB互連;
USB設(shè)備;
USB主機。
USB互連是指USB設(shè)備與主機之間進行連接和通信的操作,支持?jǐn)?shù)據(jù)在USB主機與USB設(shè)備之間的流動。在任何USB系統(tǒng)中,只有一個主機。USB和主機系統(tǒng)的接口稱作主機控制器,主機控制器可由硬件、固件和軟件綜合實現(xiàn)。USB的主機通過主機控制器與USB設(shè)備進行交互。主機功能如下:
檢測USB設(shè)備的安裝和拆卸;
管理主機和USB設(shè)備之間的控制流;
收集狀態(tài)和動作信息;
提供能量給連接的USB設(shè)備。
USB設(shè)備包含一些設(shè)備描述符,它們指出了一個給定設(shè)備的屬性和特征。當(dāng)設(shè)備被連接、編號后,該設(shè)備就擁有一個唯一的USB地址。設(shè)備就是通過該USB地址被操作的,每一個USB設(shè)備通過一個或多個通道與主機通訊。所有USB設(shè)備必須在零號端口上有一指定的通道,每個USB設(shè)備的USB控制通道將與之相連。通過此控制通道,所有的USB設(shè)備都列入一個共同的準(zhǔn)入機制,以獲得控制操作的信息。
圖2展示了USB通信模型之間基本的信息流與互連關(guān)系。
USB通信基礎(chǔ)
傳輸基礎(chǔ)
USB通信可以分為兩類:配置通信、應(yīng)用通信。在配置通信中,主機通知設(shè)備,然后使它準(zhǔn)備好交換數(shù)據(jù)。大部分這類通信發(fā)生在上電或連接時主機檢測到外設(shè)的時候。應(yīng)用通信出現(xiàn)在主機的應(yīng)用程序與一個檢測到的外設(shè)交換數(shù)據(jù)的時候。這些是實現(xiàn)設(shè)備目的的通信。例如:對鍵盤來說,應(yīng)用通信是發(fā)送按鍵數(shù)據(jù)給主機,告訴一個應(yīng)用程序顯示一個特性或執(zhí)行其他動作。
配置通信
在檢測過程中,設(shè)備的固件對主機的一系列標(biāo)準(zhǔn)請求做出響應(yīng)。設(shè)備必須識別出每一個請求,返回被請求的信息,并且采取其他一些請求指定的動作。在PC上,Windows執(zhí)行檢測工作,所以不涉及用戶編程的問題。然而,為了完成檢測工作,Windows必須有兩個可用的文件:一個識別這個設(shè)備的驅(qū)動程序的文件名和位置的INF文件和設(shè)備驅(qū)動程序本身。
應(yīng)用通信
在主機已經(jīng)與設(shè)備交換了檢測信息并且設(shè)備驅(qū)動已經(jīng)被分配并載入后,應(yīng)用程序段可以非常順利地進行。在主機上,應(yīng)用程序可以使用標(biāo)準(zhǔn)Windows API功能來讀取和寫設(shè)備。在外設(shè)上,傳輸數(shù)據(jù)通常需要把要發(fā)送的數(shù)據(jù)放在USB控制器的傳輸緩存器中,當(dāng)一個硬件中斷發(fā)出數(shù)據(jù)已經(jīng)到達(dá)的信號時從接收器中讀取接收到的數(shù)據(jù),并且在完成傳輸時確保外設(shè)準(zhǔn)備好下一次傳輸。總線上的每一次數(shù)據(jù)傳輸使用下列四種類型之一:控制、中斷、批量或同步。
傳輸類型
USB共有四種類型傳輸方式:分別為控制傳輸,中斷傳輸,批量傳輸和同步傳輸。
控制傳輸:用于主機對USB外設(shè)的配置,對USB設(shè)備的狀態(tài)查詢和控制命令的發(fā)送,也可用于用戶自定義的命令的發(fā)送。
中斷傳輸:用于小批量的、點式的、非連續(xù)性的數(shù)據(jù)傳輸?shù)膱龊希堑退僭O(shè)備可以傳輸數(shù)據(jù)的唯一方法。
批量傳輸:用于批量的,非實時的數(shù)據(jù)傳輸,即那些需要一次傳輸較多的數(shù)據(jù),但傳輸過程對時間要求不嚴(yán)格的傳輸類型。
同步傳輸:適用于那些要求數(shù)據(jù)連續(xù)的、實時的,以固定的數(shù)據(jù)率產(chǎn)生、傳送的場合。
傳輸(transfers)和事務(wù)(transactions)是經(jīng)常提到的兩個概念,分清這兩個概念是設(shè)計USB外設(shè)的關(guān)鍵。傳輸是指一次完整的發(fā)出請求到該請求被完整的處理結(jié)束的整個過程。事務(wù)是傳輸中的一個基本元素,或者叫一個傳輸?shù)膬?nèi)建模塊。每一次傳輸由一個或多個事務(wù)組成。事務(wù)又由包組成,而包還包含一個包識別器(PID),一個錯誤校驗位以及有時還有其他信息。參見圖3。
事務(wù)按照它們的目的和數(shù)據(jù)流方向可以分為三種類型:SETUP事務(wù)、IN事務(wù)、OUT事務(wù)。它們都是由一個令牌階段,一個數(shù)據(jù)階段和一個握手階段組成。對于SETUP事務(wù)來說,在令牌階段有主機發(fā)出SETUP令牌,然后主機又發(fā)出數(shù)據(jù)包,由該數(shù)據(jù)包指出本次請求的具體的內(nèi)容。在握手階段指出本次事務(wù)是否成功。各種事務(wù)的組成如圖4。
IN事務(wù)是從一個設(shè)備接收數(shù)據(jù),OUT事務(wù)是發(fā)送數(shù)據(jù)給其他一個設(shè)備。(IN和OUT事務(wù)的命名是從主機的角度出發(fā)的,在一個IN事務(wù)中,數(shù)據(jù)是從外設(shè)傳輸給主機的;在一個OUT事務(wù)中,數(shù)據(jù)是從主機傳輸?shù)酵庠O(shè)的。)在一個Setup事務(wù)中,數(shù)據(jù)也是從主機傳輸?shù)酵庠O(shè)的,但一個Setup事務(wù)是一個特殊情況,因為它啟動一個控制傳輸。任何事務(wù)都可以用IN或OUT事務(wù),但只有控制傳輸可以使用Setup事務(wù)。
在應(yīng)用程序可與一個設(shè)備通信之前,主機需知道設(shè)備支持哪些傳輸類型和終端。主機也須分配一個地址給設(shè)備,主機通過一個被稱為枚舉的信息交換來完成這些工作。
USB設(shè)備的枚舉過程
枚舉是使得主機的設(shè)備驅(qū)動程序能與這個設(shè)備通信的最基本的信息交換。該過程可以由以下動作來完成:
1、一個設(shè)備連到一個USB端口
或者系統(tǒng)上電時有一個設(shè)備已經(jīng)插入到一個端口中了。這個端口可以在主機的根基線器上或者在連接主機下游的基線器上。集線器正常給這個端口供電,這個設(shè)備正處于上電狀態(tài)。
2、集線器檢測到這個設(shè)備
集線器監(jiān)視著它的每一個端口的信號線的電壓。集線器端口的兩根信號線(D+和D-)的每一根都有一個15k 的下拉電阻,而一個設(shè)備在D+(為全速設(shè)備)和D-(為低速設(shè)備)都有一個1.5 k 的上拉電阻。當(dāng)一個設(shè)備插入到一個端口中時,設(shè)備的上拉電阻使信號線為高,使得集線器可以檢測到一個設(shè)備連接上了。
3、主機知道了這個新設(shè)備
每個集線器使用它的中斷流程來報告發(fā)生在集線器上的事件。當(dāng)主機知道了這個事件,它給集線器發(fā)送一個Get_Port_Status請求來了解更多的知識。返回的信息告訴主機該設(shè)備是什么時候連接的。
4、集線器重新設(shè)置這個設(shè)備
當(dāng)主機知道有一個新設(shè)備時,主機控制器給集線器發(fā)送一個Set_Port_Feature請求,請求集線器來重新設(shè)置端口。集線器使得設(shè)備的USB數(shù)據(jù)線處于重啟狀態(tài)至少10ms。
5、集線器在設(shè)備和總線之間建立一個信號通路
主機通過發(fā)送一個Get_Port_Status請求來驗證設(shè)備是否激起重啟狀態(tài)。返回的數(shù)據(jù)的一位表示設(shè)備是否仍然處于重啟狀態(tài)。當(dāng)集線器已經(jīng)釋放了重啟狀態(tài),設(shè)備就處于默認(rèn)狀態(tài)了。設(shè)備的USB寄存器已經(jīng)處于它們的默認(rèn)狀態(tài),設(shè)備已經(jīng)準(zhǔn)備好通過終端0的默認(rèn)流程來響應(yīng)控制傳輸。設(shè)備現(xiàn)在可以能與主機通信,使用默認(rèn)地址0h。在這一點上,設(shè)備可以從總線上抽取不超過100毫安的電流。
6、集線器檢測設(shè)備速度
或在重啟之前或在重啟之后,集線器通過檢查兩個信號線的電壓來檢測設(shè)備的速度。集線器通過測試那根信號線在空閑時有更高的電壓來檢測一個設(shè)備的速度。集線器發(fā)送信息給主機,以響應(yīng)下一個Get_Port_Status請求。
7、主機發(fā)送一個Get_Descriptor請求來獲取默認(rèn)流程的最大包的大小
主機發(fā)送請求給設(shè)備地址0、終端0。因為主機一次只列舉一個設(shè)備,只有一個設(shè)備將響應(yīng)尋址設(shè)備地址0的通信。最大包的大小是這個描述符的第8位,因此主機只需要讀取頭8B。一個Windows主機請求64B,但在僅接收一個包后,它就開始了狀態(tài)階段。在完成狀態(tài)階段時,主機請求集線器來重啟這個設(shè)備。這里不需要重啟,因為設(shè)備應(yīng)該可以用響應(yīng)下一個設(shè)置階段的動作來處理任何時候的主機放棄一個控制傳輸情況。
8、主機分配一個地址
主機控制器通過發(fā)送一個Set_Address請求來分配一個單獨的地址給設(shè)備。設(shè)備讀取這個請求,返回一個確認(rèn),并且保存新的地址。這個設(shè)備現(xiàn)在處于一個地址狀態(tài)。從這現(xiàn)在開始的所有通信使用這個新地址。
9、主機知道了設(shè)備的能力
主機給新地址發(fā)送一個Get_Descriptor請求來讀取這個設(shè)備描述符,這次讀取整個部分。這個描述符是一個數(shù)據(jù)結(jié)構(gòu)包括終端0的最大包的大小,設(shè)備支持的配置號,及關(guān)于這個設(shè)備的其他信息。主機把這些信息應(yīng)用在其后的通信中。然后主機通過請求在設(shè)備描述符規(guī)定的一個或多個配置描述符來了解這個設(shè)備。一個Windows主機開始申請配置描述符的9B。含在這些B中的是這個配置描述符和它所有的從屬描述符的總長度。Windows然后再次請求配置描述符,這次使用得到的總長度,最多可達(dá)到FFhB。這導(dǎo)致設(shè)備發(fā)送跟隨在每個配置額的接口描述符后的配置描述符,在它后面是每個接口的終端描述符。若這些描述符總共超過了FFhB,則Windows在第三次請求時得到整套描述符。每個描述符以它的長度和類型開始,使主機能分解其后的數(shù)據(jù)。
10、主機分配和載入一個設(shè)備驅(qū)動
在主機已經(jīng)從它的描述符中知道了能夠知道的所有信息后,它開始在一個設(shè)備啟動中查找最合適的匹配來管理與設(shè)備間的通信。在選擇一個驅(qū)動時,Windows盡量去與從設(shè)備得到的、保存在系統(tǒng)INF文件中的信息中的銷售商和產(chǎn)品ID、發(fā)布號和類信息相匹配。在驅(qū)動程序被載入以后,它經(jīng)常請求設(shè)備來重新發(fā)送描述符或者發(fā)送應(yīng)用于這個設(shè)備的類描述符。
11、主機的設(shè)備驅(qū)動選擇一個配置
在從描述符了解了設(shè)備后,設(shè)備驅(qū)動程序發(fā)送一個Set_Configuration命令來請求希望的配置號。設(shè)備讀取這個請求并且設(shè)置它的配置來匹配它。設(shè)備現(xiàn)在處于配置狀態(tài),并且設(shè)備的接口已經(jīng)被使能。
主機枚舉是通過給端點0發(fā)送包含標(biāo)準(zhǔn)USB請求的控制傳輸。所有的USB設(shè)備必須支持控制傳輸,標(biāo)準(zhǔn)USB請求和端點0。對一個成功的枚舉來說,設(shè)備必須對每一個請求響應(yīng),返回請求的信息以及采取其他請求的動作。USB設(shè)備的枚舉過程是在缺省的控制管道進行的,每一步都是在控制傳輸?shù)腟ETUP階段提出請求的。而具體的請求在SETUP事務(wù)的數(shù)據(jù)階段中,用戶可讀取并根據(jù)USB協(xié)議來分析該請求,然后根據(jù)分析的結(jié)果進入該控制傳輸?shù)臄?shù)據(jù)階段。在USB設(shè)備的枚舉過程中,主機要讀取USB設(shè)備的設(shè)備描述符、配置描述符、接口描述符和端點描述符。
固件設(shè)計
為了實現(xiàn)上述的枚舉過程在設(shè)備端需要固件程序的支持。下面以PDIUSBD12為例講述一下固件的設(shè)計方法。PDIUSBD12的固件設(shè)計成完全的中斷驅(qū)動,當(dāng)PDIUSBD12檢測到有相應(yīng)的事務(wù)發(fā)生時,就中斷CPU處理器調(diào)用中斷服務(wù)程序。
D12的固件程序可采用如圖5的積木式結(jié)構(gòu)。
硬件抽象層:這是固件中的最低層代碼,它執(zhí)行對PDIUSBD12和硬件與I/O 相關(guān)的訪問。當(dāng)與其它CPU 平臺接口時這部分代碼需要修改或增加。
PDIUSBD12命令接口:利用這些命令實現(xiàn)對D12的控制。
中斷服務(wù)程序:處理USB的各種事務(wù)。
標(biāo)準(zhǔn)請求:USB設(shè)備必須對這11種標(biāo)準(zhǔn)請求做出響應(yīng),這11種標(biāo)準(zhǔn)代碼可以查詢設(shè)備的能力和狀態(tài)以及選擇配置。當(dāng)收到請求時,程序通過解析接收到的請求把要發(fā)送的數(shù)據(jù)存放到發(fā)送緩沖器中。設(shè)備不必執(zhí)行每一個請求;它只需要以一種可以理解的方式對請求做出響應(yīng)。
廠商請求:一個供應(yīng)商也可以與特定設(shè)備進行的傳輸控制而定義請求。
主程序:完成D12的初始化。
在USB通信過程中需要處理多種事務(wù),有些事務(wù)的處理需要特別注意,設(shè)計者往往忽視,下面分別介紹。
D12初始化過程
D12的中斷寄存器清零
Set Address Enable
Set Endpoint Enable
Disconnect
延時1~2秒鐘
Connect
Setup Transaction處理流程
如圖6所示,對于Setup Transaction的處理需要注意,在讀取D12的FIFO數(shù)據(jù)前必須要選擇端點,為了使以后的Setup Packet數(shù)據(jù)包能夠被接收要用Acknowledge Setup命令使能Control In和Control Out端點。當(dāng)D12接收到一個數(shù)據(jù)包時一個內(nèi)部端點緩存滿標(biāo)志有效。后續(xù)的數(shù)據(jù)包將不能夠被接收,必須通過Clear Buffer命令來清出標(biāo)志位。在讀取D12的數(shù)據(jù)后先要利用Acknowlege命令對主機進行回應(yīng),然后再清除D12的緩存。這兩個命令處理順序不能交換,因為在沒有回應(yīng)主機前不能夠清除掉D12的緩存,這樣就不能接收新的數(shù)據(jù)。
Control In Transaction處理流程
如圖7所示,在Control In Transaction處理過程中注意,要發(fā)送的數(shù)據(jù)是端點0能傳送的最大數(shù)據(jù)報的整數(shù)倍時,在傳送完所有的數(shù)據(jù)后,必須向主機發(fā)送零長度數(shù)據(jù)報。
Get Descriptor命令處理流程
如圖8所示,在列舉過程中,被請求的描述符逐涉及設(shè)備的小的元素:首先是整個設(shè)備,然后是每個配置,接著是每個配置的接口,最后是每個接口的終端。對于字符串描述符是可選的。關(guān)于描述符是設(shè)計者可以配置的,可以根基設(shè)備的通信能力和要求來定義需要的描述符。
Set Address命令處理流程
如圖9所示,通過這個請求,主機指定以后與設(shè)備通信的地址。值字段是要設(shè)置的設(shè)備的新的地址。允許值為1到127。當(dāng)上電或連接后集線器使能一個端口,端口使用默認(rèn)地址0直到它 從主機接收到一個Set_Address請求。這個請求和大部分的其他請求不同,因為設(shè)備直到通過發(fā)送零長度數(shù)據(jù)包完成請求的狀態(tài)階段后才執(zhí)行這個請求。主機發(fā)送狀態(tài)階段標(biāo)志包到默認(rèn)地址,因為設(shè)備必須在改變地址之前發(fā)送這個包。完成這個請求后,所有通信都使用這個新地址。一個使用默認(rèn)地址0的設(shè)備處于默認(rèn)狀態(tài)。在完成Set_Address請求設(shè)置一個非0的新地址后,設(shè)備進入地址狀態(tài)。一個設(shè)備必須在接收到請求后的50毫秒內(nèi)發(fā)送交換包,并且它必須在完成狀態(tài)階段后的2毫秒內(nèi)完成請求。
另外要注意的是當(dāng)USB設(shè)備接收主機發(fā)送的IN事務(wù),如果設(shè)備沒有要發(fā)送到主機的數(shù)據(jù)時,這時設(shè)備進入掛起狀態(tài),為了避免這種情況出現(xiàn),當(dāng)沒有數(shù)據(jù)要發(fā)送時可以發(fā)送零長度的數(shù)據(jù)報。
同時利用D12開發(fā)時有兩個突出的優(yōu)點:軟連接和GoodLink接口。所謂的軟連接就是把D12內(nèi)部集成的1.5K的上拉電阻連接到數(shù)據(jù)線D+上,通過此特性可以使設(shè)備CPU有充足的時間進行初始化,同時也避免頻繁的插拔USB數(shù)據(jù)線。GoodLink接口可以連接發(fā)光二極管,當(dāng)設(shè)備枚舉成功后發(fā)光二極管常亮,當(dāng)D12進行傳送數(shù)據(jù)時發(fā)光二極管閃爍。