本文摘要:本文首先對I2C協(xié)議的通信模式和AT24C16-EEPROM芯片時序控制進行分析和理解,設(shè)計了一個i2c通信方案。人為按下寫操作按鍵后,F(xiàn)PGA(Altera EP4CE10)對EEPROM指定地址寫入字節(jié)數(shù)據(jù),并接后按下讀操作按鍵,讀取該地址上的一個字節(jié)數(shù)據(jù)在數(shù)碼管低兩位顯示出來。其中包括了對此方案的Modelsim仿真測試,并且接續(xù)完成板級驗證。(過程筆記)
關(guān)鍵詞:EEPROM、I2C協(xié)議、Verilog HDL、FPGA
框圖設(shè)計:
輸入端口包括系統(tǒng)時鐘、復位信號、寫操作和讀操作按鍵,輸出端口包括IIC通信接口、數(shù)碼管段選和位選信號。
共計用到了四種子模塊,分別是按鍵消抖、i2c通信數(shù)據(jù)處理、i2c通信控制、2khz時鐘分配。按邏輯鏈接成體,完成本文設(shè)計的測試方案。在調(diào)試過程中,為方便觀察操作反應(yīng),另外加入了兩個LED燈接口,具體框圖如下。
【I2C協(xié)議通信模式】
I2C協(xié)議(通常稱為IIC協(xié)議)是一種串行、同步、半雙工通信協(xié)議。I2C協(xié)議支持多主機功能,允許多個具備主控能力的設(shè)備在同一總線上競爭控制權(quán),并通過硬件仲裁機制避免沖突。其使用串行數(shù)據(jù)線(SDA )和串行時鐘線(SCL )進行通信,標準模式的傳輸速率為100 kbit/s(Standard-mode, Sm),快速模式下的I2C傳輸速率提高至400 kbit/s(Fast-mode,F(xiàn)m),在高速模式下可達3.4Mbit/s。
發(fā)送到SDA 線上的每個字節(jié)必須為8位,且每次傳輸可以發(fā)送的字節(jié)數(shù)量不受限制,每個字節(jié)后必須跟一個ACK響應(yīng),位首先傳輸?shù)氖菙?shù)據(jù)的最高位MSB,SDA線上的數(shù)據(jù)必須在SCL 時鐘的高電平周期保持穩(wěn)定,數(shù)據(jù)線的高或低電平狀態(tài)只有在SCL 時鐘是低電平時才能改變。
傳輸信號類型:(見上圖)
- 啟動信號(START)(S條件):在
SCL 線處于高電平,SDA 上的數(shù)據(jù)由高向低轉(zhuǎn)換,則表示啟動IIC總線;
- 應(yīng)答信號(ACK):在接收到了8bit的信息后, 接收數(shù)據(jù)一方需要向發(fā)送信息的另一方傳遞默認的低電平脈沖作為信號,表明已經(jīng)獲取了數(shù)據(jù);
- 結(jié)束信號(STOP)(P條件):在
SCL 線處于高電平,SDA 上的數(shù)據(jù)由低向高轉(zhuǎn)換,則表示停止IIC總線。
起始(S)和停止(P)條件一般由主機產(chǎn)生,總線在起始條件后被認為處于忙的狀態(tài),在停止條件的某段時間后總線被認為再次處于空閑狀態(tài) 。
由于I2C 總線沒有中央控制,其控制只能由地址或主機碼以及競爭主機發(fā)送的數(shù)據(jù)決定,總線也沒有任何定制的優(yōu)先權(quán)。所以,當發(fā)生多主機通信時,需要一個控制仲裁機制來決定通信優(yōu)先。
仲裁過程中的時鐘同步:
在I2C通信中,所有主機在SCL 線上生成自己的時鐘信號以傳輸數(shù)據(jù)。數(shù)據(jù)僅在時鐘高電平時有效,因此需要同步時鐘以實現(xiàn)逐位仲裁。時鐘同步通過線與連接實現(xiàn),即SCL 線狀態(tài)由所有設(shè)備共同決定。
①見上圖中,當SCL線 從高變低時,所有設(shè)備開始計數(shù)其低電平周期。若某設(shè)備時鐘先變低,則它會保持SCL 線在低電平直到其時鐘再次變高。若此時有其他設(shè)備仍處于低電平周期,它們的時鐘變化不會改變SCL線 狀態(tài),直至最長低電平周期的設(shè)備完成計數(shù)。
②一旦所有設(shè)備完成低電平周期,SCL 線釋放并變?yōu)楦唠娖?,隨后所有設(shè)備同步開始計數(shù)高電平周期。
③首先完成高電平周期的設(shè)備將再次拉低SCL 線。因此,SCL 時鐘的低電平周期由最長低電平周期的設(shè)備決定 ,而高電平周期由最短高電平周期的設(shè)備 決定。(巧記:保證最長低電平周期)
仲裁判定優(yōu)先:
主機只能在總線空閑時啟動傳輸,兩個或多個主機可能在起始條件的最小持續(xù)時間內(nèi)產(chǎn)生一個起始條件,結(jié)果在總線上產(chǎn)生一個規(guī)范的起始條件(如下框S條件內(nèi))。當SCL 線是高電平時,仲裁在SDA 線發(fā)生,在其他主機保持低電平狀態(tài)時,首先拉高電平的主機將斷開數(shù)據(jù)輸出級,如下圖DATA1失去了通信的優(yōu)先權(quán)。
仲裁可以持續(xù)多位,第一個階段是比較地址位。 如果各主機都嘗試尋址同一器件,仲裁機制會持續(xù)到數(shù)據(jù)位。在仲裁過程中不會丟失信息(仲裁區(qū)間有效信息一致),丟失仲裁的主機可以產(chǎn)生時鐘脈沖直到丟失仲裁的該字節(jié)末尾 。
補充:如果主機也結(jié)合了從機功能,并且在尋址階段丟失仲裁,由于它存在是贏得仲裁的主機所尋址的器件。因此,丟失仲裁的主機必須立即切換到從機模式。
【AT24C16時序分析】
AT24C16 EEPROM存儲芯片的相關(guān)信息:存儲容量為16Kbit,即2048字節(jié)。芯片內(nèi)部分成128頁,每頁16字節(jié),讀寫操作都是以字節(jié)為基本單位。AT24C16具有低電壓工作、高速串行通信和硬件寫保護等特點。(下圖為芯片引腳說明)
- 地址組成:AT24C16的器件地址包括高4位固定地址(1010)和用戶需設(shè)置的低3位地址(
A0、A1、A2 );
- 地址設(shè)置:通過連接芯片的
A0、A1、A2 這3個引腳到VCC或GND來實現(xiàn)地址的低3位設(shè)置。例如這3個引腳均連接到VCC,則器件地址為1010_111。由于該 3 位只能組合出 8 種情況,因此,一個主機最多可以連接8個AT24C16存儲芯片。
1、EEPROM驅(qū)動寫時序進行分析
字節(jié)寫入時序 (Byte Write):通信開始,由主機發(fā)送一個起始條件。緊接著,主機發(fā)送EEPROM的設(shè)備地址,選擇目標EEPROM芯片。如果EEPROM支持字地址尋址,主機將接續(xù)發(fā)送一個或多個字節(jié)的字地址來指定要寫入數(shù)據(jù)的內(nèi)存位置。然后,主機寫入數(shù)據(jù)字節(jié),最高有效位(MSB)首先發(fā)送。 EEPROM在接收到每個字節(jié)后,返回一個應(yīng)答信號(ACK),應(yīng)答信號是低電平脈沖,表示已成功接收字節(jié)并準備接收下一個字節(jié)或停止信號。待所有數(shù)據(jù)字節(jié)都發(fā)送完畢后,主機發(fā)送停止信號(STOP)來結(jié)束目前的通信。
頁寫入時序 (Page Write):與字節(jié)寫入時序相比,頁寫入時序類似,但數(shù)據(jù)被分組為多個字節(jié),作為一個連續(xù)的數(shù)據(jù)塊發(fā)送。 發(fā)送起始設(shè)備地址后,接續(xù)發(fā)送一系列的數(shù)據(jù)字節(jié)(DATA (n), DATA (n + 1),......, DATA (n + x))單個字節(jié)發(fā)送完成,EEPROM都會返回一個應(yīng)答信號(ACK)。
補充:所有I2C設(shè)備均支持單字節(jié)數(shù)據(jù)寫入操作,但只有部分I2C設(shè)備支持頁寫操作;且支持頁寫操作的設(shè)備,一次頁寫操作寫入的字節(jié)數(shù)不能超過設(shè)備單頁包含的存儲單元數(shù)。
2、讀時序進行分析
IIC協(xié)議支持三種EEPROM讀時序。首先是指定地址單字節(jié)讀取方式:操作時序和寫時序類似,不同的是,在寫入目標地址后,主機的操作方式換為讀取。
順序讀取時序:主機發(fā)送一個起始地址后,EEPROM開始連續(xù)發(fā)送數(shù)據(jù)(DATA n, DATA n+1, DATA n+2, ... DATA n+X)。在每個數(shù)據(jù)字節(jié)的末尾,EEPROM同樣等待主機的應(yīng)答信號(ACK)。主機在接收到每個數(shù)據(jù)字節(jié)后發(fā)送ACK信號,直到所有數(shù)據(jù)都被接收。當所有數(shù)據(jù)發(fā)送完畢或主機決定停止時,它會發(fā)送一個停止信號(STOP),結(jié)束順序讀取操作。
隨機讀取時序:起始條件后,發(fā)送設(shè)備地址和讀寫位(R/W=1),接著發(fā)送隨機地址。EEPROM發(fā)送數(shù)據(jù),主機接收后發(fā)送ACK。所有數(shù)據(jù)發(fā)送完畢后,發(fā)送停止信號。EEPROM在接收到有效地址后,通過SDA線連續(xù)發(fā)送數(shù)據(jù)(DATA n, DATA n+1, ...)。在每個數(shù)據(jù)字節(jié)的末尾,EEPROM等待主機的應(yīng)答信號(ACK)。主機待接收到數(shù)據(jù)字節(jié)后,通過發(fā)送ACK信號來確認接收,并告知EEPROM可以繼續(xù)發(fā)送下一個數(shù)據(jù)字節(jié)。
【時序邏輯設(shè)計方案】
1、時鐘處理與i2c通信啟動
系統(tǒng)時鐘頻率為50Mhz,頻率很高,這里首先需要從系統(tǒng)時鐘分頻提供一個1Mhz的i2c_clk 時鐘用于i2c通信處理。下圖中cnt_clk 為一個時鐘分頻計數(shù)器。
以寫操作為例,待寫觸發(fā)信號write 發(fā)生,拉高寫有效信號write_valid ,并且為使i2c_clk 時鐘信號要在上升沿檢測到其高電平,write 觸發(fā)要保持≥2個時鐘周期,對應(yīng)100個系統(tǒng)時鐘周期。這里設(shè)定有效計數(shù)器cnt_wr ,計數(shù)150個系統(tǒng)周期,即300ns,滿足要求。計數(shù)完成,拉低寫有效信號write_valid 完成觸發(fā)操作,具體時序見下圖,當然,寫有效時序也是如此。
寫有效信號write_valid 觸發(fā),在其拉高的下一個i2c_clk 時鐘上升沿,觸發(fā)寫使能wr_en 信號,并且,啟動cnt_start 計數(shù)器,計數(shù)值為5000(1Mhz ->1us)≈ 5ms。這是因為AT64C16單次操作間隔周期需要保持5ms空閑狀態(tài)。完成計數(shù)后,啟動i2c_start 起始信號觸發(fā),后面就是i2c通信的具體流程。當完成操作后,i2c_end 結(jié)束信號標志通信完成,從而拉低寫使能wr_en 信號。過程中,設(shè)定了寫操作的目標地址為16'H00_4D,寫入數(shù)據(jù)為8'H8A。
注意,大部分信號時鐘觸發(fā)源都是i2c_clk ,而不是系統(tǒng)時鐘。當i2c_start 起始信號觸發(fā),i2c_clk 啟動,作為i2c_scl 通信時鐘的觸發(fā)源。同時,根據(jù)下圖邏輯,狀態(tài)機狀態(tài)由IDLE 轉(zhuǎn)到START1 。起始信號僅占一個i2c_clk 周期。cnt_i2c_clk 是i2c_scl 通信時鐘線的計數(shù)器,計數(shù)值范圍0-3,使得i2c_scl 周期為250khz。
完成后,進入SEND_ADDR 狀態(tài),向IIC總線發(fā)生器件地址1010011 +控制位0 ,表示寫入。比特位計數(shù)器cnt_bit 用于比特位0-7的計數(shù)。在ACK1 狀態(tài),等待總線回應(yīng)。ACK 是從機,即EEPROM,傳回來的低電平信號。對于主機來說SDA 線此時是高阻態(tài),總線的上拉電阻將電位鉗位在高電位(sda 為inout類型)。所以在后面,可以看到這里是處于高阻態(tài)的。通信后面的流程根據(jù)狀態(tài)機的跳轉(zhuǎn),在時序圖表現(xiàn)得明顯。在STOP 停止狀態(tài),F(xiàn)PGA向EEPROM發(fā)送停止信號,一次單字節(jié)數(shù)據(jù)寫操作完成,拉低使能信號i2c_clk_en 和we_en ,并且及時觸發(fā)i2c_end ,隨后狀態(tài)機跳回IDLE 初始狀態(tài)。
讀控制時序處理與寫時序處理流程類似,具體見上圖,不同在ACK3 狀態(tài)的跳轉(zhuǎn),接收一個周期回應(yīng)信號后,進入的是起始狀態(tài)START2 ,從而觸發(fā)第二次起始信號,再次寫入器件地址,讀取一字節(jié)數(shù)據(jù)。rd_data_reg 作為一個暫存器,存儲讀取到的字節(jié)數(shù)據(jù),待完成后,轉(zhuǎn)錄到rd_data 。在N_ACK 等待回應(yīng)一個高電平回應(yīng)信號,將i2c_scl 由地拉高產(chǎn)生一個停止信號,同時觸發(fā)i2c_end 。兩個操作過程具體狀態(tài)判斷條件,需具體分析,但都類似。
2、STATE狀態(tài)機轉(zhuǎn)換邏輯
i2c整個通信的過程可以分為很多階段,將它們細分開:空閑、起始、器件地址寫入、字/字節(jié)地址寫入、各級響應(yīng)、字節(jié)數(shù)據(jù)寫入、讀取字節(jié)數(shù)據(jù)、停止。主機視角對從設(shè)備操作過程,具體可見如下。
設(shè)備啟動,主機處于空閑狀態(tài)IDLE ,待檢測到寫/讀操作信號后,程序轉(zhuǎn)入到第一個起始狀態(tài)START_1 ,表現(xiàn)為SDA 線產(chǎn)生一個由高到低的電平轉(zhuǎn)換信號。接續(xù)進入器件地址寫入狀態(tài)SEND_ADDR ,根據(jù)硬件圖,這里預(yù)先設(shè)定器件是1010_011。器件確認后,向主機發(fā)生一個低電平回應(yīng)ACK_1 。寄存器存儲地址類型分為字地址和字節(jié)地址,分別對應(yīng)不同的狀態(tài)切換。完成后ACK_3 響應(yīng)后,寫操作,進入字節(jié)數(shù)據(jù)寫入狀態(tài)WR_DATA ,寫入一個預(yù)先數(shù)據(jù),并回應(yīng)ACK_4 進入結(jié)束停止狀態(tài)STOP 。而ACK_3 響應(yīng)后,進入讀操作流程,需再次發(fā)生起始START_2 ,接后寫入讀取目標地址,等待從機完成數(shù)據(jù)發(fā)送后,進入結(jié)束停止狀態(tài)STOP 。最終保持一定周期,再次轉(zhuǎn)換至空閑狀態(tài)IDLE 。
根據(jù)時序圖邏輯,確定狀態(tài)機狀態(tài)轉(zhuǎn)換條件:
當前狀態(tài) |
目標跳轉(zhuǎn)狀態(tài) |
跳轉(zhuǎn)條件 |
操作類型 |
IDLE |
START1 |
i2c_start拉高 |
讀/寫 |
START1 |
SEND_ADDR |
cnt_i2c_clk == 2'd3(一個i2c_clk周期 ) |
讀/寫 |
SEND_ADDR |
ACK1 |
(cnt_i2c_clk == 2'd3)&&(!ack) |
讀/寫 |
ACK1 |
SEND_BH |
(cnt_bit == 3'd7)&&(cnt_i2c_clk == 2'd3) |
讀/寫 |
SEND_BH |
ACK2 |
(cnt_bit == 3'd7)&&(cnt_i2c_clk == 2'd3) |
讀/寫 |
ACK2 |
SEND_BL |
(cnt_i2c_clk == 2'd3)&&(!ack) |
讀/寫 |
SEND_BL |
ACK3 |
(cnt_bit == 3'd7)&&(cnt_i2c_clk == 2'd3) |
讀/寫 |
ACK3 |
WR_DATA |
(cnt_i2c_clk == 2'd3)&&(!ack) |
讀/寫 |
WR_DATA |
ACK4 |
(cnt_bit == 3'd7)&&(cnt_i2c_clk == 2'd3) |
寫 |
ACK4 |
STOP |
(cnt_i2c_clk == 2'd3)&&(!ack) |
寫 |
ACK3 |
START2 |
rd_en拉高 |
讀 |
START2 |
SEND_RA |
cnt_i2c_clk == 2'd3 |
讀 |
SEND_RA |
ACK5 |
(cnt_bit == 3'd7)&&(cnt_i2c_clk == 2'd3) |
讀 |
ACK5 |
RD_DATA |
(cnt_i2c_clk == 2'd3)&&(!ack) |
讀 |
RD_DATA |
N_ACK |
(cnt_bit == 3'd7)&&(cnt_i2c_clk == 2'd3) |
讀 |
N_ACK |
STOP |
cnt_i2c_clk == 2'd3 |
讀 |
STOP |
IDLE |
(cnt_bit == 3'd3)&&(cnt_i2c_clk == 2'd3) |
讀/寫 |
對上面的表格可以總結(jié),ACK1 - ACK5 條件都是相同的,只是跳轉(zhuǎn)目標不同,單字節(jié)讀/寫結(jié)束后狀態(tài)跳轉(zhuǎn)判斷條件相同,兩個起始狀態(tài)跳轉(zhuǎn)判斷條件也是相同的 ,N_ACK 和STOP 的跳轉(zhuǎn)注意區(qū)別。跳轉(zhuǎn)機Verilog HDL具體程序如下:
| //dispose state condition | | always @(posedge i2c_clk or negedge sys_rst)begin | | if(!sys_rst) state <= IDLE; | | else case(state) | | IDLE: if(i2c_start) state <= START1;else state<= state; | | START1: if(cnt_i2c_clk == 2'd3) state <= SEND_ADDR; | | else state <= state; | | SEND_ADDR: | | if((cnt_bit == 3'd7)&&(cnt_i2c_clk == 2'd3)) | | state <= ACK1; | | else state <= state; | | ACK1: if((cnt_i2c_clk == 2'd3)&&(!ack))begin | | if(addr_num)state <= SEND_BH; | | else state<= SEND_BL; | | end else state <= state; | | SEND_BH:if((cnt_bit == 3'd7)&&(cnt_i2c_clk == 2'd3)) | | state <= ACK2; | | else state<= state; | | ACK2: if((cnt_i2c_clk == 2'd3)&&(!ack)) | | state <= SEND_BL; | | else state <= state; | | SEND_BL:if((cnt_bit == 3'd7)&&(cnt_i2c_clk == 2'd3)) | | state <= ACK3; | | else state <= state; | | ACK3: if((cnt_i2c_clk == 2'd3)&&(!ack))begin | | if(wr_en) state <= WR_DATA; | | else if(rd_en) state <= START2; | | end | | else state <= state; | | WR_DATA:if((cnt_bit == 3'd7)&&(cnt_i2c_clk == 2'd3)) | | state <= ACK4; | | else state <= state; | | ACK4: if((cnt_i2c_clk == 2'd3)&&(!ack)) | | state <= STOP; | | else state <= state; | | START2: if(cnt_i2c_clk == 2'd3) state <= SEND_RA; | | else state <= state; | | SEND_RA:if((cnt_bit == 3'd7)&&(cnt_i2c_clk == 2'd3)) | | state <= ACK5; | | else state <= state; | | ACK5: if((cnt_i2c_clk == 2'd3)&&(!ack)) | | state <= RD_DATA; | | else state <= state; | | RD_DATA:if((cnt_bit == 3'd7)&&(cnt_i2c_clk == 2'd3)) | | state <= N_ACK; | | else state <= state; | | N_ACK: if(cnt_i2c_clk == 2'd3) | | state <= STOP; | | else state <= state; | | STOP: if((cnt_bit == 3'd3)&&(cnt_i2c_clk == 2'd3)) | | state <= IDLE; | | else state <= state; | | endcase | | end |
STATE狀態(tài)機在整個程序過程中十分重要,i2c_scl 時鐘電平和i2c_sda 輸出電平情況,也要根據(jù)其狀態(tài)的不同做出具體分析。
| //dispose i2c_scl sequence | | always@(*)begin | | case(state) | | IDLE: i2c_scl <= 1'b1; | | START1: | | if(cnt_i2c_clk == 2'd3) i2c_scl <= 1'b0; | | else i2c_scl <= 1'b1; | | SEND_ADDR,ACK1,SEND_BH,ACK2,SEND_BL, | | ACK3,WR_DATA,ACK4,START2,SEND_RA,ACK5,RD_DATA,N_ACK: | | if((cnt_i2c_clk == 2'd1) || (cnt_i2c_clk == 2'd2)) i2c_scl <= 1'b1; | | else i2c_scl <= 1'b0; | | STOP: | | if((cnt_bit == 3'd0) &&(cnt_i2c_clk == 2'd0)) i2c_scl <= 1'b0; | | else i2c_scl <= 1'b1; | | default: i2c_scl <= 1'b1; | | endcase | | end | | | | //dispose i2c_sda_reg & rd_data_reg sequence | | always @(*)begin | | case(state) | | IDLE: begin | | i2c_sda_reg <= 1'b1; | | rd_data_reg <= 8'd0; | | end | | START1: if(cnt_i2c_clk == 2'd0) i2c_sda_reg <= 1'b1; | | else i2c_sda_reg <= 1'b0; | | SEND_ADDR: if(cnt_bit <= 3'd6) i2c_sda_reg<= DEVICE_ADDR[6-cnt_bit]; | | else i2c_sda_reg<= 1'b0; | | ACK1: i2c_sda_reg<= 1'b1; | | SEND_BH: i2c_sda_reg<= byte_addr[15-cnt_bit]; | | ACK2: i2c_sda_reg<= 1'b1; | | SEND_BL: i2c_sda_reg<= byte_addr[7-cnt_bit]; | | ACK3: i2c_sda_reg<= 1'b1; | | WR_DATA: i2c_sda_reg<= wr_data[7-cnt_bit]; | | ACK4: i2c_sda_reg<= 1'b1; | | START2: if(cnt_i2c_clk <= 2'd1)i2c_sda_reg <= 1'b1; | | else i2c_sda_reg <= 1'b0; | | SEND_RA: if(cnt_bit <= 3'd6)i2c_sda_reg<= DEVICE_ADDR[6-cnt_bit]; | | else i2c_sda_reg<= 1'b1; | | ACK5: i2c_sda_reg<= 1'b1; | | RD_DATA: if(cnt_i2c_clk == 2'd2) rd_data_reg[7-cnt_bit] <= sda_in; | | else rd_data_reg <= rd_data_reg; | | N_ACK: i2c_sda_reg<= 1'b1; | | STOP: if((cnt_bit==3'd0)&&(cnt_i2c_clk<2'd3))i2c_sda_reg <= 1'b0; | | else i2c_sda_reg<= 1'b1; | | default: begin | | i2c_sda_reg<= 1'b1; | | rd_data_reg <= rd_data_reg; | | end | | endcase | | end |
其他信號在此不再列舉,它們的判斷條件相對狀態(tài)機來說處理起來比較簡單,邏輯也很清晰。
【階段仿真驗證】
下面看下程序的仿真結(jié)果,查看四個:讀/寫操作啟動時刻、寫操作整體時序、讀操作整體時序、讀/寫操作結(jié)束時序。
操作啟動:write 信號發(fā)生,write_valid 拉高,并在下一i2c_clk 上升沿拉高wr_en 使能信號,等待cnt_wr 完成計數(shù)150后,放低write_valid 。cnt_start 待wr_en 拉高后,開始計數(shù)。
寫操作(這里器件地址設(shè)定1010_011):cnt_start 計數(shù)到4900處,發(fā)起i2c_start 觸發(fā),state 值變?yōu)?'h01,表示IDLE 進入START1 狀態(tài),依次完成后續(xù)的狀態(tài)切換。STOP 狀態(tài)下,待cnt_bit 保持到3'h3,結(jié)束停止狀態(tài)返回IDLE 。wr_en 拉低,i2c_end 拉高一個周期后放下。從下面的仿真圖可以看到,整個寫操作的時序表現(xiàn)正常。
讀操作及讀操作結(jié)束仿真圖如下:
【最終上機驗證】
Quartus II生成框圖如下,兩個按鍵做為輸入觸發(fā),輸出包括IIC通信總線SDA和SCL,數(shù)碼管段選SEG_SEL和位選SEG_LED,以及外部掛載的兩個LED。程序燒錄后,設(shè)備低二位數(shù)碼管顯示00 ,LED均處于熄滅狀態(tài),按下key_wr后,led_wr點亮,表示寫操作啟動;接續(xù),按下key_rd后,led_rd點亮,表示讀操作啟動,并且數(shù)碼管顯示讀取數(shù)據(jù)8A 。最終得到的現(xiàn)象與預(yù)期一致。
文獻參考:
[1] I2C總線規(guī)范 (https://sumcu./_upload/article/files/74/e5/d4eb93de45808d71ad8aad542ede/a3cb5873-aaf4-4af0-9e5f-521793fbba46.pdf);
[2] 基于I2C協(xié)議的EEPROM驅(qū)動控制(https://doc./fpga/altera/ep4ce10_mini/zh/latest/fpga/I2C.html);
[3] 王榮華. 可配置的IIC協(xié)議控制器IP核的設(shè)計[D]. 黑龍江:哈爾濱理工大學,2011.( DOI:10.7666/d.y2012472);
本篇文章中使用的Verilog程序模塊,若有需見網(wǎng)頁左欄Gitee倉庫鏈接:https:///silly-big-head/little-mouse-funnyhouse/tree/FPGA-Verilog/
|