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

<例化模块>----------------------------------------------------------------//页写模块spi_page_program_ctrl#(.SECTOR_ADDR(SECTOR_ADDR),.PAGE_ADDR(PAGE_ADDR),.BYTE_ADDR(BYTE_ADDR)) spi_sector_erase_ctrl_inst(.sys_clk(sys_clk ),.sys_rst_n(sys_rst_n ),.send_done(send_done ),.spi_start(spi_start ),.spi_end(spi_end ),.data_send(data_send ));//SPI驱动spi_drive spi_drive_inst(.sys_clk(sys_clk ),.sys_rst_n(sys_rst_n ),.spi_start(spi_start ),.spi_end(spi_end ),.data_send(data_send ),.data_rec(data_rec ),.send_done(send_done ),.rec_done(rec_done ),.spi_miso(spi_miso ),.spi_sclk(spi_sclk ),.spi_cs(spi_cs),.spi_mosi(spi_mosi ));endmodule
2.1.3、及仿真结果
比较简单直接例化SPI页写模块和仿真模型即可,需要注意的是SPI的的页写操作需要一定的时间(前面已经提到过--5ms) 。
仿真结果如下:
从地址24'h0开始,一次写入数据0x00,0x02,0x04···0x12一共10个数据,可以看到在MOSI上,依次出现了上述10个数据,说明符合SPI协议规范 。
命令窗口打印内容如下(单位:ps):
在约12us处开始进行页写操作,5ms后页写操作完成,同样符合芯片参数 。
2.1.4、上板验证
同读数据操作一同验证,详见2.2.4章节 。
2.2、读数据(READ DATA BYTES) 2.2.1、时序
读数据操作,操作指令为 8’(03h),要执行数据读指令,首先拉低片选信号选中 Flash 芯片,随后写入数据读(READ)指 令,紧跟指令写入 3 字节的数据读取首地址,指令和地址会在串行时钟上升沿被芯片锁存 。随后存储地址对应存储单元中的数据在串行时钟下降沿通过串行数据总线输出 。数据读取首地址可以为芯片中的任何一个有效地址,使用数据读(READ)指令可以对芯 片内数据连续读取,当首地址数据读取完成,会自动对首地址的下一个地址进行数据读取 。若最高位地址内数据读取完成,会自动跳转到芯片首地址继续进行数据读取,只有再次拉高片选信号,才能停止数据读操作,否者会对芯片执行无线循环读操作 。具体时序如下:
2.2.2、代码
代码分为3个模块:SPI驱动模块、SPI读数据控制模块和例化前面两个子模块的读数据顶层模块 。
SPI读数据控制模块代码如下:
//FLASH读数据控制模块:合适的调用SPI驱动模块module spi_read_ctrl#(parameter BYTE_MAX= 8'd10,//一共读取多少个BYTE的数据SECTOR_ADDR = 8'b0000_0000 ,//扇区地址PAGE_ADDR= 8'b0000_0000 ,//页地址BYTE_ADDR= 8'b0000_0000//字节地址)(inputsys_clk,// 全局时钟50MHzinputsys_rst_n ,// 复位信号,低电平有效input[7:0] data_rec,// 接收到的数据inputrec_done ,// 主机接收一个字节完毕标志位 inputsend_done ,// 主机发送一个字节完毕标志位outputregspi_start ,// 发送传输开始信号,一个高电平outputregspi_end,// 发送传输结束信号,一个高电平outputreg[7:0]data_send// 要发送的数据); //指令定义 localparam READ= 8'h03;//读数据指令//reg definereg [7:0] flow_cnt;//状态跳转计数器reg [7:0] data_cnt;//数据接收计数器reg [7:0] cnt_wait;//上电等待计数器always@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)begin//复位状态data_send <= 8'd0;spi_start <= 1'b0; spi_end <= 1'b0; flow_cnt <= 1'd0;cnt_wait <= 8'd0;data_cnt <= 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:begin//发送读数据指令 data_send <= READ;//读数据指令spi_start <= 1'b1;//拉高spi开始通讯信号flow_cnt <= flow_cnt + 1'd1;end 'd2:begin//发送扇区地址if(send_done)begin//指令被发送完成flow_cnt