You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

253 lines
8.1 KiB
Coq

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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