|
module i2c(clk,rst_n,cmd,go,rx_data,tx_data,scl,sda,sda_a,trans_done);
input clk;
input rst_n;
input [5:0]cmd;
input go;
output reg [7:0]rx_data;
input [7:0]tx_data;
output reg scl;
inout sda;
output reg sda_a;
output reg trans_done;
reg[6:0]cnt1;
reg[6:0]state;
reg en_cnt1;
reg aoe;
reg[4:0]cnt;
parameter sys_clock=50000000;
parameter scl_clock=400000;
localparam scl_cnt_m=sys_clock/scl_clock/2;
localparam
start1=6'b000001,
wr1=6'b000010,
ra1=6'b000100,
ack1=6'b001000,
noack1=6'b010000,
stop1=6'b100000;
localparam
idle=7'b0000001,
gen_sta=7'b0000010,
wr_data=7'b0000100,
rd_data=7'b0001000,
check_ack=7'b0010000,
gen_nck=7'b0100000,
gen_sto=7'b1000000;
assign sda=aoe?sda_a:1'bz;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
cnt1<=7'b0;
end
else if(en_cnt1)begin
if(cnt1==scl_cnt_m)
cnt1<=7'b0;
else
cnt1<=cnt1+1'b1;
end
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
scl<=1'b1;
end
else if(en_cnt1)begin
if(cnt1==7'b0)
scl<=1'b1;
else if(cnt1==scl_cnt_m)
scl<=1'b0;
else
scl<=scl;
end
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
state<=idle;
sda_a<=1'b1;
aoe<=1'b0;
end
else begin
case(state)
idle:begin
trans_done<=1'b0;
if(go)begin
en_cnt1<=1'b1;
if(cmd & start1)
state<=gen_sta;
else if(cmd & wr1)
state<=wr_data;
else if(cmd & ra1)
state<=rd_data;
end
else
state<=idle;
en_cnt1<=1'b0;
end
gen_sta:begin
if(scl_cnt_m)begin
if(cnt==5'd3)
cnt<=5'd0;
else
cnt<=cnt+1'b1;
end
case(cnt)
0:begin sda_a<=1; aoe<=1'b0; end
1:begin scl<=1'b1;end
2:begin sda_a<=0; scl<=1'b1;end
3:begin scl<=1'b0;end
default:begin sda_a<=1'b1;scl<=1'b1;end
endcase
if(cnt==3)begin
if(cmd & wr1)
state<=wr_data;
else if(cmd & ra1)
state<=rd_data;
end
else
state<=gen_sta;
end
wr_data:begin
if(cnt==5'd31)
cnt<=5'd0;
else
cnt<=cnt+1'b1;
case(cnt)
0,4,8,12,16,20,24,28:begin sda_a<=tx_data[7:0]; aoe<=1'b1; end
1,5,9,13,17,21,25,29:begin scl<=1'b1;end
2,6,10,14,18,22,26,30:begin sda_a<=0; scl<=1'b1;end
3,7,11,15,19,23,27,31:begin scl<=1'b0;end
default:begin sda_a<=1'b1;scl<=1'b1;end
endcase
if(cnt==5'd3)begin
if(cmd & ack1)
state<=check_ack;
end
else
state<=wr_data;
end
check_ack:begin
if(scl_cnt_m)begin
if(cnt==5'd3)
cnt<=5'd0;
else
cnt<=cnt+1'b1;
end
case(cnt)
0:begin
scl<=1'b0;
aoe<=1'b1;
if(cmd & ack1)
sda_a<=1'b0;
else if(cmd & noack1)
sda_a<=1'b1;
end
1:begin scl<=1'b1;end
2:begin sda_a<=0; scl<=1'b1;end
3:begin scl<=1'b0;end
default:begin sda_a<=1'b1;scl<=1'b1;end
endcase
if(cnt==5'd3)begin
if(cmd & stop1)
state<=gen_sto;
trans_done<=1'b1;
end
else
state<=check_ack;
trans_done<=1'b0;
end
rd_data:begin
if(cnt==5'd31)
cnt<=5'd0;
else
cnt<=cnt+1'b1;
case(cnt)
0,4,8,12,16,20,24,28:begin scl<=1'b0; aoe<=1'b0; end
1,5,9,13,17,21,25,29:begin scl<=1'b1;end
2,6,10,14,18,22,26,30:begin rx_data<={rx_data[6:0],sda_a}; scl<=1'b1;end
3,7,11,15,19,23,27,31:begin scl<=1'b0;end
default: begin sda_a<=1'b1;scl<=1'b0;end
endcase
if(cnt==5'd3)begin
if(cmd & noack1)
state<=gen_nck;
end
else
state<=rd_data;
end
gen_nck:begin
if(scl_cnt_m)begin
if(cnt==5'd3)
cnt<=5'd0;
else
cnt<=cnt+1'b1;
end
case(cnt)
0:begin
scl<=1'b0;
aoe<=1'b1;
if(cmd & ack1)
sda_a<=1'b0;
else if(cmd & noack1)
sda_a<=1'b1;
else
sda_a<=sda_a;
end
1:begin scl<=1'b1;end
2:begin sda_a<=0; scl<=1'b1;end
3:begin scl<=1'b0;end
default:begin sda_a<=1'b1;scl<=1'b1;end
endcase
if(cnt==5'd3)begin
if(cmd & stop1)
state<=gen_sto;
trans_done<=1'b1;
end
else
state<=gen_nck;
trans_done<=1'b0;
end
gen_sto:begin
state<=idle;
end
endcase
end
endmodule
|
-
|