module i2c_me(
clk,
rst_n,
Cmd,
Go,
Rx_DATA,
Tx_DATA,
Trans_Done,
ack_o,
i2c_sclk,
i2c_sdat
);
input clk;
input rst_n;
input [5:0]Cmd;
input Go;
output reg[7:0]Rx_DATA;
input [7:0]Tx_DATA;
output reg Trans_Done;
output reg ack_o;
output reg i2c_sclk;
inout i2c_sdat;
//系统时钟采用50MHz
parameter SYS_CLOCK = 50_000_000;
parameter SCL_CLOCK = 400_000;
localparam SCL_CNT_M = SYS_CLOCK/SCL_CLOCK/4 - 1;
reg [19:0]div_cnt;
reg en_div_cnt;
always@(posedge clk or negedge rst_n)
if(!rst_n)
div_cnt <= 20'd0;
else if(en_div_cnt)begin
if(div_cnt < SCL_CNT_M)
div_cnt <= div_cnt + 1'b1;
else
div_cnt <= 0;
end
else
div_cnt <= 0;
wire sclk_plus = div_cnt == SCL_CNT_M;
reg sclk_plus_state ;
always@(posedge clk or negedge rst_n)
if(!rst_n)
sclk_plus_state <= 1'b0;
else if(sclk_plus)
sclk_plus_state <= 1'b1;
else
sclk_plus_state <= 1'b0;
localparam
IDLE = 8'b00000001,
GEN_STA = 8'b00000010,
WR_DATA = 8'b00000100,
RD_DATA = 8'b00001000,
CHECK_ACK = 8'b00010000,
GEN_ACK = 8'b00100000,
GEN_STO = 8'b01000000;
reg [7:0]c_state,n_state;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
c_state <= IDLE;
else
c_state <= n_state;
end
localparam
WR = 6'b000001,
STA = 6'b000010,
RD = 6'b000100,
STO = 6'b001000,
ACK = 6'b010000,
NACK = 6'b100000;
reg [4:0]cnt;
always@(*)
begin
case(c_state)
IDLE :
begin
if(Go)begin
if(Cmd & STA)
n_state <= GEN_STA;
else if(Cmd & WR)
n_state <= WR_DATA;
else if(Cmd & RD)
n_state <= RD_DATA;
end
else
n_state <= c_state;
end
GEN_STA :
begin
if(cnt==5'd3&&sclk_plus)begin
if(Cmd & WR)
n_state <= WR_DATA;
else if(Cmd & RD)
n_state <= RD_DATA;
end
else
n_state <= c_state;
end
WR_DATA :
begin
if(cnt==5'd31&&sclk_plus)
n_state <= CHECK_ACK;
else
n_state <= c_state;
end
RD_DATA :
begin
if(cnt==5'd31&&sclk_plus)
n_state <= GEN_ACK ;
else
n_state <= c_state;
end
CHECK_ACK:
begin
if(cnt==5'd3&&sclk_plus)begin
if(Cmd & STO)
n_state <= GEN_STO;
else
n_state <= IDLE;
end
else
n_state <= c_state;
end
GEN_ACK :
begin
if(cnt==5'd3&&sclk_plus)begin
if(Cmd & STO)
n_state <= GEN_STO;
else
n_state <= IDLE;
end
else
n_state <= c_state;
end
GEN_STO :
begin
if(cnt==5'd3&&sclk_plus)
n_state <= IDLE;
else
n_state <= c_state;
end
default:
n_state <= IDLE;
endcase
end
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt <= 0;
else if(sclk_plus == 1)begin
if(cnt==3&&c_state==GEN_STA)
cnt <=0 ;
else if(cnt==31&&c_state==WR_DATA)
cnt <=0 ;
else if(cnt==31&&c_state==RD_DATA)
cnt <=0 ;
else if(cnt==3&&c_state==CHECK_ACK)
cnt <=0 ;
else if(cnt==3&&c_state==GEN_ACK )
cnt <=0 ;
else if(cnt==3&&c_state==GEN_STO )
cnt <=0 ;
else
cnt <= cnt +1'b1;
end
always@(posedge clk or negedge rst_n)
if(!rst_n)
en_div_cnt <= 1'b0;
else if((c_state == GEN_STO) && (cnt >3'd3))
en_div_cnt <= 1'b0;
else if(Go == 1'b1)
en_div_cnt <= 1'b1;
else
en_div_cnt <=en_div_cnt;
reg i2c_sdat_o;
reg i2c_sdat_oe;
assign i2c_sdat = !i2c_sdat_o && i2c_sdat_oe ? 1'b0:1'bz;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
Rx_DATA <= 0 ;
i2c_sdat_oe <= 1'd0;
en_div_cnt <= 1'b0;
i2c_sdat_o <= 1'd1;
Trans_Done <= 1'b0;
ack_o <= 0 ;
end
else begin
case(c_state)
IDLE :
begin
Trans_Done <= 1'b0;i2c_sdat_oe<= 1'd1;
// if(Go)begin
// en_div_cnt <= 1'b1;
// Done_IDLE <= 1'b1;
// end
// else begin
// en_div_cnt <= 1'b0;
// Done_IDLE <= 1'b0;
// end
/* case(cnt)
3:begin i2c_sclk <= 0;Trans_Done <= 1'b1;end
default:begin Trans_Done <= 1'b0;i2c_sdat_oe <= 1'd1;end
endcase */
end
GEN_STA :
begin
if(sclk_plus)begin
case(cnt)
0:begin i2c_sdat_o <= 1; i2c_sdat_oe <= 1'd1;end
1:begin i2c_sclk<= 1;end
2:begin i2c_sdat_o <= 0; i2c_sclk <= 1;end
3:begin i2c_sclk <= 0;end
default:begin i2c_sdat_o <= 1; i2c_sclk <= 1;end
endcase
end
end
WR_DATA :
begin
if(sclk_plus)begin
case(cnt)
0,4,8,12,16,20,24,28:begin i2c_sdat_o <= Tx_DATA[7-cnt[4:2]]; i2c_sdat_oe <= 1'd1;end //set data;
1,5,9,13,17,21,25,29:begin i2c_sclk <= 1;end //sclk posedge
2,6,10,14,18,22,26,30:begin i2c_sclk <= 1;end //sclk keep high
3,7,11,15,19,23,27,31:begin i2c_sclk <= 0;end //sclk negedge
default:begin i2c_sdat_o <= 1; i2c_sclk <= 1;end
endcase
end
end
RD_DATA :
begin
if(sclk_plus)begin
case(cnt)
0,4,8,12,16,20,24,28:begin i2c_sdat_oe <= 1'd0; i2c_sclk <= 0;end //set data;
1,5,9,13,17,21,25,29:begin i2c_sclk <= 1;end //sclk posedge
2,6,10,14,18,22,26,30:begin i2c_sclk <= 1; Rx_DATA <= {Rx_DATA[6:0],i2c_sdat};end //sclk keep high
3,7,11,15,19,23,27:begin i2c_sclk <= 0;end //sclk negedge
31:begin i2c_sclk <= 0;end
default:begin i2c_sdat_o <= 1; i2c_sclk <= 1;end
endcase
end
end
CHECK_ACK :
begin
if(sclk_plus)begin
case(cnt)
0:begin i2c_sdat_oe <= 1'd0; i2c_sclk <= 0;end
1:begin i2c_sclk <= 1;end
2:begin ack_o <= i2c_sdat; i2c_sclk <= 1;end
3:begin i2c_sclk <= 0;
if(Cmd & STO)
Trans_Done <= 1'b0;
else
Trans_Done <= 1'b1;
end
default:begin i2c_sdat_o <= 1; i2c_sclk <= 1;end
endcase
end
end
GEN_ACK :
begin
if(sclk_plus)begin
case(cnt)
0:begin
i2c_sdat_oe <= 1'd1;
i2c_sclk <= 0;
if(Cmd & ACK)
i2c_sdat_o <= 1'b0;
else if(Cmd & NACK)
i2c_sdat_o <= 1'b1;
end
1:begin i2c_sclk <= 1;end
2:begin i2c_sclk <= 1;end
3:begin i2c_sclk <= 0;
if(Cmd & STO)
Trans_Done <= 1'b0;
else
Trans_Done <= 1'b1;
end
default:begin i2c_sdat_o <= 1; i2c_sclk <= 1;end
endcase
end
end
GEN_STO :
begin
if(sclk_plus)begin
case(cnt)
0:begin i2c_sdat_o <= 0; i2c_sdat_oe <= 1'd1;end
1:begin i2c_sclk <= 1;end
2:begin i2c_sdat_o <= 1; i2c_sclk <= 1;end
3:begin i2c_sclk <= 1;Trans_Done <= 1'b1;end
default:begin i2c_sdat_o <= 1; i2c_sclk <= 1;end
endcase
end
end
endcase
end
endmodule
说明以后补;
出现了几个bug,读写数据使用的状态时钟使用的n_state导致写下一个状态信号会直接和状态一起跳变。