📄 i2c_slv_ctrl.v
字号:
module i2c_slv_ctrl(rst,
clk,
dev_addr,
scl,
sda,
dat_in,
dat_out,
wr,
rd,
reg_addr,
busy,
i2c_s,
i2c_p,
pos);
input rst,clk;
input [6:0] dev_addr;
input scl;
inout sda;
input [7:0]dat_in;
input busy;
output wr,rd;
output [7:0]reg_addr;
output [7:0]dat_out;
output i2c_s,i2c_p;
output [7:0]pos;
parameter I2C_STA_P = 3'd0;
parameter I2C_STA_S = 3'd1;
parameter I2C_STA_AACK = 3'd2;
parameter I2C_STA_RACK = 3'd3;
parameter I2C_STA_WACK = 3'd4;
parameter I2C_STA_A = 3'd5;
parameter I2C_STA_WD = 3'd6;
parameter I2C_STA_RD = 3'd7;
reg scl_dir; //scl方向控制,1输入,0输出
reg sda_dir; //sda方向控制,1输入,0输出
reg scl_r;
reg sda_r;
reg _scl,__scl,___scl,_sda,__sda,___sda;
assign sda = sda_dir ? 1'bz : sda_r;
reg [2:0] i2c_sta;
reg [2:0] bit_pos;
reg i2c_rw; //1:r,0:w
reg [6:0] addr;
reg [7:0] dat_out;
reg [7:0] reg_addr;
reg [7:0] pos;
reg rd,_wr,wr;
wire i2c_s = ___scl && __scl && _scl && ___sda && !__sda && !_sda ;
wire i2c_p = ___scl && __scl && _scl && !___sda &&__sda && _sda;
wire scl_up = !___scl && __scl && _scl;
wire scl_down = ___scl && !__scl && !_scl;
//reg i2c_s,i2c_p,scl_up,scl_down;
always@(posedge clk)
begin
_scl <= scl;
_sda <= sda;
__scl <= _scl;
__sda <= _sda;
___scl <= __scl;
___sda <= __sda;
end
always@(posedge clk)
begin
if(rst)
i2c_sta <= I2C_STA_P;
else begin
if(i2c_s && i2c_sta == I2C_STA_P) //i2c开始
i2c_sta <= I2C_STA_S;
else if(i2c_p) //i2c停止
i2c_sta <= I2C_STA_P;
else if(scl_down) begin //scl下降延
case(i2c_sta)
I2C_STA_S:begin
i2c_sta <= I2C_STA_A;
end
I2C_STA_A: begin
if(bit_pos == 0)
if(addr[6:0] == dev_addr)
i2c_sta <= I2C_STA_AACK;
else
i2c_sta <= I2C_STA_P;
end
I2C_STA_AACK: begin
i2c_sta <= i2c_rw ? I2C_STA_RD : I2C_STA_WD;
end
I2C_STA_RD: begin
if(bit_pos == 0)
i2c_sta <= I2C_STA_RACK;
end
I2C_STA_RACK: begin
if(i2c_rw)
i2c_sta <= I2C_STA_RD;
else
i2c_sta <= I2C_STA_P;
end
I2C_STA_WD: begin
if(bit_pos == 0)
i2c_sta <= I2C_STA_WACK;
end
I2C_STA_WACK:begin
i2c_sta <= I2C_STA_WD;
end
default:
i2c_sta <= I2C_STA_P;
endcase
end
end
end
always@(posedge clk)
begin
/*
if(i2c_sta == I2C_STA_S && scl_down)
bit_pos <= 7;
else if(scl_up && (i2c_sta == I2C_STA_A || i2c_sta == I2C_STA_WD))
bit_pos <= bit_pos - 1;
else if(scl_down && (i2c_sta == I2C_STA_RD))
bit_pos <= bit_pos - 1;
*/
if(scl_down)
if(i2c_sta == I2C_STA_S)
bit_pos <= 7;
else if(i2c_sta == I2C_STA_A
|| i2c_sta == I2C_STA_WD
|| i2c_sta == I2C_STA_RD)
bit_pos <= bit_pos - 1;
end
always@(posedge clk)
begin
rd <= 0;
_wr <= 0;
sda_r <= 1;
sda_dir <= 1;
case(i2c_sta)
I2C_STA_S:
if(scl_down)
pos <= 0;
I2C_STA_A:
if(scl_up)
if(bit_pos == 0)
i2c_rw <= sda;
else
addr[bit_pos-1] <= sda;
I2C_STA_WD:
if(scl_up) begin
dat_out[bit_pos] <= sda;
if(bit_pos == 0) begin
_wr <= 1;
end
end
I2C_STA_RD: begin
sda_r <= dat_in[bit_pos];
sda_dir <= 0;
end
I2C_STA_AACK: begin
sda_r <= busy;
sda_dir <= 0;
if(i2c_rw && scl_up)
rd <= 1;
end
I2C_STA_RACK: begin
if(scl_up) begin
pos <= pos + 1;
rd <= ~_sda;
i2c_rw <= ~_sda;
end
end
I2C_STA_WACK: begin
sda_r <= busy;
sda_dir <= 0;
if(scl_up)
pos <= pos + 1;
end
endcase
end
always@(posedge clk)
begin
wr <= 0;
if(_wr)
if(pos == 0)
reg_addr <= dat_out;
else
wr <= 1;
end
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -