裴曉勇,李 儼,趙凱瑞
(西北工業(yè)大學(xué)自動化學(xué)院,西安710072)
USB設(shè)備結(jié)構(gòu)簡單,通用性好,因而得到了大規(guī)模使用。不僅在PC機上,越來越多的嵌入式應(yīng)用中也提到了USB。在很多的嵌入式應(yīng)用中,需要實現(xiàn)USB主機控制器的功能。OHCI(Open Host Control Interface)是Compaq,Microsoft等公司提出的一個USB主機控制器接口規(guī)范,廣泛應(yīng)用于嵌入式設(shè)備中。目前有關(guān)OHCI主機驅(qū)動程序的開發(fā),大多數(shù)是基于操作系統(tǒng)(Linux或者WinCE)的,參考文獻[3,5-6]就是典型實例。由于這種 OHCI驅(qū)動程序過于復(fù)雜和抽象,而且依賴于特定的操作系統(tǒng)環(huán)境,在無操作系統(tǒng)平臺上的移植與使用有一定的困難。同時,越來越多的OHCI控制器出現(xiàn)在不能移植復(fù)雜操作系統(tǒng)的硬件平臺上,比如LCP2478。本文以LPC2478為硬件平臺(ARM7TDMI內(nèi)核),以適用于無操作系統(tǒng)或者輕量級的操作系統(tǒng)(μC/OS-II,freeRTOS)環(huán)境為目的,實現(xiàn)了簡單而且可靠的基于OHCI的USB主機驅(qū)動。
首先介紹USB主機控制器的體系結(jié)構(gòu),然后著重介紹了OHCI規(guī)范的主要細節(jié),最后實現(xiàn)了主機驅(qū)動程序,并對所實現(xiàn)的驅(qū)動程序進行了驗證。
USB設(shè)備結(jié)構(gòu)簡單,通用性好,大量用于電子設(shè)備中。在數(shù)據(jù)采集系統(tǒng)中,可以通過USB總線將采集到的數(shù)據(jù)保存到U盤,移動硬盤等大容量存儲設(shè)備中。在此過程中,需要USB主機控制器的參與,才能將數(shù)據(jù)從主機傳輸?shù)経SB存儲設(shè)備中。在USB2.0規(guī)范中定義了USB主機控制器的體系結(jié)構(gòu),USB主機控制器負責(zé)連接USB設(shè)備和上位機。當(dāng)有USB設(shè)備插入USB主機控制器的時候,主機控制器會將此信息通過中斷的方式告知上位機;上位機與USB設(shè)備的數(shù)據(jù)交互最終也必須通過USB主機控制器來進行。USB主機控制器是連接上位機控制器內(nèi)核和USB設(shè)備的必要介質(zhì)。
USB主控制器的邏輯結(jié)構(gòu)如圖1所示。
圖1 USB主機的軟硬件體系結(jié)構(gòu)
HC(Host Controler)是USB主機系統(tǒng)的硬件核心,它位于USB主機協(xié)議棧中最低層。HC負責(zé)物理和電氣特性,比如對傳輸?shù)目刂坪吞幚怼?shù)據(jù)包的解析以及對傳輸信號的編碼和解碼。HCD(Host Controler Driver)負責(zé)對HC進行配置和管理,而HC通過HCD來與USB功能軟件進行通信。目前USB的HC芯片組有三種,隨之對應(yīng)的HCI(Host Controller Interface)也有三種:EHCI(Enhanced Host Controller Interface),OHUHCI(Universal Host Controller Interface)和OHCI。在大多數(shù)的嵌入式系統(tǒng)中使用的是遵循OHCI規(guī)范的USB主機控制器。
在操作和數(shù)據(jù)傳輸上,HC同HCD之間的接口有兩條通道。第一個通道是HC的操作寄存器,包括控制、狀態(tài)和列表指針寄存器。操作寄存器包含了指向一個稱之為HCCA(Host Controller Communications Area)的指針,而HCCA是第二個通訊通道。HCCA保存了到中斷端點描述的列表指針,完成隊列的頭指針以及與SOF處理相關(guān)的狀態(tài)信息。
OHCI使用端點描述ED(EndpointDescriPtor)和傳輸描述TD(TransferDescriptor)來組織USB數(shù)據(jù)的傳輸,HC從ED列表獲取端點信息,并從ED的TD列表逐次獲取傳輸信息,以實現(xiàn)數(shù)據(jù)的傳輸。典型的鏈表結(jié)構(gòu)如圖2所示。
批量和控制ED列表的頭指針由HC操作寄存器管理。HCD初始化這些指針,使得HC能夠訪問它們,當(dāng)這些指針需要變更時,HC應(yīng)該停止HC對需更新指針的列表的處理,更新指針,并重新啟動HC。
圖2 典型的OHCI的ED鏈表
特別要注意,LPC2478規(guī)定了USB設(shè)備使用的RAM區(qū)域,即0x7FD00000—0x7FD03FFF共16KB。HCCA以及ED,TD等數(shù)據(jù)結(jié)構(gòu)定義的變量必須定義在這個區(qū)域,否則HC不能正常工作。
HCD主要構(gòu)建的數(shù)據(jù)結(jié)構(gòu)有端點描述符ED、傳輸描述符TD和主機控制器通信區(qū)域HCCA。
每個ED對應(yīng)一個USB設(shè)備端點,不同的設(shè)備端點擁有不同的ED。同種傳輸類型的ED組成一鏈表,OHCI有三種ED鏈表:控制傳輸數(shù)據(jù)鏈表,批量傳輸數(shù)據(jù)鏈表和周期性數(shù)據(jù)鏈表(中斷數(shù)據(jù)傳輸和同步傳輸同屬此類),HC通過相應(yīng)的操作寄存器訪問各個ED鏈表。程序中ED數(shù)據(jù)結(jié)構(gòu)定義如下:
TD用來指定每次發(fā)送給USB設(shè)備的數(shù)據(jù)所保存的位置或者接收USB設(shè)備發(fā)送給主機數(shù)據(jù)的保存位置。根據(jù)OHCI規(guī)范對TD的定義,定義TD的數(shù)據(jù)結(jié)構(gòu)。程序中TD的數(shù)據(jù)結(jié)構(gòu)定義如下:
HCCA是256字節(jié)的系統(tǒng)內(nèi)存結(jié)構(gòu),系統(tǒng)軟件通過這一結(jié)構(gòu)來向HC發(fā)送和從HC接收特定的控制和狀態(tài)信息。這一結(jié)構(gòu)在內(nèi)存中以256字節(jié)為單位來對齊綁定。系統(tǒng)必須為HC指定HcHCCA的值即HCCA結(jié)構(gòu)地址。通常系統(tǒng)與HC的交互能夠通過讀取HC寫入這一結(jié)構(gòu)的數(shù)值來完成。程序中HCCA結(jié)構(gòu)定義如下:
HCD向USB功能軟件提供以下幾個接口函數(shù),用來操作和控制主機控制器。
4.2.1 OHCI主機控制器初始化函數(shù)Host_Init(void)
USB 2.0規(guī)范要求USB外設(shè)的工作時鐘必須是48MHZ。LPC2478的外設(shè)功率控制寄存器(PCONP)決定外設(shè)的使能與否,最高位(32位)置1使能USB外設(shè),初始化OHCI控制器首先要將此位置1。同時,通過置OTG時鐘控制寄存器(OTGClkCtrl)的主機時鐘使能位,使能主機時鐘,至此OHCI可以正常工作了。
將LPC2478對應(yīng)功能的引腳配置為OHCI后,需要初始化一些常用的變量如控制ED,批量ED,HCCA區(qū)域,TD數(shù)組等,另外,為了便于數(shù)據(jù)傳輸,要定義一個數(shù)據(jù)緩沖區(qū)指針。注意這些變量必須定義到LPC2478所指定的USB RAM(0x7FD00000-0x7FD03FFF)中,要傳輸?shù)経SB設(shè)備的數(shù)據(jù)必須首先將數(shù)據(jù)保存到USB RAM中,然后啟動發(fā)送過程;接收到來自USB設(shè)備的數(shù)據(jù)也首先保存到USB RAM中,然后再將數(shù)據(jù)拷貝到所對應(yīng)的緩沖區(qū)中。
最后初始化OHCI寄存器。OHCI寄存器分為4類:控制與狀態(tài)類寄存器,存儲器指針類寄存器,幀計數(shù)器類寄存器和根集線器類寄存器。
控制與狀態(tài)類寄存器中,最主要是初始化與中斷有關(guān)的寄存器。與USB設(shè)備通信的中斷標(biāo)志位主要有兩個,分別是WDH位和RHSC位。每當(dāng)一個TD傳輸結(jié)束后,HC會將此TD的地址寫入Hc-DoneHead寄存器,HC然后將此寄存器的內(nèi)容寫入HCCA區(qū)域,此時就會產(chǎn)生WDH中斷,程序可以通過此中斷來標(biāo)識一次數(shù)據(jù)傳輸?shù)慕Y(jié)束;而每次USB設(shè)備插入主機或者從主機拔出的時候,都會初始化RHSC中斷,程序通過此標(biāo)志來枚舉USB設(shè)備或者處理USB設(shè)備拔出的善后工作。
存儲器指針類寄存器,主要用來初始化一些指針,比如控制ED的指針,批量ED的指針,HCCA區(qū)域的指針等。這些指針可以隨時修改。
幀計數(shù)器類寄存器,主要用來設(shè)置處理在一個幀的時間長短,HC處理周期ED和非周期ED的時間比率。通過設(shè)置 HcFmInterval寄存器的FrameInterval來決定HC處理一個幀的時間長短,注意此域的頻率是12MHZ,及1ms中的 bit時間是12000。默認(rèn)設(shè)置是11999,即一個USB幀的時間長度的1ms。另外HcPeriodicStart決定了在一個幀中處理非周期ED的長度。
根集線器寄存器主要用來標(biāo)識根集線器的狀態(tài),初始化一般按照默認(rèn)配置,在程序運行期間,通過讀取此對應(yīng)寄存器的各個位來得到端口的狀態(tài)。至此,OHCI的初始化結(jié)束。初始化流程如圖3所示。
圖3 OHCI控制器初始化過程
4.2.2 USB設(shè)備枚舉函數(shù)Host_EnumDev(void)
當(dāng)有USB設(shè)備插入到OHC的端口上的時候,程序調(diào)用此函數(shù)對USB設(shè)備進行枚舉過程。枚舉過程主要是根據(jù)USB規(guī)范所定義的枚舉過程進行的。通過枚舉,程序可以獲得USB設(shè)備的設(shè)備描述符,類描述符,配置描述符,端點描述符等,根據(jù)這些信息來初識化對應(yīng)的ED。本實現(xiàn)根據(jù)USB2.0規(guī)范實現(xiàn)了標(biāo)準(zhǔn)的枚舉過程。
4.2.3 TD傳輸函數(shù)Host_ProcessTD()
Host_ProcessTD()函數(shù)原型為Host_ProcessTD(HCED*ed,INT32U token,INT08U*buffer,INT32U buffer_len);此函數(shù)用來處理鏈接到端點描述符ED上的TD。根據(jù)參數(shù)ed的Control域,可以知道USB數(shù)據(jù)傳輸?shù)念愋?控制傳輸,批量傳輸,中斷傳輸和同步傳輸),然后根據(jù)參數(shù)token來決定每種數(shù)據(jù)傳輸類型所處的階段,這樣就可以把從起始地址為buffer、一共buffer_len個字節(jié)的數(shù)據(jù)發(fā)送到USB設(shè)備對應(yīng)的端點緩沖區(qū),或者從對應(yīng)的端點緩沖區(qū)接收buffer_len字節(jié)的數(shù)據(jù)到起始地址為buffer的緩沖區(qū)。連續(xù)調(diào)用該函數(shù)可以完成USB協(xié)議定義的標(biāo)準(zhǔn)傳輸類型。在此基礎(chǔ)上,就可以實現(xiàn)基于USB標(biāo)準(zhǔn)傳輸?shù)母鼜?fù)雜的協(xié)議。
通過Host_ProcessTD()函數(shù)就可以實現(xiàn)USB設(shè)備中常用的控制傳輸和批量傳輸。控制傳輸首先傳輸一個SETUP TD,然后根據(jù)需要傳輸兩個IN TD或者OUT TD。而批量傳輸,根據(jù)需要,在生成對應(yīng)的ED后,直接就可以傳輸IN TD或者OUT TD。以控制寫為例,流程圖如下:
圖4 控制寫流程
驅(qū)動程序?qū)崿F(xiàn)了標(biāo)準(zhǔn)的USB設(shè)備枚舉過程。通過測試枚舉過程中讀取到的USB設(shè)備描述符來驗證驅(qū)動程序的正確與否。嵌入式開發(fā)環(huán)境Keil uVision4配合仿真器J-LINK可以在仿真調(diào)試環(huán)境下查看全局和局部變量的值。驗證過程中選擇了一款金士頓的U盤作為USB設(shè)備。圖5為通過Keil uVision4在仿真狀態(tài)下讀取到的U盤設(shè)備描述符:
圖5 金士頓U盤的設(shè)備描述符
圖6為同一個U盤在Windows XP操作系統(tǒng)中枚舉成功后所讀取到的屬性。
可以看出,在圖5中,idVendor0和idVender1兩個字節(jié)組合起來代表了U盤的VID(Vender ID),由于是大端顯示,所以驅(qū)動程序顯示的VID實際為0x1043,同理idProduct0和idProduct1兩個字節(jié)組合起來代表了U盤的PID(Product ID),PID為0x8012。在圖6中,U盤的VID顯示是0x1043,PID顯示是0x8012。通過圖5和圖6,說明驅(qū)動程序設(shè)計是正確的。
圖6 金士頓U盤在PC機上的屬性
本文實現(xiàn)了一種適用于簡單嵌入式軟硬件平臺的OHCI主機驅(qū)動程序。在實際的實現(xiàn)過程中,首先初始化了OHCI主機控制器,根據(jù)具體的實際應(yīng)用,優(yōu)化了OHCI規(guī)范中規(guī)定的ED鏈表操作。并在此基礎(chǔ)上通過實驗,分別實現(xiàn)了控制傳輸,批量傳輸和中斷傳輸。另外程序還實現(xiàn)了對USB設(shè)備的標(biāo)準(zhǔn)枚舉過程,一旦USB設(shè)備枚舉成功,通過相應(yīng)的USB設(shè)備描述符,加載不同類型的驅(qū)動程序,為上層的應(yīng)用程序提供了穩(wěn)定可靠的接口函數(shù)。實驗證明,驅(qū)動程序的設(shè)計是正確實用的。
[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驅(qū)動的設(shè)計與實現(xiàn)[J].計算機應(yīng)用,2009,29(6):53-56.
[4] 陳明智,李鋒,尚淮.USB通信協(xié)議分析和系統(tǒng)設(shè)計[J].自動化與儀器儀表,2006(6):43-46.
[5] 張卓亮.基于Linux系統(tǒng)的USB HOST驅(qū)動程序設(shè)計與實現(xiàn)[J].中國集成電路,2007,16(11):30-33.
[6] 劉鋒,韓超,汪磊峰,等.基于linux的嵌入式USB主機控制器接口實現(xiàn)[J].微計算機信息,2010,26(42):75-77.