📄 i2c_slave.v
字号:
`timescale 1us/10ps
`define true 1'b1
`define false 1'b0
`define clk_period 60
module i2c_slave( //input
scl,sda_i,
sda_oe,
//output
sda_o);
input scl,sda_i;
input sda_oe;
output sda_o;
reg start,stop,rd,wr;
integer i;
reg sda;
wire sda_o=~sda_oe? sda: 0;
reg [6:0] addr;
reg [7:0] mem[0:1023];
reg [7:0] temp;
reg tmp;
reg wp;
reg continue,burst;
reg [3:0] index;
initial begin
start=0;sda=0;burst=0;
stop=0;wp=0; tmp=0;
rd=0;wr=0;temp=0;
index=0; //for debugging
continue=`true;
end
//----- start condition -----
always @(negedge sda_i or posedge stop)
begin
if (scl==1)
begin
@(negedge scl) ;
start=1;
wr=0; //---- clear original write command
rd=0;
stop=#1 0;
$display(" i2c_slave; start condition detected at %t us", $time);
end
end
//------ stop condition ------
always @(posedge sda_i)
begin
if ((scl==1))
begin
stop=#1 1;
start=0;
addr=0;
$display(" i2c_slave; stop condition detected at %t us", $time);
end
end
//------addr decode -------
always @(posedge start)
begin
//if (start==1)
begin
i=0;
for (i=0;i<=6;i=i+1)
begin
//index=6-i;
@(posedge scl);
addr[6-i]=sda_i; //--- first address decode
end
//--- read or write decode -----
@(posedge scl);
rd=sda_i;
wr=~sda_i;
//--- gen slave's ack ----
wait (~sda_oe);
sda=0;
start=0;
end
end
always @(posedge wr) $display(" i2c_slave; wr command at %t us", $time);
always @(posedge rd) $display(" i2c_slave; rd command at %t us", $time);
always @(posedge wr)
begin
repeat(2) // one wait for rd wr command,
@(negedge scl);// one wait for ack
wp=0; // gen a write pulse to write to MEM
while (continue) // for burst write
begin
if (burst==0)
begin
for (i=0;i<=7;i=i+1)
begin
//index=7-i;
@(posedge scl)
temp[7-i]<=sda_i;
end
wp=1;
#5 wp=0;
end else if (burst==1)
begin
temp[7]<=tmp;
for (i=1;i<=7;i=i+1)
begin
@(posedge scl)
temp[7-i]<=sda_i;
end
wp=1;
#5 wp=0;
end
@(negedge scl);
@(negedge scl);
@(posedge scl);
tmp<=sda_i;
#(`clk_period); // the delay time/100000 should be modified
// delay time/100000 see line 194 document
if (stop==1) begin // depend on the scl clk period, judge if burst mode
continue=`false;
burst=1'b0;
end else begin
continue=`true;
burst=1'b1;
end
end// end while
continue=`true; // return to it's initial state
burst=1'b0;
end
always @(negedge wp)
addr<=#1 addr+1;
always @(negedge wp)
begin
mem[addr]<=temp;
end
wire [7:0] test1,test2,test3,test4,test5;
assign test1=mem[45];
assign test2=mem[46];
assign test3=mem[47];
assign test4=mem[12];
assign test5=mem[13];
always @(posedge rd)
begin
temp=mem[addr];
@(negedge scl); //wait rd scl pulse end
while(continue)
begin
temp=mem[addr];
if (burst==0)
begin
for (i=0;i<=7;i=i+1)
begin
@(negedge scl); //while i=0 , @(negedge is for ack)
#(`clk_period/4);
sda=temp[7-i];
#(`clk_period/4);
end
end else if (burst==1)
for (i=1;i<=7;i=i+1)
begin
//index=7-i; // debugging usage
@(negedge scl);
#(`clk_period/4);
sda=temp[7-i];
#(`clk_period/4);
end
@(negedge scl); // wait for last transfer bit
#(`clk_period/4);
addr<=addr+1;
sda<=0; // eliminate the glitch
@(negedge scl); // wait for master ack
temp=mem[addr];
sda=temp[7];
@(posedge scl);
// sda_i ___________/-----
// scl _____/----------
// |<-t->|
// delay #(clk_period) must > t to meet stop condition
// must not accross the scl clk period
// the delay time/100000 should be modified
#(`clk_period);
if (stop==1) begin // ¦b¦¹¦۰ʧP©w¬O§_¬° burst mode
continue=`false;
burst=1'b0;
end else begin
continue=`true;
burst=1'b1;
end
end// end while
continue=`true; // return to it's initial state
burst=1'b0;
end
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -