配置文件:根据具体的IIC设备改一下时钟频率就可以产生正确的时钟波形
`define SYS_CLK 50_000_000
`define SCL_CLK 400_000
`define COUNT_MAX (`SYS_CLK/`SCL_CLK)
`define HALF (`COUNT_MAX/2 -1)
`define H_HALF (`HALF/2)
`define NEG (`HALF +1)
`define L_HALF (`H_HALF+NEG)
RTL代码:
`include "config.v"
module I2C(
clk, //system clk 50MHZ
rstn, //active low
data_in,
data_out,
sda,
scl,
wr, //wr=0 write; wr=1 read
fail,
req,
address,
wr_done,
rd_done
);
input clk;
input rstn;
input [7:0]data_in;
input wr;
input req;
input [7:0] address;
output [0:0]scl;
output reg[7:0] data_out;
inout sda;
output fail;
output rd_done;
output wr_done;
reg [7:0] clk_cnt;
wire sda_in;
reg sda_out;
reg [29:0] state;
reg [0:0] sda_mode;
wire clk_en;
parameter IN =0,
OUT =1;
parameter idle =30'b00_0000_0000_0000_0000_0000_0000_0001,
start =30'b00_0000_0000_0000_0000_0000_0000_0010,
mode0 =30'b00_0000_0000_0000_0000_0000_0000_0100,
mode1 =30'b00_0000_0000_0000_0000_0000_0000_1000,
mode2 =30'b00_0000_0000_0000_0000_0000_0001_0000,
mode3 =30'b00_0000_0000_0000_0000_0000_0010_0000,
mode4 =30'b00_0000_0000_0000_0000_0000_0100_0000,
mode5 =30'b00_0000_0000_0000_0000_0000_1000_0000,
mode6 =30'b00_0000_0000_0000_0000_0001_0000_0000,
mode7 =30'b00_0000_0000_0000_0000_0010_0000_0000,
ack_mode =30'b00_0000_0000_0000_0000_0100_0000_0000,
addr0 =30'b00_0000_0000_0000_0000_1000_0000_0000,
addr1 =30'b00_0000_0000_0000_0001_0000_0000_0000,
addr2 =30'b00_0000_0000_0000_0010_0000_0000_0000,
addr3 =30'b00_0000_0000_0000_0100_0000_0000_0000,
addr4 =30'b00_0000_0000_0000_1000_0000_0000_0000,
addr5 =30'b00_0000_0000_0001_0000_0000_0000_0000,
addr6 =30'b00_0000_0000_0010_0000_0000_0000_0000,
addr7 =30'b00_0000_0000_0100_0000_0000_0000_0000,
ack_addr =30'b00_0000_0000_1000_0000_0000_0000_0000,
bit0 =30'b00_0000_0001_0000_0000_0000_0000_0000,
bit1 =30'b00_0000_0010_0000_0000_0000_0000_0000,
bit2 =30'b00_0000_0100_0000_0000_0000_0000_0000,
bit3 =30'b00_0000_1000_0000_0000_0000_0000_0000,
bit4 =30'b00_0001_0000_0000_0000_0000_0000_0000,
bit5 =30'b00_0010_0000_0000_0000_0000_0000_0000,
bit6 =30'b00_0100_0000_0000_0000_0000_0000_0000,
bit7 =30'b00_1000_0000_0000_0000_0000_0000_0000,
ack_bit =30'b01_0000_0000_0000_0000_0000_0000_0000,
stop =30'b10_0000_0000_0000_0000_0000_0000_0000;
//generate clk 400khz
always@(posedge clk)
if(!rstn)
clk_cnt <=8'd0;
else if(clk_en)
begin
if(clk_cnt==`COUNT_MAX)
clk_cnt <=8'd0;
else
clk_cnt <=clk_cnt + 1'b1;
end
else
clk_cnt <=8'd0;
//wire neg=(clk_cnt==`NEG)?1:0; //negedge of the scl_clk
wire h_half =(clk_cnt==h_half);
wire l_half =(clk_cnt==l_half);
wire scl_clk =(clk_cnt <`HALF);
assign scl =(clk_en&scl_clk)|(!clk_en);
//control sda direction
assign sda=(sda_mode==OUT)?sda_out:1'bz;
assign sda_in=(sda_mode==IN)?sda:1'bz;
wire full=(clk_cnt==`COUNT_MAX);
//state control
always@(posedge clk)
if(!rstn)
state <=idle;
else
case(state)
idle:
if(req)
state <=start;
else
state <=state;
start: //at the same time start clock generator
if(full)
state <=mode0;
else
state <=state;
mode0:
if(full)
state <=mode1;
else
state <=state;
mode1:
if(full)
state <=mode2;
else
state <=state;
mode2:
if(full)
state <=mode3;
else
state <=state;
mode3:
if(full)
state <=mode4;
else
state <=state;
mode4:
if(full)
state <=mode5;
else
state <=state;
mode5:
if(full)
state <=mode6;
else
state <=state;
mode6:
if(full)
state <=mode7;
else
state <=state;
mode7:
if(full)
state <=ack_mode;
else
state <=state;
ack_mode:
if(h_half)
begin
if(sda_in==1'b1)
state <=addr0;
else
state <=stop;
end
else
state <=state;
addr0:
if(full)
state <=addr1;
else
state <=state;
addr1:
if(full)
state <=addr2;
else
state <=state;
addr2:
if(full)
state <=addr3;
else
state <=state;
addr3:
if(full)
state <=addr4;
else
state <=state;
addr4:
if(full)
state <=addr5;
else
state <=state;
addr5:
if(full)
state <=addr6;
else
state <=state;
addr6:
if(full)
state <=addr7;
else
state <=state;
addr7:
if(full)
state <=ack_addr;
else
state <=state;
ack_addr:
if(h_half)
begin
if(sda_in==1'b0)
state <=bit0;
else
state <=stop;
end
else
state <=state;
bit0:
if(full)
state <=bit1;
else
state <=bit2;
bit1:
if(full)
state <=bit2;
else
state <=state;
bit2:
if(full)
state <=bit3;
else
state <=state;
bit3:
if(full)
state <=bit4;
else
state <=state;
bit4:
if(full)
state <=bit5;
else
state <=state;
bit5:
if(full)
state <=bit6;
else
state <=state;
bit6:
if(full)
state <=bit7;
else
state <=state;
bit7:
if(full)
state <=ack_bit;
else
state <=state;
ack_bit:
if((!wr)&h_half)
begin
if(sda_in==1'b0)
state <=stop;
else
state <=stop;
end
else if(wr&l_half)
state <=stop;
else
state <=state;
stop:
if(full)
state <=idle;
else
state <=state;
default: state <=stop;
endcase
always@(posedge clk)
if(!rstn)
begin
sda_mode <=OUT;
sda_out <=1'b1;
data_out <=8'b0;
end
else
case(state)
idle:
begin
sda_mode <=OUT;
sda_out <=1'b1;
end
start:
begin
sda_mode <=OUT;
if(l_half)
sda_out <=1'b0;
else
sda_out <=1'b1;
end
mode0:
begin
sda_mode <=OUT;
if(l_half)
sda_out <=1'b1;
else
sda_out <=sda_out;
end
mode1:
begin
sda_mode <=OUT;
if(l_half)
sda_out <=1'b0;
else
sda_out <=sda_out;
end
mode2:
begin
sda_mode <=OUT;
if(l_half)
sda_out <=1'b1;
else
sda_out <=sda_out;
end
mode3:
begin
sda_mode <=OUT;
if(l_half)
sda_out <=1'b0;
else
sda_out <=sda_out;
end
mode4:
begin
sda_mode <=OUT;
if(l_half)
sda_out <=1'b1;
else
sda_out <=sda_out;
end
mode5:
begin
sda_mode <=OUT;
if(l_half)
sda_out <=1'b0;
else
sda_out <=sda_out;
end
mode6:
begin
sda_mode <=OUT;
if(l_half)
sda_out <=1'b0;
else
sda_out <=sda_out;
end
mode7:
begin
sda_mode <=OUT;
if(l_half)
sda_out <=wr;
else
sda_out <=sda_out;
end
ack_mode:
begin
sda_mode <=IN;
end
addr0:
begin
sda_mode <=OUT;
if(l_half)
sda_out <=address[7];
else
sda_out <=sda_out;
end
addr1:
begin
sda_mode <=OUT;
if(l_half)
sda_out <=address[6];
else
sda_out <=sda_out;
end
addr2:
begin
sda_mode <=OUT;
if(l_half)
sda_out <=address[5];
else
sda_out <=sda_out;
end
addr3:
begin
sda_mode <=OUT;
if(l_half)
sda_out <=address[4];
else
sda_out <=sda_out;
end
addr4:
begin
sda_mode <=OUT;
if(l_half)
sda_out <=address[3];
else
sda_out <=sda_out;
end
addr5:
begin
sda_mode <=OUT;
if(l_half)
sda_out <=address[2];
else
sda_out <=sda_out;
end
addr6:
begin
sda_mode <=OUT;
if(l_half)
sda_out <=address[1];
else
sda_out <=sda_out;
end
addr7:
begin
sda_mode <=OUT;
if(l_half)
sda_out <=address[0];
else
sda_out <=sda_out;
end
ack_addr:
begin
sda_mode <=IN;
end
bit0:
if(wr)//read
begin
sda_mode <=IN;
if(h_half)
data_out[7] <=sda_in;
else
data_out[7] <=data_out[7];
end
else//write
begin
sda_mode <=OUT;
if(l_half)
sda_out <=data_in[7];
else
sda_out <=sda_out;
end
bit1:
if(wr)//read
begin
sda_mode <=IN;
if(h_half)
data_out[6] <=sda_in;
else
data_out[6] <=data_out[6];
end
else//write
begin
sda_mode <=OUT;
if(l_half)
sda_out <=data_in[6];
else
sda_out <=sda_out;
end
bit2:
if(wr)//read
begin
sda_mode <=IN;
if(h_half)
data_out[5] <=sda_in;
else
data_out[5] <=data_out[5];
end
else//write
begin
sda_mode <=OUT;
if(l_half)
sda_out <=data_in[5];
else
sda_out <=sda_out;
end
bit3:
if(wr)//read
begin
sda_mode <=IN;
if(h_half)
data_out[4] <=sda_in;
else
data_out[4] <=data_out[4];
end
else//write
begin
sda_mode <=OUT;
if(l_half)
sda_out <=data_in[4];
else
sda_out <=sda_out;
end
bit4:
if(wr)//read
begin
sda_mode <=IN;
if(h_half)
data_out[3] <=sda_in;
else
data_out[3] <=data_out[3];
end
else//write
begin
sda_mode <=OUT;
if(l_half)
sda_out <=data_in[3];
else
sda_out <=sda_out;
end
bit5:
if(wr)//read
begin
sda_mode <=IN;
if(h_half)
data_out[2] <=sda_in;
else
data_out[2] <=data_out[2];
end
else//write
begin
sda_mode <=OUT;
if(l_half)
sda_out <=data_in[2];
else
sda_out <=sda_out;
end
bit6:
if(wr)//read
begin
sda_mode <=IN;
if(h_half)
data_out[1] <=sda_in;
else
data_out[1] <=data_out[1];
end
else//write
begin
sda_mode <=OUT;
if(l_half)
sda_out <=data_in[1];
else
sda_out <=sda_out;
end
bit7:
if(wr)//read
begin
sda_mode <=IN;
if(h_half)
data_out[0] <=sda_in;
else
data_out[0] <=data_out[0];
end
else//write
begin
sda_mode <=OUT;
if(l_half)
sda_out <=data_in[0];
else
sda_out <=sda_out;
end
ack_bit:
if(!wr)
sda_mode <=IN;
else
begin
sda_mode <=OUT;
if(l_half)
sda_out <=1'b1;
else
sda_out <=sda_out;
end
stop:
if(h_half)//閹峰鐝
begin
sda_mode <=OUT;
sda_out <=1;
end
else if(!h_half)//閹峰缍
begin
sda_mode <=OUT;
sda_out <=0;
end
default:begin
sda_out <=1'b1;
sda_mode <=OUT;
data_out <=8'd0;
end
endcase
assign clk_en =(state==idle);
assign wr_done =(state==ack_bit)&(h_half)&(sda_in==1'b0);
assign fail =((state==ack_mode)&(h_half)&(sda_in!=1'b0))|
((state==ack_addr)&(h_half)&(sda_in!=1'b0))|
((state==ack_bit)&(h_half)&(sda_in!=1'b0));
assign rd_done =(state==stop);
endmodule