文獻標識碼: A
DOI:10.16157/j.issn.0258-7998.2017.07.014
中文引用格式: 胡唯唯,王宜懷,張永. 基于K64的USB驅(qū)動構(gòu)件化設計[J].電子技術(shù)應用,2017,43(7):55-58.
英文引用格式: Hu Weiwei,Wang Yihuai,Zhang Yong. The development of USB driver component based on K64[J].Application of Electronic Technique,2017,43(7):55-58.
0 引言
USB現(xiàn)已成為嵌入式設備的一種主要通信接口,但是由于USB協(xié)議的復雜性和硬件平臺的多樣性,使得USB驅(qū)動程序開發(fā)存在難度大、成本高、可移植差、難以維護等缺點。為了解決這些問題,本文在深入分析USB協(xié)議的基礎上,對USB設備的功能進行抽象,并采用驅(qū)動構(gòu)件化的設計思想開發(fā)USB驅(qū)動構(gòu)件[1]。同時,在Kinetis Design Studio 3.0集成開發(fā)環(huán)境下,使用恩智浦半導體公司的K64微控制器對該構(gòu)件進行測試,將其作為一個HID設備與上位機程序進行通信。上位機軟件在VS 2010環(huán)境下使用C#語言開發(fā),可以動態(tài)找到目標設備,實現(xiàn)快速連接和通信。另外,將該通信系統(tǒng)用于3D打印中,通過對打印產(chǎn)品的紋理進行分析,驗證本文所開發(fā)的USB構(gòu)件的穩(wěn)定性。
1 USB協(xié)議分析
USB驅(qū)動程序主要完成USB設備的初始化、枚舉和數(shù)據(jù)傳輸。USB主機與USB設備之間有4種數(shù)據(jù)傳輸類型,分別是批量傳輸、中斷傳輸、同步傳輸和控制傳輸,每種傳輸方式執(zhí)行一次需要多個事務處理[2]。對于控制傳輸,其只能用于USB設備枚舉,包括3個階段,分別為設置階段、數(shù)據(jù)階段和狀態(tài)階段。設置階段是一次SETUP事務處理,數(shù)據(jù)階段是多個IN或者OUT事務處理,狀態(tài)階段是一次無數(shù)據(jù)傳輸?shù)腎N或者OUT事務處理。USB設備枚舉完成后,將使用其他傳輸方式用于實際數(shù)據(jù)收發(fā),具體使用哪種方式則取決于設備的類型。USB設備連接到PC后,PC便開始對其進行枚舉[3]。不同操作系統(tǒng)下枚舉過程可能會有所不同,Windows操作系統(tǒng)下的USB設備枚舉過程為:
(1)用戶將USB設備插入到PC(USB主機)的USB端口上,USB主機給USB設備上電,USB設備獲取100 mA的電流,并處于上電狀態(tài);
(2)USB主機檢測USB設備是全速還是低速設備,如果D+數(shù)據(jù)線上有高電平則是全速設備,如果D-數(shù)據(jù)線上有高電平則是低速設備;
(3)USB主機復位USB設備,復位時間至少10 ms。復位結(jié)束后USB設備處于默認狀態(tài),并使用默認的地址0和端點0與USB主機進行通信;
(4)USB主機獲取USB設備的18 B的設備描述符,完成一次控制傳輸。這是USB主機第一次得到設備描述符,主機并不會分析各個字段的含義,只會得到設備描述符中端點0所支持的最大數(shù)據(jù)包長度(設備描述符的第8字節(jié));
(5)USB主機再一次復位USB設備,這一步在USB 2.0協(xié)議中并不要求。另外,對于高速設備,Windows 8及以上版本會跳過這一步;
(6)USB主機給USB設備分配一個唯一的地址,USB設備進入地址狀態(tài),之后USB設備將使用這個新的地址與USB主機進行通信。只要USB設備不被移除、復位或者重新啟動,那么這個地址將一直存在;
(7)USB主機獲取配置描述符,及其從屬的接口和端點描述符。如果還有字符串描述符,則繼續(xù)獲取。對于HID類設備,USB主機還會獲取報告描述符;
(8)獲取以上USB設備的相關(guān)信息后,USB主機會為USB設備分配并加載一個合適的設備驅(qū)動程序;
(9)USB主機對USB設備進行配置,USB設備進入配置狀態(tài)。對于HID類設備,則初始化一個上行傳輸IN端點和一個下行傳輸OUT端點,上行傳輸是USB設備向PC上傳數(shù)據(jù),下行傳輸是PC向USB設備發(fā)送數(shù)據(jù)[4]。
枚舉完成后,USB設備可以和USB主機進行數(shù)據(jù)傳輸。枚舉和枚舉完成后的數(shù)據(jù)傳輸過程中執(zhí)行一次事務處理就會產(chǎn)生一次中斷。USB中斷包括復位中斷、令牌中斷、STALL中斷和SOF中斷等,其中令牌中斷包括SETUP令牌中斷、IN令牌中斷和OUT令牌中斷。一次事務處理由令牌包、數(shù)據(jù)包和握手包組成,令牌包表明此次事務處理的目的,數(shù)據(jù)包中包含了要傳輸?shù)臄?shù)據(jù),握手包表明此次事務處理的完成狀態(tài)[5]。圖1是USB設備枚舉和數(shù)據(jù)收發(fā)的執(zhí)行流程圖。
2 USB驅(qū)動構(gòu)件設計
驅(qū)動構(gòu)件的設計應滿足可復用性、可移植性和可維護性,其中復用性是設計目標,是軟件成熟的標志。軟件的復用可以降低軟件開發(fā)的難度、減少重復勞動、降低開發(fā)成本、提高開發(fā)效率和軟件質(zhì)量、縮短軟件開發(fā)周期[6]。驅(qū)動構(gòu)件由.c源文件和.h頭文件組成。源文件是構(gòu)件的功能函數(shù)實現(xiàn),函數(shù)分為對外接口函數(shù)和內(nèi)部函數(shù),對外接口函數(shù)供外部調(diào)用,內(nèi)部函數(shù)僅內(nèi)部調(diào)用;頭文件是構(gòu)件的功能描述,其中包含了對外接口函數(shù)聲明、相關(guān)宏定義和類型定義等。在實際使用時,構(gòu)件應滿足兩點:無需打開源文件,只要通過讀頭文件就知道如何使用;在不同芯片上使用時,只需要做少量修改或者無需修改。
K64要作為USB設備使用,必須初始化USB模塊。上電后需要完成設備枚舉,設備枚舉過程需要做很多處理,但是所有USB設備的枚舉過程基本上是一樣的,因此設備枚舉可以作為一個函數(shù)進行集中處理。USB總線是輪詢式的,所有的通信都是由USB主機發(fā)起的,因此設備不能主動向USB主機發(fā)送數(shù)據(jù),只能將要發(fā)給USB主機的數(shù)據(jù)準備好等待USB主機來取。為了方便向USB主機發(fā)送數(shù)據(jù),在構(gòu)件中封裝一個發(fā)送數(shù)據(jù)函數(shù)。如果有數(shù)據(jù)要發(fā)送給USB主機,則調(diào)用該函數(shù)將要發(fā)送的數(shù)據(jù)填入指定的緩沖區(qū)內(nèi)即可,在下一次事務處理中由USB主機取出,使得USB設備可以“主動”發(fā)送數(shù)據(jù)?;谝陨戏治觯?USB驅(qū)動構(gòu)件將封裝4個函數(shù),分別是初始化函數(shù)usb_init、枚舉處理函數(shù)usb_enumerate、發(fā)送數(shù)據(jù)函數(shù)usb_send和接收數(shù)據(jù)函數(shù)usb_recv。
2.1 usb_init函數(shù)
初始化函數(shù)usb_init完成對USB模塊的初始化,主要包括內(nèi)存分配、時鐘源使能和使能USB中斷等。每一個USB設備都有一個序列號,同VID和PID一起作為設備的標識符,當兩個VID和PID都一樣的USB設備插入到PC時,序列號可以起到進一步區(qū)分的作用。序列號實際上是一個字符串描述符,考慮其用于唯一性標識USB設備的作用,將其作為USB設備的名稱,并傳入初始化函數(shù)中,這樣開發(fā)者就能夠方便命名自己的USB設備。
2.2 usb_enumerate函數(shù)
枚舉處理函數(shù)usb_enumerate完成枚舉過程中的控制傳輸,該函數(shù)一般情況下無需改動。本驅(qū)動構(gòu)件是針對HID設備的,如果要開發(fā)為其他類型的設備,在修改描述符后,只需要對該函數(shù)做少量修改即可。以MSD設備為例,將HID設備的描述符文件usb_hid_device_descriptor.c替換為MSD設備的描述符文件usb_msd_device_descriptor.c。比較這兩個描述符文件,發(fā)現(xiàn)前者比后者多一個報告描述符,同時字符串描述符也不同。為了盡量減少對usb_enumerate函數(shù)代碼的修改,可以將MSD設備的設備描述符、配置描述符及其從屬的接口和端點描述符的名稱根據(jù)HID設備作對應修改。這樣,只需要刪除usb_enumerate函數(shù)中對報告描述符的處理即可。
2.3 usb_send和usb_recv函數(shù)
發(fā)送數(shù)據(jù)函數(shù)usb_send和接收數(shù)據(jù)函數(shù)usb_recv用于數(shù)據(jù)的收發(fā)。為了方便數(shù)據(jù)的收發(fā),這兩個函數(shù)都有兩個參數(shù)。usb_send函數(shù)的兩個參數(shù)為SendBuff和DataLenght,usb_recv函數(shù)的兩個參數(shù)為RecvBuff和DataLength。進行數(shù)據(jù)發(fā)送時,只要將待發(fā)送數(shù)據(jù)的緩沖區(qū)地址和發(fā)送的數(shù)據(jù)長度傳入發(fā)送數(shù)據(jù)函數(shù)usb_send的SendBuff和DataLength即可,下一次事務處理結(jié)束后,相應緩沖區(qū)中的數(shù)據(jù)就會被發(fā)送出去。接收數(shù)據(jù)和發(fā)送數(shù)據(jù)的執(zhí)行是一樣的,只是接收的數(shù)據(jù)已經(jīng)在本次事務處理中,只要使用usb_recv函數(shù)從相應端點的BD中取出即可,RecvBuff用于存放取出的數(shù)據(jù),DataLength是取出的數(shù)據(jù)長度。
3 上位機軟件設計
上位機軟件使用Windows提供的API函數(shù)對HID設備進行訪問,這些API函數(shù)包含在hid.dll、setupapi.dll、kernel32.dll文件中,分別起到與HID設備通信、尋找與識別設備、交換數(shù)據(jù)的作用[7],關(guān)于相關(guān)API函數(shù)的介紹可以查看MSDN。
PC與USB設備建立連接的第一步就是找到該設備,上位機軟件必須時刻能夠檢測到USB設備的插入和移除事件,因此必須在相關(guān)窗體句柄創(chuàng)建時將這些事件通過RegisterDeviceNotification函數(shù)進行注冊,該函數(shù)位于user32.dll文件中。
當檢測到一個新的USB設備插入或者被移除時,Windows將向應用程序發(fā)送一個WM_DEVICECHANGE消息,該消息宏定義為0x0219。然后由默認的消息處理函數(shù)WndProc進行處理,程序中對WndProc進行了重寫,以滿足尋找目標設備的要求[8]。WndProc函數(shù)首先獲取USB總線上指定類型的設備列表,通過調(diào)用setupapi.dll文件中函數(shù)SetupDiGetClassDevs實現(xiàn)。SetupDiGetClassDevs函數(shù)的第一個參數(shù)是HID GUID,GUID是設備類型的唯一標識符,HID類設備的GUID可以通過hid.dll文件中的HidD_GetHidGuid函數(shù)獲取,為固定值4d1e55b2-f16f-11cf-88cb-001111000030。該函數(shù)的返回值是當前USB總線上所有HID類設備的信息,并保存于InfoSet隊列中。為了從InfoSet隊列中找到目標設備,需要調(diào)用setupapi.dll 文件中的SetupDiEnumDeviceInterfaces函數(shù)遍歷InfoSet隊列,并將每個設備的信息保存于DeviceInterfaceData 結(jié)構(gòu)體變量oInterface中。接著,從oInterface中獲取該設備的VID和PID,然后和目標設備的VID和PID進行匹配檢查,以確定該設備是否為目標設備[9]。如果匹配則找到了目標設備,否則繼續(xù)調(diào)用SetupDiEnumDeviceInterfaces函數(shù),獲取下一個設備的信息并繼續(xù)進行匹配檢查,直到找到目標設備或者InfoSet隊列中的設備都查找完畢為止。
如果沒有找到目標設備,則回收InfoSet占用的內(nèi)存。如果目標設備找到,則使用該設備路徑作為參數(shù)并調(diào)用CreateFile函數(shù)打開該設備,之后就可以像讀寫文件一樣操作該設備。圖2是上位機軟件尋找USB設備和執(zhí)行數(shù)據(jù)傳輸?shù)牧鞒虉D。
4 構(gòu)件測試與分析
圖3為數(shù)據(jù)和局部波形圖,圖3(a)是獲取設備描述符時使用TravelBus協(xié)議分析儀采集的數(shù)據(jù),圖3(b)是對應的局部波形。枚舉過程中USB主機首先獲取USB設備的設備描述符。USB主機向USB設備發(fā)送一個SETUP令牌包,然后是DATA0數(shù)據(jù)包,該數(shù)據(jù)包中包含了8個字節(jié)的十六進制數(shù)據(jù)80 06 00 01 00 00 40 00,該8個字節(jié)的數(shù)據(jù)是獲取設備描述符的標準設備請求。USB設備接收到該請求后開始處理并向USB主機返回一個ACK握手包,表明此次SETUP事務處理是成功的,從而完成控制傳輸?shù)脑O置階段。隨后USB主機發(fā)送IN令牌包開始取設備描述符,但是USB設備此時并沒有將設備描述符準備好,因此USB設備直接向USB主機發(fā)送一個NACK不確認包。
USB主機繼續(xù)發(fā)送獲取設備描述符的IN令牌包,USB設備返回準備好的18個字節(jié)的設備描述符12 01 00 02 00 00 00 40 A2 15 7F 00 01 01 01 02 00 01,其中PID是0x15A2(第9和第10字節(jié)),VID是0x007F(第11和第12字節(jié))。之后,USB主機向USB設備發(fā)送一個ACK確認包,完成控制傳輸?shù)臄?shù)據(jù)階段。最后,USB主機發(fā)送一個OUT令牌包,再發(fā)送一個無數(shù)據(jù)的DATA1數(shù)據(jù)包,USB設備接收到之后返回一個ACK握手包,從而完成此次控制傳輸?shù)臓顟B(tài)階段[10]。設備枚舉成功后,PC將USB設備掛載到設備列表中。
5 應用
目前使用DLP技術(shù)的3D打印機需要與PC進行通信,通信的實時性和穩(wěn)定性至關(guān)重要。將該USB通信系統(tǒng)應用于3D打印中,可以提高打印的穩(wěn)定性和實時性。打印過程中數(shù)據(jù)丟包率低、實時性高,使得所打印的產(chǎn)品紋理的連續(xù)性高(無斷層)、效果逼真。打印成品與局部紋理放大20 000倍效果如圖4所示。
6 結(jié)論
本文在深入分析USB協(xié)議的基礎上,按照構(gòu)件化設計思想編寫USB驅(qū)動構(gòu)件,同時以恩智浦半導體公司的K64作為測試對象,并編寫上位機軟件,實現(xiàn)與PC之間的USB通信。另外,將該USB通信系統(tǒng)用于實際項目3D打印中,打印的產(chǎn)品滿足要求。本文所設計的USB驅(qū)動構(gòu)件封裝簡單合理、設備枚舉清晰、代碼移植性高、通信穩(wěn)定高效,可以作為驅(qū)動程序的開發(fā)模板,同時對USB驅(qū)動程序開發(fā)的規(guī)范性和可移植性具有很高的參考意義。
參考文獻
[1] 龍飛,何欽銘.構(gòu)件化開發(fā)方法在J2EE 項目中的應用[J].計算機工程與設計,2007,28(3):591-594.
[2] 黃櫻,劉君,劉卉,等.基于ARM的嵌入式USB主機系統(tǒng)設計[J].微計算機信息(嵌入式與SOC),2007,22(2):156-157.
[3] ZHU J,WANG S,ZHANG S Y,et al.Embedded diver system for USB mouse[C].International Conference on Electrical & Control Engineering,2011:180-183.
[4] 侯代文,孫濤,鄧磊明.TMS320VC33與主機通信的USB接口設計[J].電子設計工程,2015,23(7):166-170.
[5] 王宜懷,吳璟,蔣銀珍.嵌入式系統(tǒng)原理與實踐—ARM Cortex-M4 Kinetis微控制器[M].北京:電子工業(yè)出版社,2012.
[6] 呂明琪,薛錦云,胡啟敏.基于軟件體系結(jié)構(gòu)的可復用構(gòu)件模型[J].計算機應用研究,2008,25(1):120-122.
[7] 楊晶晶,江春華.USB HID設備驅(qū)動程序設計[J].微計算機信息(嵌入式與SOC),2006,22(6):140-142.
[8] 郭夏夏.動平衡測試系統(tǒng)的關(guān)鍵技術(shù)研究[D].上海:上海交通大學,2014.
[9] WATANABE H,MASAOKA H,OHIGASHI T,et al.Supporting USB devices for the global migration[J].IPSJ International Symposium on Applications & the Internet,2010:153-156.
[10] DONG Z Y,ZHAO H.Data transfer principles and implementation in USB microwave power sensor[C].Seventh International Symposium on Computational Intelligence & Design,2014:76-79.
作者信息:
胡唯唯1,王宜懷1,張 永2
(1.蘇州大學 計算機科學與技術(shù)學院,江蘇 蘇州215006;2.蘇州華祥信息科技有限公司,江蘇 蘇州215006)