裴曉勇,李 儼,趙凱瑞
(西北工業大學自動化學院,西安710072)
USB設備結構簡單,通用性好,因而得到了大規模使用。不僅在PC機上,越來越多的嵌入式應用中也提到了USB。在很多的嵌入式應用中,需要實現USB主機控制器的功能。OHCI(Open Host Control Interface)是Compaq,Microsoft等公司提出的一個USB主機控制器接口規范,廣泛應用于嵌入式設備中。目前有關OHCI主機驅動程序的開發,大多數是基于操作系統(Linux或者WinCE)的,參考文獻[3,5-6]就是典型實例。由于這種 OHCI驅動程序過于復雜和抽象,而且依賴于特定的操作系統環境,在無操作系統平臺上的移植與使用有一定的困難。同時,越來越多的OHCI控制器出現在不能移植復雜操作系統的硬件平臺上,比如LCP2478。本文以LPC2478為硬件平臺(ARM7TDMI內核),以適用于無操作系統或者輕量級的操作系統(μC/OS-II,freeRTOS)環境為目的,實現了簡單而且可靠的基于OHCI的USB主機驅動。
首先介紹USB主機控制器的體系結構,然后著重介紹了OHCI規范的主要細節,最后實現了主機驅動程序,并對所實現的驅動程序進行了驗證。
USB設備結構簡單,通用性好,大量用于電子設備中。在數據采集系統中,可以通過USB總線將采集到的數據保存到U盤,移動硬盤等大容量存儲設備中。在此過程中,需要USB主機控制器的參與,才能將數據從主機傳輸到USB存儲設備中。在USB2.0規范中定義了USB主機控制器的體系結構,USB主機控制器負責連接USB設備和上位機。當有USB設備插入USB主機控制器的時候,主機控制器會將此信息通過中斷的方式告知上位機;上位機與USB設備的數據交互最終也必須通過USB主機控制器來進行。USB主機控制器是連接上位機控制器內核和USB設備的必要介質。
USB主控制器的邏輯結構如圖1所示。

圖1 USB主機的軟硬件體系結構
HC(Host Controler)是USB主機系統的硬件核心,它位于USB主機協議棧中最低層。HC負責物理和電氣特性,比如對傳輸的控制和處理、數據包的解析以及對傳輸信號的編碼和解碼。HCD(Host Controler Driver)負責對HC進行配置和管理,而HC通過HCD來與USB功能軟件進行通信。目前USB的HC芯片組有三種,隨之對應的HCI(Host Controller Interface)也有三種:EHCI(Enhanced Host Controller Interface),OHUHCI(Universal Host Controller Interface)和OHCI。在大多數的嵌入式系統中使用的是遵循OHCI規范的USB主機控制器。
在操作和數據傳輸上,HC同HCD之間的接口有兩條通道。第一個通道是HC的操作寄存器,包括控制、狀態和列表指針寄存器。操作寄存器包含了指向一個稱之為HCCA(Host Controller Communications Area)的指針,而HCCA是第二個通訊通道。HCCA保存了到中斷端點描述的列表指針,完成隊列的頭指針以及與SOF處理相關的狀態信息。
OHCI使用端點描述ED(EndpointDescriPtor)和傳輸描述TD(TransferDescriptor)來組織USB數據的傳輸,HC從ED列表獲取端點信息,并從ED的TD列表逐次獲取傳輸信息,以實現數據的傳輸。典型的鏈表結構如圖2所示。
批量和控制ED列表的頭指針由HC操作寄存器管理。HCD初始化這些指針,使得HC能夠訪問它們,當這些指針需要變更時,HC應該停止HC對需更新指針的列表的處理,更新指針,并重新啟動HC。

圖2 典型的OHCI的ED鏈表
特別要注意,LPC2478規定了USB設備使用的RAM區域,即0x7FD00000—0x7FD03FFF共16KB。HCCA以及ED,TD等數據結構定義的變量必須定義在這個區域,否則HC不能正常工作。
HCD主要構建的數據結構有端點描述符ED、傳輸描述符TD和主機控制器通信區域HCCA。
每個ED對應一個USB設備端點,不同的設備端點擁有不同的ED。同種傳輸類型的ED組成一鏈表,OHCI有三種ED鏈表:控制傳輸數據鏈表,批量傳輸數據鏈表和周期性數據鏈表(中斷數據傳輸和同步傳輸同屬此類),HC通過相應的操作寄存器訪問各個ED鏈表。程序中ED數據結構定義如下:

TD用來指定每次發送給USB設備的數據所保存的位置或者接收USB設備發送給主機數據的保存位置。根據OHCI規范對TD的定義,定義TD的數據結構。程序中TD的數據結構定義如下:

HCCA是256字節的系統內存結構,系統軟件通過這一結構來向HC發送和從HC接收特定的控制和狀態信息。這一結構在內存中以256字節為單位來對齊綁定。系統必須為HC指定HcHCCA的值即HCCA結構地址。通常系統與HC的交互能夠通過讀取HC寫入這一結構的數值來完成。程序中HCCA結構定義如下:

HCD向USB功能軟件提供以下幾個接口函數,用來操作和控制主機控制器。
4.2.1 OHCI主機控制器初始化函數Host_Init(void)
USB 2.0規范要求USB外設的工作時鐘必須是48MHZ。LPC2478的外設功率控制寄存器(PCONP)決定外設的使能與否,最高位(32位)置1使能USB外設,初始化OHCI控制器首先要將此位置1。同時,通過置OTG時鐘控制寄存器(OTGClkCtrl)的主機時鐘使能位,使能主機時鐘,至此OHCI可以正常工作了。
將LPC2478對應功能的引腳配置為OHCI后,需要初始化一些常用的變量如控制ED,批量ED,HCCA區域,TD數組等,另外,為了便于數據傳輸,要定義一個數據緩沖區指針。注意這些變量必須定義到LPC2478所指定的USB RAM(0x7FD00000-0x7FD03FFF)中,要傳輸到USB設備的數據必須首先將數據保存到USB RAM中,然后啟動發送過程;接收到來自USB設備的數據也首先保存到USB RAM中,然后再將數據拷貝到所對應的緩沖區中。
最后初始化OHCI寄存器。OHCI寄存器分為4類:控制與狀態類寄存器,存儲器指針類寄存器,幀計數器類寄存器和根集線器類寄存器。
控制與狀態類寄存器中,最主要是初始化與中斷有關的寄存器。與USB設備通信的中斷標志位主要有兩個,分別是WDH位和RHSC位。每當一個TD傳輸結束后,HC會將此TD的地址寫入Hc-DoneHead寄存器,HC然后將此寄存器的內容寫入HCCA區域,此時就會產生WDH中斷,程序可以通過此中斷來標識一次數據傳輸的結束;而每次USB設備插入主機或者從主機拔出的時候,都會初始化RHSC中斷,程序通過此標志來枚舉USB設備或者處理USB設備拔出的善后工作。
存儲器指針類寄存器,主要用來初始化一些指針,比如控制ED的指針,批量ED的指針,HCCA區域的指針等。這些指針可以隨時修改。
幀計數器類寄存器,主要用來設置處理在一個幀的時間長短,HC處理周期ED和非周期ED的時間比率。通過設置 HcFmInterval寄存器的FrameInterval來決定HC處理一個幀的時間長短,注意此域的頻率是12MHZ,及1ms中的 bit時間是12000。默認設置是11999,即一個USB幀的時間長度的1ms。另外HcPeriodicStart決定了在一個幀中處理非周期ED的長度。
根集線器寄存器主要用來標識根集線器的狀態,初始化一般按照默認配置,在程序運行期間,通過讀取此對應寄存器的各個位來得到端口的狀態。至此,OHCI的初始化結束。初始化流程如圖3所示。

圖3 OHCI控制器初始化過程
4.2.2 USB設備枚舉函數Host_EnumDev(void)
當有USB設備插入到OHC的端口上的時候,程序調用此函數對USB設備進行枚舉過程。枚舉過程主要是根據USB規范所定義的枚舉過程進行的。通過枚舉,程序可以獲得USB設備的設備描述符,類描述符,配置描述符,端點描述符等,根據這些信息來初識化對應的ED。本實現根據USB2.0規范實現了標準的枚舉過程。
4.2.3 TD傳輸函數Host_ProcessTD()
Host_ProcessTD()函數原型為Host_ProcessTD(HCED*ed,INT32U token,INT08U*buffer,INT32U buffer_len);此函數用來處理鏈接到端點描述符ED上的TD。根據參數ed的Control域,可以知道USB數據傳輸的類型(控制傳輸,批量傳輸,中斷傳輸和同步傳輸),然后根據參數token來決定每種數據傳輸類型所處的階段,這樣就可以把從起始地址為buffer、一共buffer_len個字節的數據發送到USB設備對應的端點緩沖區,或者從對應的端點緩沖區接收buffer_len字節的數據到起始地址為buffer的緩沖區。連續調用該函數可以完成USB協議定義的標準傳輸類型。在此基礎上,就可以實現基于USB標準傳輸的更復雜的協議。
通過Host_ProcessTD()函數就可以實現USB設備中常用的控制傳輸和批量傳輸。控制傳輸首先傳輸一個SETUP TD,然后根據需要傳輸兩個IN TD或者OUT TD。而批量傳輸,根據需要,在生成對應的ED后,直接就可以傳輸IN TD或者OUT TD。以控制寫為例,流程圖如下:

圖4 控制寫流程
驅動程序實現了標準的USB設備枚舉過程。通過測試枚舉過程中讀取到的USB設備描述符來驗證驅動程序的正確與否。嵌入式開發環境Keil uVision4配合仿真器J-LINK可以在仿真調試環境下查看全局和局部變量的值。驗證過程中選擇了一款金士頓的U盤作為USB設備。圖5為通過Keil uVision4在仿真狀態下讀取到的U盤設備描述符:

圖5 金士頓U盤的設備描述符
圖6為同一個U盤在Windows XP操作系統中枚舉成功后所讀取到的屬性。
可以看出,在圖5中,idVendor0和idVender1兩個字節組合起來代表了U盤的VID(Vender ID),由于是大端顯示,所以驅動程序顯示的VID實際為0x1043,同理idProduct0和idProduct1兩個字節組合起來代表了U盤的PID(Product ID),PID為0x8012。在圖6中,U盤的VID顯示是0x1043,PID顯示是0x8012。通過圖5和圖6,說明驅動程序設計是正確的。

圖6 金士頓U盤在PC機上的屬性
本文實現了一種適用于簡單嵌入式軟硬件平臺的OHCI主機驅動程序。在實際的實現過程中,首先初始化了OHCI主機控制器,根據具體的實際應用,優化了OHCI規范中規定的ED鏈表操作。并在此基礎上通過實驗,分別實現了控制傳輸,批量傳輸和中斷傳輸。另外程序還實現了對USB設備的標準枚舉過程,一旦USB設備枚舉成功,通過相應的USB設備描述符,加載不同類型的驅動程序,為上層的應用程序提供了穩定可靠的接口函數。實驗證明,驅動程序的設計是正確實用的。
[1] Universal Serial Bus Mass Storage Class Bulk-Only Transport revision1.0[S].USB-IF,1999.
[2] Open Host Controller Interface Specification for USB Compaq Microsoft National Semiconductor[S].Release:1.0a,1999-09.
[3] 馮光磊,郭忠文,李正寶,等.基于 ARM和 Linux的USB OHCI驅動的設計與實現[J].計算機應用,2009,29(6):53-56.
[4] 陳明智,李鋒,尚淮.USB通信協議分析和系統設計[J].自動化與儀器儀表,2006(6):43-46.
[5] 張卓亮.基于Linux系統的USB HOST驅動程序設計與實現[J].中國集成電路,2007,16(11):30-33.
[6] 劉鋒,韓超,汪磊峰,等.基于linux的嵌入式USB主機控制器接口實現[J].微計算機信息,2010,26(42):75-77.