12.4 实验原理
12.4.1 AT24C02芯片介绍
AT24C02是一种带电可擦除可编程只读存储器,采用8-pin DIP和8-pin SOP封装,有2线串行接口,完全兼容I2C总线,管脚功能描述如下。

AT24C02芯片典型电路连接如下:

12.4.2 AT24C02芯片连接
STEP BaseBoard V4.0底板上的AT24C02模块电路图如下

上图为数据存储芯片AT24C02模块电路,与FPGA硬件接口有I2C总线(SCL、SDA),AT24C02是美国ATmel公司的低功耗CMOS型E2PROM,内含256*8位存储空间,具有工作电压宽(2.5V~5.5V),擦写次数多(大于10000次),写入速度快(小于10ms),抗干扰能力强,数据不易丢失,体积小等特点。并且它是采用I2C总线式进行数据读写的串行操作,只占用很少的资源和I/O线。AT24C02有一个16字节页写缓冲器,该器件通过I2C总线接口进行操作,还有一个专门的写保护功能。

12.4.3 AT24C02驱动设计
通过前面的了解,我们对于整个I2C总线的驱动原理有了一定的了解,接下来我们根据AT24C02的芯片手册了解其驱动方法及参数要点。


通过AT24C02时序参数了解,AT24C02支持I2C通信400KHz快速模式的同时兼容100KHz的标准模式,还有两种模式下时序中的各种时间参数,所以通信速度不需要调整。
- 分频得到400KHz的时钟,程序实现同智能接近系统设计实验。
I2C时序基本单元(启动、停止、发送、接收、发应答、读应答)协议里统一的,所以所以基本单元状态的设计也是不需要调整的。
-启动时序状态设计程序实现同智能接近系统设计实验。 -发送单元和读应答单元合并,时序状态设计程序实现同智能接近系统设计实验。 -接收单元和写应答单元合并,时序状态设计程序实现同智能接近系统设计实验。 -停止时序状态设计程序实现同智能接近系统设计实验。
各型号芯片器件地址如下,最后一位用于区分读写

对于写操作而言,分为两种,字节写和页写,本实验采用了字节写;对于读操作而言,则有当前地址读,随机读,顺序读三种,本实验采用了随机读方式完成。
字节写操作时序流程如下:

我们将这种操作设计成一个一个状态,程序实现如下:
MODE1:begin //单次写操作
if(cnt_mode1 >= 3'd5)
cnt_mode1 <= 1'b0; //对START中的子状态执行控制cnt_start
else cnt_mode1 <= cnt_mode1 + 1'b1;
state_back <= MODE1;
case(cnt_mode1)
3'd0: begin state <= START; end //I2C通信时序中的START
3'd1: begin data_wr <= dev_addr; state <= WRITE; end //设备地址
3'd2: begin data_wr <= reg_addr; state <= WRITE; end //寄存器地址
3'd3: begin data_wr <= `WRITE_DATA; state <= WRITE; end //写入数据
3'd4: begin state <= STOP; end //I2C通信时序中的STOP
3'd5: begin state <= MAIN; end //返回MAIN
default: state <= IDLE; //如果程序失控,进入IDLE自复位状态
endcase
随机读操作时序流程如下:

同理,程序实现如下
MODE2:begin //随机读操作
if(cnt_mode2 >= 4'd8)
cnt_mode2 <= 1'b0; //对START中的子状态执行控制cnt_start
else
cnt_mode2 <= cnt_mode2 + 1'b1;
state_back <= MODE2;
case(cnt_mode2)
4'd0: begin state <= START; end //I2C通信时序中的START
4'd1: begin data_wr <= dev_addr; state <= WRITE; end //设备地址
4'd2: begin data_wr <= reg_addr; state <= WRITE; end //寄存器地址
4'd3: begin state <= START; end //I2C通信时序中的START
4'd4: begin data_wr <= dev_addr_r; state <= WRITE; end //设备地址
4'd5: begin ack <= ACK; state <= READ; end //读寄存器数 据
4'd6: begin seg_data <= data_r; end
4'd7: begin ack <= NACK; state <= STOP; end //I2C通信时序中的STOP
4'd8: begin state <= MAIN; end //返回MAIN
default: state <= IDLE; //如果程序失控,进入IDLE自复位状态
endcase
end
最后我们编程控制状态机按照驱动例程代码中 流程运行,程序实现如下:
MAIN:begin
if(cnt_main >= 2'd2)
cnt_main <= 2'd0; //写完控制指令后循环读数据
else
cnt_main <= cnt_main + 1'b1;
case(cnt_main)
2'd0: begin dev_addr <= 8'ha0; reg_addr <= 8'h80; state <= MODE1; end //写入数据
2'd1: begin num_delay <= 24'd2000; state <= DELAY; end //5ms延时
2'd2: begin dev_addr <= 8'ha0; dev_addr_r <= 8'ha1; reg_addr <= 8'h80; state <= MODE2; end //读取数据
default: state <= IDLE; //如果程序失控,进入IDLE自复位状态
endcase
end
12.4.4 系统总体实现
本实验例程往EEPROM写0~255的递增数,同时读取出来显示在数码管上:
at24_driver u1(
.clk (clk ), //系统时钟
.rst_n (rst_n ), //系统复位,低有效
.i2c_scl (i2c_scl ), //I2C总线SCL
.i2c_sda (i2c_sda ), //I2C总线SDA
.data_valid (),
.data_out (data_out)
);
wire [19:0] data_bcd;
bin_to_bcd u2
(
.rst_n (rst_n ), //系统复位,低有效
.bin_code (data_out ), //需要进行BCD转码的二进制数据
.bcd_code (data_bcd ) //转码后的BCD码型数据输出
);
segment_scan u3(
.clk (clk ), //系统时钟
.rst_n (rst_n ), //系统复位,低有效
.dat_1 ( ), //SEG1
.dat_2 ( ), //SEG2
.dat_3 ( ), //SEG3
.dat_4 (data_bcd[19:16] ), //SEG4
.dat_5 (data_bcd[15:12]), //SEG5
.dat_6 (data_bcd[11: 8]), //SEG6
.dat_7 (data_bcd[ 7: 4]), //SEG7
.dat_8 (data_bcd[ 3: 0]), //SEG8
.dat_en (8'b0001_1111 ), //各位数码管数据显示使能,[MSB~LSB]=[SEG1~SEG8]
.dot_en (8'b0000_0000 ), //各位数码管小数点显示使能,[MSB~LSB]=[SEG1~SEG8]
.seg_rck (seg_rck ), //74HC595的RCK管脚
.seg_sck (seg_sck ), //74HC595的SCK管脚
.seg_din (seg_din ) //74HC595的SER管脚
);
综合后的设计框图如下:
