0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

IIC傳輸協(xié)議及其代碼的實(shí)現(xiàn)

HJ18656750788 ? 來源:Cascatrix ? 2023-01-08 09:16 ? 次閱讀

01

IIC基礎(chǔ)知識(shí)

集成電路總線(Inter-Intergrated Circuit),通常稱作IICBUS,簡(jiǎn)稱為IIC,是一種采用多主從結(jié)構(gòu)的串行通信總線。IIC由PHILIPS公司于1980年推出,利用該總線可實(shí)現(xiàn)多主機(jī)系統(tǒng)所需的裁決和高低速設(shè)備同步等功能。

IIC串行總線一般有兩根信號(hào)線,分別是時(shí)鐘線SCL和數(shù)據(jù)線SDA,所有IIC總線各設(shè)備的串行數(shù)據(jù)SDA接到總線SDA上,時(shí)鐘線SLC接到總線SCL上。

雙向串行數(shù)據(jù)SDA:輸出電路用于向總線發(fā)送數(shù)據(jù),輸入電路用于接收總線上的數(shù)據(jù);

雙向時(shí)鐘數(shù)據(jù)SCL:輸出電路用于向總線發(fā)送時(shí)鐘信號(hào),輸入電路用于檢測(cè)總線時(shí)鐘電平以決定下次時(shí)鐘脈沖電平時(shí)間。

各設(shè)備與總線相連的輸出端采用高阻態(tài)以避免總線信號(hào)的混亂,通常采用漏極開路輸出或集電極開路輸出??偩€空閑時(shí),各設(shè)備都是開漏輸出,通??刹捎蒙侠?a target="_blank">電阻使總線保持高電平,而任一設(shè)備輸出低電平都將拉低相應(yīng)的總線信號(hào)。

57191204-8e9c-11ed-bfe3-dac502259ad0.png

IIC總線上的設(shè)備可分為主設(shè)備和從設(shè)備兩種:主設(shè)備有權(quán)利主動(dòng)發(fā)起/結(jié)束一次通信;從設(shè)備只能被動(dòng)響應(yīng)。

所有連接在IIC總線上的設(shè)備都有各自唯一的地址(原地址位寬為7bits,改進(jìn)后采用10bits位寬),每個(gè)設(shè)備都可以作為主設(shè)備或從設(shè)備,但是同一時(shí)刻只能有一個(gè)主設(shè)備控制。

如果總線上有多個(gè)設(shè)備同時(shí)啟用總線,IIC通過檢測(cè)和仲裁機(jī)制解決傳輸沖突。IIC允許連接的設(shè)備傳輸速率不同,多臺(tái)設(shè)備之間時(shí)鐘信號(hào)的同步過程稱為同步化。

02

IIC傳輸協(xié)議

2.1 IIC協(xié)議模式

IIC協(xié)議為半雙工模式,同一條數(shù)據(jù)線上完成讀/寫操作,不同操作時(shí)的數(shù)據(jù)幀格式可分為寫操作、讀操作、讀寫操作。

2.1.1 寫操作數(shù)據(jù)幀格式

主機(jī)向從機(jī)寫數(shù)據(jù)的數(shù)據(jù)幀格式如下:

573bf314-8e9c-11ed-bfe3-dac502259ad0.png

白色為主機(jī)發(fā)送數(shù)據(jù),灰色為從機(jī)發(fā)送數(shù)據(jù)。

1. 主機(jī)發(fā)送開始信號(hào)S;

2. 主機(jī)發(fā)送地址數(shù)據(jù)ADDR;

3. 主機(jī)發(fā)送寫信號(hào)0;

4. 從機(jī)響應(yīng)主機(jī)寫信號(hào)ACK;

5. 主機(jī)發(fā)送數(shù)據(jù)信息DATA;

6. 從機(jī)響應(yīng)主機(jī)發(fā)送數(shù)據(jù)ACK;

7. 循環(huán)5 6步驟可完成主機(jī)向從機(jī)連續(xù)寫數(shù)據(jù)過程;

8. 主機(jī)發(fā)送結(jié)束信號(hào)P.

2.1.2 讀操作數(shù)據(jù)幀格式

主機(jī)從從機(jī)讀數(shù)據(jù)的數(shù)據(jù)幀格式如下:

5757227e-8e9c-11ed-bfe3-dac502259ad0.png

白色為主機(jī)發(fā)送數(shù)據(jù),灰色為從機(jī)發(fā)送數(shù)據(jù)。

1. 主機(jī)發(fā)送開始信號(hào)S;

2. 主機(jī)發(fā)送地址數(shù)據(jù)ADDR;

3. 主機(jī)發(fā)送讀信號(hào)1;

4. 從機(jī)響應(yīng)主機(jī)讀信號(hào)ACK;

5. 從機(jī)發(fā)送數(shù)據(jù)信息DATA;

6. 主機(jī)響應(yīng)從機(jī)發(fā)送數(shù)據(jù)ACK;

7. 循環(huán)5 6步驟可完成主機(jī)向從機(jī)連續(xù)讀數(shù)據(jù)過程;

8. 主機(jī)發(fā)送結(jié)束信號(hào)P.

2.1.3 讀寫同時(shí)操作數(shù)據(jù)幀格式

主機(jī)先向從機(jī)寫數(shù)據(jù)后從從機(jī)讀數(shù)據(jù)的數(shù)據(jù)幀格式如下:

577905c4-8e9c-11ed-bfe3-dac502259ad0.png

白色為主機(jī)發(fā)送數(shù)據(jù),灰色為從機(jī)發(fā)送數(shù)據(jù)。

主機(jī)可以在完成寫操作后不發(fā)送結(jié)束信號(hào)P,直接進(jìn)行讀操作。該過程主機(jī)不可變,而從機(jī)可以通過發(fā)送不同地址選擇不同的從機(jī)。

2.2 IIC寫時(shí)序

IIC協(xié)議寫時(shí)序可分為單字節(jié)寫時(shí)序和連續(xù)寫時(shí)序:

2.2.1 單字節(jié)寫時(shí)序

單字節(jié)地址寫時(shí)序過程:

579d0316-8e9c-11ed-bfe3-dac502259ad0.png

1. 主機(jī)發(fā)送開始信號(hào)S;

2. 主機(jī)發(fā)送控制字節(jié)CONTROL BYTE(7bits設(shè)備地址dev addr和1bit讀寫信號(hào)),最低位為0表示主機(jī)向從機(jī)寫數(shù)據(jù);

3. 從機(jī)響應(yīng)主機(jī)控制字節(jié)ACK;

4. 主機(jī)發(fā)送單字節(jié)寄存器地址信息WORD ADDRESS;

5. 從機(jī)響應(yīng)主機(jī)發(fā)送寄存器地址ACK;

6. 主機(jī)發(fā)送單字節(jié)數(shù)據(jù)信息DATA;

7. 從機(jī)響應(yīng)主機(jī)發(fā)送數(shù)據(jù)信息ACK;

8. 主機(jī)發(fā)送結(jié)束信號(hào)P.

雙字節(jié)地址寫時(shí)序過程:

57d0eb86-8e9c-11ed-bfe3-dac502259ad0.png

1. 主機(jī)發(fā)送開始信號(hào)S;

2. 主機(jī)發(fā)送控制字節(jié)CONTROL BYTE(7bits設(shè)備地址dev addr和1bit讀寫信號(hào)),最低位為0表示主機(jī)向從機(jī)寫數(shù)據(jù);

3. 從機(jī)響應(yīng)主機(jī)控制字節(jié)ACK;

4. 主機(jī)發(fā)送寄存器地址信息高字節(jié)ADDRESS HIGH BYTE;

5. 從機(jī)響應(yīng)主機(jī)發(fā)送寄存器地址高字節(jié)ACK;

6. 主機(jī)發(fā)送寄存器地址信息低字節(jié)ADDRESS LOW BYTE;

7. 從機(jī)響應(yīng)主機(jī)發(fā)送寄存器地址低字節(jié)ACK;

8. 主機(jī)發(fā)送單字節(jié)數(shù)據(jù)信息DATA;

9. 從機(jī)響應(yīng)主機(jī)發(fā)送數(shù)據(jù)信息ACK;

10. 主機(jī)發(fā)送結(jié)束信號(hào)P.

2.2.2 連續(xù)寫時(shí)序

單字節(jié)地址寫時(shí)序過程:

57f8c480-8e9c-11ed-bfe3-dac502259ad0.png

1. 主機(jī)發(fā)送開始信號(hào)S;

2. 主機(jī)發(fā)送控制字節(jié)CONTROL BYTE(7bits設(shè)備地址dev addr和1bit讀寫信號(hào)),最低位為0表示主機(jī)向從機(jī)寫數(shù)據(jù);

3. 從機(jī)響應(yīng)主機(jī)控制字節(jié)ACK;

4. 主機(jī)發(fā)送單字節(jié)寄存器地址信息WORD ADDRESS;

5. 從機(jī)響應(yīng)主機(jī)發(fā)送寄存器地址ACK;

6. 主機(jī)發(fā)送單字節(jié)數(shù)據(jù)信息DATA;

7. 從機(jī)響應(yīng)主機(jī)發(fā)送數(shù)據(jù)信息ACK;

8. 循環(huán)6 7步驟可以連續(xù)向從機(jī)寫數(shù)據(jù)DATA(D+n);

9. 主機(jī)發(fā)送結(jié)束信號(hào)P.

雙字節(jié)地址寫時(shí)序過程:

581c8b5e-8e9c-11ed-bfe3-dac502259ad0.png

1. 主機(jī)發(fā)送開始信號(hào)S;

2. 主機(jī)發(fā)送控制字節(jié)CONTROL BYTE(7bits設(shè)備地址dev addr和1bit讀寫信號(hào)),最低位為0表示主機(jī)向從機(jī)寫數(shù)據(jù);

3. 從機(jī)響應(yīng)主機(jī)控制字節(jié)ACK;

4. 主機(jī)發(fā)送寄存器地址信息高字節(jié)ADDRESS HIGH BYTE;

5. 從機(jī)響應(yīng)主機(jī)發(fā)送寄存器地址高字節(jié)ACK;

6. 主機(jī)發(fā)送寄存器地址信息低字節(jié)ADDRESS LOW BYTE;

7. 從機(jī)響應(yīng)主機(jī)發(fā)送寄存器地址低字節(jié)ACK;

8. 主機(jī)發(fā)送單字節(jié)數(shù)據(jù)信息DATA;

9. 從機(jī)響應(yīng)主機(jī)發(fā)送數(shù)據(jù)信息ACK;

10. 循環(huán)8 9步驟可以連續(xù)向從機(jī)寫數(shù)據(jù)DATA(D+n);

11. 主機(jī)發(fā)送結(jié)束信號(hào)P.

2.3 IIC讀時(shí)序

IIC協(xié)議讀時(shí)序可分為單字節(jié)讀時(shí)序和連續(xù)讀時(shí)序:

2.3.1 單字節(jié)讀時(shí)序

單字節(jié)地址讀時(shí)序過程:

5838e736-8e9c-11ed-bfe3-dac502259ad0.png

1. 主機(jī)發(fā)送開始信號(hào)S;

2. 主機(jī)發(fā)送控制字節(jié)CONTROL BYTE(7bits設(shè)備地址dev addr和1bit讀寫信號(hào)),最低位為0表示主機(jī)向從機(jī)寫數(shù)據(jù);

3. 從機(jī)響應(yīng)主機(jī)控制字節(jié)ACK;

4. 主機(jī)發(fā)送單字節(jié)寄存器地址信息WORD ADDRESS;

5. 從機(jī)響應(yīng)主機(jī)發(fā)送寄存器地址ACK;

6. 主機(jī)發(fā)送開始信號(hào)S;

7. 主機(jī)發(fā)送控制字節(jié)CONTROL BYTE(7bits設(shè)備地址dev addr和1bit讀寫信號(hào)),最低位為1表示主機(jī)從從機(jī)讀數(shù)據(jù);

8. 從機(jī)響應(yīng)主機(jī)控制字節(jié)ACK;

9. 從機(jī)發(fā)送單字節(jié)數(shù)據(jù)信息DATA;

10. 主機(jī)響應(yīng)從機(jī)發(fā)送數(shù)據(jù)信息NACK(非應(yīng)答位: 接收器是主機(jī)時(shí),在接收到最后一個(gè)字節(jié)后發(fā)送NACK已通知被控發(fā)送從機(jī)結(jié)束數(shù)據(jù)發(fā)送,并釋放SDA數(shù)據(jù)線以便主機(jī)發(fā)送停止信號(hào)P);

11. 主機(jī)發(fā)送結(jié)束信號(hào)P.

雙字節(jié)地址讀時(shí)序過程:

586baa7c-8e9c-11ed-bfe3-dac502259ad0.png

1. 主機(jī)發(fā)送開始信號(hào)S;

2. 主機(jī)發(fā)送控制字節(jié)CONTROL BYTE(7bits設(shè)備地址dev addr和1bit讀寫信號(hào)),最低位為0表示主機(jī)向從機(jī)寫數(shù)據(jù);

3. 從機(jī)響應(yīng)主機(jī)控制字節(jié)ACK;

4. 主機(jī)發(fā)送寄存器地址信息高字節(jié)ADDRESS HIGH BYTE;

5. 從機(jī)響應(yīng)主機(jī)發(fā)送寄存器地址高字節(jié)ACK;

6. 主機(jī)發(fā)送寄存器地址信息低字節(jié)ADDRESS LOW BYTE;

7. 從機(jī)響應(yīng)主機(jī)發(fā)送寄存器地址低字節(jié)ACK;

8. 主機(jī)發(fā)送開始信號(hào)S;

9. 主機(jī)發(fā)送控制字節(jié)CONTROL BYTE(7bits設(shè)備地址dev addr和1bit讀寫信號(hào)),最低位為1表示主機(jī)從從機(jī)讀數(shù)據(jù);

10. 從機(jī)響應(yīng)主機(jī)控制字節(jié)ACK;

11. 從機(jī)發(fā)送單字節(jié)數(shù)據(jù)信息DATA;

12. 主機(jī)響應(yīng)從機(jī)發(fā)送數(shù)據(jù)信息NACK(非應(yīng)答位: 接收器是主機(jī)時(shí),在接收到最后一個(gè)字節(jié)后發(fā)送NACK已通知被控發(fā)送從機(jī)結(jié)束數(shù)據(jù)發(fā)送,并釋放SDA數(shù)據(jù)線以便主機(jī)發(fā)送停止信號(hào)P);

13. 主機(jī)發(fā)送結(jié)束信號(hào)P.

2.3.2 連續(xù)讀時(shí)序

單字節(jié)地址讀時(shí)序過程:

588c590c-8e9c-11ed-bfe3-dac502259ad0.png

1. 主機(jī)發(fā)送開始信號(hào)S;

2. 主機(jī)發(fā)送控制字節(jié)CONTROL BYTE(7bits設(shè)備地址dev addr和1bit讀寫信號(hào)),最低位為0表示主機(jī)向從機(jī)寫數(shù)據(jù);

3. 從機(jī)響應(yīng)主機(jī)控制字節(jié)ACK;

4. 主機(jī)發(fā)送單字節(jié)寄存器地址信息WORD ADDRESS;

5. 從機(jī)響應(yīng)主機(jī)發(fā)送寄存器地址ACK;

6. 主機(jī)發(fā)送開始信號(hào)S;

7. 主機(jī)發(fā)送控制字節(jié)CONTROL BYTE(7bits設(shè)備地址dev addr和1bit讀寫信號(hào)),最低位為1表示主機(jī)從從機(jī)讀數(shù)據(jù);

8. 從機(jī)響應(yīng)主機(jī)控制字節(jié)ACK;

9. 從機(jī)發(fā)送單字節(jié)數(shù)據(jù)信息DATA;

10. 主機(jī)響應(yīng)從機(jī)發(fā)送數(shù)據(jù)信息ACK;

11. 循環(huán)9 10步驟可完成主機(jī)向從機(jī)連續(xù)讀數(shù)據(jù)過程,讀取最后一個(gè)字節(jié)數(shù)據(jù)時(shí)主機(jī)應(yīng)響應(yīng)NACK(非應(yīng)答位: 接收器是主機(jī)時(shí),在接收到最后一個(gè)字節(jié)后發(fā)送NACK已通知被控發(fā)送從機(jī)結(jié)束數(shù)據(jù)發(fā)送,并釋放SDA數(shù)據(jù)線以便主機(jī)發(fā)送停止信號(hào)P);

12. 主機(jī)發(fā)送結(jié)束信號(hào)P.

雙字節(jié)地址讀時(shí)序過程:

58aee86e-8e9c-11ed-bfe3-dac502259ad0.png

1. 主機(jī)發(fā)送開始信號(hào)S;

2. 主機(jī)發(fā)送控制字節(jié)CONTROL BYTE(7bits設(shè)備地址dev addr和1bit讀寫信號(hào)),最低位為0表示主機(jī)向從機(jī)寫數(shù)據(jù);

3. 從機(jī)響應(yīng)主機(jī)控制字節(jié)ACK;

4. 主機(jī)發(fā)送寄存器地址信息高字節(jié)ADDRESS HIGH BYTE;

5. 從機(jī)響應(yīng)主機(jī)發(fā)送寄存器地址高字節(jié)ACK;

6. 主機(jī)發(fā)送寄存器地址信息低字節(jié)ADDRESS LOW BYTE;

7. 從機(jī)響應(yīng)主機(jī)發(fā)送寄存器地址低字節(jié)ACK;

8. 主機(jī)發(fā)送開始信號(hào)S;

9. 主機(jī)發(fā)送控制字節(jié)CONTROL BYTE(7bits設(shè)備地址dev addr和1bit讀寫信號(hào)),最低位為1表示主機(jī)從從機(jī)讀數(shù)據(jù);

10. 從機(jī)響應(yīng)主機(jī)控制字節(jié)ACK;

11. 從機(jī)發(fā)送單字節(jié)數(shù)據(jù)信息DATA;

12.主機(jī)響應(yīng)從機(jī)發(fā)送數(shù)據(jù)信息ACK;

13. 循環(huán)11 12步驟可完成主機(jī)向從機(jī)連續(xù)讀數(shù)據(jù)過程,讀取最后一個(gè)字節(jié)數(shù)據(jù)時(shí)主機(jī)應(yīng)響應(yīng)NACK(非應(yīng)答位: 接收器是主機(jī)時(shí),在接收到最后一個(gè)字節(jié)后發(fā)送NACK已通知被控發(fā)送從機(jī)結(jié)束數(shù)據(jù)發(fā)送,并釋放SDA數(shù)據(jù)線以便主機(jī)發(fā)送停止信號(hào)P);

14. 主機(jī)發(fā)送結(jié)束信號(hào)P.

03

IIC代碼實(shí)現(xiàn)

3.1 IIC目標(biāo)實(shí)現(xiàn)功能

設(shè)計(jì)一個(gè)IIC模塊,具體要求如下:

設(shè)計(jì)一個(gè)IIC協(xié)議提供給主設(shè)備,通過查找表實(shí)現(xiàn)對(duì)從設(shè)備寄存器進(jìn)行配置。按查找表順序lut_index依次對(duì)設(shè)備地址為lut_dev_addr的從設(shè)備寄存器進(jìn)行配置,為lut_reg_addr配置寄存器數(shù)據(jù)lut_reg_data,同時(shí)將傳輸異常和傳輸結(jié)束信號(hào)引出以對(duì)傳輸過程進(jìn)行監(jiān)控。模塊的定義如下:

module i2c(

input rst,//復(fù)位信號(hào)

input clk, //時(shí)鐘信號(hào)

input[15:0] clk_div_cnt, //時(shí)鐘計(jì)數(shù)器

input i2c_addr_2byte, //雙字節(jié)地址

output reg[9:0] lut_index, //查找表順序號(hào)

input[7:0] lut_dev_addr, //從設(shè)備地址

input[15:0] lut_reg_addr, //寄存器地址

input[7:0] lut_reg_data, //寄存器數(shù)據(jù)

output reg error, //傳輸異常信號(hào)

output done, //傳輸結(jié)束信號(hào)

inout i2c_scl, //IIC時(shí)鐘信號(hào)

inout i2c_sda //IIC數(shù)據(jù)信號(hào)

);

3.2 Verilog代碼

1. 頂層模塊 (i2c):

module i2c(

input rst,

input clk,

input[15:0] clk_div_cnt,

input i2c_addr_2byte,

output reg[9:0] lut_index,

input[7:0] lut_dev_addr,

input[15:0] lut_reg_addr,

input[7:0] lut_reg_data,

output reg error,

output done,

inout i2c_scl,

inout i2c_sda

);

wire scl_pad_i;

wire scl_pad_o;

wire scl_padoen_o;

wire sda_pad_i;

wire sda_pad_o;

wire sda_padoen_o;

assign sda_pad_i = i2c_sda;

assign i2c_sda = ~sda_padoen_o ? sda_pad_o : 1'bz;

assign scl_pad_i = i2c_scl;

assign i2c_scl = ~scl_padoen_o ? scl_pad_o : 1'bz;

reg i2c_read_req;

wire i2c_read_req_ack;

reg i2c_write_req;

wire i2c_write_req_ack;

wire[7:0] i2c_slave_dev_addr;

wire[15:0] i2c_slave_reg_addr;

wire[7:0] i2c_write_data;

wire[7:0] i2c_read_data;

wire err;

reg[2:0] state;

localparam S_IDLE = 0;

localparam S_WR_I2C_CHECK = 1;

localparam S_WR_I2C = 2;

localparam S_WR_I2C_DONE = 3;

assign done = (state == S_WR_I2C_DONE);

assign i2c_slave_dev_addr = lut_dev_addr;

assign i2c_slave_reg_addr = lut_reg_addr;

assign i2c_write_data = lut_reg_data;

//cascatrix carson

always@(posedge clk or posedge rst)

begin

if(rst)

begin

state <= S_IDLE;

error <= 1'b0;

lut_index <= 8'd0;

end

else

case(state)

S_IDLE:

begin

state <= S_WR_I2C_CHECK;

error <= 1'b0;

lut_index <= 8'd0;

end

S_WR_I2C_CHECK:

begin

if(i2c_slave_dev_addr != 8'hff)

begin

i2c_write_req <= 1'b1;

state <= S_WR_I2C;

end

else

begin

state <= S_WR_I2C_DONE;

end

end

S_WR_I2C:

begin

if(i2c_write_req_ack)

begin

error <= err ? 1'b1 : error;?

lut_index <= lut_index + 8'd1;

i2c_write_req <= 1'b0;

state <= S_WR_I2C_CHECK;

end

end

S_WR_I2C_DONE:

begin

state <= S_WR_I2C_DONE;

end

default:

state <= S_IDLE;

endcase

end

i2c_ctrl i2c_ctrl

(

.rst(rst),

.clk(clk),

.clk_div_cnt(clk_div_cnt),

// I2C signals

// i2c clock line

.scl_pad_i(scl_pad_i), // SCL-line input

.scl_pad_o(scl_pad_o), // SCL-line output (always 1'b0)

.scl_padoen_o(scl_padoen_o), // SCL-line output enable (active low)

// i2c data line

.sda_pad_i(sda_pad_i), // SDA-line input

.sda_pad_o(sda_pad_o), // SDA-line output (always 1'b0)

.sda_padoen_o(sda_padoen_o), // SDA-line output enable (active low)

.i2c_read_req(i2c_read_req),

.i2c_addr_2byte(i2c_addr_2byte),

.i2c_read_req_ack(i2c_read_req_ack),

.i2c_write_req(i2c_write_req),

.i2c_write_req_ack(i2c_write_req_ack),

.i2c_slave_dev_addr(i2c_slave_dev_addr),

.i2c_slave_reg_addr(i2c_slave_reg_addr),

.i2c_write_data(i2c_write_data),

.i2c_read_data(i2c_read_data),

.error(err)

);

endmodule

2. 組幀模塊 (i2c_ctrl):

module i2c_ctrl

(

input rst,

input clk,

input[15:0] clk_div_cnt,

// I2C signals

// i2c clock line

input scl_pad_i, //SCL-line input

output scl_pad_o, //SCL-line output (always 1'b0)

output scl_padoen_o, //SCL-line output enable (active low)

// i2c data line

input sda_pad_i, //SDA-line input

output sda_pad_o, //SDA-line output (always 1'b0)

output sda_padoen_o, //SDA-line output enable (active low)

input i2c_addr_2byte, //register address 16bit or 8bit

input i2c_read_req, //Read register request

output i2c_read_req_ack, //Read register request response

input i2c_write_req, //Write register request

output i2c_write_req_ack, //Write register request response

input[7:0] i2c_slave_dev_addr, //I2c device address

input[15:0] i2c_slave_reg_addr, //I2c register address

input[7:0] i2c_write_data, //I2c write register data

output reg[7:0] i2c_read_data,//I2c read register data

output reg error //The error indication, generally there is no response

);

//State machine definition cascatrix carson

localparam S_IDLE= 0;

localparam S_WR_DEV_ADDR=1;

localparam S_WR_REG_ADDR=2;

localparam S_WR_DATA=3;

localparam S_WR_ACK=4;

localparam S_WR_ERR_NACK=5;

localparam S_RD_DEV_ADDR0=6;

localparam S_RD_REG_ADDR=7;

localparam S_RD_DEV_ADDR1=8;

localparam S_RD_DATA=9;

localparam S_RD_STOP=10;

localparam S_WR_STOP=11;

localparam S_WAIT=12;

localparam S_WR_REG_ADDR1=13;

localparam S_RD_REG_ADDR1=14;

localparam S_RD_ACK=15;

reg start;

reg stop;

reg read;

reg write;

reg ack_in;

reg[7:0] txr;

wire[7:0] rxr;

wire i2c_busy;

wire i2c_al;

wire done;

wire irxack;

reg[3:0] state, next_state;

assign i2c_read_req_ack = (state == S_RD_ACK);

assign i2c_write_req_ack = (state == S_WR_ACK);

always@(posedge clk or posedge rst)

begin

if(rst)

state <= S_IDLE;

else

state <= next_state;? ??

end

always@(*)

begin

case(state)

S_IDLE:

//Waiting for read and write requests

if(i2c_write_req)

next_state <= S_WR_DEV_ADDR;

else if(i2c_read_req)

next_state <= S_RD_DEV_ADDR0;

else

next_state <= S_IDLE;

//Write I2C device address

S_WR_DEV_ADDR:

if(done && irxack)

next_state <= S_WR_ERR_NACK;

else if(done)

next_state <= S_WR_REG_ADDR;

else

next_state <= S_WR_DEV_ADDR;

//Write the address of the I2C register

S_WR_REG_ADDR:

if(done)

//If it is the 8bit register address, it enters the write data state

next_state<=i2c_addr_2byte? S_WR_REG_AD DR1? : S_WR_DATA;

else

next_state <= S_WR_REG_ADDR;

S_WR_REG_ADDR1:

if(done)

next_state <= S_WR_DATA;

else

next_state <= S_WR_REG_ADDR1;?

//Write data

S_WR_DATA:

if(done)

next_state <= S_WR_STOP;

else

next_state <= S_WR_DATA;

S_WR_ERR_NACK:

next_state <= S_WR_STOP;

S_RD_ACK,S_WR_ACK:

next_state <= S_WAIT;

S_WAIT:

next_state <= S_IDLE;

S_RD_DEV_ADDR0:

if(done && irxack)

next_state <= S_WR_ERR_NACK;

else if(done)

next_state <= S_RD_REG_ADDR;

else

next_state <= S_RD_DEV_ADDR0;

S_RD_REG_ADDR:

if(done)

next_state<=i2c_addr_2byte?S_RD_REG_ADDR1 : S_RD_DEV_ADDR1;

else

next_state <= S_RD_REG_ADDR;

S_RD_REG_ADDR1:

if(done)

next_state <= S_RD_DEV_ADDR1;

else

next_state <= S_RD_REG_ADDR1;? ? ? ? ? ? ? ?

S_RD_DEV_ADDR1:

if(done)

next_state <= S_RD_DATA;

else

next_state <= S_RD_DEV_ADDR1;? ?

S_RD_DATA:

if(done)

next_state <= S_RD_STOP;

else

next_state <= S_RD_DATA;

S_RD_STOP:

if(done)

next_state <= S_RD_ACK;

else

next_state <= S_RD_STOP;

S_WR_STOP:

if(done)

next_state <= S_WR_ACK;

else

next_state <= S_WR_STOP;? ? ? ? ? ? ? ??

default:

next_state <= S_IDLE;

endcase

end

always@(posedge clk or posedge rst)

begin

if(rst)

error <= 1'b0;

else if(state == S_IDLE)

error <= 1'b0;

else if(state == S_WR_ERR_NACK)

error <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

start <= 1'b0;

else if(done)

start <= 1'b0;

else if(state == S_WR_DEV_ADDR || state == S_RD_DEV_ADDR0 || state == S_RD_DEV_ADDR1)

start <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

stop <= 1'b0;

else if(done)

stop <= 1'b0;

else if(state == S_WR_STOP || state == S_RD_STOP)

stop <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

ack_in <= 1'b0;

else

ack_in <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

write <= 1'b0;

else if(done)

write <= 1'b0;

else if(state == S_WR_DEV_ADDR || state == S_WR_REG_ADDR || state == S_WR_REG_ADDR1|| state == S_WR_DATA || state == S_RD_DEV_ADDR0 || state == S_RD_DEV_ADDR1 || state == S_RD_REG_ADDR || state == S_RD_REG_ADDR1)

write <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

read <= 1'b0;

else if(done)

read <= 1'b0;

else if(state == S_RD_DATA)

read <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

i2c_read_data <= 8'h00;

else if(state == S_RD_DATA && done)

i2c_read_data <= rxr;

end

always@(posedge clk or posedge rst)

begin

if(rst)

txr <= 8'd0;

else

case(state)

S_WR_DEV_ADDR,S_RD_DEV_ADDR0:

txr <= {i2c_slave_dev_addr[7:1],1'b0};

S_RD_DEV_ADDR1:

txr <= {i2c_slave_dev_addr[7:1],1'b1};

S_WR_REG_ADDR,S_RD_REG_ADDR:

txr<=(i2c_addr_2byte==1'b1)?i2c_slave_reg_addr[15 :8] : i2c_slave_reg_addr[7:0];

S_WR_REG_ADDR1,S_RD_REG_ADDR1:

txr <= i2c_slave_reg_addr[7:0];? ? ? ? ? ? ?

S_WR_DATA:

txr <= i2c_write_data;

default:

txr <= 8'hff;

endcase

end

i2c_byte_ctrl byte_controller (

.clk ( clk ),

.rst ( rst ),

.nReset ( 1'b1 ),

.ena ( 1'b1 ),

.clk_cnt ( clk_div_cnt ),

.start ( start ),

.stop ( stop ),

.read ( read ),

.write ( write ),

.ack_in ( ack_in ),

.din ( txr ),

.cmd_ack ( done ),

.ack_out ( irxack ),

.dout ( rxr ),

.i2c_busy ( i2c_busy ),

.i2c_al ( i2c_al ),

.scl_i ( scl_pad_i ),

.scl_o ( scl_pad_o ),

.scl_oen ( scl_padoen_o ),

.sda_i ( sda_pad_i ),

.sda_o ( sda_pad_o ),

.sda_oen ( sda_padoen_o )

);

endmodule

3. 字節(jié)控制模塊(i2c_byte_ctrl):

`define I2C_CMD_NOP 4'b0000

`define I2C_CMD_START 4'b0001

`define I2C_CMD_STOP 4'b0010

`define I2C_CMD_WRITE 4'b0100

`define I2C_CMD_READ 4'b1000

module i2c_byte_ctrl (

input clk, // master clock

input rst, // synchronous active high reset

input nReset, // asynchronous active low reset

input ena, // core enable signal

input [15:0] clk_cnt, // 4x SCL

// control inputs

input start,

input stop,

input read,

input write,

input ack_in,

input [7:0] din,

// status outputs

output reg cmd_ack,

output regack_out,

output i2c_busy,

output i2c_al,

output [7:0] dout,

// I2C signals

input scl_i,

output scl_o,

output scl_oen,

input sda_i,

output sda_o,

output sda_oen

);

//

// Variable declarations cascatrix carson

//

// statemachine

parameter [4:0] ST_IDLE = 5'b0_0000;

parameter [4:0] ST_START = 5'b0_0001;

parameter [4:0] ST_READ = 5'b0_0010;

parameter [4:0] ST_WRITE = 5'b0_0100;

parameter [4:0] ST_ACK = 5'b0_1000;

parameter [4:0] ST_STOP = 5'b1_0000;

// signals for bit_controller

reg [3:0] core_cmd;

reg core_txd;

wire core_ack, core_rxd;

// signals for shift register

reg [7:0] sr; //8bit shift register

reg shift, ld;

// signals for state machine

wire go;

reg [2:0] dcnt;

wire cnt_done;

// bit_controller

i2c_bit_ctrl bit_controller (

.clk ( clk ),

.rst ( rst ),

.nReset ( nReset ),

.ena ( ena ),

.clk_cnt ( clk_cnt ),

.cmd ( core_cmd ),

.cmd_ack ( core_ack ),

.busy ( i2c_busy ),

.al ( i2c_al ),

.din ( core_txd ),

.dout ( core_rxd ),

.scl_i ( scl_i ),

.scl_o ( scl_o ),

.scl_oen ( scl_oen ),

.sda_i ( sda_i ),

.sda_o ( sda_o ),

.sda_oen ( sda_oen )

);

// generate go-signal

assign go = (read | write | stop) & ~cmd_ack;

// assign dout output to shift-register

assign dout = sr;

// generate shift register

always @(posedge clk or negedge nReset)

if (!nReset)

sr <= #1 8'h0;

else if (rst)

sr <= #1 8'h0;

else if (ld)

sr <= #1 din;

else if (shift)

sr <= #1 {sr[6:0], core_rxd};

// generate counter

always @(posedge clk or negedge nReset)

if (!nReset)

dcnt <= #1 3'h0;

else if (rst)

dcnt <= #1 3'h0;

else if (ld)

dcnt <= #1 3'h7;

else if (shift)

dcnt <= #1 dcnt - 3'h1;

assign cnt_done = ~(|dcnt);

//

// state machine

//

reg [4:0] c_state; // synopsys enum_state

always @(posedge clk or negedge nReset)

if (!nReset)

begin

core_cmd <= #1 `I2C_CMD_NOP;

core_txd <= #1 1'b0;

shift <= #1 1'b0;

ld <= #1 1'b0;

cmd_ack <= #1 1'b0;

c_state <= #1 ST_IDLE;

ack_out <= #1 1'b0;

end

else if (rst | i2c_al)

begin

core_cmd <= #1 `I2C_CMD_NOP;

core_txd <= #1 1'b0;

shift <= #1 1'b0;

ld <= #1 1'b0;

cmd_ack <= #1 1'b0;

c_state <= #1 ST_IDLE;

ack_out <= #1 1'b0;

end

else

begin

// initially reset all signals

core_txd <= #1 sr[7];

shift <= #1 1'b0;

ld <= #1 1'b0;

cmd_ack <= #1 1'b0;

case (c_state) // synopsys full_case parallel_case

ST_IDLE:

if (go)

begin

if (start)

begin

c_state <= #1 ST_START;

core_cmd <= #1 `I2C_CMD_START;

end

else if (read)

begin

c_state <= #1 ST_READ;

core_cmd <= #1 `I2C_CMD_READ;

end

else if (write)

begin

c_state <= #1 ST_WRITE;

core_cmd <= #1 `I2C_CMD_WRITE;

end

else // stop

begin

c_state <= #1 ST_STOP;

core_cmd <= #1 `I2C_CMD_STOP;

end

ld <= #1 1'b1;

end

ST_START:

if (core_ack)

begin

if (read)

begin

c_state <= #1 ST_READ;

core_cmd <= #1 `I2C_CMD_READ;

end

else

begin

c_state <= #1 ST_WRITE;

core_cmd <= #1 `I2C_CMD_WRITE;

end

ld <= #1 1'b1;

end

ST_WRITE:

if (core_ack)

if (cnt_done)

begin

c_state <= #1 ST_ACK;

core_cmd <= #1 `I2C_CMD_READ;

end

else

begin

// stay in same state

c_state <= #1 ST_WRITE;? ? ? ?

// write next bit

core_cmd <= #1 `I2C_CMD_WRITE;?

shift <= #1 1'b1;

end

ST_READ:

if (core_ack)

begin

if (cnt_done)

begin

c_state <= #1 ST_ACK;

core_cmd <= #1 `I2C_CMD_WRITE;

end

else

begin

// stay in same state

c_state <= #1 ST_READ;? ? ? ?

// read next bit

core_cmd <= #1 `I2C_CMD_READ;

end

shift <= #1 1'b1;

core_txd <= #1 ack_in;

end

ST_ACK:

if (core_ack)

begin

if (stop)

begin

c_state <= #1 ST_STOP;

core_cmd <= #1 `I2C_CMD_STOP;

end

else

begin

c_state <= #1 ST_IDLE;

core_cmd <= #1 `I2C_CMD_NOP;

// generate command acknowledge signal

cmd_ack <= #1 1'b1;

end

// assign ack_out output to bit_controller_rxd (contains last received bit)

ack_out <= #1 core_rxd;

core_txd <= #1 1'b1;

end

else

core_txd <= #1 ack_in;

ST_STOP:

if (core_ack)

begin

c_state <= #1 ST_IDLE;

core_cmd <= #1 `I2C_CMD_NOP;

// generate command acknowledge signal

cmd_ack <= #1 1'b1;

end

endcase

end

endmodule

4. bit控制模塊(i2c_bit_ctrl):

`define I2C_CMD_NOP 4'b0000

`define I2C_CMD_START 4'b0001

`define I2C_CMD_STOP 4'b0010

`define I2C_CMD_WRITE 4'b0100

`define I2C_CMD_READ 4'b1000

module i2c_bit_ctrl (

input clk, // system clock

input rst, // synchronous active high reset

input nReset, // asynchronous active low reset

input ena, // core enable signal

input [15:0] clk_cnt, // clock prescale value

input [ 3:0] cmd, // command (from byte controller)

output reg cmd_ack, // command complete acknowledge

output reg busy, // i2c bus busy

output reg al, // i2c bus arbitration lost

input din,

output reg dout,

input scl_i, // i2c clock line input

output scl_o, // i2c clock line output

output reg scl_oen, // i2c clock line output enable (active low)

input sda_i, // i2c data line input

output sda_o, // i2c data line output

output reg sda_oen // i2c data line output enable (active low)

);

//

// variable declarations

//

reg [ 1:0] cSCL, cSDA; // capture SCL and SDA

reg [ 2:0] fSCL, fSDA; // SCL and SDA filter inputs

reg sSCL, sSDA; // filtered and synchronized SCL and SDA inputs

reg dSCL, dSDA; // delayed versions of sSCL and sSDA

reg dscl_oen; // delayed scl_oen

reg sda_chk; // check SDA output (Multi-master arbitration)

reg clk_en; // clock generation signals

reg slave_wait; // slave inserts wait states

reg [15:0] cnt; // clock divider counter (synthesis)

reg [13:0] filter_cnt; // clock divider for filter

// state machine variable

reg [17:0] c_state; // synopsys enum_state

//

// module body

//

// whenever the slave is not ready it can delay the cycle by pulling SCL low

// delay scl_oen

always @(posedge clk)

dscl_oen <= #1 scl_oen;

// slave_wait is asserted when master wants to drive SCL high, but the slave pulls it low

// slave_wait remains asserted until the slave releases SCL

always @(posedge clk or negedge nReset)

if (!nReset) slave_wait <= 1'b0;

else slave_wait <= (scl_oen & ~dscl_oen & ~sSCL) | (slave_wait & ~sSCL);

// master drives SCL high, but another master pulls it low

// master start counting down its low cycle now (clock synchronization)

wire scl_sync = dSCL & ~sSCL & scl_oen;

// generate clk enable signal

always @(posedge clk or negedge nReset)

if (~nReset)

begin

cnt <= #1 16'h0;

clk_en <= #1 1'b1;

end

else if (rst || ~|cnt || !ena || scl_sync)

begin

cnt <= #1 clk_cnt;

clk_en <= #1 1'b1;

end

else if (slave_wait)

begin

cnt <= #1 cnt;

clk_en <= #1 1'b0;? ??

end

else

begin

cnt <= #1 cnt - 16'h1;

clk_en <= #1 1'b0;

end

// generate bus status controller

// capture SDA and SCL

// reduce metastability risk

always @(posedge clk or negedge nReset)

if (!nReset)

begin

cSCL <= #1 2'b00;

cSDA <= #1 2'b00;

end

else if (rst)

begin

cSCL <= #1 2'b00;

cSDA <= #1 2'b00;

end

else

begin

cSCL <= {cSCL[0],scl_i};

cSDA <= {cSDA[0],sda_i};

end

// filter SCL and SDA signals; (attempt to) remove glitches

always @(posedge clk or negedge nReset)

if (!nReset ) filter_cnt <= 14'h0;

else if (rst || !ena ) filter_cnt <= 14'h0;

else if (~|filter_cnt) filter_cnt <= clk_cnt >> 2; //16x I2C bus frequency

else filter_cnt <= filter_cnt -1;

always @(posedge clk or negedge nReset)

if (!nReset)

begin

fSCL <= 3'b111;

fSDA <= 3'b111;

end

else if (rst)

begin

fSCL <= 3'b111;

fSDA <= 3'b111;

end

else if (~|filter_cnt)

begin

fSCL <= {fSCL[1:0],cSCL[1]};

fSDA <= {fSDA[1:0],cSDA[1]};

end

// generate filtered SCL and SDA signals

always @(posedge clk or negedge nReset)

if (~nReset)

begin

sSCL <= #1 1'b1;

sSDA <= #1 1'b1;

dSCL <= #1 1'b1;

dSDA <= #1 1'b1;

end

else if (rst)

begin

sSCL <= #1 1'b1;

sSDA <= #1 1'b1;

dSCL <= #1 1'b1;

dSDA <= #1 1'b1;

end

else

begin

sSCL <= #1 &fSCL[2:1] | &fSCL[1:0] | (fSCL[2] & fSCL[0]);

sSDA <= #1 &fSDA[2:1] | &fSDA[1:0] | (fSDA[2] & fSDA[0]);

dSCL <= #1 sSCL;

dSDA <= #1 sSDA;

end

// detect start condition => detect falling edge on SDA while SCL is high

// detect stop condition => detect rising edge on SDA while SCL is high

reg sta_condition;

reg sto_condition;

always @(posedge clk or negedge nReset)

if (~nReset)

begin

sta_condition <= #1 1'b0;

sto_condition <= #1 1'b0;

end

else if (rst)

begin

sta_condition <= #1 1'b0;

sto_condition <= #1 1'b0;

end

else

begin

sta_condition <= #1 ~sSDA &? dSDA & sSCL;

sto_condition <= #1? sSDA & ~dSDA & sSCL;

end

// generate i2c bus busy signal

always @(posedge clk or negedge nReset)

if (!nReset) busy <= #1 1'b0;

else if (rst ) busy <= #1 1'b0;

else busy <= #1 (sta_condition | busy) & ~sto_condition;

// generate arbitration lost signal cascatrix carson

// aribitration lost when:

// 1) master drives SDA high, but the i2c bus is low

// 2) stop detected while not requested

reg cmd_stop;

always @(posedge clk or negedge nReset)

if (~nReset)

cmd_stop <= #1 1'b0;

else if (rst)

cmd_stop <= #1 1'b0;

else if (clk_en)

cmd_stop <= #1 cmd == `I2C_CMD_STOP;

always @(posedge clk or negedge nReset)

if (~nReset)

al <= #1 1'b0;

else if (rst)

al <= #1 1'b0;

else

al <= #1 (sda_chk & ~sSDA & sda_oen) | (|c_state & sto_condition & ~cmd_stop);

// generate dout signal (store SDA on rising edge of SCL) cascatrix carson

always @(posedge clk)

if (sSCL & ~dSCL) dout <= #1 sSDA;

// generate statemachine cascatrix carson

// nxt_state decoder

parameter [17:0] idle = 18'b0_0000_0000_0000_0000;

parameter [17:0] start_a = 18'b0_0000_0000_0000_0001;

parameter [17:0] start_b = 18'b0_0000_0000_0000_0010;

parameter [17:0] start_c = 18'b0_0000_0000_0000_0100;

parameter [17:0] start_d = 18'b0_0000_0000_0000_1000;

parameter [17:0] start_e = 18'b0_0000_0000_0001_0000;

parameter [17:0] stop_a = 18'b0_0000_0000_0010_0000;

parameter [17:0] stop_b = 18'b0_0000_0000_0100_0000;

parameter [17:0] stop_c = 18'b0_0000_0000_1000_0000;

parameter [17:0] stop_d = 18'b0_0000_0001_0000_0000;

parameter [17:0] rd_a = 18'b0_0000_0010_0000_0000;

parameter [17:0] rd_b = 18'b0_0000_0100_0000_0000;

parameter [17:0] rd_c = 18'b0_0000_1000_0000_0000;

parameter [17:0] rd_d = 18'b0_0001_0000_0000_0000;

parameter [17:0] wr_a = 18'b0_0010_0000_0000_0000;

parameter [17:0] wr_b = 18'b0_0100_0000_0000_0000;

parameter [17:0] wr_c = 18'b0_1000_0000_0000_0000;

parameter [17:0] wr_d = 18'b1_0000_0000_0000_0000;

always @(posedge clk or negedge nReset)

if (!nReset)

begin

c_state <= #1 idle;

cmd_ack <= #1 1'b0;

scl_oen <= #1 1'b1;

sda_oen <= #1 1'b1;

sda_chk <= #1 1'b0;

end

else if (rst | al)

begin

c_state <= #1 idle;

cmd_ack <= #1 1'b0;

scl_oen <= #1 1'b1;

sda_oen <= #1 1'b1;

sda_chk <= #1 1'b0;

end

else

begin

// default no command acknowledge + assert cmd_ack only 1clk cycle

cmd_ack <= #1 1'b0;?

if (clk_en)// synopsys full_case parallel_case

case (c_state)

// idle state

idle:

begin// synopsys full_case parallel_case

case (cmd)

`I2C_CMD_START: c_state <= #1 start_a;

`I2C_CMD_STOP: c_state <= #1 stop_a;

`I2C_CMD_WRITE: c_state <= #1 wr_a;

`I2C_CMD_READ: c_state <= #1 rd_a;

default: c_state <= #1 idle;

endcase

// keep SCL in same state

scl_oen <= #1 scl_oen;?

// keep SDA in same state

sda_oen <= #1 sda_oen;

// don't check SDA output

sda_chk <= #1 1'b0;? ??

end

// start

start_a:

begin

c_state <= #1 start_b;

// keep SCL in same state

scl_oen <= #1 scl_oen;?

sda_oen <= #1 1'b1;? ? // set SDA high

// don't check SDA output

sda_chk <= #1 1'b0;? ??

end

start_b:

begin

c_state <= #1 start_c;

scl_oen <= #1 1'b1; // set SCL high

sda_oen <= #1 1'b1; // keep SDA high

// don't check SDA output

sda_chk <= #1 1'b0;?

end

start_c:

begin

c_state <= #1 start_d;

scl_oen <= #1 1'b1; // keep SCL high

sda_oen <= #1 1'b0; // set SDA low

// don't check SDA output

sda_chk <= #1 1'b0;?

end

start_d:

begin

c_state <= #1 start_e;

scl_oen <= #1 1'b1; // keep SCL high

sda_oen <= #1 1'b0; // keep SDA low

// don't check SDA output

sda_chk <= #1 1'b0;?

end

start_e:

begin

c_state <= #1 idle;

cmd_ack <= #1 1'b1;

scl_oen <= #1 1'b0; // set SCL low

sda_oen <= #1 1'b0; // keep SDA low

// don't check SDA output

sda_chk <= #1 1'b0;?

end

// stop

stop_a:

begin

c_state <= #1 stop_b;

scl_oen <= #1 1'b0; // keep SCL low

sda_oen <= #1 1'b0; // set SDA low

// don't check SDA output

sda_chk <= #1 1'b0;?

end

stop_b:

begin

c_state <= #1 stop_c;

scl_oen <= #1 1'b1; // set SCL high

sda_oen <= #1 1'b0; // keep SDA low

// don't check SDA output

sda_chk <= #1 1'b0;?

end

stop_c:

begin

c_state <= #1 stop_d;

scl_oen <= #1 1'b1; // keep SCL high

sda_oen <= #1 1'b0; // keep SDA low

// don't check SDA output

sda_chk <= #1 1'b0;?

end

stop_d:

begin

c_state <= #1 idle;

cmd_ack <= #1 1'b1;

scl_oen <= #1 1'b1; // keep SCL high

sda_oen <= #1 1'b1; // set SDA high

// don't check SDA output

sda_chk <= #1 1'b0;?

end

// read

rd_a:

begin

c_state <= #1 rd_b;

scl_oen <= #1 1'b0; // keep SCL low

sda_oen <= #1 1'b1; // tri-state SDA

// don't check SDA output

sda_chk <= #1 1'b0;?

end

rd_b:

begin

c_state <= #1 rd_c;

scl_oen <= #1 1'b1; // set SCL high

sda_oen <= #1 1'b1; // keep SDA tri-stated

// don't check SDA output

sda_chk <= #1 1'b0;?

end

rd_c:

begin

c_state <= #1 rd_d;

scl_oen <= #1 1'b1; // keep SCL high

sda_oen <= #1 1'b1; // keep SDA tri-stated

// don't check SDA output

sda_chk <= #1 1'b0;

end

rd_d:

begin

c_state <= #1 idle;

cmd_ack <= #1 1'b1;

scl_oen <= #1 1'b0; // set SCL low

sda_oen <= #1 1'b1; // keep SDA tri-stated

// don't check SDA output

sda_chk <= #1 1'b0;?

end

// write

wr_a:

begin

c_state <= #1 wr_b;

scl_oen <= #1 1'b0; // keep SCL low

sda_oen <= #1 din;? // set SDA

// don't check SDA output (SCL low)

sda_chk <= #1 1'b0;?

end

wr_b:

begin

c_state <= #1 wr_c;

scl_oen <= #1 1'b1; // set SCL high

sda_oen <= #1 din;? // keep SDA

// don't check SDA output yet

sda_chk <= #1 1'b0;?

// allow some time for SDA and SCL to settle

end

wr_c:

begin

c_state <= #1 wr_d;

scl_oen <= #1 1'b1; // keep SCL high

sda_oen <= #1 din;

sda_chk <= #1 1'b1; // check SDA output

end

wr_d:

begin

c_state <= #1 idle;

cmd_ack <= #1 1'b1;

scl_oen <= #1 1'b0; // set SCL low

sda_oen <= #1 din;

sda_chk <= #1 1'b0; // don't check SDA output (SCL low)

end

endcase

end

// assign scl and sda output (always gnd)

assign scl_o = 1'b0;

assign sda_o = 1'b0;

endmodule

04

IIC的優(yōu)缺點(diǎn)

4.1 IIC協(xié)議優(yōu)點(diǎn)

1. 通信只需要兩條信號(hào)線;

2. 多主設(shè)備結(jié)構(gòu)下,總線系統(tǒng)無需額外的邏輯與線路;

3. 應(yīng)答機(jī)制完善,通信傳輸穩(wěn)定。

4.2 IIC協(xié)議缺點(diǎn)

1. 硬件結(jié)構(gòu)復(fù)雜;

2. 支持傳輸距離較短;

3. 半雙工速率慢于全雙工,SPI全雙工一般可實(shí)現(xiàn)10Mbps以上的傳輸速率,IIC最高速度僅能達(dá)到3.4Mbps。








審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 上拉電阻
    +關(guān)注

    關(guān)注

    5

    文章

    360

    瀏覽量

    30621
  • IIC總線
    +關(guān)注

    關(guān)注

    1

    文章

    66

    瀏覽量

    20304
  • SDA
    SDA
    +關(guān)注

    關(guān)注

    0

    文章

    124

    瀏覽量

    28134
  • SCL
    SCL
    +關(guān)注

    關(guān)注

    1

    文章

    239

    瀏覽量

    17081

原文標(biāo)題:常用串行總線(三)——IIC協(xié)議(Verilog實(shí)現(xiàn))

文章出處:【微信號(hào):Carlinx FPGA,微信公眾號(hào):Carlinx FPGA】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    FPGA實(shí)現(xiàn)IIC協(xié)議的設(shè)計(jì)

    今天給大家?guī)淼氖?b class='flag-5'>IIC通信,IIC協(xié)議應(yīng)用非常廣泛,例如與MPU6050進(jìn)行通信,配置OV5640攝像頭、驅(qū)動(dòng)OLED屏幕等等,都需要使用到IIC
    的頭像 發(fā)表于 03-04 10:49 ?1268次閱讀
    FPGA<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>IIC</b><b class='flag-5'>協(xié)議</b>的設(shè)計(jì)

    用verilog實(shí)現(xiàn)IIC。

    我想用verilog實(shí)現(xiàn)一個(gè)控制AT24C08讀寫的IIC協(xié)議的狀態(tài)機(jī),現(xiàn)在出現(xiàn)了一個(gè)很奇怪的問題,我的狀態(tài)機(jī)在功能仿真時(shí)可以實(shí)現(xiàn)讀寫,但下到芯片里卻發(fā)現(xiàn)不成功。特此求教大家,望大家不
    發(fā)表于 01-29 11:18

    IIc 協(xié)議及VHDL代碼實(shí)現(xiàn)

    位在前。3.2.2位時(shí)序和實(shí)現(xiàn)3.2.2.1IIC的通信協(xié)議:主機(jī)和從機(jī)在 iic總線上通信的時(shí)候, 它們之間有用類似 “ hello” ( 起始信號(hào))和 “ Goodbye”(結(jié)束信
    發(fā)表于 04-07 13:12

    spi,uart,iic協(xié)議之間的對(duì)比

    spi,uart,iic協(xié)議之間的對(duì)比:spi和uart的區(qū)別,spi結(jié)構(gòu)上可以實(shí)現(xiàn)一主多從進(jìn)行通信,依靠時(shí)鐘進(jìn)行傳輸數(shù)據(jù)的同步傳輸模式。S
    發(fā)表于 08-19 08:41

    IIC協(xié)議總線特點(diǎn)簡(jiǎn)介

    IIC協(xié)議簡(jiǎn)介I2C 通訊協(xié)議(Inter-Integrated Circuit)是由Phiilps公司開發(fā)的,由于它引腳少,硬件實(shí)現(xiàn)簡(jiǎn)單,可擴(kuò)展性強(qiáng),不需要USART、CAN等通訊
    發(fā)表于 08-20 06:12

    STM32的IIC協(xié)議簡(jiǎn)介

    、地址及數(shù)據(jù)方向4.5、響應(yīng)(五)STM32的IIC特性及架構(gòu)5.1、STM32的IIC外設(shè)簡(jiǎn)介5.2、STM32的IIC架構(gòu)剖析5.3、通信過程IIC
    發(fā)表于 01-05 06:13

    IIC協(xié)議原理是什么

    連接微控制器以及其外圍設(shè)備,IIC也被成為I2C,其實(shí)兩者是完全相同的,只是名詞不一樣而已。它是由數(shù)據(jù)線SDA和時(shí)鐘線SCL構(gòu)成的串行總線,可發(fā)送和接收數(shù)據(jù)。IIC特點(diǎn):①數(shù)據(jù)線SDA:數(shù)據(jù)線用來
    發(fā)表于 01-06 06:23

    IIC協(xié)議的相關(guān)資料推薦

    STM32 IIC實(shí)驗(yàn)講解,從入門到放棄。文章目錄STM32 IIC實(shí)驗(yàn)講解,從入門到放棄。前言一、IICIIC是什么?IIC協(xié)議二、代碼
    發(fā)表于 01-17 08:12

    IIC協(xié)議軟件模擬方法

    關(guān)于iic協(xié)議和對(duì)AT24C16進(jìn)行讀寫數(shù)據(jù)的代碼解讀認(rèn)識(shí)IIC協(xié)議IIC
    發(fā)表于 02-09 07:00

    介紹IIC通信協(xié)議以及代碼開發(fā)的注意事項(xiàng)

    FPGA IIC接口通信本文介紹IIC通信協(xié)議以及代碼開發(fā)的注意事項(xiàng),跑通了IIC協(xié)議,那么后續(xù)
    發(fā)表于 02-16 07:24

    如何使用代碼實(shí)現(xiàn)IIC協(xié)議

    1. 綜述  由上篇博客可知道IIC協(xié)議如何用代碼實(shí)現(xiàn),本篇博客就不涉及協(xié)議內(nèi)容,只講解如何使用?! ”敬蔚膶?shí)驗(yàn)傳感為:DS3231(時(shí)鐘模
    發(fā)表于 02-21 06:36

    IIC通信以及AT24C02使用

    文章目錄1.什么是通信協(xié)議①什么是IIC協(xié)議IIC協(xié)議原理講解③IIC
    發(fā)表于 11-30 20:51 ?15次下載
    <b class='flag-5'>IIC</b>通信以及AT24C02使用

    關(guān)于iic協(xié)議和對(duì)AT24C02進(jìn)行讀寫數(shù)據(jù)的理解和代碼解讀

    關(guān)于iic協(xié)議和對(duì)AT24C16進(jìn)行讀寫數(shù)據(jù)的代碼解讀認(rèn)識(shí)IIC協(xié)議IIC
    發(fā)表于 12-05 16:36 ?8次下載
    關(guān)于<b class='flag-5'>iic</b><b class='flag-5'>協(xié)議</b>和對(duì)AT24C02進(jìn)行讀寫數(shù)據(jù)的理解和<b class='flag-5'>代碼</b>解讀

    3行代碼實(shí)現(xiàn)單片機(jī)IIc通信

    文章目錄前言一、實(shí)現(xiàn)功能二、接線圖三、完整代碼四、代碼運(yùn)行效果前言shineblink core 開發(fā)板(簡(jiǎn)稱Core)的庫(kù)函數(shù)支持IIc通信功能,所以只需要調(diào)用兩三個(gè)API,即可
    發(fā)表于 12-20 19:19 ?1次下載
    3行<b class='flag-5'>代碼</b><b class='flag-5'>實(shí)現(xiàn)</b>單片機(jī)<b class='flag-5'>IIc</b>通信

    詳解物聯(lián)網(wǎng)常用協(xié)議IIC和RS485通信協(xié)議

    科技常用的兩種通信協(xié)議——IIC和RS485。IIC通信協(xié)議是一種半雙工通信協(xié)議,雙總線串行,主要用在主機(jī)和從機(jī)對(duì)于數(shù)據(jù)量較少且
    的頭像 發(fā)表于 03-02 17:12 ?1466次閱讀
    詳解物聯(lián)網(wǎng)常用<b class='flag-5'>協(xié)議</b>:<b class='flag-5'>IIC</b>和RS485通信<b class='flag-5'>協(xié)議</b>