本文有参考【精品博文】IIC 通信协议的Verilog实现作者的一些思想,并尝试补充eeprom一端的代码,并不完美,主要是
一eeprom完全按照scl上升沿或下降沿采取动作(写数据或读数据),很难在scl低电平中间点使sda线发生变化(似乎不太符合iic协议要求),
二另外在FPGA放弃sda线控制权和eeprom取得sda线控制权之间会有一小段高阻态(衔接并不连续),以下代码
`timescale 1 ns / 100ps
module exx( clk,rst_n,keywr,keyrd,sda,scl); //fpga端代码
input clk;
input rst_n;
input keywr;
input keyrd;
output reg scl;
inout sda;
reg[3:0] cnt;
reg[3:0] count;
reg wr;
reg rd;
reg link;
reg sdabuf;
reg[8:1] buffer;
reg[3:0] state;
parameter
idl=0,
st1=1,
wdv=2,
ac1=3,
wwd=4,
ac2=5,
wdt=6,
ac3=7,
st2=8,
rdv=9,
ac4=10,
rdt=11,
nac=12,
stp=13;
assign sda=link?sdabuf:1'bz; //fpga控制或放弃sda线
always @(negedge clk or negedge rst_n)
if(!rst_n) scl<=1;
else if(state>st1)scl<=~scl;
always @(posedge clk or negedge rst_n)
if(!rst_n) begin
state<=idl;
wr<=0;
rd<=0;
count<=8;
link<=1;
sdabuf<=1;
buffer<=0;
end
else
case(state)
idl: //空闲状态
if(!keyrd||!keywr)
begin
if(!keywr)wr<=1;
if(!keyrd)rd<=1;
sdabuf<=0;
state<=st1;
buffer<=8'b10100000;
end
st1: state<=wdv; //发送启动信号
wdv:if(!scl&&count>0) //发送器件地址8'b10100000;
begin
sdabuf<=buffer[count];
count<=count-1;
end
else if(!scl&&count==0)
begin
count<=8;
link<=0; //放弃sda线控制权,等待检测应答信号
state<=ac1;
end
ac1: //接收第一次应答
begin
if(scl)
begin
if(!sda)
begin
buffer<=8'b1000_0001; //准备写字地址8'b1000_0001=d'129;
sdabuf<=0;
link<=1; //接收到应答信号后重新获取sda线控制权,准备写字地址
state<=wwd;
end
end
end
wwd:if(!scl&&count>0) //发送字地址
begin
sdabuf<=buffer[count];
count<=count-1;
end
else if(!scl&&count==0)
begin
count<=8;
link<=0;
state<=ac2;
&