1.EEPROM简介
EEPROM (Electrically Erasable Programmable read only memory)是指带电可擦可编程只读存储器。是一种掉电后数据不丢失的存储芯片。在嵌入式控制系统中常常用来保存设备初始化所需数据。发展过程:ROM – > PROM –> EPROM –> EEPROM,大概就是从只能复杂的一次写入,发展到后来的电子可擦除。三种类型的存储器大概的区别,FLASH用于存放程序,在程序运行过程中不能更改,我们编写的程序是烧录到FLASH中的;RAM用作程序运行时的数据存储器;EEPROM用于存放数据,是用来保存掉电后用户不希望丢的数据,开机时用到的参数。运行过程中可以改变。多数EEPROM器件用到的都是IIC协议,本节以ATMEL(现属于MicroChip)的AT24C04芯片为例,基于IIC协议,提供一种驱动写法,完成对EEPROM的读写操作。本例用到的资料和工程链接
2.AT24C04简介
该系列芯片包含了AT24C01,AT24C02,AT24C04,AT24C08,AT24C16,AT24C32,AT24C64,AT24C128,AT24C256,其中不同的后缀代表不同的容量,单位是kbit,如AT24C04代表容量为4kbit。一个地址对应一个大小为8bit的数据单元,4kbit=512Bytes,即需要9bit二进制表示512个地址。因此写操作就是通过IIC协议分别写入EEPROM内部地址和相应数据即可,读操作也是类似的。由于存在协议的开销,如果按照这种方法进行读写效率会很低,于是生成芯片的厂家将内部地址分为“页”,在同一个“页”内可以连续读写,而不需要重新发起IIC的起始信号。例如AT24C04容量为4kbit分为了32页,每页16Bytes。即可以连续写的个数是16次,如下图所示(页写,或者叫连续写),一次IIC传输,发送了一次EEPROM地址,随后就连续发送数据,芯片内部会自动处理,但是当数据个数超过当前页中的字节时,会覆盖当前页中的第一个字节。当进行读操作时会自动翻页。需要注意的是,内部地址有9位,低8位作为单独的字节,第9位是器件地址部分的最后一位。芯片的器件地址为1010,其地址控制字格式为1 0 1 0 A2 A1 P0 R/W,1010为固定的值,而A2 A1是芯片引脚,具体值看板卡连接,P0代表内部地址的第9位。其他特性包括,两线串行接口(IIC);400kHz兼容性;具有写保护引脚,当该引脚拉高的时候,禁止所有写操作,用于硬件数据保护;高可靠性,100万次写入周期,数据可保留100年。
3.逻辑框架设计
假定一个应用场景是,向EEPROM最低位地址写入一个数据值为0x5a,然后在读出来,二者相等则认为读写正确。在这个应用中,何时对EEPROM执行什么操作,读写几个数,把这个问题且叫做“应用层“要解决的问题;而不同的EEPROM器件读写操作略有不同,例如容量大的器件可能需要两个地址字节,从另一个角度看,不同IIC的器件对数据传输顺序也有不同的要求,把区分器件称之为“器件层”;在此场景中,FPGA读写EEPROM使用的是IIC协议,因此一定有一层是解决驱动问题,称之为驱动层。通过这三层协调,完成应用需求。具体协调如下图所示。
应用层根据应用需求,产生信号告诉器件层执行一次动作,例如,执行一次EEPROM写入操作,当然要提供写入的数据内容和写入的地址。器件层将一次EEPROM写入操作分解为,首先要写器件地址与从机设备通信,然后写入EEPROM内部地址,最后写入数据,调用驱动层完成这些数据的下发。驱动层将按照器件层的指示,将数据打包成IIC协议的数据放到SDA线上发送,并完成起始位、终止位的生成和从机响应的接收和处理,以完成一次应用层指示的操作。请结合代码将有更准确的认识,关于驱动层请参考FPGA实现IIC接口。这样做的好处是,当换成其他器件或者相同器件不同应用的时候,需要修改的地方很明确,便于程序的扩展和移植。
4.随机读写时序
随机读时序如上图所示,随机写时序如下图所示。连续读或连续写的时序略有不同,请查看芯片手册。
5.仿真代码与仿真结果分析
仿真顶层文件sim_ctrl,解复位之后,其执行步骤如下所示,步骤与图中示意序号对应一致。
①下面代码为应用层代码,指示器件层,生成一条“向0地址写入数据0xA5的指令”
②iic_ctrl模块接到上层eep_en的指令,将所有携带信息全部寄存,并产生eep_busy信号指示ctrl模块状态。
③根据上层模块的指示,例如是EEPROM的读还是写操作,读几个地址,这些情况将这些指示分解成多个8bitIIC操作,然后下发。如图所示,首先在收到eep_en信号后,1状态判断读还是写,2状态分解并“调用”写操作任务,8状态等待iic_busy信号就绪(一个周期),3状态等待busy信号清零。另外关注,一个上层的读写命令被iic_en和cmd信号,以及data信号分解成了几种不同的8bit操作。
④可以在图中清晰的看到,iic_driver模块接到上层模块的指示,SCL信号生成400KHz时钟,SDA信号按照既定顺序输出bit(上拉电阻,因此无需输出高电平)。(下图中第二个eep_en脉冲指示读出操作,仿真时序不太对,但是依照上述代码执行出来仿真结果是对的)
仿真代码如下:
module sim_ctrl();
reg clk_50;
reg rst_n;
reg eep_en;
reg eep_rw;
wire [7:0]eep_rd_data;
wire eep_rd_valid;
wire eep_busy;
reg [7:0]eep_wr_data;
reg [8:0]eep_addr;
wire iic_clk;
wire iic_data;
initial begin
rst_n = 0;
clk_50 = 1;
eep_en = 0;
eep_rw = 0;
#1000
rst_n = 1;
//写入操作
#1000
eep_en = 1;
eep_rw = 0;
eep_wr_data = 8'hA5;
eep_addr = 9'd0;
#20
eep_en = 0;
@(negedge eep_busy)
#20
eep_en = 1;
eep_rw = 1;
eep_addr = 9'b0;
#20
eep_en = 0;
end
always #10 begin
clk_50 = ~clk_50;
end
iic_ctrl sub_for_one_rw(
.clk_50(clk_50),
.rst_n (rst_n),
.eep_en(eep_en), //eep前缀代表eeprom,代表执行一次eeprom操作
.eep_rw(eep_rw),
.eep_wr_data(eep_wr_data),
.eep_addr(eep_addr),
.eep_rd_data(eep_rd_data),
.eep_rd_valid(eep_rd_valid),
.eep_busy(eep_busy),
.iic_clk(iic_clk),
.iic_data(iic_data)
);
endmodule
6.注意事项
(1)工程里有三种读写操作指示信号需要区分
①第一种是在cmd[0]指示,1为读操作,0为写操作。此指令指示的是向iic_driver模块指示一个8bit操作时,该8bit操作是读还是写。例如eeprom执行一次随机读操作,那首先要写入器件地址,然后要写入要读取的地址,在写入器件地址,最后才能读取数据。上述四个步骤中,只有最后一步读取数据,iic_driver模块执行的是读8bit操作。
②第二种是顶层应用模块中的eep_rw,该信号指示的是是执行器件的读还是写操作,例如1代表执行eeprom读操作。
③第三种是IIC协议要求的,指示该次通信是读还是写,“该次通信”是指在一个起始位和一个终止位之间的通信称之为一次通信,该读写指示位应该在带起始位的8bit操作中的最后一个bit打出。例如,一次随机EEPROM读操作分为两次IIC通信,第一个为写入器件地址加写入内部地址,该通信是写操作;第二次是写入器件地址,读出有效数据,该次通信是读操作。这个通信指示位是按照8bit操作中的数据部分进行的。
(2)写保护功能,手册中:When the WP pin is connected directly to V CC , all write operations to the protected memory are inhibited.当该引脚接高电平时,禁止写操作,接低电平时可以写操作,如果悬空也可以写操作,但建议明确上下拉。实际应用中,在产品出厂之前拉低该信号以写入初始化配置等,在产品交付后拉高以禁止写操作。
(3)在写完一次之后 应该等待时间,等待写入数据进入到EEPROM内部电路,才能开始下一次的读写操作,否则无法正确操作,手册中是t WR ,即 self-timed write cycle。During the internally self-timed write cycle, any attempts to read from or write to the memory array will not be processed. 至少是5ms.如未达到5ms间隔,强行写入或者读出,将导致从机应答失败,反过来想,当从机应答失败时,这是很可能的原因。
(4)在en信号发出之后应该间隔一个周期等待busy信号,否则busy无法快速响应造成程序出错。
(5)器件硬件设计原理图参考,需要上拉,因此在HDL代码中,高电平不用输出,靠管脚电平即可。
7.效果
上板调试,使用ILA可以抓取到有效读出数据与写入数据一致,均为0xA5。