IIC读写EEPROM
文章目录
前言
iic协议前一章已讲,此次不在赘述。
一、EEPROM是什么?
1.1 EEPROM简介
1、EEPROM,全称电可擦除可编程只读存储器 (Electrically-Erasable Programmable Read-Only Memory),是一种可以通过电子方式多次复写的半导体存储设备。相比EPROM,EEPROM不需要用紫外线照射,也不需取下,就可以用特定的电压,来抹除芯片上的信息,以便写入新的数据。
2、我们使用的是C4开发板,型号为24LC04B的EEPROM存储芯片。24LC04B的存储容量为512Bytes/4Kbits,其内部有两个Block,每个Block中有256个字节(一个字节为8bit)。其读写操作都是以字节(8bit)为基本单位。
3、16字节页写入缓冲区(能够接收缓存的数据最多是16字节)
4、100 kHz和400 kHz时钟兼容性
5、页面写入时间通常为3 ms
1.2 IIC对EEPROM进行设备寻址
在使用IIC协议进行主从设备通讯时,主机在发送了起始信号后,接着会向从机发送控制命令。控制命令长度为1个字节,它的高7位为设备的器件地址,最低位为读写控制位。
24LC04B EEPROM 存储芯片的器件地址包括:
厂商设置的高4位1010,这里设备代码
用户需自主设置的低3位 x、x、B0 来选择块地址
字节存储地址,一共8bit
1.2.1读写控制位
读写控制位为 0 时,表示主机(FPGA)要对从机(EEPROM)进行数据写入操作;
读写控制位为1 时,表示主机(FPGA)要对从机(EEPROM)进行数据读出操作。
1.3 IIC总线传输特征
在数据传输过程中,当时钟线(SCL)为高电平时,数据线(SDA)必须保持稳定,此时从机开始接收主机数据或主机接收从机的应答。
当时钟线(SCL)为低电平时,数据线(SDA)的数据可变化,来更新数据用来下一次的接收。
1.3.1 IIC起止信号
如上图:
当时钟线(SCL)为高电平期间,数据线(SDA)由高电平变为低电平即为起始信号。
当时钟线(SCL)为高电平期间,数据线(SDA)由低电平变为高电平即为停止信号。
(问:IIC协议 为啥要在时钟线(SCL)拉低的时候 数据线(SDA)数据才能变换?
答:如果在scl高电平的时候发生数据改变的话他会认为是起始信号或是停止信号)
二、EEPROM读写时序
2.1.写操作
在数据传输过程中,当时钟线(SCL)为高电平时,从机开始接收主机数据或主机接收从机的应答。
当时钟线(SCL)为低电平时,数据线(SDA)的数据可变化,来更新数据用来下一次的接收。而写操作就是在时钟线(SCL)低电平期间改变数据线(SDA)的值来传输数据。
写操作分为字节写和页写。
2.1.1 字节写(一次只能写入一个字节)
在进行字节写操作时,首先需要发送起始位(START),然后依次发送 写控制字节、地址字节、数据字节,在每发送完一个字节后,均需要一个应答信号ACK,最后发送停止位(STOP)。(注:如果地址超过一个字节,在发送地址时,先发送地址高字节)
-
起始位:主机拉低总线
-
控制字节:4bit控制码+3bit片选+1bit写标志。以24LC04B为例,要进行写操作的,地址随机的话,需要发送的控制字节为1010_0000。
-
应答信号ACK:由从机发送给主机,从机每接收到一字节数据时,向主机发送应答信号ACK,确认收到数据,此时主机方可进行下一字节数据发送。
-
非应答信号NACK:在读操作时,如果主机停止读取数据,由主机发送给从机非应答信号NACK。
-
停止位:主机拉高总线。
2.1.2 页写(一次最多写入十六字节)
在进行页写操作时,其写控制字节、地址字节、数据字节的方式与字节写操作基本相同,不同的是,页写操作可以将多个数据字节临时存储在片上页缓冲器中,当主机发送停止信号后,这些数据才被写入存储器,每接收到一个字节,内部地址计数器+1。
2.读操作
在数据传输过程中,当时钟线(SCL)为高电平时,数据线(SDA)必须保持稳定,此时主机开始接收从机数据或者从机接收主机的应答或者非应答。读操作就是在时钟线(SCL)为高电平期间读取(SDA)的值,数据线(SDA)的高低电平代表“1”或者“0”。
2.2.1 当前地址读
24LC04B内置一个自动+1的地址计数器,该计数器保留最后一次访问的地址,如果先前对地址n进行了读或写操作,则下一条读或写操作将从n+1开始读写。注意在读操作时,从机不会回复应答信号ACK,但是主机会产生非应答信号NACK。
- 起始位:主机拉低总线。
- 控制字节:4bit控制码+3bit片选+1bit读标志,以24LC04B为例,要进行读操作的,地址随机的话,需要发送的控制字节为1010_0001。
- 非应答信号NACK:在读操作时,如果主机停止读取数据,由主机发送给从机非应答信号NACK。
- 停止位:主机拉高总线。
2.2.2 随机读
随机读操作允许主机以任意方式访问从机存储单元,在此之前需要主机先发送地址字节给从机完成地址字节的设置(此过程是写操作,读写标志为0),随机读操作将从设置的地址开始读取。
地址字节发送完成后接收应答信号ACK,随后主机产生起始信号,随后发送控制字节(此过程是读操作,读写标志为1),然后从机响应应答信号,并发送8位数据字节,最后主机发送非应答信号NACK,发送停止位。读取数据完成后,内部地址计数器自增1,指向下一个地址单元。
2.2.3 顺序读
顺序读操作启动过程与随机读操作相同,但是在顺序读操作时,从机发送完第一个数据字节后,主机发送应答信号ACK进行确认,随后从机继续发送顺序地址的数据字节,发送完最后一个数据字节后,主机发送发送非应答信号NACK,并发送停止位。
24LC04B内置一个地址指针,每次操作完成后指针+1,地址指针允许一次操作顺序读取整个存储器内容,读到最后一个字节时,地址指针计满返回0。
三、工程设计
3.1.总体设计思想
1.使用外设按键模拟读写请求,收到读写请求后,FPGA通过IIC接口模块(iic_master)向EEPROM芯片写入单字节数据或者从EEPROM中读出单字节数据,在使用数码管显示需要写入的数据或显示被读出的数据。
2.主机(FPGA)接收从机(EEPROM)发送的数据,简称读。
- 按下key3,经过按键消抖模块(key_filter)后输出key_flag,模拟(rd_en)信号到eeprom读写控制模块(eeprom_control)中
- eeprom_control模块接收到读请求后,向iic_master模块发送读请求
- iic_master模块接收到读请求后,发送读控制字和读地址,以及以及将接收到的SDA信号进行串并转换发送给eeprom_control模块
- eeprom_control模块接收到的rd_data[7:0]发送到数码管显示模块进行显示
3.主机(FPGA)发送数据(EEPROM)给从机,简称写。
- 通过按键key1,将数据写入EEPROM中,
- eeprom_control模块向iic_master模块发送写请求和需要写入到数据,每次发送一字节的数据,在收到从机发送的应答信号后在发送1个字节
- i2c_master模块接收到写命令后便开始发送写控制字和写地址,然后将接收到的并行数据wr_data[7:0]进行一个串并转换来写入EEPROM中
3.2. 模块框图
3.3. iic_master模块转移图
- WRITE : 写完一个字节
- READ : 读完一个字节
- START : 发起始位
- STOP : 发停止位
- S_ACK : 主机发送应答 (应答或非应答)
- R_ACK : 主机接收应答 (应答或非应答)
// *******************************************************************************************************
// ** 作者 : 肥嘟嘟左卫门
// ** 邮箱 :
// ** 博客 :
// ** 日期 : 2023/03/30
// ** 功能 :1、基于FPGA的iic接口驱动模块;
// *******************************************************************************************************
module iic_master (
input clk ,
input rst_n ,
input wire sda_in ,
input wire req ,
input wire [3:0] cmd ,
input wire [7:0] wr_din ,
output reg scl ,
output reg [7:0] rd_out ,
output wire rd_out_vld ,
output reg ack_out ,
output wire rw_done ,
output reg sda_out ,
output reg sda_out_en
);
parameter IDLE = 8'b0000_0001 ,
START = 8'b0000_0010 ,
WR_DATA = 8'b0000_0100 ,
RD_DATA = 8'b0000_1000 ,
CHECK_ACK = 8'b0001_0000 ,
SEND_ACK = 8'b0010_0000 ,
STOP = 8'b0100_0000 ,
RST = 8'b1000_0000 ;
wire idle2start ;
wire idle2wrdata ;
wire idle2rddata ;
wire start2wrdata ;
wire start2rddata ;
wire wrdata2checkack ;
wire rddata2sendack ;
wire checkack2stop ;
wire sendack2stop ;
wire checkack2idle ;
wire sendack2idle ;
wire stop2idle ;
wire rst2idle ;
reg [7:0] state_c ;
reg [7:0] state_n ;
reg [7:0] din_flag ;
reg [5:0] cmd_flag ;
reg [9:0] cnt_scl ;
reg [3:0] cnt_bit ;
reg [3:0] num ;
wire add_cnt_scl ;
wire end_cnt_scl ;
wire add_cnt_bit ;
wire end_cnt_bit ;
parameter TIME_SCL = 300 ;
parameter TIME_REVER = 150;
parameter HIGH = 225 ;
parameter LOW = 75