参考自夏宇闻老师《verilog系统设计原理》

系统设计基础原理:
IIC串行总线工作状态定义如下:

(1)总线非忙状态(A段):SDA和SCL均保持高电平;
(2)启动数据传输(B段):SCL为高电平,SDA的下降沿被认为是启动信号,只有出现启动信号之后,其他的命令才有效。
(3)停止数据传输(C段):SCL为高电平,SDA的上升沿被认为是停止信号。
(4)数据有效(D段):出现启动信号后,在SCL高电平时,数据线稳定,表示要传输的数据;SDA必须在SCL低电平时改变。每个数据占用一个时钟脉冲。
EEPROM写操作帧格式:
写操作过程即通过EEPROM读写控制器将一个字节数据发送到EEPROM中指定地址的存储单元。
过程如下:EEPROM读写控制器发送启动信号,紧跟着一个控制字节(包含特征编码1010+芯片地址/页地址XXX+写状态(0))至总线上;收到EEPROM产生的一个应答位后,紧跟着发送一字节地址和一字节数据,EEPROM分别产生一次应答位,最后读写控制器产生停止信号。

EEPROM读操作帧格式:
读操作即通过读写控制器读取EEPROM中指定地址的存储单元中的一个字节数据。
过程如下:EEPROM读写控制器发送启动信号和一个控制字节(此时控制状态为写)至总线上,通过写操作设置EEPROM存储单元地址,此期间EEPROM会产生必要的应答位;读写控制器紧跟着重新发送启动信号和一个控制字节(此时控制状态为读),EEPROM发出应答信号后,寻址存储单元的数据从SDA线上输出。EEPROM产生一次非应答(高电平),最后读写控制器产生停止信号。

Verilog程序由三个模块构成:
Signal:信号源模块,产生用于EEPROM读写器件的仿真测试信号,能产生相应的复位信号(RESET),时钟信号(CLK),读信号(WR),写信号(RD),并行地址信号(ADDR)和并行数据信号(DATA),并能接收串行EEPROM读写期间的应答信号(ACK)及,以此来调节发送或接收数据的速度。
其中ACK为输入信号,DATA为双向信号,可输出EEPROM写操作的数据,也可接收EEPROM读操作的数据。该模块为行为仿真,采用阻塞赋值,不可综合为门级网表。
代码如下所示:
module Signal(
input ACK ,//应答信号,EEPROM读写器用于控制信号源读写速度
inout[7:0] DATA ,//写操作数据
output reg RESET ,//复位信号
output reg CLK ,//时钟周期200ns
output reg RD ,//读标志 持续一个时钟
output reg WR ,//写标志 持续一个时钟
output reg[10:0] ADDR //读/写地址
);
reg W_R ;
reg[7:0] data_to_eeprom ;//DATA输出写EEPROM操作的数据
reg[10:0] addr_mem[0:255] ;//地址存储器
reg[7:0] data_mem[0:255] ;//数据(写)存储器
reg[7:0] ROM[0:2047] ;//表示EEPROM存储器
integer i,j ;//循环参数
integer OUTFILE ;//文件句柄,文件内容为写操作地址,数据
parameter test_number =50; //测试次数
assign DATA =(W_R)? 8'bz:data_to_eeprom;//W_R=0,DATA输出写EEPROM操作的数据
//-----------------时钟输入-----------------
always #(`timeslice2/2) CLK = ~CLK ;
//-----------------读写信号输入--------------
initial begin
RESET=1 ;
i=0 ;
j=0 ;
W_R=0 ;
CLK=0 ;
RD=0 ;
WR=0 ;
#1000 ;
RESET=0 ;
//WR拉高一个时钟,收到ACK后再次循环,循环次数test_number
repeat(test_number)begin
#(5*`timeslice2);
WR=1;
#(`timeslice2)
WR=0;
@(posedge ACK);
end
//写操作完成后,W_R拉高,进入读操作
#(10*`timeslice2);
W_R=1;
//RD拉高一个时钟,收到ACK后再次循环,循环次数test_number
repeat(test_number)begin
#(5*`timeslice2)
RD=1;
#(`timeslice2)
RD=0;
@(posedge ACK);
end
end
//读地址存储器,数据存储器,test_number个时钟;并将地址与对应数据写入eeprom.dat文件
initial begin
$display("writing----writing----writing----writing");
#(2*`timeslice2);
for(i=0;i<test_number;i=i+1)begin
ADDR=addr_mem[i];
data_to_eeprom=data_mem[i];
// $fdisplay(OUTFILE,"@%0h %0h",ADDR,data_to_eeprom);
$fdisplay(OUTFILE,"%0h",data_to_eeprom);
@(posedge ACK);
end
end
//将eeprom.dat文件数据存于ROM;比较读eeprom.dat文件数据与写入数据是否一致
initial@(posedge W_R)begin
ADDR=addr_mem[0];
$fclose(OUTFILE);
$readmemh("C:/users/lenovo/Desktop/example/eeprom.dat",ROM);
$display("Begin READING----READING----READING----READING");
for(j=0;j<=test_number;j=j+1)begin
ADDR=addr_mem[j];
@(posedge ACK);
if(data_mem[ADDR]==ROM[ADDR])
$display("data_mem%0h==ROM_[%0h]%0h---READ RIGHT",data_mem[ADDR],ADDR,ROM[ADDR]);
else
$display("data_mem%0h!==ROM[%0h]%0h---READ WRONG",data_mem[ADDR],ADDR,ROM[ADDR]);
end
end
//将dat文件中地址,数据分别储存在addr_mem,data_mem存储器;打开eeprom.dat文件
initial begin
OUTFILE=$fopen("C:/users/lenovo/Desktop/example/eeprom.dat");
$readmemh("C:/users/lenovo/Desktop/example/addr.dat",addr_mem);
$readmemh("C:/users/lenovo/Desktop/example/data.dat",data_mem);
end
endmodule
其中,addr.dat,data.dat分别为存放EEPROM读/写操作地址,写操作数据的文件;eeprom.dat用于输出EEPROM读操作的数据,与写入数据对比是否一致(文件中数据为十六进制表示)。
00
01
02
03
04
05
06
07
08
09
0a
0b
0c
0d
0e
0f
10
11
12
13
14
15
16
17
18
19
1a
1b
1c
1d
1e
1f
20
21
22
23
24
25
26
27
28
29
2a
2b
2c
2d
2e
2f
30
31
32
33
34
35
36
37
38
39
3a
3b
3b
3a
39
38
37
36
35
34
33
32
31
30
2f
2e
2d
2c
2b
2a
29
28
27
26
25
24
23
22
21
20
1f
1e
1d
1c
1b
1a
19
18
17
16
15
14
13
12
11
10
0f
0e
0d
0c
0b
0a
09
08
07
06
05
04
03
02
01
00
仿真结果如下图所示:
写操作:

可观察到DATA此时从Signal模块输出至EEPROM读写器,该数据为EEPROM写操作的数据;WR为写信号,EEPROM读写器检测到该信号后,从SDA数据线给EEPROM器件发出写入帧信号;ADDR为写入地址。
读操作:

可观察到Signal发出读信号RD一段时间后,EEPROM读写器会发出应答信号ACK,同时返回读EEPROM数据DATA;将读数据与写入数据进行对比,可验证程序正确性:

本文介绍了一种基于Verilog的IIC接口EEPROM读写控制器的设计方法,包括信号源模块、EEPROM行为模型及EEPROM读写控制器模块的具体实现细节。详细解释了各个模块的功能、工作流程及仿真结果。
最低0.47元/天 解锁文章
1573

被折叠的 条评论
为什么被折叠?



