MAX3420E便于使用通用微控制器設計USB外設。在介紹MAX3420E之后,本文重點介紹器件的SPI接口。本文演示了如何使用硬連線SPI單元或對通用I/O引腳進行位敲擊來訪問器件。給出了使用MAXQ2000微控制器的USB設計的示例C代碼。
介紹
有關通用串行總線 (USB) 的文章,首先證明 USB 是個人計算機的新連接標準。值得慶幸的是,這不再是必需的,所以這個介紹可以很簡短。如果您有嵌入式系統并想連接到PC,則主流管道是USB。
Maxim Integrated的新型芯片MAX3420E可輕松將USB添加到任何系統中。本文重點介紹MAX3420E的集成SPI(串行外設接口)接口,并提供通用SPI實現的示例C代碼。本文最后介紹了一個簡單的USB HID(人機接口設備)的代碼,這是一個基于Windows的緊急按鈕。
將 USB 添加到任何內容
微控制器 (μC) 的選擇通常基于集成外設。一些處理器包括USB功能,但大多數處理器,尤其是真正低成本的版本,沒有。您是否曾經選擇過I/O和外設完美結合的微控制器,但發現它缺少USB?另外,是否要添加 USB 并繼續使用現有的開發工具?
現在可以使用Maxim的新型MAX3420E將USB添加到任何微控制器中。該芯片提供USB全速收發器、智能USB串行接口引擎(SIE)和SPI從接口,可與高達26MHz的SCLK時鐘信號一起運行。MAX3420E作為全速USB外設工作,具有一個控制端點、兩個雙緩沖64字節數據端點和一個64字節中斷端點。
總線驅動的小部件
圖1.USB 總線供電的小組件。
圖 1 說明了一種常見的 USB 外設架構。The USB V總線電線為5.3V穩壓器提供3V電源,3420.3V穩壓器為微控制器和MAX4E供電,無需外部電源。SPI 接口可以包含 5、1 或 5 根電線。表 <> 顯示了完整的 <> 引腳接口。
信號 | MAX3420E方向 | 描述 |
莫西 | 在 | SPI 主站出站,從站輸入 |
醬 | 外 | SPI 主輸入,從輸出 |
高萊克 | 在 | 串行時鐘 |
黨衛軍# | 在 | 從屬選擇 |
國際 | 外 | 中斷(電平或脈沖) |
如果應用不需要中斷(所有MAX3420E中斷條件都可以通過讀取寄存器位直接測試),則可以省去INT引腳,使用4引腳接口。如果您的SPI主機具有雙向數據接口(MOSI/MISO位于同一雙向引腳上),則可以再減少一個引腳。因此,不支持中斷和雙向數據引腳的SPI接口僅使用三個引腳。
如果微控制器沒有SPI端口,該怎么辦?沒關系。通過直接切換通用I/O引腳,很容易制作固件驅動的SPI主機。USB 的一個強大功能是它是自節流的;它自動適應SPI側的任何速度接口。(它通過使用 USB 端的 NAK 握手來指示“現在忙,請重試”來實現此目的。許多USB外設,尤其是那些連接到人類的外設,即使是最慢的SPI接口,也能非常靈敏地運行。
如果圖1中的微控制器真的很小,可能不到10個引腳怎么辦?您是否需要使用所有這些有價值的I / O引腳來與USB芯片通信?是的,但這正是MAX3420E提供3420路通用輸入和3420路通用輸出的原因。簡單地說,MAX3420E有<>個通用I/O來代替與其通信所需的引腳,但MAX<>E增加了更多的I/O。因此,連接MAX<>E后,您的系統實際上有更多的I/O引腳。
大籌碼
圖2.連接到大芯片的一個小角落。
MAX3420E不限于小型系統。圖 2 說明了如何將 USB 功能添加到大型 ASIC、FPGA、DSP 或其他大型芯片。這樣做的一個明顯原因是大芯片可能沒有內置USB,或者里面的USB可能不是你想要的。這種架構的另一個很好的原因是,隨著大型芯片在工藝幾何形狀中的縮小,它們不太能夠觸及“高”電壓,例如USB所需的3.3V。具有低壓SPI接口的外部USB芯片是應對這些設計挑戰的良好解決方案。為了運行低壓接口,MAX3420E具有內部電平轉換器和一個VL引腳,用于將SPI接口的工作電壓設置為1.7V至3.6V之間的任何電壓。
隔離式 USB
圖3.隔離 USB。
如上圖3所示,SPI接口是放置光隔離的簡單位置。這是因為SPI信號是單向的,它們可以在低頻下工作,以支持低成本光耦合器。
SPI 接口
SPI是一個簡單的串行接口,使用兩條數據線、一個串行時鐘和一個片選信號。SPI主機將SS#降至低電平以開始傳輸,然后驅動串行時鐘SCLK,以同時對數據進行時鐘輸入和傳出從設備。SPI 主機通過返回 SS# 高電平來終止傳輸。
SPI接口有四種時鐘模式,反映兩種模式信號,稱為CPOL(時鐘極性)和CPHA(時鐘相位)。這些信號以(CPOL,CPHA)的形式表示。期望在第一個正邊沿之前同時提供正邊沿 SCKS 和 MOSI 數據的接口可以在模式 (0,0) 和 (1,1) 下工作而無需更改。該特性允許MAX3420E工作在上述任一模式,無需模式引腳。
圖4和圖5給出了微控制器(MAXQ2000,稍后介紹)和MAX3420E之間的相同數據傳輸。圖 4 使用 SPI 模式 (0,0),圖 5 使用 SPI 模式 (1,1)。區別在于SCLK信號的非活動電平,模式(0,0)為低電平,模式(1,1)為高電平。
圖4.SPI 接口在模式 (0,0) 下工作。
圖5.SPI 接口在模式 (1,1,) 下工作。
MAX3420E接受命令字節作為每次傳輸的第一個字節。命令字節包含寄存器編號和方向位。第二個和后續字節包含數據。圖3420和圖4中的命令字節輸入(MOSI引腳)時,來自MAX5E (MISO引腳)的<>位是每次輸入命令字節時可用的USB狀態位。此功能僅對使用單獨數據引腳 MISO 和 MOSI 的接口有效。
SPI 代碼
為MAX3420E編寫通用C代碼的關鍵是將最少的SPI操作隔離在單獨的模塊中,并僅定制從SPI接口到SPI接口的模塊。此模塊至少只需要做三件事:
Initialize_SPI
讀取字節
寫入字節
此處的示例應用程序使用硬件 SPI 單元。對于沒有這種單元的應用,我們將首先回顧一些通用的C代碼,用于位敲擊SPI接口。
位敲擊 SPI
初始化 SPI
Initialize_SPI功能在不同處理器之間變化最大。它負責分配接口使用的特定 I/O 引腳,設置其方向,然后設置 SS = 1 和 SCLK = 0 的初始條件。(我們正在制作一個模式 (0,0) SPI 主站。
讀寄存器、寫寄存器
rreg是讀取MAX3420E寄存器的C功能。宏(全部大寫)將功能與各種微控制器的各種I/O方案隔離開來。使用宏使代碼易于閱讀且獨立于處理器。wreg 是寫入 MAX3420E 寄存器的例程。
如果更改處理器,則只需更改少量宏即可使用這些例程。例如,下面的宏適用于不包含硬件SPI單元的微控制器。
#define SCLK_HI OUTA = PINSA | 0x02; #define SCLK_LO OUTA = PINSA & 0xFD; #define SS_HI OUTA = PINSA | 0x04; #define SS_LO OUTA = PINSA & 0xFB; #define MOSI(v) OUTA = (PINSA & 0x7F) | (v & 0x80); #define MISO inval |= PINSA & 0x01; BYTE
#define SCLK_HI OUTA = PINSA | 0x02; #define SCLK_LO OUTA = PINSA & 0xFD; #define SS_HI OUTA = PINSA | 0x04; #define SS_LO OUTA = PINSA & 0xFB; #define MOSI(v) OUTA = (PINSA & 0x7F) | (v & 0x80); #define MISO inval |= PINSA & 0x01; BYTE rreg(BYTE r) // Read a register, return its value. { int j; BYTE bv,inval; inval = 0; SS_LO bv = r<<3; // Left-shift the reg number, WRITE=0 for (j=0; j<8; j++) // send the register number and direction bit { MOSI(bv) // put out a bit bv <<= 1; // shift one bit left SCLK_HI SCLK_LO } for (j=0; j<7; j++) // get 7 bits and shift left into 'inval' { SCLK_HI MISO inval <<= 1; // shift in one bit SCLK_LO } SCLK_HI // one more bit, but don't shift 'inval' this time MISO SCLK_LO SS_HI return inval; // return the byte we read in } void wreg(BYTE r,BYTE v) // register, value { int j; BYTE bv; SS_LO bv = (r<<3)+2; // Left-shift the reg number, set the WRITE direction bit for (j=0; j<8; j++) // send the register number and direction bit { MOSI(bv) // put out a bit bv <<= 1; // shift one bit left SCLK_HI SCLK_LO } for (j=0; j<8; j++) // send the register data { MOSI(v) // put out a bit v <<= 1; // shift one bit left SCLK_HI SCLK_LO } SS_HI }
硬件 SPI
本節討論前面提到的MAXQ2000微控制器。簡而言之,MAXQ2000是低功耗、16位、高性能RISC處理器系列中的首款產品。MAXQ2000中的“Q”表示“安靜”,表示該架構設計為與敏感的模擬電路良好共存。MAXQ2000具有內置的SPI端口,使其對MAX3420E特別友好。以下示例使用MAXQ2000開發板和MAX3420E構建一個簡單但有趣的Windows小部件。
MAXQ2000硬件SPI單元提供SCLK、MOSI和MISO,但不提供SS#。由于 SS# 的工作方式各不相同(例如,用于訪問一個字節與字節突發),因此最好對 SS# 使用通用 I/O 引腳。
MAXQ I/O 單元
圖6.一個 MAXQ I/O 單元。
圖6所示為基本的MAXQ I/O單元。I/O 端口位以“port.bit”格式標記,其中“p”是端口,“b”是位。在本例中,我們專注于 I/O 端口 5 位 3(引腳標記為 P53)。
每個 I/O 單元都有一個觸發器,在本例中,該觸發器是使用稱為 PO5.3 的位編寫的。“O”表示輸出。你總是可以寫這個觸發器;它是否連接到引腳取決于方向位。配置輸出引腳時,為了避免毛刺,最好在將觸發器連接到引腳之前寫入觸發器。
P53引腳的方向由稱為PD5.3的位設置。“D”表示方向,D信號用作引腳驅動器的輸出使能:1 = 驅動,0 = 浮點。引腳的狀態始終可以在稱為PI5.3的位中讀取,其中“I”表示輸入。無論引腳如何驅動,由內部觸發器 (PD5.3 = 1) 或外部觸發器 (PD5.3 = 0) 驅動,PI 位指示引腳狀態。
此結構中有一個值得注意的功能。如果將P53引腳配置為輸入(PD5.3 = 0),則觸發器的輸出不用作輸出,因此可以重復使用為上拉電阻開關。當D = 0時,O信號被重新定義為“連接上拉電阻”,如圖6中的虛線和開關所示。
一些I/O引腳具有中斷能力,如圖6下面的模塊所示。中斷塊有三個信號:
在中斷請求處于活動狀態時設置并由 CPU 重置的標志位。
一個邊沿選擇位,用于確定是正信號轉換還是負信號轉換導致中斷請求。
特定引腳的中斷使能位。
我們的示例應用將MAX3420E INT輸出引腳配置為正邊沿觸發中斷。在MAXQ2000端,代碼直接測試掛起USB中斷的中斷觸發器,而不是使用MAXQ2000中斷系統。該程序除了檢查按鈕的狀態并響應USB請求外,什么都不做,因此只需要輪詢循環。
初始化 SPI
MAXQ2000 I/O引腳在通用I/O和特殊功能硬件(如SPI單元)之間共享。要使用特殊硬件,請先配置硬件塊,然后使其能夠連接到 I/O 引腳。下面的 SPI_Init() 例程設置引腳方向,配置 SPI 接口,最后啟用它。
void SPI_Init(void) { // MAXQ2000 SPI port CKCN = 0x00; // system clock divisor is 1 SS_HI // SS# high PD5 |= 0x070; // Set SPI output pins (SS, SCLK, DOUT) as output. PD5 &= ~0x080; // Set SPI input pin (DIN) as input. SPICK = 0x00; // fastest SPI clock--div by 2 SPICF = 0x00; // mode(0,0), 8 bit data SPICN_bit.MSTM = 1; // Set Q2000 as the master. SPICN_bit.SPIEN = 1; // Enable SPI // MAX3420E INT pin is tied to MAXQ2000 P60; make it an input PD6 &= ~0x01; // PD6.0=0 (turn off output) }
讀寄存器、寫寄存器
以下功能利用了MAXQ2000的硬件SPI單元,因此比位爆炸的同類產品更小、更快。
// Read a MAX3420E register, return its value. BYTE rreg(BYTE reg) { BYTE dum; SS_LO SPIB = reg<<3; // reg number w. dir=0 (IN) while(SPICN_bit.STBY); // loop if data still being sent dum = SPIB; // read and toss the input byte SPIB=0x00; // data is don't care, we're clocking in MISO bits while(SPICN_bit.STBY); // loop if data still being sent SS_HI return(SPIB); } // Write a MAX3420E register. void wreg(BYTE reg, BYTE dat) { SS_LO // Set SS# low SPIB = (reg<<3)+2; // send reg. number w. DIR bit (b1) set to WRITE while(SPICN_bit.STBY); // loop if data still being sent SPIB = dat; // send the data while(SPICN_bit.STBY); // loop if data still being sent SS_HI // set SS# high }
示例:基于 Windows 的緊急按鈕
這個USB小部件是基于Windows的USB HID(人機接口設備),具有一個“緊急”按鈕。當您按下按鈕時,所有活動的PC窗口都將最小化,并且您正在查看桌面。再次按下它,所有應用程序窗口都會恢復生機。
USB鍵盤很有趣。如果插入多個鍵盤,它們將同時處于活動狀態。因此,此緊急按鈕可與您的普通鍵盤配合使用。
如果電腦掛起,緊急按鈕將扮演新角色 - 它可以用作電腦的遠程喚醒按鈕。此操作高度依賴于你的電腦是否支持從 USB 喚醒。有些 PCS 可以,有些則不會。此按鈕可幫助確定你的電腦是否具有此功能。
本代碼示例在MAXQ2000開發板上運行,將小型USB子板(包含MAX3420E)插入擴展連接器。
USB 詳細信息
此應用程序包含執行枚舉基本工作的 USB 樣板代碼。本文檔末尾的 Panic_Button_Enum_Data.h 列表中的字符數組完全描述了此設備的特性。
此應用程序使用兩個終結點:必需的 CONTROL 終結點零和 EP3-IN(單緩沖 64 字節終結點)。雖然MAX3420E包含兩個雙緩沖64字節端點(EP1輸出和EP2輸入),但本應用不需要雙緩沖的吞吐量優勢。
一個常見的 HID 誤解是 HID 設備僅以低速運行。此應用程序演示了即使是像鍵盤這樣慢的東西也可以從全速運行中受益。這是正確的,因為鍵盤使用較少的總線帶寬,發送 12MHz 而不是 1.5MHz 數據包。
圖7.緊急按鈕的流程圖。
中斷終結點具有輪詢間隔,該間隔確定 USB 主機向 IN 終結點請求數據的頻率。在每個時間間隔內,我們可以期望主機向設備的終結點 3 發送 IN 請求。圖 7 說明了處理這些請求的簡單狀態機。枚舉器件后,微控制器會重復執行此例程。為簡化起見,此應用程序輪詢中斷引腳的活動。如果在微控制器中運行其他操作,則需要調用 Do_IN3 函數以響應中斷。
狀態機使用兩個全局變量:狀態和按鈕。C 宏定義了三種狀態:空閑、發布和等待。狀態變量初始化為 IDLE。如果按下連接到MAX3420E GPIN0引腳的按鈕,則可變按鈕為高電平,否則為低電平。main()中的無限循環遞增按鈕檢查定時器,到期時讀取MAX3420E中的GPIO寄存器以確定按鈕狀態。這樣可以節省不必要的 SPI 流量。
當按鈕向上時,狀態圖采用兩個向左的分支,并且不執行任何操作。如果在空閑狀態下按下按鈕,則是時候發送鍵碼以清除活動窗口了。這是序列 08(Windows 鍵)00(保留)和 07(字母 d)。下一個狀態設置為“發布”,并且操作已完成。
一旦MAX3420E通過USB發送該數據包,就會產生另一個EP3-IN中斷請求,指示EP3-IN FIFO再次可用于加載數據。再次輸入圖 7 函數。此時間狀態 = RELEASE,因此函數發送序列 00 00 00,指示“鍵啟動”。下一個狀態設置為 WAIT,意思是“等待按鈕松開”。
現在,該函數只需要使用 WAIT 狀態分支來檢測按鈕釋放。當按鈕保持按下狀態時,沒有任何反應。釋放按鈕時,狀態圖采用兩個向右的分支,并將狀態變量重新初始化為 IDLE,為下一次按下按鈕準備函數。
大多數時間執行的代碼非常小。下面是整個函數,它實現了圖 7 中的流程圖:
void Do_IN3(void) { switch(state) { case IDLE: if (button) { wreg(rEP3INFIFO,0x08); // "Windows" prefix key wreg(rEP3INFIFO,0); wreg(rEP3INFIFO,0x07); // "D" key wreg(rEP3INBC,3); // arm it state = RELEASE; // next state sends the "keys up" code } break; // else do nothing (and the SIE will NAK) // case RELEASE: { wreg(rEP3INFIFO,0x00); // key up wreg(rEP3INFIFO,0x00); wreg(rEP3INFIFO,0x00); // key up wreg(rEP3INBC,3); // arm it state = WAIT; // next state waits for the PB to be unpressed } break; case WAIT: if (!button) state = IDLE; break; default: state = IDLE; } // end switch }
代碼花絮
代碼中的一些細節值得評論。
時間關鍵型 USB 事件
MAX3420E通過驅動總線上的“K”狀態10ms來發出遠程喚醒信號。為了減輕SPI主機的計數負擔,MAX3420E在內部對該信號進行計時(實際上,每隔一個USB時間敏感事件),然后在間隔結束時給SPI主機一個中斷。SPI 主站不需要為這些事件使用自己的定時器;它只是啟動操作,然后等待完成中斷。
ACKSTAT 位
函數 rregAS 和 wregAS 做一件事與 rreg 和 wreg 不同;他們在 SPI 命令字節中設置了一個 ACK 狀態位。SPI主機(在我們的例子中為MAXQ2000)使用該位告訴MAX3420E它已完成當前的控制傳輸,因此通過確認其狀態級來終止CONTROL傳輸。盡管 ACKSTAT 作為內部寄存器位存在,但將其包含在 SPI 命令字節中可以更快地執行此常用操作,并且使用更少的代碼。
readbytes(), writebytes() 函數
readbytes()、writebytes()功能利用了MAX3420E的突發功能。它們不是每字節發送兩個 SPI 字節訪問(一個命令字節和一個數據字節),而是首先丟棄 SS#,然后發送命令字節,輸入/輸出字節突發,最后引發 SS# 以終止 SPI 傳輸。
在哪里可以找到產品 ID
圖8.此處顯示產品 ID 字符串。
產品 ID (PID) 字符串(以 Panic_Button_Enum_Data.h 為單位)在您首次插入緊急按鈕時顯示為短消息。此 ID 字符串在枚舉過程中彈出,該過程將緊急按鈕標識為 HID,并將其與內置 Windows 驅動程序關聯。
每個后續附件都是靜音的,除了插入任何 USB 設備時聽到的一點“ba-deep”Windows 聲音。如果要隨時檢查設備狀態,請轉到圖 8 中所示的屏幕。您可以通過右鍵單擊“我的電腦”,選擇“屬性”、“硬件”選項卡、“設備管理器”按鈕,展開“人機接口設備”項,右鍵單擊“USB 人機接口設備”并選擇“屬性”來訪問此屏幕。
符合 USB 標準
也許你看了代碼,然后想,“對于一個一鍵式USB設備來說,這是很多工作。這是正確的,因為存在與任何 USB 設備關聯的特定開銷。幸運的是,USB 被精心指定,以至于此枚舉代碼可以用作任何 USB 設備的模板(如復制粘貼)。
像所有勤奮的開發人員一樣,我們希望我們的設計可以通過USB-IF認證,這有助于確保它在任何PC上都能正常運行。此應用程序通過了 USB 命令驗證程序(USBCV 版本 1.2.1.0)和 HID 測試,測試套件可供開發人員在 USB-IF 網站上使用。下面的圖 9 是此緊急按鈕的記分卡。
圖9.此緊急按鈕上的 USB 和 HID 測試的測試日志和狀態報告。
結論
如果需要制作USB外設,可以考慮使用MAX3420E。該設備體積小,易于編程,并帶有免費的示例代碼。MAX3420E在設計中增加了I/O引腳,可在任何支持SPI的系統中很好地工作。由于SPI非常容易位爆炸,因此該設計包括每個微控制器。如果需要更高的性能,可以將SPI接口的時鐘頻率設置為高達26MHz。
審核編輯:郭婷
-
微控制器
+關注
關注
48文章
7496瀏覽量
151086 -
usb
+關注
關注
60文章
7903瀏覽量
264053 -
SPI
+關注
關注
17文章
1701瀏覽量
91345
發布評論請先 登錄
相關推薦
評論