2 FPGA实现SPI接口--SPI接口芯片的实际使用( 五 )

<设置初始测试条件>----------------------------------------initial beginsys_clk = 1'b0;//初始时钟为0sys_rst_n <= 1'b0;//初始复位#20//20个时钟周期后sys_rst_n <= 1'b1;//拉高复位,系统进入工作状态 end//打印数据always@(*)beginif(spi_read_inst.rec_done && spi_read_inst.spi_read_ctrl_inst.flow_cnt == 'd7)$display("READ :%h",spi_read_inst.data_rec);//打印读取的数据end//重定义初始化数值defparam memory.mem_access.initfile = "initM25P16_test.txt"; //其中的每页数据是从00累加到FF //------------<设置时钟>----------------------------------------------always #10 sys_clk = ~sys_clk;//系统时钟周期20nsendmodule
需要注意的是:
所以我们仿真的预期结果应该是读取的数据结果为00~09(共10个数据),仿真结果如下:
命令窗口打印如下:
可以看到读取的数据分别为0x00~0x09,与初始化的数据一致 。
2.2.4、上板验证
使用使用一块 IV E的开发板上板验证,该开发板板载了一个芯片作为上电后读取程序的FLASH 。需要注意的是,该FLASH的管脚需要从专用下载管脚,配置成普通的IO管脚,如下:
首先验证写模块:从地址24’d0开始分别写入10个数据:0x00~0x12 。使用 Tap II抓取的波形如下:
可以看到抓取的波形与仿真波形一致 。
接下来使用读数据模块从地址24’d0开始分别读取数据11次,比较读取的数据与写入的数据是否一致(第十一次用来对比) 。使用 Tap II抓取的波形如下:
可以前10个读取的数据分别为0x00~0x12,第11个数据因为前面没有写,所以是默认的0xFF,符合预期结果 。
2.3、扇区擦除( Erase) 2.3.1、时序
扇区擦除( Erase)操作,简称 SE,操作指令为 8’(D8h),扇区擦除指令是将 Flash 芯片中的被选中扇区的所有存储单元设置为全 1,在 Flash 芯片写入扇区擦出指令之前,需要先写入写使能 (WREN)指令;随后要拉低片选信号,写入扇区擦除指令、扇区地址、页地址和字节地址,在指令、地址写入过程中,片选信号始终保持低电平,待指令、地址被芯片锁存后,将片选信号拉高;扇区擦除指令、地址被锁存并执行后,需要等待一个完整的扇区擦除周期(tSE),才能完成 Flash 芯片的扇区擦除操作 。时序图如下:
2.3.2、代码
代码分为3个模块:SPI驱动模块、SPI扇区擦除控制模块l和扇区擦除顶层模块 。
SPI扇区擦除控制模块l代码如下:
//SPI扇区擦除控制模块`timescale 1ns/1ns//时间单位/精度module spi_sector_erase_ctrl#(parameterSECTOR_ADDR = 8'b0000_0000,//扇区地址parameter PAGE_ADDR= 8'b0000_0000,//页地址parameter BYTE_ADDR= 8'b0000_0000//字节地址)(inputsys_clk,// 全局时钟50MHzinputsys_rst_n ,// 复位信号,低电平有效inputsend_done ,// 主机发送一个字节完毕标志位outputregspi_start ,// 发送传输开始信号,一个高电平outputregspi_end,// 发送传输结束信号,一个高电平outputreg[7:0]data_send// 要发送的数据);//指令定义localparamWR_EN= 8'b0000_0110,//写使能指令 SECTOR_ERASE = 8'b1101_1000;//扇区擦除指令//reg definereg [7:0] flow_cnt;//状态跳转计数器reg [7:0] cnt_wait;//上电等待计数器always@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)begindata_send <= 8'd0;spi_start <= 1'b0; spi_end <= 1'b0; flow_cnt <= 1'd0;cnt_wait <= 8'd0;endelse beginspi_start <= 1'b0;//便于生成脉冲信号spi_end <= 1'b0;//便于生成脉冲信号case(flow_cnt)'d0:beginif(cnt_wait == 100)begin//上电后等待稳定cnt_wait <= 8'd0;flow_cnt <= flow_cnt + 1'd1;endelse begincnt_wait <= cnt_wait + 1'd1;flow_cnt <= flow_cnt;endend'd1:begindata_send <= WR_EN;//数据为写使能指令spi_start <= 1'b1;//拉高spi开始通讯信号flow_cnt <= flow_cnt + 1'd1;end'd2:beginif(send_done)begin//主机一个字节数据被发送完成flow_cnt