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)。
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ù)幀格式如下:
白色為主機(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ù)幀格式如下:
白色為主機(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ù)幀格式如下:
白色為主機(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í)序過程:
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í)序過程:
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í)序過程:
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í)序過程:
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í)序過程:
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í)序過程:
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í)序過程:
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í)序過程:
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。
審核編輯:劉清
-
上拉電阻
+關(guān)注
關(guān)注
5文章
360瀏覽量
30621 -
IIC總線
+關(guān)注
關(guān)注
1文章
66瀏覽量
20304 -
SDA
+關(guān)注
關(guān)注
0文章
124瀏覽量
28134 -
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)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論