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.

399 lines
15 KiB
Coq

7 months ago
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;
//
7 months ago
parameter IDLE = 4'd0,
START = 4'd1,
SLAVE_ADDR = 4'd2,
ACK_1 = 4'd3,
ACK_2 = 4'd4,
ACK_3 = 4'd5,
DEVICE_ADDR = 4'd6,
DATA = 4'd7,
WAIT = 4'd8,
STOP = 4'd9;
reg [3: 0] state_c;
reg [3: 0] state_n;
7 months ago
////
//i2c
reg [4: 0] cnt_clk;
reg i2c_clk;
/////
//
reg [9: 0] cnt_wait ;//1000us
7 months ago
reg skip_en_1 ;//1
reg skip_en_2 ;//2
7 months ago
reg [2: 0] step ;//
reg [1: 0] cnt_i2c_clk ;//i2c
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 ;
7 months ago
reg ack ;//
7 months ago
//
7 months ago
assign sda_en = ((state_c == ACK_1) || (state_c == ACK_2) || (state_c == ACK_3)) ? 1'b0: 1'b1;//
7 months ago
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 i2c_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)
7 months ago
IDLE: if((skip_en_1 == 1'b1) || (skip_en_2 == 1'b1))begin
7 months ago
state_n = START;
end
else begin
state_n = IDLE;
end
7 months ago
START: if((skip_en_1 == 1'b1) || (skip_en_2 == 1'b1))begin
7 months ago
state_n = SLAVE_ADDR;
end
else begin
state_n = START;
end
SLAVE_ADDR: if(skip_en_1 == 1'b1)begin
state_n = WAIT;
end
7 months ago
else if(skip_en_2 == 1'b1)begin
state_n = ACK_1;
end
7 months ago
else begin
state_n = SLAVE_ADDR;
end
7 months ago
ACK_1: if(skip_en_2 == 1'b1)begin
state_n = DEVICE_ADDR;
end
else begin
state_n = ACK_1;
end
DEVICE_ADDR:if(skip_en_2 == 1'b1)begin
state_n = ACK_2;
end
else begin
state_n = DEVICE_ADDR;
end
ACK_2: if(skip_en_2 == 1'b1)begin
state_n = DATA;
end
else begin
state_n = ACK_2;
end
DATA: if(skip_en_2 == 1'b1)begin
state_n = ACK_3;
end
else begin
state_n = DATA;
end
ACK_3: if(skip_en_2 == 1'b1)begin
state_n = STOP;
end
else begin
state_n = ACK_3;
end
7 months ago
WAIT: if(skip_en_1 == 1'b1)begin
state_n = STOP;
end
else begin
state_n = WAIT;
end
7 months ago
STOP: if((skip_en_1 == 1'b1) || (skip_en_2 == 1'b1))begin
7 months ago
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;
7 months ago
skip_en_2 <= 1'b0;//2
7 months ago
step <= 3'd0;
cnt_i2c_clk <= 2'd0;
cnt_bit <= 3'd0;
i2c_end <= 1'b0;
end
else begin
case(state_c)
IDLE: begin
7 months ago
if(cnt_wait == MAX - 1)begin
7 months ago
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
7 months ago
if((cnt_wait == MAX - 2'd2) && (step == 3'd1))begin
skip_en_2 <= 1'b1;
end
else begin
skip_en_2 <= 1'b0;
end
7 months ago
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
7 months ago
if((cnt_i2c_clk == 2'd2) && (step == 3'd1))begin
skip_en_2 <= 1'b1;
end
else begin
skip_en_2 <= 1'b0;
end
7 months ago
end
SLAVE_ADDR: begin
cnt_i2c_clk <= cnt_i2c_clk + 1'd1;
if((cnt_i2c_clk == 2'd2) && (step == 3'd0) && (cnt_bit == 3'd7))begin
skip_en_1 <= 1'b1;
end
else begin
skip_en_1 <= 1'b0;
end
7 months ago
if((cnt_i2c_clk == 2'd2) && (step == 3'd1) && (cnt_bit == 3'd7))begin
skip_en_2 <= 1'b1;
end
else begin
skip_en_2 <= 1'b0;
end
7 months ago
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
7 months ago
ACK_1: begin
cnt_i2c_clk <= cnt_i2c_clk + 1'd1;
if((ack == 1'b1) && (cnt_i2c_clk == 2'd2) && (step == 3'd1))begin
skip_en_2 <= 1'b1;
end
else begin
skip_en_2 <= 1'b0;
end
end
DEVICE_ADDR:begin
cnt_i2c_clk <= cnt_i2c_clk + 1'b1;
if((cnt_i2c_clk == 2'd3) && (cnt_bit == 3'd7))begin
cnt_bit <= 3'd0;
end
else if(cnt_i2c_clk == 2'd3)begin
cnt_bit <= cnt_bit + 1'b1;
end
else begin
cnt_bit <= cnt_bit;
end
if((cnt_i2c_clk == 2'd2) && (cnt_bit == 3'd7) && (step == 3'd1))begin
skip_en_2 <= 1'b1;
end
else begin
skip_en_2 <= 1'b0;
end
end
ACK_2: begin
cnt_i2c_clk <= cnt_i2c_clk + 1;
if((ack == 1'b1) && (cnt_i2c_clk == 2'd2) && (step == 3'd1))begin
skip_en_2 <= 1'b1;
end
else begin
skip_en_2 <= 1'b0;
end
end
DATA: begin
cnt_i2c_clk <= cnt_i2c_clk + 1'b1;
if((cnt_i2c_clk == 2'd3) && (cnt_bit == 3'd7))begin
cnt_bit <= 3'd0;
end
else if(cnt_i2c_clk == 2'd3)begin
cnt_bit <= cnt_bit + 1'b1;
end
else begin
cnt_bit <= cnt_bit;
end
if((cnt_i2c_clk == 2'd2) && (cnt_bit == 3'd7) && (step == 3'd1))begin
skip_en_2 <= 1'b1;
end
else begin
skip_en_2 <= 1'b0;
end
end
ACK_3: begin
cnt_i2c_clk <= cnt_i2c_clk + 1;
if((ack == 1'b1) && (cnt_i2c_clk == 2'd2) && (step == 3'd1))begin
skip_en_2 <= 1'b1;
end
else begin
skip_en_2 <= 1'b0;
end
end
7 months ago
WAIT: begin
if(cnt_wait == MAX - 1'd1)begin
7 months ago
cnt_wait <= 10'd0;
7 months ago
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
7 months ago
if((cnt_i2c_clk == 2'd2) && (step == 3'd1))begin
skip_en_2 <= 1'b1;
end
else begin
skip_en_2 <= 1'b0;
end
7 months ago
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;
7 months ago
skip_en_2 <= 1'b0;
7 months ago
step <= step;
cnt_i2c_clk <= 2'd0;
cnt_bit <= 3'd0;
i2c_end <= 1'b0;
end
endcase
end
end
7 months ago
//ack
always @(*)begin
case(state_c)
ACK_1, ACK_2, ACK_3: ack = ~sda_in;
default: ack = 1'b0;
endcase
end
7 months ago
//step
always @(*)begin
case(step)
3'd0: begin
slave_addr = {SLAVE_ID, 1'b0};
device_addr = 8'h0;
wr_data = 8'h0;
end
7 months ago
3'd1: begin
slave_addr = {SLAVE_ID, 1'b0};
device_addr= {8'hef};
wr_data = {8'h00};
end
7 months ago
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;
7 months ago
SLAVE_ADDR, DEVICE_ADDR, DATA, ACK_1, ACK_2, ACK_3:
i2c_scl = ((cnt_i2c_clk == 2'd1) || (cnt_i2c_clk == 2'd2)) ? 1'b1 : 1'b0;
7 months ago
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];
7 months ago
DEVICE_ADDR:i2c_sda = device_addr[7 - cnt_bit];
DATA: i2c_sda = wr_data[7 - cnt_bit];
ACK_1, ACK_2, ACK_3:
i2c_sda = 1'b0;
7 months ago
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