|
這幾天一直在學習關于IIC的時序,總結一下學習中遇到的問題。 一、IIC的時序很簡單,主要有: (1)起始信號S:是在SCL信號為高電平期間,信號SDA由1變?yōu)?,代表著數(shù)據(jù)開始要傳輸,注意:SCL信號和SDA信號在空閑的時候為高電平。 (2)停止信號P:是在SCL信號為高電平期間,信號SDA由0變?yōu)?,代表著數(shù)據(jù)傳輸完成; (3)數(shù)據(jù)傳輸:在 I2C 總線上傳送的每一位數(shù)據(jù)都有一個時鐘脈SCL沖相對應。在對數(shù)據(jù)傳送時,在 SCL 高電平期間,SDA 上的電平必項保持穩(wěn)定,低電平為數(shù)據(jù) 0,高電平為數(shù)據(jù) 1。只有在 SCL 為低電平期間,才允講 SDA 上的電平改變狀態(tài)。 重點:(4)應答信號ACK與非應答信號NACK:I2C 總線上的所有數(shù)據(jù)都是以 8 位字節(jié)傳送的,發(fā)送器(FPGA)每發(fā)送一個字節(jié),就在時鐘脈沖 9 期間釋放數(shù)據(jù)線(也就是將SDA信號的傳輸方向改變?yōu)檩斎?,由接收器(EEPROM)反饋一個應答信號ACK,為低電平時是有效應答位,表示接收器已經(jīng)成功地接收了該字節(jié),接收器(EEPROM)在第9 個時鐘脈沖之前的低電平期間將SDA 線拉低,并且確保在第9個時鐘脈的高電平期間為穩(wěn)定的低電平。 應答信號為高電平時,規(guī)定為非應答位(NACK),一般表示接收器接收該字節(jié)沒有成功。 如果接收器(EEPROM)是主控器,則在它收到最后一個字節(jié)后,發(fā)送一個 NACK 信號,以通知被控發(fā)送器(FPGA)結束數(shù)據(jù)發(fā)送,并釋放 SDA 線,以便接收器(FPGA)發(fā)送一個停止信號。 下面是關于IIC 的時序圖,采用的是24LC04B的EEPROM芯片。
圖一 二、關于IIC的幾種讀寫 自己主要是采用的是:單字節(jié)寫,隨機讀 圖二是關于讀寫的方式:
圖二 三、在寫代碼時所遇到的問題: 1、自己看了特權的關于IIC的代碼與黑金資料的IIC的代碼,馬上就遇到第一個問題:關于IIC的傳輸?shù)乃俾蕟栴}:在網(wǎng)絡上和datasheet上都給了兩種傳輸速率,標準速率100kb/s和快速速率400kb/s。還以為IIC只是有這兩種速率而已,但是看了黑金的資料后,發(fā)現(xiàn)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;來實現(xiàn)數(shù)據(jù)的傳輸,其中sda_link 是控制SDA是作為輸出(sda_link 為1,輸出的是sda_r 的數(shù)據(jù))還是輸入(sda_link 為0,)。 (3)input [1:0] key;作為控制IIC的寫與讀的控制信號。自己也在這栽了跟頭,由于參考的是特權的代碼,自己稍微做了改動,將前后兩次的按鍵值取反相與,為了使檢測有按鍵所按下,輸出的信號其實是檢驗下降沿的一個高脈沖,但是在后面的狀態(tài)機仍使用該輸出的信號,但此時的輸出信號以為低電平,所以會返回到初始狀態(tài)。 (4)output [3:0];作為檢驗讀取信號是否正確的方法。 3、關于ACK信號: (1)信號的方向:代碼寫完之后一直發(fā)現(xiàn)怎么就是不返回ACK信號呢,一直覺得自己代碼沒有錯,從chipscope所看到的信號就是為低,怎么判斷 就是不為低呢,后來經(jīng)同學指點,才發(fā)現(xiàn),自己在寫關于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信號拉低,說明就有應答信號。 在進行讀操作的時候,在進行讀取 數(shù)據(jù)之前,還有一個ACK信號,別忘記了,自己就把這個ACK信號忘記了,之后讀取完數(shù)據(jù)之后會有個NACK信號,那么這個信號是FPGA給EEPROM的。(很容易理解錯誤,以為都是EEPROM所給的呢) 4、SCL的時鐘 一定要記?。簲?shù)據(jù)的改變只能在SCL信號的低電平期間,在SCL高電平器件保持平穩(wěn)。如在SCL高電平期間有數(shù)據(jù)改變很容易被認為是起始信號或是停止信號。 5、代碼問題 自己主要采用的特權的IIC時序代碼,讓我更 容易理解;而黑金資料中的IIC時序代碼,自己將時序圖在紙上畫出來才明白怎么一回事,這個看個人理解吧。
|
|
|