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)缺點
4.1 IIC協(xié)議優(yōu)點
4.2 IIC協(xié)議缺點
- 硬件結構復雜;
- 支持傳輸距離較短;
- 半雙工速率慢于全雙工,SPI全雙工一般可實現(xiàn)10Mbps以上的傳輸速率,IIC最高速度僅能達到3.4Mbps。
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。
舉報投訴
-
IIC
+關注
關注
11文章
302瀏覽量
38542 -
通信總線
+關注
關注
0文章
45瀏覽量
9893 -
SDA
+關注
關注
0文章
124瀏覽量
28282
發(fā)布評論請先 登錄
相關推薦
一文詳解IIC總線
IIC(Inter-Integrated Circuit)集成電路總線,它是一種兩線式串行通信總線,又叫I2C,使用多主從架構,由飛利浦公司
發(fā)表于 06-07 15:38
?1w次閱讀
![<b class='flag-5'>一</b><b class='flag-5'>文</b>詳解<b class='flag-5'>IIC</b><b class='flag-5'>總線</b>](https://file1.elecfans.com//web2/M00/89/4C/wKgaomSAM-aARtvuAAJwA-mo2z0756.jpg)
一文詳解IIC總線
IIC(Inter-Integrated Circuit)是一個多主從的串行總線,又叫I2C,是由飛利浦公司發(fā)明的通訊總線,屬于半雙工同步傳
發(fā)表于 09-12 11:15
?2393次閱讀
![<b class='flag-5'>一</b><b class='flag-5'>文</b>詳解<b class='flag-5'>IIC</b><b class='flag-5'>總線</b>](https://file1.elecfans.com/web2/M00/A2/98/wKgZomT_17OAfMeuAAC3OX_IP-s899.png)
常用的串行總線協(xié)議有哪些
一、常用的串行總線協(xié)議目前常用的微機與外設之間進行數(shù)據傳輸?shù)?b class='flag-5'>
發(fā)表于 11-03 07:14
IIC總線協(xié)議的相關資料下載
(串行數(shù)據線)和SCL(串行時鐘線)及上拉電阻組成。通信原理是通過對SCL和SDA線高低電平時序的控制,來 產生I2C總線協(xié)議所需要的信號進行數(shù)據的傳遞。在
發(fā)表于 11-30 08:29
IIC協(xié)議的相關資料推薦
STM32 IIC實驗講解,從入門到放棄。文章目錄STM32 IIC實驗講解,從入門到放棄。前言一、IICIIC是什么?IIC協(xié)議二、代碼部
發(fā)表于 01-17 08:12
IIC總線接口學習
在多主設備IIC 總線模式下,多個S3C2440A 微處理器可以從從屬設備接收或發(fā)送串行數(shù)據。主設備S3C2440A 可以初始化和終止
發(fā)表于 04-27 15:31
?61次下載
![<b class='flag-5'>IIC</b><b class='flag-5'>總線</b>接口學習](https://file.elecfans.com/web2/M00/49/59/pYYBAGKhtEeAAD0fAAANAuHGrgk379.jpg)
FPGA基礎知識之IIC協(xié)議讀寫解析
很多數(shù)字傳感器、數(shù)字控制的芯片(DDS、串行ADC、串行DAC)都是通過IIC總線來和控制器通信的。不過IIC
發(fā)表于 05-05 10:17
?8311次閱讀
![FPGA基礎知識<b class='flag-5'>之</b><b class='flag-5'>IIC</b><b class='flag-5'>協(xié)議</b>讀寫解析](https://file.elecfans.com/web1/M00/50/23/pIYBAFrtI2iADxYeAAAf8ue__p4874.png)
IIC總線協(xié)議及應用
(串行數(shù)據線)和SCL(串行時鐘線)及上拉電阻組成。通信原理是通過對SCL和SDA線高低電平時序的控制,來 產生I2C總線協(xié)議所需要的信號進行數(shù)據的傳遞。在
發(fā)表于 11-20 15:21
?10次下載
![<b class='flag-5'>IIC</b><b class='flag-5'>總線</b><b class='flag-5'>協(xié)議</b>及應用](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
一文帶你迅速了解常用串行總線之IIC協(xié)議2
集成電路總線** (Inter-Intergrated Circuit),通常稱作IICBUS,簡稱為IIC,是一種采用多主從結構的串行通信總線
評論