本應(yīng)用筆記是應(yīng)用筆記3997,"建立Maxim USB庫"。 可下載包含Maxim演示程序的Keil?項目。
緒論
Maxim USB庫是兩塊電路板和C語言程序的組合。利用這個系統(tǒng),可以:- 研究、操作、測試和修改基于ARM7微控制器(μC)與MAX3420E USB外設(shè)控制器連接的USB功能設(shè)備。
- 研究、操作、測試和修改基于ARM7微控制器(μC)與MAX3421E USB主機控制器連接的USB功能主機。圖1顯示了主機從USB存儲棒中的數(shù)據(jù)檢索。
- 使用USB電纜將主機連接至外設(shè),并同時運行主機和外設(shè)。開發(fā)USB主機或USB外設(shè)代碼時,USB電纜的另一端有一個參考設(shè)計是非常有用的。這樣,USB電纜的兩端,主機和外設(shè)因為都是執(zhí)行相同的C語言代碼,從而具有可控性和定制性。
圖1. MAX3421主機/ARM從任意的USB外設(shè)重新得到枚舉數(shù)據(jù),并通過串口連接至運行有終端仿真程序的PC來報告結(jié)果。
其它資料
編程指南、數(shù)據(jù)資料和Maxim網(wǎng)站提供的MAX3420E和MAX3421E應(yīng)用筆記:MAX3420E
MAX3421E
Maxim應(yīng)用筆記AN3937,"建立Maxim USB庫"
硬件
本應(yīng)用C語言代碼運行在兩板裝置上:- MAX3421評估(EV)板,第一塊電路板
- Keil MCB2130板,第二塊電路板
圖2. Maxim評估板插進Keil MCB2130板。
圖2展示了板級設(shè)備。藍色電路板是Keil MCB2130,其中包含一塊ARM7芯片,Philips? LPC2138。這個微控制器包含2個SPI?硬件單元,連接至兩塊Maxim USB控制芯片。
豎立的電路板是MAX3421EEVKIT-1。一個MAX3420E外設(shè)控制器連接至ARM的一個SPI端口,并布線連接至USB的“B”連接器(J5),在圖2中用“3420 P”標記(P代表外設(shè))。MAX3421E主機/外設(shè)控制器連接至ARM的另外一個SPI端口,并布線連接至“3421P” (J2)和“3421H” (J1)連接器(H代表主機)。應(yīng)用中運行的代碼將MAX3421E作為主機使用,因此評估套間電路板中部的USB連接器(J2)沒有使用。
主機軟件使用兩個串口中的一個(MCB2130電路板上的P1)將USB說明信息發(fā)送到運行終端仿真程序的PC。終端程序,如Tera終端程序,可以仿真終端(VT100),識別由程序發(fā)送的專用“轉(zhuǎn)移碼”序列以實現(xiàn)清屏和指針復(fù)位。終端程序的串口設(shè)置為38400、N、8、1,無流量控制。
圖2中的米色方盒和帶狀電纜是Keil ULINK JTAG裝載-調(diào)試器。Keil μVision?3開發(fā)環(huán)境支持該調(diào)試單元。MCB2130附帶一個評估版μVision3,具有完整功能版本的Keil工具集。但評估版在代碼容量上有16kB的限制。
本應(yīng)用筆記的附件包含整個Keil工程的源文件,另還有hex格式的裝載模塊。如有ULINK JTAG單元,可編譯該代碼,并可通過JTAG端口進行加載和調(diào)試。這對于快速開發(fā)USB、修改工作主機和/或外設(shè)代碼使其適合開發(fā)目的是一條極好的途徑。如果沒有ULINK,可使用稱為Flash Magic的免費程序加載、運行hex文件,這個程序可從網(wǎng)站www.esacademy.com獲得。參考Maxim應(yīng)用筆記3937可獲得如何配置和使用該程序的信息。
圖3. MAX3421EEVKIT-1電路板框圖。帶陰影的橢圓形是主要軟件模塊。
程序功能
圖3顯示了MAX3421EEVKIT-1電路框圖和本應(yīng)用筆記的軟件模塊。MAX3420E和MAX3421E都使用SPI總線訪問其寄存器組。LPC2138含有2個硬件SPI單元:- 一個專用SPI端口(SPI)
- 一個通用串行接口(SSP,同步串行端口)
MAX3420E屬于SPI單元,所以對這塊芯片來說函數(shù)有一個“P” (例如Prreg和Preg)前綴,表明外設(shè)操作。MAX3421E屬于SSP單元,所以其訪問函數(shù)有一個“H”前綴(例如Hwreg),表明為主機操作。
外設(shè)程序
C模塊3420_HIDKB.C實現(xiàn)一個通過使用評估電路的連接器J5連接至PC機的USB外設(shè)。MAX3420E的INT輸出引腳連接至ARM7的EINT0 (外部中斷0)引腳。這個中斷可在由MAX3420E實現(xiàn)的USB外設(shè)需要服務(wù)時隨時觸發(fā)。本應(yīng)用列舉和實現(xiàn)了標準的USD HID (人性化接口設(shè)備)。符合標準Windows?平臺的一大優(yōu)勢是設(shè)備驅(qū)動內(nèi)置在Windows中,從而不需要安裝專用的驅(qū)動。Windows將由本應(yīng)用實現(xiàn)的設(shè)備識別為一個標準鍵盤。按任意的連接至MAX3420E GP-IN引腳的四個按鈕,將使“鍵盤”在任意打開的接收文本窗中輸入文本字符串,如記事本和寫字板。
注意:本應(yīng)用可在任何可接收文本應(yīng)用中輸入文本,如電子郵件、匯編編輯器、或Word文檔。在按鍵之前請確認有一個安全的應(yīng)用,如記事本被打開,并處于有效狀態(tài)。作者根據(jù)經(jīng)驗可以確定:在一個打開的C源文件中輸入無效文本將不能進行完全編譯。
主機代碼
3241_Host_EVK.C文件包含主機代碼,其使MAX3421E完成一定的枚舉步驟,該枚舉步驟與有USB設(shè)備插入連接器J4時PC所執(zhí)行的枚舉步驟相似。這個模塊中的main()函數(shù)就像HID鍵盤代碼的中斷服務(wù)程序。EINT0中斷服務(wù)程序簡單如下:// EINT0 Interrupt handler--MAX3420E INT pin void INT3420 (void) __irq { service_irqs(); // Do the USB thing in 3420_HIDKB_INT_EVK.C module EXTINT = 1; // Clear EINT0 interrupt flag (b0) VICVectAddr = 0; // Dummy write to indicate end of interrupt service }基礎(chǔ)程序main( )包含以下無限循環(huán)子程序:
while(1) { detect_device(); waitframes(200); // Some devices require this enumerate_device(); wait_for_disconnect(); }Enumerate_device()函數(shù)完成絕大部分的工作,向連接設(shè)備發(fā)送USB請求,并通過串口報告結(jié)果。任意的USB設(shè)備插入評估板的連接器J1,這個函數(shù)將向設(shè)備發(fā)送枚舉請求,并通過串口報告結(jié)果(圖1)。
同步主機/外設(shè)操作
因為MAX3421EEVKIT-1電路板包含一個USB外設(shè)和一個USB主機,且它們使用ARM7上單獨的SPI接口,所以軟件將可以很容易的編寫,使主機和外設(shè)應(yīng)用同時的運行。主機應(yīng)用運行main()在后臺與MAX3421E對話,而HID外設(shè)代碼使用MAX3420E中斷激活service_irqs()函數(shù)。如果用USB電纜連接評估板的連接器J5和J1,ARM處理器可作為USB主機與外設(shè)對話,而這個外設(shè)就是其自身。圖4顯示了3421_Host.C的主機代碼詢問由3420_HIDKB.C實現(xiàn)外設(shè)的報告。
圖4. 通過USB詢問自身的代碼演示
主機代碼開發(fā)
通讀enumerate_device()函數(shù)有助于理解USB主機是如何工作的,也有助于理解如何命令MAX3421E完成枚舉USB設(shè)備時的各種主機操作。而開發(fā)主機代碼,如果對外設(shè)插入主機的響應(yīng)過程不清楚,有時將很難診斷問題。如果在全部的控制中(3420_HIDKB.C模塊)擁有參考外設(shè),將使問題很容易發(fā)現(xiàn),并可改變設(shè)備的響應(yīng)以測試主機紉件。外設(shè)代碼開發(fā)
主機是用于開發(fā)USB外設(shè)代碼的優(yōu)秀詢問工具。MAX3421E和3421_Host.C模塊的結(jié)合,產(chǎn)生一個簡單但功能強大的USB信息包生成器和分析器。通過編寫C語言主機代碼,可以控制外設(shè)狀態(tài);MAX3421E顯示外設(shè)的響應(yīng)過程。實例
假設(shè)編寫外設(shè)代碼以處理USB字符串。在hidkb_enum_tables.h文件中按如下方式編寫生產(chǎn)商字符串XYZ Widget Company:// STRING descriptor 1--Manufacturer ID { 18, // bLength 0x03, // bDescriptorType = string 'X','Y','Z',' ','W','i','d','g','e','t',' ','C','o','m','p','a','n','y' },編譯該文件,將其裝入ARM的flash存儲器,并運行。主機程序?qū)蟾嫒缦律a(chǎn)商字符串:
圖5. 不良結(jié)果,例程沒有按照要求顯示生產(chǎn)商名字,代碼有問題。
出現(xiàn)了什么問題?原來,USB規(guī)定文本字符串用Unicode表示,即每個字符用兩個字節(jié)表示?;仡櫷庠O(shè)的源代碼,更改如下:
// STRING descriptor 1--Manufacturer ID { 35 // bLength 0x03, // bDescriptorType = string 'X',0,'Y',0,'Z',0,' ',0,'W',0,'i',0,'d',0,'g',0,'e',0,'t',0, ' ',0,'C',0,'o',0,'m',0,'p',0,'a',0,'n',0,'y' // Unicode! },編譯、運行,應(yīng)該可以看到:
圖6. 正常的代碼例程,使用Unicode格式,可看到結(jié)果。
該結(jié)果有所改善,但并不完美。Company中的“y”到哪去了?仔細計數(shù)該字符串有35個字符,并將其作為第一個字節(jié)輸入以顯示字符串長度。設(shè)計沒有注意的是:長度字節(jié)也是字符串,必須包含前兩個字節(jié)。代碼最終的修改如下:
// STRING descriptor 1--Manufacturer ID { 37 // bLength 0x03, // bDescriptorType = string 'X',0,'Y',0,'Z',0,' ',0,'W',0,'i',0,'d',0,'g',0,'e',0,'t',0, ' ',0,'C',0,'o',0,'m',0,'p',0,'a',0,'n',0,'y' // Unicode! },這是結(jié)果應(yīng)為如下所示:
圖7. 最佳的代碼實例。代碼現(xiàn)在可實現(xiàn)設(shè)計想要實現(xiàn)的功能。
通過測試外設(shè)代碼和使用主機控制器及編碼運行/分析,由于報告的結(jié)果是由MAX3420E發(fā)送至MAX3421E的實際USB報文,從而可以看到與PC機響應(yīng)完全相同的結(jié)果。最好的是,這些都可在一個可控的基礎(chǔ)上實現(xiàn),因而不必擔心PC機的如何響應(yīng)而使代碼開發(fā)出現(xiàn)錯誤。
代碼說明
圖8. Keil工程的結(jié)構(gòu)
圖8顯示了三個主要模塊,并展開顯示了它們的文件依靠。沒有展開的模塊是Keli開發(fā)環(huán)境所需要的內(nèi)部處理文件。
SPI_FNs.C
這個模塊包含由其它兩個模塊調(diào)用的公用函數(shù)。void init_PLL(void)
此函數(shù)設(shè)定LPC2138的PLL和時鐘除法器。附著于LPC2138 (FOSC)的晶體為12.000MHz。根據(jù)公式CCLK = FOSC × M,設(shè)定CPU頻率為48MHz,其中M = 4。LPC2138使用內(nèi)部CCO (電流控制振蕩器)倍頻FOSC以獲得更高的內(nèi)部頻率。FCCO = CCLK × 2 × P。FCCO必須處于156MHz和320MHz之間。對于P = 2,F(xiàn)CCO = 48MHz × 2 × 2 = 192MHz。注意:Keil文件startup.s也包含設(shè)置PLL參數(shù)的啟動代碼。init_PLL()函數(shù)將有效的取代這些設(shè)置。
重要警告:修改這些設(shè)定會有一定的風險。錯誤的設(shè)定能迫使LPC2138超出其規(guī)定的限度,從而使Keil調(diào)試器停止作用。如果這種情況發(fā)生,補救方法是使用Flash Magic公用軟件擦除LPC2138的flash存儲器(使用第二個串口,連接至Keil電路板的P2),修改代碼中的PLL設(shè)定,然后再試驗。
init_IO
這個函數(shù)初始化LPC2138的I/O引腳和SPI單元(SPI和SSP):- SPI由CCLK/8時鐘控制,允許最大值。SCLK為48MHz/8 = 6MHz。
- SSP由CCLK/(2 x VBDIV)時鐘控制。VBDIV設(shè)置為1,使MAX3421E的SCK信號為48MHz/2 = 24MHz。MAX3421E的SCK輸入最高可運行至26MHz。
SPI接口使用如下信號:
- MOSI 主機輸出數(shù)據(jù),從機輸入數(shù)據(jù)
- MISO 主機輸入數(shù)據(jù),從機輸出數(shù)據(jù)
- SCLK 串口時鐘,由LPC2138提供
- SS# 從機選擇,由LPC2138驅(qū)動
關(guān)于SSP接口
雖然SSP有一個硬件SS#引腳,但使用GP-OUT引腳作SS# (P0.20)更簡單。
Hwreg
Hwritebytes
這些函數(shù)使用LPC2138的SSP硬件向MAX3421E寫入寄存器和FIFO數(shù)據(jù)。H前綴表示主機操作。Hwreg寫入一個信號寄存器值;Hwritebites向MAX3421E的FIFO寫入多個字節(jié)。
Hrreg
Hreadbytes
這些函數(shù)使用LPC2138的SSP硬件從MAX3421E中讀出寄存器和FIFO數(shù)據(jù)。
SSP接口
SSP硬件需要譯碼,從而在發(fā)送和接收通道上需要數(shù)據(jù)FIFO。在一個SPI操作中,每8位數(shù)據(jù)移出總是伴隨著8位數(shù)據(jù)移入。LPC2138使用如下步驟訪問MAX3421E的SPI接口:
- 觸發(fā)SS# (低)
- 發(fā)送由登記號和方向位構(gòu)成的命令字節(jié)
- 發(fā)送/接收一個或多個數(shù)據(jù)字節(jié)
- 釋放SS# (高)
Pwreg
PwregAS
Pwritebytes
這些函數(shù)使用LPC2138的SPI硬件向MAX3420E寫入寄存器和FIFO數(shù)據(jù)。第二個函數(shù)與第一個函數(shù)一樣寫入寄存器值,但其還設(shè)置SPI命令字節(jié)中的ACKSTAT位。這是停止USB控制轉(zhuǎn)移的捷徑。細節(jié)請參考應(yīng)用筆記3598,"MAX3420E編程指南"。
Prreg
PrregAS
Preadbytes
這些函數(shù)使用LPC2138的SPI硬件從MAX3420E中讀出寄存器和FIFO數(shù)據(jù)。第二個函數(shù)與第一個函數(shù)一樣讀出寄存器值,但還設(shè)置SPI命令中的ACKSTAT位。
readout
readout這個函數(shù)更新連接至MAX3421E通用輸出引腳GPO[6:0]的7段信息顯示,函數(shù)保留GPO[7]的設(shè)置,GPO[7]控制USB “A”連接器(評估板的J1)的VBUS開關(guān)。3421_Host.C
這個模塊實現(xiàn)MAX3421E USB主機,該主機訪問USB設(shè)備并通過MCB22310的串口報告枚舉數(shù)據(jù)。作為參考,附錄A給出了主機枚舉由3420_HIDKB.C實現(xiàn)的內(nèi)置設(shè)備的LeCroy (CATC)總線過程。這個模塊中有三種函數(shù)類型:
- 初始化函數(shù)
- 公用函數(shù)
- main()中調(diào)用的高級函數(shù)
Reset_Host
MAX3421E包含上電復(fù)位,因此這個操作并不是必須的。盡管如此,程序開發(fā)階段使用該字段,不需要重復(fù)上電即可初始化調(diào)試過程,是復(fù)位功能的很好方式。啟動該函數(shù)使器件清零,不會帶有以前的調(diào)試信息。復(fù)位MAX3421E使片上振蕩器停止工作。解除復(fù)位后,這個函數(shù)在返回之前將等待OSCOKIRQ位(振蕩器正常中斷請求)變?yōu)橛行А?br>
initialize_3420
這個函數(shù)在3420_HIDKB.C模塊中。initialize_ARM_Interrupts
這個函數(shù)建立ARM向量中斷如下:- EINT0連接至MAX3420E的INT引腳,使用優(yōu)先級0 (最高)。
- Timer0用于功能發(fā)光體閃爍,使用優(yōu)先級1。
- EINT2連接至MAX3421E的INT引腳,指定優(yōu)先級為2,在這個程序中沒有使用到該中斷。當然,這個中斷是為了方便才提供的。
- Timer1用于檢測發(fā)送/停止按鈕(在3420_HIDKB.C中使用),使用優(yōu)先級3。
service_irqs
該函數(shù)在3420_HIDKB.C模塊中。它進行HID鍵盤仿真。初始化ARM中斷的代碼僅需將該地址置為一個中斷向量。waitframes
用于USB主機測量時間的一個簡單方法是計算1ms幀標志的個數(shù)。當微控制器設(shè)定寄存器位SOFKANAB = 1時,MAX3421E自動產(chǎn)生這些由全速模式的SOF數(shù)據(jù)包或低速模式的“保持激活”脈沖組成的幀標志,隨后FRAMIRQ位每毫秒觸發(fā)一次。USB 規(guī)定要求確定的長延遲時間,例如復(fù)位一個設(shè)備后給它一個“復(fù)位恢復(fù)時間”。調(diào)用waitframes函數(shù)將是實現(xiàn)相對長的延遲時間的一個簡便方法。
detect_device
這個函數(shù)在檢測到一個USB設(shè)備插入USB-A連接器J1后返回。wait_for_disconnect
該函數(shù)在檢測到一個插入USB-A連接器的設(shè)備斷開后返回。Send_Packet
所有發(fā)送USB數(shù)據(jù)包的函數(shù)都調(diào)用這個函數(shù)。圖9顯示了IN事務(wù)處理的總線過程和實現(xiàn)它的C程序。圖9. 啟動USB總線動作,由MAX3421E調(diào)用C程序函數(shù)
- 微控制器在FNADDR寄存器中設(shè)定函數(shù)地址。因為在微控制器重新載入FNADDR寄存器之前,裝載值一直保持不變,所以每個數(shù)據(jù)包不需重復(fù)這個步驟。
- 微控制器通過寫入HXFR寄存器開始傳輸數(shù)據(jù),指明USB令牌和終端。然后等待HXFRDNIRQ (主機傳輸完成)觸發(fā)IRQ,發(fā)送信號完成。
- 微控制器讀HRSL (主機計算結(jié)果)寄存器來決定事務(wù)處理的結(jié)果。16個計算結(jié)果代碼表示下列結(jié)果:
A.成功(ACK)
B.設(shè)備占用(NAK)
C.非正常握手(STALL)
D.設(shè)備故障,如超時、串音或總線錯誤 - 微控制器讀計數(shù)寄存器字節(jié),然后卸載RCVFIFO并將數(shù)據(jù)存入一個字節(jié)數(shù)組中。
這個函數(shù)處理NAK重試,連續(xù)重新啟動數(shù)據(jù)傳輸直到:
- 收到ACK握手,或
- 超過常數(shù)NAK_LIMIT設(shè)定的預(yù)設(shè)限制
CTL_Write_ND
這個函數(shù)以無數(shù)據(jù)模式執(zhí)行控制-寫操作(_ND = no data)。這個函數(shù)僅在主機Set_Address請求時調(diào)用。它可以實現(xiàn)Sent_Packet的兩個調(diào)用:第一個用于SETUP數(shù)據(jù)包,第二用于IN-Handshake數(shù)據(jù)包。IN_Transfer
這個函數(shù)盡可能多地調(diào)用Send_Packet (指定的IN),以重新獲得USB的數(shù)據(jù)記錄。MAX3420E和MAX3421E終端FIFOS為64字節(jié)長,如此長的字符描述,舉例來說,需要多個IN請求數(shù)據(jù)包組成一個大數(shù)組(XfrData[2000])。CTL_Read
這個函數(shù)處理3態(tài)CONTROL-Read USB事務(wù),調(diào)用三個函數(shù):- 調(diào)用Send_Packet發(fā)送SETUP數(shù)據(jù)包
- 調(diào)用IN_Transfer使數(shù)據(jù)進入XfrDaTa[]中
- 調(diào)用Send_Packet發(fā)送OUT-Handshake數(shù)據(jù)包
enumerate_device
這個函數(shù)執(zhí)行附錄A所示的10個數(shù)據(jù)傳輸。因為它調(diào)用以前的函數(shù)來實現(xiàn)低級USB操作,所以通過研究這個函數(shù)可很容易理解枚舉步驟。print_error
這個函數(shù)檢查4位HRSL值(圖9中的第3項)以打印輸出主機的傳輸結(jié)果。如果通過數(shù)據(jù)為0,不打印輸出。這個函數(shù)返回HRSL值,因此調(diào)用這個函數(shù)可以很容易地檢測錯誤,例如:if(print_error(HR)) return;
3420_HIDKB.C
這個模塊使用MAX3420E實現(xiàn)一個USB外設(shè),符合標準HID類,可以象標準鍵盤輸入一樣自動輸入文本。入口點是service_irqs函數(shù),該函數(shù)在響應(yīng)LPC2138的EINT1引腳時作為中斷服務(wù)程序調(diào)用。ENT1引腳連接至MAX3420E的INT輸出引腳。Reset_Peripheral
這個函數(shù)以與Reset_Host相同的方式復(fù)位MAX3420E。initialize_3420
這個函數(shù)完成三件事:- 配置MAX3420E SPI接口以實現(xiàn)全雙工操作(分離MOSI和MISO引腳)
- 配置MAX3420E INT引腳為上升沿有效
- 通過應(yīng)用程序使能MAX3420E中斷
service_irqs
這個函數(shù)直接處理總線復(fù)位和設(shè)備斷開。這個函數(shù)也調(diào)用do_SETUPC處理枚舉和do_IN3處理鍵盤輸入。注意:為精簡代碼,本應(yīng)用不處理USB的掛起-恢復(fù)任務(wù)。實現(xiàn)該功能的例子可參考Maxim應(yīng)用筆記3690,"MAX3420E的USB杖舉程序(及其他)"。AN3690中的枚舉代碼作為3420_HIDKB.C的基礎(chǔ)。
do_SETUP
這個函數(shù)通過檢查8字節(jié)SETUP數(shù)據(jù)包中的各個字節(jié)處理設(shè)備枚舉,然后調(diào)用函數(shù)以處理特定的請求。代碼僅處理USB標準請求類,因為本應(yīng)用程序中沒有實現(xiàn)USB分類或客戶請求。do_IN3
這個函數(shù)根據(jù)HIDKB_enum_tables.h中的Message[]字符數(shù)組發(fā)出按鍵信息。每字符三個字節(jié)的格式定義在與HID Report Descriptor相同的文件中,如圖10所示。圖10. Report Descriptor詳述了一個鍵盤按鍵的3字節(jié)數(shù)據(jù)格式
最終考慮和免責聲明
插入J1的USB設(shè)備可能是十億個左右可用設(shè)備的任意一個,因此不必說,將有各種各樣的響應(yīng)滿足主機的枚舉請求。任意一個通過兼容性測試的設(shè)備(有USB標識顯示證明)都將在枚舉時顯示無誤。本程序中的故障檢測由每次主機事務(wù)處理后對HRSL值的檢查完成。因為許多故障條件難以模擬,所以故障檢查沒有進行廣泛的測試。附錄A
3240E_HIDKB.C枚舉的USB總線跟蹤過程
更詳細的圖(PDF, 234kB)
評論
查看更多