ZYNQ-QSPI Flash读写操作
学习内容
本文首先介绍Flash和QSPI Flash控制器的相关内容,然后使用 QSPI Flash 控制器,开发板上的 QSPI Flash 进行写、 读操作。通过对比读出的数据是否等于写入的数据, 从而验证读写操作是否正确。
开发环境
vivado 18.3&SDK,PYNQ-Z2开发板。
Flash简介
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读写速度慢,需要的硬件引脚少且不同容量的硬件兼容。
QSPI 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配置。
QSPI Flash 控制器内部框图
由上图可知,在线性地址模式下,使用的是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 控制器编程设计进行了指导开发,用户可以根据自己的设计需要参考指导手册中的编程顺序实现自己的应用功能。
启动顺序
- 配置时钟。
- 配置发送/接收信号。(以上两步在vivado底层搭建中已经完成设计)
- 重置控制器。
- 配置控制器。
配置控制器
该步骤适用于线性寻址和I / O模式。 它配置了控制器的波特率,FIFO,flash模式,时钟相位/极性和对环回延迟进行编程。
- 配置控制器。 写入qspi.Config_reg寄存器。
a. 设置波特率[BAUD_RATE_DIV]。
b. 选择主模式,[MODE_SEL] = 1。
C. 选择flash模式(不是传统SPI),[LEG_FLSH] = 1。
d. 选择Little Endian,[endian] = 0。
e. 将FIFO宽度设置为32位[FIFO_WIDTH]。
F. 设置时钟相位[CLK_PH]和极性[CLK_POL]。 - 启用回送时钟。 如果使用回送时钟,确保将qspi.Config_reg [BAUD_RATE_DIV]设置为0b00,并使用以下设置配置qspi.LPBK_DLY_ADJ(回送延迟调整)寄存器:
a. 设置为选择内部时钟。 qspi.LPBK_DLY_ADJ [USE_LPBK] = 1。
b. 将时钟延迟设置为0。qspi.LPBK_DLY_ADJ [DLY0] = 0b00。
c. 设置时钟延迟1. qspi.LPBK_DLY_ADJ [DLY1] = 0b00。
线性寻址模式
线性寻址模式下数据读取(存储器读取)的操作顺序如下:
- 将手动启动启用设置为自动模式。 设置qspi.Config_reg [Man_start_en] = 0。
- 使能片选信号。 设置qspi.Config_reg [PCS] = 0。
- 将配置寄存器编程为线性寻址模式。
- 启用控制器。 设置qspi.En_REG [SPI_EN] = 1。
- 从线性地址存储区读取数据。 内存范围取决于大小和设备数量。 范围是从0xFC00_0000到0xFDFF_FFFF。
- 禁用控制器。 设置qspi.En_REG [SPI_EN] = 0。
- 取消使能片选信号。 设置qspi.Config_reg [PCS] = 1。
配置I / O模式
使用I / O模式进行读取和写入编程步骤如下:
- 启用手动模式。qspi.Config_reg [Man_start_en,Manual_CS] = 1。
- 配置flash设备。 对单个闪存设备使用qspi.LQSPI_CFG寄存器的重置值。 如果是并行双闪存设备,则将1写入TWO_MEM,SEP_BUS位字段。
- 使能片选。 设置qspi.Config_reg [PCS] = 0。
- 启用控制器。 设置qspi.En_REG [SPI_EN] = 1。
- 将字节序列写入闪存。 使用TXD从1到4字节写入TxFIFO寄存器。
- 避免TxFIFO溢出。当TxFIFO为空时,可以写入252个字节。此后,软件可以通过读取qspi.Intr_status_REG [TX_FIFO_full]并等待直到它等于0之后再写入TXD寄存器,来避免TxFIFO溢出。
- 启用中断。写入qspi.Intrpt_en_REG。
- 开始数据传输。设置qspi.Config_reg [Man_start_com] = 1。
- 中断处理程序:在编程/读取操作期间,将所有需要的数据传输到QSPI flash,并传输到Quad-SPI flash。
- 如果执行了读取操作:重新排列READ数据以消除由于空循环而读取的数据。
- 取消使能片选信号。设置QSPI.Config_reg [PCS] = 1。
- 禁用控制器。设置qspi.En_REG [SPI_EN] = 0。
I/O模式中断服务程序
配置ISR以根据Quad-SPI器件类型处理中断条件。 要从Quad-SPI器件读取数据,最简单的ISR从RxFIFO读取数据并将内容写入TxFIFO。控制器生成系统外设中断(SPI),IRQ ID#51。对以下两种情况进行触发中断。
a. 读取传输中断。 RxFIFO不为空中断
b. 写传输中断。 TxFIFO未完全中断
I/O模式中断
中断仅在I / O模式下使用。只要满足任何中断条件,控制器中断就被置为有效。 Quad-SPI中断处理程序检查中断原因。单个中断服务程序可以管理所有中断条件。
Rx和Tx的中断处理程序
中断处理程序由IRQ ID#51触发。示例读取RxFIFO直到其为空,然后填充TxFIFO。 RxFIFO非空中断状态用于确定是否可以从RxFIFO读取内容。 TxFIFO未满中断指示TxFIFO中是否有空间容纳更多内容。
- 禁用控制器中的所有中断。将qspi.Intrpt_dis_REG [TX_FIFO_not_full,RX_FIFO_full]都设置为1。
- 清除中断。将1s写入中断状态寄存器qspi.Intr_status_REG。
- 清空RxFIFO。检查是否声明了RxFIFO非空中断。如果qspi.Intr_status_REG [RX_FIFO_not_empty] = 1,则RxFIFO中有数据。
a. 如果状态为有效,则从RxFIFO读取数据。使用qspi.RX_data_REG寄存器读取数据。
b. 从RxFIFO读取数据并轮询中断状态,直到RxFIFO为空。当qspi.Intr_status_REG [RX_FIFO_not_empty] = 0时,RxFIFO为空。 - 填充TxFIFO。检查TxFIFO未满状态是否有效。如果 qspi.Intr_status_REG [TX_FIFO_not_Full] = 1,则存在要发送到闪存设备的数据(编程和/或读取操作):
a. 将数据写入qspi.TXD0寄存器。
b. 轮询qspi.Intr_status_REG [TX_FIFO_full] = 1,这表明TX FIFO已满。
c. 遵循步骤a和b,直到将所有数据写入TxFIFO或直到qspi.Intr_status_REG[TX_FIFO_full] = 1。 - 启用中断。将qspi.Intrpt_en_REG [TX_FIFO_not_full,RX_FIFO_full]都设置为1。
- 开始数据传输。设置qspi.Config_reg [MANSTRTEN] = 1。
工程系统框图
本次工程的系统框图如下:
在本次工程设计中,使用QSPI Flash控制器对ZYNQ的QSPI Flash进行读写操作。通过对比读取数据和写入数据是否相等验证读写功能是否正常。
硬件平台搭建
新建工程,创建 Block Design。添加ZYNQ7 ip,根据本次工程需要对IP进行配置。勾选本次工程使用的资源。
完成对所用资源的勾选,
在clock configuration这里可以查看对QSPI的时钟配置。
这里不需要对其他资源进行配置,所以可以使用默认配置。
整体硬件系统构建完成如下:
然后我们进行generate output product 然后生成HDL封装。这里用到了仅仅用到了PS部分的资源,所以不需要进行管脚分配。点击导出硬件资源(不用包含bit流文件),接着launch SDK,进入软件部分编写。
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;//初始化QSPIQspiConfig = XQspiPs_LookupConfig(QspiDeviceId);XQspiPs_CfgInitialize(QspiInstancePtr, QspiConfig,QspiConfig->BaseAddress);//自测Status = XQspiPs_SelfTest(QspiInstancePtr);if (Status != XST_SUCCESS) {return XST_FAILURE;}//初始化读写BUFFERfor (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 IDFlashReadID();//使能FLASH Quad模式FlashQuadEnable(QspiInstancePtr);//擦除FLASHFlashErase(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;
}
运行效果
读写测试正常,运行效果如下:
References
- ZYNQ正点原子开发视频
- UG585
ZYNQ-QSPI Flash读写操作相关推荐
- Xilinx ZYNQ 7000学习笔记三(qspi flash读写操作)
参考文献:Zynq-7000 SoC Technical Reference Manual (UG585)-ch12 Quad-SPI Flash Controller 一.nor Flash介绍 z ...
- 瑞萨R78族Flash读写操作详细探讨
前言 最近使用到瑞萨R78族的MCU,准备做一个关于掉电保存参数配置的功能,需求大概是对200多个参数在掉电瞬间保存到芯片flash空间中,网上关于瑞萨MCU的flash读写操作教程也比较少,于是笔者 ...
- HC32 flash 读写操作
flash 读写操作 HC32 flash 简介 HC32 flash 操作和时钟之间的关系 Flash 的读写操作 解锁寄存器 单次编程无回读功能 单编程有回读 连续编程 擦除功能 全擦除功能 综合 ...
- 【FPGA】SPI协议详解及对flash读写操作
FPGA基于SPI实现对flash读写操作 概括 一.SPI协议.flash讲解 1.SPI协议 2.flash (1)WREN (2)RDID (3)WRSR (4)READ (5)PP (6)SE ...
- NAND FLASH 读写操作 简介
NAND FLASH 内存详解与读写寻址方式 一.内存详解 NAND闪存阵列分为一系列128kB的区块(block),这些区块是 NAND器件中最小的可擦除实体.擦除一个区块就是把所有的位(bit)设 ...
- Esp8266的Flash读写操作以及Flash上传文件
1.Flash的读写操作 Esp8266的Flash为4M,其中1M用于存储程序,其他的空间有一部分用于系统,3M中剩下的大部分空间可以用来存放文件. #include <FS.h> St ...
- (超详细)STM32芯片Flash读写操作讲解和代码(寄存器版本)
关于Flash,官方的解释为:Flash为32位宽的存储单元,可用于存储代码和数据常量.Flash模块位于微控制器内存映射中的特定基址--.而对于我们来说,只要知道Flash闪存区是一个掉电后也不会清 ...
- c语言指针flash,STM32F103RCT6之FLASH读写操作
一.STM32F103的FLASH简介 1.如图所示,STM32F103内部FLASH存储区分为三个区域:主存储区.信信息块和闪存存储器接口寄存器. 储存储区是我们读写FLASH的主要的存储区,MCU ...
- STM32远程升级IAP功能+备份功能实现。(flash读写操作)
远程升级加备份一共需要4个扇区,要确保flash可以被分成四个扇区(F4的扇区好大,4个16k,1个64k,剩下都是128k,对于小容量芯片非常不友好). 第一个存放出厂程序,也叫启动程序boot l ...
最新文章
- java 头尾 队列_超详细的java集合讲解
- Scrapy爬虫及案例剖析
- WPF 展示视频修改为WriteableBitmap
- MySQL 练习 创建表格2
- 调用GPU进行神经网络的训练 GPU环境的搭建
- C#中图片单击旋转事件
- BootStrap FileInput 插件实现多文件上传前端功能
- 网络工具之PacketTracer8安装
- FOSSID(开源代码检测工具)
- 计算机办公软件的课件,计算机常用办公软件ppt课件
- centos7安装搜狗拼音
- Unity获取组件的几种方式(拖拽法、标签法、名字法)
- 802.11协议wifi新加密方式WPA3介绍
- VIJOS 1206 CoVH之再破难关
- 成功解决wps文档中输入英文单词出现对应英文单词下边红色波浪线(英文拼写自动检测)去掉或加上图文教程
- 在现有oracle服务器上新建一个oracle实例
- 编码器-解码器入门级理解
- 东大22春电子政务X《电子政务》在线平时作业1答案非答案
- 微机原理伪指令大全及在C语言中的结合应用举例
- cdn加速华为云obs桶文件配置过程(详细)
热门文章
- DDMS 无法显示进程解决方案
- 100天精通Python丨基础知识篇 —— 08、Python 最常用的 20 个包(按使用频率排序)
- c++ cmake 项目 引入 googletest
- C语言指针函数和函数指针详解
- 计算机网络启动慢,网络链接太慢 这4个小技巧可以试试
- 电脑使用“映射网络驱动器”导致开机变慢
- 笔记本外接显示器后网速变慢解决办法
- 交叉熵、相对熵(KL散度)、JS散度和Wasserstein距离(推土机距离)
- 虾皮Shopee新加坡北京上海深圳 提前批 开启啦!年薪百万没那么难!
- HDU3999-The order of a Tree