电子说
Flash存储器,又叫做闪存,是一种非易失性存储器。具有操作方便读写速度快等优点。一般用于存储操作系统和程序代码,或者用于数据存储。Flash的存储单元组织为块阵列,块是擦除操作的最小单位,擦除操作将块内的所有为置位为1,页是读写操作的基本单位。在对页进行写操作前,要判断该页内所有位是否为1。如果全部为1可以写操作,否则要对整块进行擦除操作(Flash只能从1反转到0)。Flash在内部结构(接口)上主要分为Nor flash 和NAND flash。Nor Flash :写入和擦除的速度低;结构复杂,成本高;存储容量较小;一般用于存储Bootloader以及操作系统或者程序代码,可以在芯片内部直接运行代码。NAND Flash :写入和擦除的速度较快;结构简单,成本低;存储容量较大;一般用于存储材料和数据。
Flash在外部接口上主要分为CFI flash 和SPI(STD/Dual/Quad) flash。CFI flash 读写速度快,需要的硬件引脚多且不同容量的硬件不兼容;而SPI(STD/Dual/Quad) flash读写速度慢,需要的硬件引脚少且不同容量的硬件兼容。
Quad-SPI闪存控制器是位于PS内的输入/输出外设(IOP)的一部分。它用于访问多位串行闪存设备,以实现高吞吐量和低引脚数应用。
控制器可以以三种模式运行: I / O模式 ,线性寻址模式和 传统SPI模式 。
在I / O模式下,软件与闪存设备协议紧密交互,所以在该模式下需要对协议进行详细了解。软件通过使用四个TXD寄存器将闪存命令和数据写入控制器。软件通过读取RXD寄存器。
线性寻址模式使用设备操作的子集来消除I / O模式读取闪存所需的软件开销。也就是说线性寻址模式比IO模式要快的多。线性模式采用硬件来向闪存发出命令,并控制从flash到AXI接口的数据。控制器响应AXI接口上的存储器请求,就好像闪存是ROM存储器。
在传统模式下,QSPI控制器充当普通的SPI控制器。
控制器可以与一或两个闪存设备接口。可以并行连接两个设备以实现8位性能,也可以以堆叠的4位布局连接以最大程度地减少引脚数。
QSPI Flash 控制器的系统框图如下所示:
从上图中可知, QSPI Flash 控制器通过 MIO 与外部 Flash 器件连接,支持三种模式:单个从器件模式、双从器件并行模式和双从器件堆叠模式。双从器件并行模式把每个flash的IO进行单独连接,扩展成8位用于控制对不同flash的访问。而双从器件堆叠模式,使用SS片选信号进行区分flash的使能,所以想扩展 QSPI Flash 的存储容量,可以使用双从器件并行模式。
当使用单个设备时,直接存储器读取的地址映射从FC00_0000开始,最大为FCFF_FFFF(16 MB)。两台设备系统的地址映射取决于存储设备和I / O配置。
由上图可知,在线性地址模式下,使用的是AXI的接口进行数据交互的,首先由AXI总线读取到响应的指令,并存到Command FIFO,然后使用AXI to SPI的命令转化器传输到选择器。在IO模式下,使用的是APB接口直接把接收到的信号传输给选择器进行选择。然后选择器进行功能选择后传输到TxFIFO,接着把Tx FIFO的数据进行串行化,然后通过MIO引脚发送。接收部分原理相反,而且可以看出在线性地址模式下,接收信号的转换使用的是数据转换器。所以在线性地址模式下,只支持读取数据,不支持发送数据。
在数据传输期间,I / O模式具有不同的流控制模式。用户可以在自动和手动模式之间进行选择,该模式由config_reg.MANSTARTEN(Man_start_com)控制。在自动模式下,包括芯片选择控制在内的整个传输过程都在硬件中完成。无需软件干预。在手动模式下,用户控制数据传输的开始。在这种情况下,软件要么将整个传输序列写入TxFIFO,要么直到TxFIFO已满。在手动模式下,用户除了控制传输开始之外,还可以选择控制芯片选择。从命令开始,软件再次将传输序列写入TxFIFO,直到TxFIFO已满。然后,软件拉高CS,然后手动启动进行硬件管理。
在xilinx给出的UG585指导手册中,对QSPI Flash 控制器编程设计进行了指导开发,用户可以根据自己的设计需要参考指导手册中的编程顺序实现自己的应用功能。
该步骤适用于线性寻址和I / O模式。它配置了控制器的波特率,FIFO,flash模式,时钟相位/极性和对环回延迟进行编程。
线性寻址模式下数据读取(存储器读取)的操作顺序如下:
使用I / O模式进行读取和写入编程步骤如下:
配置ISR以根据Quad-SPI器件类型处理中断条件。要从Quad-SPI器件读取数据,最简单的ISR从RxFIFO读取数据并将内容写入TxFIFO。控制器生成系统外设中断(SPI),IRQ ID#51。对以下两种情况进行触发中断。a. 读取传输中断。RxFIFO不为空中断 b. 写传输中断。TxFIFO未完全中断
中断仅在I / O模式下使用。只要满足任何中断条件,控制器中断就被置为有效。Quad-SPI中断处理程序检查中断原因。单个中断服务程序可以管理所有中断条件。
Rx和Tx的中断处理程序
中断处理程序由IRQ ID#51触发。示例读取RxFIFO直到其为空,然后填充TxFIFO。RxFIFO非空中断状态用于确定是否可以从RxFIFO读取内容。TxFIFO未满中断指示TxFIFO中是否有空间容纳更多内容。
本次工程的系统框图如下:
在本次工程设计中,使用QSPI Flash控制器对ZYNQ的QSPI Flash进行读写操作。通过对比读取数据和写入数据是否相等验证读写功能是否正常。
新建工程,创建 Block Design。添加ZYNQ7 ip,根据本次工程需要对IP进行配置。勾选本次工程使用的资源。
完成对所用资源的勾选,
在clock configuration这里可以查看对QSPI的时钟配置。
这里不需要对其他资源进行配置,所以可以使用默认配置。整体硬件系统构建完成如下:
然后我们进行generate output product 然后生成HDL封装。这里用到了仅仅用到了PS部分的资源,所以不需要进行管脚分配。点击导出硬件资源(不用包含bit流文件),接着launch SDK,进入软件部分编写。
打开SDK后,新建application project。在system.mss中可以打开相关参考文档辅助设计。
可以选择qspi的例程进行参考设计,导入例程模板,
根据提供的模板,主要使用的函数如下,这里对他的读写测试进行了简化,
int QspiFlashPolledExample(XQspiPs *QspiInstancePtr, u16 QspiDeviceId)
{
int Status;
u8 *BufferPtr;
u8 UniqueValue;
int Count;
int Page;
XQspiPs_Config *QspiConfig;
//初始化QSPI
QspiConfig = XQspiPs_LookupConfig(QspiDeviceId);
XQspiPs_CfgInitialize(QspiInstancePtr, QspiConfig,QspiConfig- >BaseAddress);
//自测
Status = XQspiPs_SelfTest(QspiInstancePtr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
//初始化读写BUFFER
for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < PAGE_SIZE;
Count++, UniqueValue++) {
WriteBuffer[DATA_OFFSET + Count] = (u8)(UniqueValue + Test);
}
memset(ReadBuffer, 0x00, sizeof(ReadBuffer));
//设置手动启动和手动片选模式
XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_MANUAL_START_OPTION |
XQSPIPS_FORCE_SSELECT_OPTION |
XQSPIPS_HOLD_B_DRIVE_OPTION);
//设置QSPI时钟的分频系数
XQspiPs_SetClkPrescaler(QspiInstancePtr, XQSPIPS_CLK_PRESCALE_8);
//片选信号置为有效
XQspiPs_SetSlaveSelect(QspiInstancePtr);
//读FLASH ID
FlashReadID();
//使能FLASH Quad模式
FlashQuadEnable(QspiInstancePtr);
//擦除FLASH
FlashErase(QspiInstancePtr, TEST_ADDRESS, MAX_DATA);
//向FLASH中写入数据
for (Page = 0; Page < PAGE_COUNT; Page++) {
FlashWrite(QspiInstancePtr, (Page * PAGE_SIZE) + TEST_ADDRESS,
PAGE_SIZE, WRITE_CMD);
}
//使用QUAD模式从FLASH中读出数据
FlashRead(QspiInstancePtr, TEST_ADDRESS, MAX_DATA, READ_CMD);
//对比写入FLASH与从FLASH中读出的数据
BufferPtr = &ReadBuffer[DATA_OFFSET];
for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA;
Count++, UniqueValue++) {
if (BufferPtr[Count] != (u8)(UniqueValue + Test)) {
return XST_FAILURE;
}
}
return XST_SUCCESS;
}
读写测试正常,运行效果如下:
全部0条评论
快来发表一下你的评论吧 !