|
|
|
@ -1,253 +0,0 @@
|
|
|
|
|
module i2c_ctrl(
|
|
|
|
|
input wire sys_clk ,
|
|
|
|
|
input wire sys_rst_n ,
|
|
|
|
|
|
|
|
|
|
output wire scl ,
|
|
|
|
|
inout wire sda
|
|
|
|
|
|
|
|
|
|
);
|
|
|
|
|
parameter I2C_CLK_DIV = 5'd24,
|
|
|
|
|
MAX = 10'd1000,
|
|
|
|
|
SLAVE_ID = 7'h73;
|
|
|
|
|
//状态机参数定义
|
|
|
|
|
parameter IDLE = 3'd0,
|
|
|
|
|
START = 3'd1,
|
|
|
|
|
SLAVE_ADDR= 3'd2,
|
|
|
|
|
WAIT = 3'd3,
|
|
|
|
|
STOP = 3'd4;
|
|
|
|
|
reg [2: 0] state_c;
|
|
|
|
|
reg [2: 0] state_n;
|
|
|
|
|
////
|
|
|
|
|
|
|
|
|
|
//i2c时钟计数器
|
|
|
|
|
reg [4: 0] cnt_clk;
|
|
|
|
|
reg i2c_clk;
|
|
|
|
|
/////
|
|
|
|
|
|
|
|
|
|
//中间信号定义
|
|
|
|
|
reg [9: 0] cnt_wait ;//1000us
|
|
|
|
|
reg skip_en_1 ;//跳转信号
|
|
|
|
|
reg [2: 0] step ;//步骤
|
|
|
|
|
reg [1: 0] cnt_i2c_clk ;//
|
|
|
|
|
reg [2: 0] cnt_bit ;//bit计数器
|
|
|
|
|
reg i2c_end ;//i2c结束信号
|
|
|
|
|
wire sda_en ;
|
|
|
|
|
wire sda_in ;
|
|
|
|
|
reg i2c_sda ;
|
|
|
|
|
reg i2c_scl ;
|
|
|
|
|
reg [7: 0] slave_addr ;
|
|
|
|
|
reg [7: 0] device_addr ;
|
|
|
|
|
reg [7: 0] wr_data ;
|
|
|
|
|
//三态门
|
|
|
|
|
assign sda_en = 1'b1;//主机控制从机
|
|
|
|
|
assign sda_in = sda;
|
|
|
|
|
assign sda = (sda_en == 1'b1)? i2c_sda : 1'bz;
|
|
|
|
|
//i2c驱动时钟设计
|
|
|
|
|
always @(posedge sys_clk or negedge sys_rst_n) begin
|
|
|
|
|
if(!sys_rst_n)begin
|
|
|
|
|
cnt_clk <= 5'd0;
|
|
|
|
|
end
|
|
|
|
|
else if(cnt_clk == I2C_CLK_DIV)begin
|
|
|
|
|
cnt_clk <= 5'd0;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
cnt_clk <= cnt_clk + 1;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
always @(posedge sys_clk or negedge sys_rst_n) begin
|
|
|
|
|
if(!sys_rst_n)begin
|
|
|
|
|
i2c_clk <= 1'b1;
|
|
|
|
|
end
|
|
|
|
|
else if(cnt_clk == I2C_CLK_DIV)begin
|
|
|
|
|
i2c_clk <= ~i2c_clk;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
i2c_clk <= i2c_clk;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
/////////
|
|
|
|
|
//状态机,第一段
|
|
|
|
|
always @(posedge sys_clk or negedge sys_rst_n) begin
|
|
|
|
|
if(!sys_rst_n)begin
|
|
|
|
|
state_c <= IDLE;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
state_c <= state_n;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
//状态机第二段
|
|
|
|
|
always @(*)begin
|
|
|
|
|
case(state_c)
|
|
|
|
|
IDLE: if(skip_en_1 == 1'b1)begin
|
|
|
|
|
state_n = START;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
state_n = IDLE;
|
|
|
|
|
end
|
|
|
|
|
START: if(skip_en_1 == 1'b1)begin
|
|
|
|
|
state_n = SLAVE_ADDR;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
state_n = START;
|
|
|
|
|
end
|
|
|
|
|
SLAVE_ADDR: if(skip_en_1 == 1'b1)begin
|
|
|
|
|
state_n = WAIT;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
state_n = SLAVE_ADDR;
|
|
|
|
|
end
|
|
|
|
|
WAIT: if(skip_en_1 == 1'b1)begin
|
|
|
|
|
state_n = STOP;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
state_n = WAIT;
|
|
|
|
|
end
|
|
|
|
|
STOP: if(skip_en_1 == 1'b1)begin
|
|
|
|
|
state_n = IDLE;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
state_n = STOP;
|
|
|
|
|
end
|
|
|
|
|
default: begin
|
|
|
|
|
state_n = IDLE;
|
|
|
|
|
end
|
|
|
|
|
endcase
|
|
|
|
|
end
|
|
|
|
|
//状态机第三段
|
|
|
|
|
always @(posedge i2c_clk or negedge sys_rst_n)begin
|
|
|
|
|
if(!sys_rst_n)begin
|
|
|
|
|
cnt_wait <= 10'd0;
|
|
|
|
|
skip_en_1 <= 1'b0;
|
|
|
|
|
step <= 3'd0;
|
|
|
|
|
cnt_i2c_clk <= 2'd0;
|
|
|
|
|
cnt_bit <= 3'd0;
|
|
|
|
|
i2c_end <= 1'b0;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
case(state_c)
|
|
|
|
|
IDLE: begin
|
|
|
|
|
if(cnt_wait == MAX - 1)begin
|
|
|
|
|
cnt_wait <= 10'd0;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
cnt_wait <= cnt_wait + 1;
|
|
|
|
|
end
|
|
|
|
|
if((cnt_wait == MAX - 2'd2) && (step == 3'd0))begin
|
|
|
|
|
skip_en_1 <= 1'b1;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
skip_en_1 <= 1'b0;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
START: begin
|
|
|
|
|
cnt_i2c_clk <= cnt_i2c_clk + 1'd1;
|
|
|
|
|
if((cnt_i2c_clk == 2'd2) && (step == 3'd0))begin
|
|
|
|
|
skip_en_1 <= 1'b1;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
skip_en_1 <= 1'b0;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
SLAVE_ADDR: begin
|
|
|
|
|
cnt_i2c_clk <= cnt_i2c_clk + 1'd1;
|
|
|
|
|
if((cnt_i2c_clk == 2'd2) && (cnt_bit == 3'd7) && (step == 3'd0))begin
|
|
|
|
|
skip_en_1 <= 1'b1;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
skip_en_1 <= 1'b0;
|
|
|
|
|
end
|
|
|
|
|
if((cnt_bit == 3'd7) && (cnt_i2c_clk == 2'd3))begin
|
|
|
|
|
cnt_bit <= 3'd0;
|
|
|
|
|
end
|
|
|
|
|
else if(cnt_i2c_clk == 2'd3)begin
|
|
|
|
|
cnt_bit <= cnt_bit + 1'd1;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
cnt_bit <= cnt_bit;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
WAIT: begin
|
|
|
|
|
if(cnt_wait == MAX - 1'd1)begin
|
|
|
|
|
cnt_wait = 10'd0;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
cnt_wait <= cnt_wait + 1'd1;
|
|
|
|
|
end
|
|
|
|
|
if((cnt_wait == MAX - 2'd2) && (step == 3'd0))begin
|
|
|
|
|
skip_en_1 <= 1'b1;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
skip_en_1 <= 1'b0;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
STOP: begin
|
|
|
|
|
cnt_i2c_clk <= cnt_i2c_clk + 1'd1;
|
|
|
|
|
if((cnt_i2c_clk == 2'd2) && (step == 3'd0))begin
|
|
|
|
|
skip_en_1 <= 1'b1;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
skip_en_1 <= 1'b0;
|
|
|
|
|
end
|
|
|
|
|
if(cnt_i2c_clk == 2'd2)begin
|
|
|
|
|
i2c_end <= 1'b1;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
i2c_end <= 1'b0;
|
|
|
|
|
end
|
|
|
|
|
if(i2c_end == 1'b1)begin
|
|
|
|
|
step <= step + 1'd1;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
step <= step;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
default: begin
|
|
|
|
|
cnt_wait <= 10'd0;
|
|
|
|
|
skip_en_1 <= 1'b0;
|
|
|
|
|
step <= step;
|
|
|
|
|
cnt_i2c_clk <= 2'd0;
|
|
|
|
|
cnt_bit <= 3'd0;
|
|
|
|
|
i2c_end <= 1'b0;
|
|
|
|
|
end
|
|
|
|
|
endcase
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
//step
|
|
|
|
|
always @(*)begin
|
|
|
|
|
case(step)
|
|
|
|
|
3'd0: begin
|
|
|
|
|
slave_addr = {SLAVE_ID, 1'b0};
|
|
|
|
|
device_addr = 8'h0;
|
|
|
|
|
wr_data = 8'h0;
|
|
|
|
|
end
|
|
|
|
|
default:begin
|
|
|
|
|
slave_addr = 8'h0;
|
|
|
|
|
device_addr = 8'h0;
|
|
|
|
|
wr_data = 8'h0;
|
|
|
|
|
end
|
|
|
|
|
endcase
|
|
|
|
|
end
|
|
|
|
|
//i2c_scl
|
|
|
|
|
always @(*)begin
|
|
|
|
|
case(state_c)
|
|
|
|
|
IDLE: i2c_scl = 1'b1;
|
|
|
|
|
START: i2c_scl = (cnt_i2c_clk >= 2'd2) ? 1'b1 : 1'b0;
|
|
|
|
|
SLAVE_ADDR: i2c_scl = ((cnt_i2c_clk == 2'd1) || (cnt_i2c_clk == 2'd2)) ? 1'b1 : 1'b0;
|
|
|
|
|
WAIT: i2c_scl = 1'b0;
|
|
|
|
|
STOP: i2c_scl = (cnt_i2c_clk >= 2'd1) ? 1'b1 : 1'b0;
|
|
|
|
|
endcase
|
|
|
|
|
end
|
|
|
|
|
//i2c_sda
|
|
|
|
|
always @(*)begin
|
|
|
|
|
case(state_c)
|
|
|
|
|
IDLE: i2c_sda = 1'b1;
|
|
|
|
|
START: i2c_sda = (cnt_i2c_clk >= 2'd1) ? 1'b0 : 1'b1;
|
|
|
|
|
SLAVE_ADDR: i2c_sda = slave_addr[7 - cnt_bit];
|
|
|
|
|
WAIT: i2c_sda = 1'b0;
|
|
|
|
|
STOP: i2c_sda = (cnt_i2c_clk >= 2'd2) ? 1'b1 : 1'b0;
|
|
|
|
|
default: i2c_sda = 1'b1;
|
|
|
|
|
endcase
|
|
|
|
|
end
|
|
|
|
|
assign scl = i2c_scl;
|
|
|
|
|
endmodule
|