FPGA学习之路—接口(2)—I2C协议详解+Verilog源码分析
FPGA學習之路——I2C協議詳解+Verilog源碼分析
定義
I2C Bus(Inter-Integrated Circuit Bus) 最早是由Philips半導體(現被NXP收購)開發的兩線時串行總線,常用于微控制器與外設之間的連接。I2C僅需兩根線就可以支持一主多從或者多主連接,主要優點為簡單、便宜、可靠性高,I2C總線示意圖如下。
- SDA(Serial Data):串行數據線
- SCL(Serial Clock):串行時鐘線
1、I2C總線共兩條雙向串行線,SDA為串行數據線,SCL為串行時鐘線。
2、SDA上的數據傳輸為最大端傳輸(先發送MSB,最后發送LSB),每次傳輸1個字節。
3、支持多主控,但任何時間只能有一個主控。
4、總線上每個設備都有自己的地址,共7個bit,第8個bit存放主設備對從設備的讀/寫操作信息,廣播地址全0。
工作流程
1、I2C位傳輸
數據傳輸: SCL為高電平時,若SDA線保持穩定,那么SDA線上在進行數據的傳輸或是空閑態;若SDA線發生跳變,則表示一個會話的開始或者結束。
數據改變: SDA僅能在SCL為低電平時改變傳輸的bit,否則表示會話狀態的改變。
2、I2C開始和結束信號
開始信號: SCL為高電平時,SDA由高電平向低電平跳變,開始數據的傳送。
結束信號: SCL為高電平時,SDA由低電平向高電平跳變,結束數據的傳送。
3、I2C應答信號
Master每發送完8bit數據后交出SDA的控制權,等待Slave的ACK。也就是在第9個Clock,若從設備發ACK,那么SDA會被拉低。如果Master未收到從設備的ACK,那么SDA會被拉高,這會導致Master發生RESTART或者STOP流程。
4、I2C寫流程
1、Master在SCL為高電平期間,拉低SDA,發起START。
2、Master發送設備地址(7bit)和寫操作0(1bit),等待ACK。
3、對應的Slave回應ACK。
4、Master發送寄存器地址(8bit),等待ACK。
5、對應的Slave回應ACK。
6、Master發送數據(8bit),也就是要寫入Slave寄存器中的數據,等待ACK。
7、對應的Slave回應ACK。
8、其中的6,7步可重復執行多次,即按順序對多個寄存器進行寫操作。
9、Master發起STOP。
5、I2C讀流程
1、Master在SCL為高電平期間,拉低SDA,發起START。
2、Master發送設備地址(7bit)和寫操作0(1bit),等待ACK。
3、Slave發送ACK。
4、Master發送寄存器地址(8bit),等待ACK。
5、Slave發ACK。
6、Master發起START。
7、Master發送I2C設備地址(7bit)和讀操作1(1bit),等待ACK。
8、Slave發送ACK。
9、Slave發送data(以字節為單位),即對應寄存器中的值。
10、Master發送ACK。
11、第9步和第10步可重復進行多次,即按順序讀多個寄存器。
Verilog代碼分析
本博客中所示代碼片段為《VERILOG HDL應用程序設計實例精講》提供的例程,僅供學習用途。
時鐘操作是I2C設計的關鍵部分,為更清楚的分析I2C時序關系,我們將一個時鐘周期分為4個部分a,b,c,d,如下圖所示。
Verilog代碼如下:
I2C總線START信號的特征:在時鐘信號SCL為高電平時,數據信號SDA由高到低跳變,Verilog代碼如下:
assign sda=(link)? sda_buf:1'bz; //link為是否傳輸數據的標志,sda_buf為sda的寄存器。//sda為雙向端口。 start:begincase(startcnt)2'b00:beginscl<=1'b1;sda_buf<=1'b1; //時鐘信號保持為高,sda數據設為高。link<=1'b1; //表示Master此時將sda_buf中的數據送到sda線上startcnt<=2'b01;end2'b01:beginscl<=1'b1; sda_buf<=1'b0; //時鐘信號保持為高,sda數據設為低,完成START。link<=1'b1; startcnt<=2'b10;end2'b10:beginscl<=1'b0; sda_buf<=1'b0; //時鐘信號和數據信號均為低。link<=1'b1; startcnt<=2'b11;end2'b11:beginscl<=1'b0; sda_buf<=1'b0; link<=1'b1; startcnt<=2'b00;inner_state<=first; //完成START操作后,進行后續操作,改變外層狀態。enddefault:beginscl<=1'b1; sda_buf<=1'b1; link<=1'b1; startcnt<=2'b00;inner_state<=start;endendcase endI2C主設備發送從設備的地址信號和讀寫標志,其中地址信號的發送順序為從高位至低位。
assign sda=(link)? sda_buf:1'bz; //link為是否傳輸數據的標志,sda_buf為sda的寄存器。//sda為雙向端口。 case(startcnt)2'b00:beginscl<=1'b0; //此時時鐘線為低,無法進行數據傳輸。sda_buf<=chipaddr[7]; //從設備地址最高位link<=1'b1;startcnt<=2'b01;end 2'b01:beginscl<=1'b1; //此時時鐘線為高,進行數據傳輸。sda_buf<=chipaddr[7]; //從設備地址最高位link<=1'b1;startcnt<=2'b10;end2'b10:beginscl<=1'b1; sda_buf<=chipaddr[7]; //scl為高時,sda需維持不變,否則會開始或終止當前會話。link<=1'b1;startcnt<=2'b11;end2'b11:beginscl<=1'b0; sda_buf<=chipaddr[7]; link<=1'b1;startcnt<=2'b00;inner_state<=second; //進行下一步操作,傳輸地址的次高bit。enddefault:beginscl<=1'b1; sda_buf<=chipaddr[7]; link<=1'b1;startcnt<=2'b00;inner_state<=first;end endcase上面的代碼用于發送從設備的地址和讀寫標志,重復7次即可完成該操作。發送完從設備的地址信號的讀寫標志后,接著Master需檢測從設備發送的應答信號,Verilog代碼如下。
assign sda=(link)? sda_buf:1'bz; //link為是否傳輸數據的標志,sda_buf為sda的寄存器。//sda為雙向端口。 ack:begincase(startcnt)2'b00:beginscl<=1'b0;link<=1'b0; //更改數據信號sda為輸入。startcnt<=2'b01;end2'b01:beginscl<=1'b1;link<=1'b0; startcnt<=2'b10;end2'b10:beginscl<=1'b1;link<=1'b0; sta_buf<=sda; //在時鐘線保持高電平時,采樣數據信號sda的值。 startcnt<=2'b11;end2'b11:beginscl<=1'b0;link<=1'b0;startcnt<=2'b00;if(sda_buf==1'b0) //若接收的sda數據為低,則表示檢測到從設備的應答信號begininner_state<=first; //返回初始狀態i2c_state<=sendaddr; //發送從設備地址成功后,進入下一階段。//發送寄存器地址。link<=1'b1; //主設備重新在sda數據線上進行數據傳輸。endelse beginmain_state<=3'b000; //回到等待讀寫請求狀態。inner_state<=start;endendendcase endI2C總線停止信號的特征:在時鐘信號scl為高電平時,sda由低到高進行跳變,Verilog代碼如下。
assign sda=(link)? sda_buf:1'bz; //link為是否傳輸數據的標志,sda_buf為sda的寄存器。//sda為雙向端口。 stop:begincase(startcnt)2'b00:begin //時鐘和數據信號都為低scl<=1'b0;sda_buf<=1'b0;link<=1'b1;startcnt<=2'b01;end2'b01:begin //時鐘信號變為高,數據信號為低scl<=1'b1;sda_buf<=1'b0;link<=1'b1;startcnt<=2'b10;end2'b10:begin //不在此周期內改變數據信號。//保證時鐘信號穩定后再進行數據信號的變化.scl<=1'b1;sda_buf<=1'b0;link<=1'b1;startcnt<=2'b11;end2'b11:begin //時鐘信號保持高,數據信號設為高,完成從低到高的跳變。scl<=1'b1;sda_buf<=1'b1;link<=1'b1;startcnt<=2'b00;inner_state<=start;i2c_state<=ini;main_state<=2'b00;enddefault:beginscl<=1'b1;sda_buf<=1'b0;link<=1'b1;startcnt<=2'b00;inner_state<=ack;endendcase end將以上的代碼段組合起來,基本就可以實現I2C協議了。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的FPGA学习之路—接口(2)—I2C协议详解+Verilog源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: unix-ln 命令
- 下一篇: WWDC 2013 Session笔记