這幾天一直在學習關于IIC的時序,總結一下學習中遇到的問題。
一、IIC的時序很簡單,主要有:
(1)起始信號S:是在SCL信號為高電平期間,信號SDA由1變?yōu)?,代表著數據開始要傳輸,注意:SCL信號和SDA信號在空閑的時候為高電平。
(2)停止信號P:是在SCL信號為高電平期間,信號SDA由0變?yōu)?,代表著數據傳輸完成;
(3)數據傳輸:在 I2C 總線上傳送的每一位數據都有一個時鐘脈SCL沖相對應。在對數據傳送時,在 SCL 高電平期間,SDA 上的電平必項保持穩(wěn)定,低電平為數據 0,高電平為數據 1。只有在 SCL 為低電平期間,才允講 SDA 上的電平改變狀態(tài)。
重點:(4)應答信號ACK與非應答信號NACK:I2C 總線上的所有數據都是以 8 位字節(jié)傳送的,發(fā)送器(FPGA)每發(fā)送一個字節(jié),就在時鐘脈沖 9 期間釋放數據線(也就是將SDA信號的傳輸方向改變?yōu)檩斎?,由接收器(EEPROM)反饋一個應答信號ACK,為低電平時是有效應答位,表示接收器已經成功地接收了該字節(jié),接收器(EEPROM)在第9 個時鐘脈沖之前的低電平期間將SDA 線拉低,并且確保在第9個時鐘脈的高電平期間為穩(wěn)定的低電平。
應答信號為高電平時,規(guī)定為非應答位(NACK),一般表示接收器接收該字節(jié)沒有成功。 如果接收器(EEPROM)是主控器,則在它收到最后一個字節(jié)后,發(fā)送一個 NACK 信號,以通知被控發(fā)送器(FPGA)結束數據發(fā)送,并釋放 SDA 線,以便接收器(FPGA)發(fā)送一個停止信號。
下面是關于IIC 的時序圖,采用的是24LC04B的EEPROM芯片。
圖一
二、關于IIC的幾種讀寫
自己主要是采用的是:單字節(jié)寫,隨機讀
圖二是關于讀寫的方式:
圖二
三、在寫代碼時所遇到的問題:
1、自己看了特權的關于IIC的代碼與黑金資料的IIC的代碼,馬上就遇到第一個問題:關于IIC的傳輸的速率問題:在網絡上和datasheet上都給了兩種傳輸速率,標準速率100kb/s和快速速率400kb/s。還以為IIC只是有這兩種速率而已,但是看了黑金的資料后,發(fā)現IIC的速率不僅僅有這兩種,原來100kb/s是最高的傳輸速率,只要比這個小就可以,比如200kb/s。只是剛才說的這兩種速率是通用的規(guī)定。所以明白了IIC的速率也是可以自己設定的,不止標準速率100kb/s和快速速率400kb/s這兩種。
2、端口的信號:
(1)output scl,是采用對SCL信號進行分段寫成的,如
reg [9:0] cnt;
reg [2:0] cnt_clk;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
cnt <=>=>
end
else if( cnt == 10'd499)begin
cnt <=>=>
end
else begin
cnt <= cnt="" +="">=>
end
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
cnt_clk <=>=>
end
else begin
case(cnt)
10'd124:cnt_clk <=>=>
10'd249:cnt_clk <=>=>
10'd374:cnt_clk <=>=>
10'd499:cnt_clk <=>=>
default:cnt_clk <=>=>
endcase
end
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
scl_r <=>=>
end
else if(cnt_clk == 3'd0)begin
scl_r <=>=>
end
else if(cnt_clk == 3'd2)begin
scl_r <=>=>
end
assign scl = scl_r;
`define SCL_POS (cnt_clk == 3'd0)
`define SCL_HIG (cnt_clk == 3'd1)
`define SCL_NEG (cnt_clk == 3'd2)
`define SCL_LOW (cnt_clk == 3'd3)
(2)inout sda,由于SDA是雙向端口,則使用assign sda = sda_link ? sda_r : 1'bz;來實現數據的傳輸,其中sda_link 是控制SDA是作為輸出(sda_link 為1,輸出的是sda_r 的數據)還是輸入(sda_link 為0,)。
(3)input [1:0] key;作為控制IIC的寫與讀的控制信號。自己也在這栽了跟頭,由于參考的是特權的代碼,自己稍微做了改動,將前后兩次的按鍵值取反相與,為了使檢測有按鍵所按下,輸出的信號其實是檢驗下降沿的一個高脈沖,但是在后面的狀態(tài)機仍使用該輸出的信號,但此時的輸出信號以為低電平,所以會返回到初始狀態(tài)。
(4)output [3:0];作為檢驗讀取信號是否正確的方法。
3、關于ACK信號:
(1)信號的方向:代碼寫完之后一直發(fā)現怎么就是不返回ACK信號呢,一直覺得自己代碼沒有錯,從chipscope所看到的信號就是為低,怎么判斷 就是不為低呢,后來經同學指點,才發(fā)現,自己在寫關于ACK的狀態(tài)時,沒有將sda信號作為判斷條件,而是將sda_r作為判斷條件,所以總是返回到初始狀態(tài)。下面就是關于ACK的狀態(tài)機,紅色就是所錯誤的地方。
ACK1: begin
sda_link <=>=>
if(`SCL_HIG)begin
if(sda== 1'b0)begin //之間將sda寫成了sda_r,造成一直返回到IDLE狀態(tài)
state <=>=>
temp_data <=>=>
end
else begin
state <=>=>
end
end
else begin
state <=>=>
end
end
(2)ACK誰給的問題:
在進行寫的操作很簡單,明白ACK信號都是由EEPROM給FPGA,只要在每發(fā)送8位的字節(jié)后,在高電平期間,若EEPROM將sda信號拉低,說明就有應答信號。
在進行讀操作的時候,在進行讀取 數據之前,還有一個ACK信號,別忘記了,自己就把這個ACK信號忘記了,之后讀取完數據之后會有個NACK信號,那么這個信號是FPGA給EEPROM的。(很容易理解錯誤,以為都是EEPROM所給的呢)
4、SCL的時鐘
一定要記?。簲祿母淖冎荒茉赟CL信號的低電平期間,在SCL高電平器件保持平穩(wěn)。如在SCL高電平期間有數據改變很容易被認為是起始信號或是停止信號。
5、代碼問題
自己主要采用的特權的IIC時序代碼,讓我更 容易理解;而黑金資料中的IIC時序代碼,自己將時序圖在紙上畫出來才明白怎么一回事,這個看個人理解吧。
聯系客服