📄 i2c.v
字号:
//I2C interface
module i2c (
clock,
reset_n,
scl,
sda,
no_ack,
ready,
data_in,
data_out,
sa,
rw,
ra,
ini
);
input clock;
input reset_n;
output scl;
inout sda;
output no_ack;
output ready;
input [7:0] data_in;
output [7:0] data_out;
input [6:0] sa;//slave address
input rw;//1---R; 0---W
input [7:0] ra;//register address
input ini;
reg ready;
reg scl_oe;
reg sda_oe;
wire sda_in;
reg sda_out;
reg no_ack;
reg [7:0] data_out;
reg [30:0] sda_write_reg;
reg [41:0] sda_read_reg;
reg [5:0] sda_count;
reg clk_scl;
reg clk_sda;
reg ini_dly;
reg ini_m_dly;
/******************************************************************************/
assign scl = (scl_oe) ? clk_scl : 1'b1;
assign sda = (sda_oe) ? sda_out : 1'bz;
assign sda_in = (!sda_oe) ? sda : 1'b0;
/******************************************************************************/
always @(posedge ini or posedge clk_sda or negedge reset_n) //ini_m_dly <= ini;
begin
if(!reset_n) ini_m_dly <= 1'b0;
else if(ini) ini_m_dly <= 1'b1;
else ini_m_dly <= 1'b0;
end
always @(posedge clk_sda) ini_dly <= ini_m_dly;
//注意:接收到ini信号后要过约4us操作才真正开始(Ready=0)
/******************************************************************************/
/******************************************************************************/
//sda_out state machine
reg [2:0] cstate;
parameter [2:0]
IDLE = 3'b001,
READ = 3'b010,
WRITE = 3'b100;
////////////////////////////////////////////////////////////////////////////////
always @(posedge clk_sda or negedge reset_n)
begin
if(!reset_n)
begin
cstate <= IDLE;
ready <= 1'b0;
sda_oe <= 1'b0;
sda_out <= 1'b0;
sda_write_reg <= 31'b0;
sda_read_reg <= 42'b0;
sda_count <= 6'b0;
end
else
begin
case(cstate)
IDLE:
begin
sda_count <= 6'b0;
sda_oe <= 1'b1;
sda_out <= 1'bz;
if(ini_dly && rw)
begin
cstate <= READ;
ready <= 1'b0;
sda_read_reg <= {2'b10, /*start*/
sa[6:0], /*slave address*/
1'b0, /*write*/
1'bz, /*ack*/
ra[7:0], /*register address*/
1'bz, /*ack*/
2'b10, /*start*/
sa[6:0], /*slave address*/
1'b1, /*read*/
1'bz, /*ack*/
8'bzzzzzzzz, /*data*/
1'b0, /*/ack*/
2'b01 /*stop*/
}; /*42 bits*/
end
else if(ini_dly && !rw)
begin
cstate <= WRITE;
ready <= 1'b0;
sda_write_reg <= {2'b10, /*start*/
sa[6:0], /*slave address*/
1'b0, /*write*/
1'bz, /*ack*/
ra[7:0], /*register address*/
1'bz, /*ack*/
data_in[7:0], /*data*/
1'bz, /*ack*/
2'b01 /*stop*/
}; /*31 bits*/
end
else
begin
ready <= 1'b1;
cstate <= IDLE;
end
end
READ:
begin
if(sda_count <= 41)
begin
cstate <= READ;
sda_out <= sda_read_reg[41];
sda_read_reg <= sda_read_reg << 1;
sda_oe <= (sda_count == 10
|| sda_count == 19
|| (sda_count >= 30 && sda_count <= 38))
? 1'b0 : 1'b1;
sda_count <= sda_count + 1;
end
else
cstate <= IDLE;
end
WRITE:
begin
if(sda_count <= 30)
begin
cstate <= WRITE;
sda_out <= sda_write_reg[30];
sda_write_reg <= sda_write_reg << 1;
sda_oe <= (sda_count == 10
|| sda_count == 19
|| sda_count == 28)
? 1'b0 :1'b1;
sda_count <= sda_count + 1;
end
else
cstate <= IDLE;
end
default: cstate <= IDLE;
endcase
end
end
/******************************************************************************/
//sda_in state machine
reg [2:0] cstate_1;
parameter [2:0]
IDLE_1 = 3'b001,
READ_1 = 3'b010,
WRITE_1 = 3'b100;
////////////////////////////////////////////////////////////////////////////////
always @(posedge clk_scl or negedge reset_n)
begin
if(!reset_n)
begin
cstate_1 <= IDLE_1;
scl_oe <= 1'b0;
data_out <= 8'b0;
no_ack <= 1'b0;
end
else
begin
case(cstate_1)
IDLE_1:
begin
scl_oe <= 1'b0;
if(ini_dly && rw)
begin
cstate_1 <= READ_1;
no_ack <= 1'b0;
end
else if(ini_dly && !rw)
begin
cstate_1 <= WRITE_1;
no_ack <= 1'b0;
end
else
begin
cstate_1 <= IDLE_1;
end
end
READ_1:
begin
if(sda_count <= 41)
begin
cstate_1 <= READ_1;
scl_oe <= ((sda_count >= 2 && sda_count <= 20)
|| (sda_count >= 22 && sda_count <= 40))
? 1'b1 : 1'b0;
if(sda_count == 11 || sda_count == 20
|| sda_count == 31)
no_ack <= no_ack || sda_in;
if(sda_count >= 31 && sda_count <= 39)
data_out[7:0] <= {data_out[6:0] , sda_in};
end
else
cstate_1 <= IDLE_1;
end
WRITE_1:
begin
if(sda_count <= 30)
begin
cstate_1 <= WRITE_1;
scl_oe <= (sda_count >= 2 && sda_count <= 29)
? 1'b1 : 1'b0;
if(sda_count == 11 || sda_count == 20
|| sda_count == 29)
no_ack <= no_ack || sda_in;
end
else
cstate_1 <= IDLE_1;
end
default: cstate_1 <= IDLE_1;
endcase
end
end
/******************************************************************************/
//Counter
//clk_scl & clk_sda
reg [6:0] counter;
always @ (posedge clock or negedge reset_n)
begin
if(!reset_n)
begin
counter <= 7'b0;
clk_sda <= 1'b0;
clk_scl <= 1'b0;
end
else
begin
counter <= counter + 1;
if(counter[5:0] == 6'b10_0000)
clk_sda <= ~ clk_sda;
if(counter[5:0] == 6'b11_1111)
clk_scl <= ~ clk_scl;
end
end
/*
f(clk_sda , clk_scl)=f(clock)/128 =33MHz/128=260KHz
___ ___ ___ ___ ___ ___ ___
clk_scl ___| |___| |___| |___| |___| |___| |___| |___
___ ___ ___ ___ ___ ___ ___
clk_sda _| |___| |___| |___| |___| |___| |___| |___
*/
/******************************************************************************/
/******************************************************************************/
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -