【接⼝时序】QSPIFlash的原理与QSPI时序的Verilog实现⼀、 软件平台与硬件平台
软件平台:
1、操作系统:Windows-8.1
2、开发套件:ISE14.7
3、仿真⼯具:ModelSim-10.4-SEfprintf作用
4、Matlab版本:Matlab2014b/Matlab2016a
硬件平台:
1、 FPGA型号:Xilinx公司的XC6SLX45-2CSG324
2、 Flash型号:WinBond公司的W25Q128BV Quad SPI Flash存储器
提⽰:如果图⽚不清晰,请把图⽚在浏览器的新建标签页打开或保存到本地打开。
⼆、 原理介绍
上⼀篇博客《SPI总线的原理与FPGA实现》中已经有关于标准SPI协议的原理与时序的介绍,这⾥不再赘述。本节主要是讨论
QSPI(Quad SPI,四线SPI总线)的相关内容。我的开发板上有⼀⽚型号是W25Q128BV的Quad SPI Flash存储器,本⽂将以它为例⼦来说明QSPI操作的⼀些内容。
W25Q128BV的Quad SPI Flash存储器的Top View如下图所⽰
这块芯⽚⼀共有8个有⽤的管脚,其每个管脚的功能定义如下图所⽰
由上图可知2号管脚DO(IO1),3号管脚 /WP(IO2),5号管脚DI(IO0)以及7号管脚/HOLD(IO3)均为双向IO⼝,所以在编写Verilog代码的时候要把它们定义为inout类型,inout类型的信号既可以做输出也可以作为输⼊,具体在代码⾥⾯如何处理后⽂会有介绍。
QSPI Flash每个引脚的详细描述如下:
1、Chip Select(/CS)
⽚选信号Chip Select(/CS)的作⽤是使能或者不使能设备的操作,当CS为⾼时,表⽰设备未被选中,串⾏数据输出线(DO或
IO0,IO1,IO2,IO3)均处于⾼阻态,当CS为低时,表⽰设备被选中,FPGA可以给QSPI Flash发送数据或从QSPI Flash接收数据。
2、串⾏数据输⼊信号DI以及串⾏输出信号DO
W25Q128BV⽀持标准SPI协议,双线SPI(Dual SPI)协议与四线SPI(Quad SPI)协议。标准的SPI协议在串⾏时钟信号(SCLK)的上升沿把串⾏输⼊信号DI上的数据存⼊QSPI Flash中,在串⾏时钟信号(SCLK)的下降沿把QSPI Flash中的数据串⾏化通过单向的DO引脚输出。⽽在Dual SPI与Quad SPI中,DI与DO均为双向信号(既可以作为输⼊,也可以作为输出)。
3、Write Project(/WP)
写保护信号的作⽤是防⽌QSPI Flash的状态寄存器被写⼊错误的数据,WP信号低电平有效,但是当状态寄存器2的QE位被置1时,WP信号失去写保护功能,它变成Quad SPI的⼀个双向数据传输信号。
4、HOLD(/HOLD)
HOLD信号的作⽤是暂停QSPI Flash的操作。当HOLD信号为低,并且CS也为低时,串⾏输出信号DO将处于⾼阻态,串⾏输⼊信号DI与串⾏时钟信号SCLK将被QSPI Flash忽略。当HOLD拉⾼以后,QSPI Flash的读写操作能继续进⾏。当多个SPI设备共享同⼀组SPI 总线相同的信号的时候,可以通过
HOLD来切换信号的流向。和WP信号⼀样,当当状态寄存器2的QE位被置1时,HOLD信号失去保持功能,它也变成Quad SPI的⼀个双向数据传输信号。
5、串⾏时钟线
串⾏时钟线⽤来提供串⾏输⼊输出操作的时钟。
W25Q128BV的内部结构框图如下图所⽰:
更多详细的内容请阅读W25Q128BV的芯⽚⼿册。由于本⽂要进⾏4线SPI的操作,但QSPI Flash默认的操作模式是标准单线SPI模式,所以在每次进⾏4线SPI操作的时候⼀定要先把状态寄存器2的QE位(倒数第2位)置1,然后才能进⾏QSPI操作。
最后介绍⼀下我的开发板上QSPI Flash硬件原理图如下图所⽰:
三、 ⽬标任务
1、编写标准SPI 协议 Verilog代码来操作QSPI Flash,并⽤ChipScope抓出各个指令的时序与芯⽚⼿册提供的时序进⾏对⽐
2、在标准SPI协议的基础上增加Quad SPI的功能,并⽤ChipScope抓出Quad SPI的读写数据的时序
3、对⽐标准SPI与Quad SPI读写W25Q128BV的ChipScope时序,感受⼆者的效率差距
四、 设计思路与Verilog代码编写
4.1、 命令类型的定义
W25Q128BV⼀共有35条命令,这⾥不可能把所有命令的逻辑都写出来,所以截取了⼀部分常⽤的命令作为⽰例来说明QSPI Flash 的操作⽅法。由于命令数⽬很多,所以在这个部分先对各个命令类型做⼀个初步定义,下⽂的代码就是按照这个定义来编写的。
命令编号命令类型(⾃定义)命令码(芯⽚⼿册定义)命令功能
15’b0XXXX8’h00⽆
25’b100008’h90读设备ID
35’b100018’h06写使能
45’b100108’h20扇区擦除
55’b100118’h05/8’h35读状态寄存器1/2
65’b101008’h04关闭写使能
75’b101018’h02写数据操作(单线模式)
85’b101108’h01写状态寄存器
95’b101118’h03读数据操作(单线模式)
105’b110008’h32写数据操作(四线模式)
115’b110018’h6b读数据操作(四线模式)
说明:
1、命令类型是我⾃⼰随便定义的,可以随便修改。命令码是芯⽚⼿册上定义好,不能修改,更详细的内容请参考W25Q128芯⽚⼿册。
2、命令类型的最⾼位是使能位,只有当最⾼位为1时,命令才有效(在代码⾥⾯写的就是只有当最⾼位为1时才能进⼊SPI操作的状态机)。
3、进⾏四线读写操作之前,⼀定要把四线读写功能的使能位打开,⽅法是通过写状态寄存器命令把
状态寄存器2的QE位(倒数第⼆位)置1。
4.2、 如何⽤Matlab产⽣存放在ROM中的.coe⽂件格式的数据
上⼀节设计了⼀个把存放在ROM中的数据⽤SPI总线发出来的例⼦,ROM⾥⾯只存放了10个数据,所以可以直接把这10个数据填写到.coe⽂件就可以了,由于QSPI Flash的页编程(写数据)指令最⼤⽀持256字节的写操作,所以下⾯的例⼦的功能是把ROM中存放的256个字节(8-bit)数据先写⼊QSPI Flash中,然后在读出来。由于数据太多(256个),所以⼀个⼀个填写肯定不现实,所以可以利⽤Matlab来直接产⽣.coe⽂件,Matlab的完整代码如下:
width=8; %rom中数据的宽度
depth=256; %rom的深度
y=0:255;
y=fliplr(y); %产⽣要发送的数据,255,254,253,...... ,2,1,0
fid = fopen('', 'w'); % 打开⼀个.coe⽂件
% 存放在ROM中的.coe⽂件第⼀⾏必须是这个字符串,16表⽰16进制,可以改成其他进制
fprintf(fid,'memory_initialization_radix=16;\n');
% 存放在ROM中的.coe⽂件第⼆⾏必须是这个字符串
fprintf(fid,'memory_initialization_vector=\n');
% 把前255个数据写⼊.coe⽂件中,并⽤逗号隔开,为了⽅便知道数据的个数,每⾏只写⼀个数据
fprintf(fid,'%x,\n',y(1:end-1));
% 把最后⼀个数据写⼊.coe⽂件中,并⽤分号结尾
fprintf(fid,'%x;\n',y(end));
fclose(fid); % 关闭⽂件指针
⽤Matlab2014b运⾏上⾯的代码以后会在与这个.m⽂件相同的⽬录下产⽣⼀个.coe⽂件,这个.coe⽂件可以导⼊到ROM中。
4.3、 标准SPI总线操作QSPI Flash思路与代码编写
上⼀篇博客《SPI总线的原理与FPGA实现》已经介绍过⽤spi_module这个模块去读取QSPI Flash的Manufacturer/Device ID,事实上除了上篇博客提供的那种⽅法以外,还可以直接在时钟信号的下降沿发送数据,时钟信号的上升沿来接受数据来完成读ID的操作,当FPGA在时钟的下降沿发送数据的时候,那么时钟的上升沿刚好在数据的正中间,QSPI Flash刚好可以在这个上升沿把数据读进来,读操作则正好相反。但是有很多有经验的⼈告诉我在设计中如⾮必要最好不要使⽤时钟下降沿触发的设计⽅法,可能是因为⼤多数FPGA⾥⾯的Flip Flops资源都是上升沿触发的,如果在Verilog代码采⽤下降沿触发的话 ,综合的时候会在CLK输⼊信号前⾯综合出⼀个反相器,这个反相器可能会对时钟信号的质量有影响,具体的原因等我再Google上继续搜索⼀段时间在说。这个例⼦由于状态机相较前⼏篇博客来说相对复杂,所以接下来写代码我还是采⽤下降沿发送数据,上升沿接收数据的⽅式来描述这个状态机。
接下来的任务就是抽象出⼀个状态机。上⼀篇博客仅仅读⼀个ID就⽤了6个状态,所以采⽤上⼀篇博客的设计思路显然不太现实,但对于初学者⽽⾔,上⼀篇博客仍然有⼀个基本的指引作⽤。通过阅读QSPI Flash的芯⽚⼿册,可以发现,所有的命令其实⾄多由以下三个部分组成:
1、发送8-bit的命令码
2、发送24-bit的地址码
3、发送数据或接收数据
所有命令的状态跳变图可由下图描述
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论