Smart ZYNQ(SP&SL 版) 工程三十二 PS端 QSPI FLASH读写测试

本文将演示如何对板载的QSPI FLASH进行数据的读写操作

之前在 工程八 中我们介绍过如何将芯片的程序固化进QSPI FLASH 中,以让系统每次开机从FLASH 芯片加载程序启动。 除了存储程序外,QSPI FLASH 还可以用来存储需要断电保存的数据。本文将对中间的过程进行演示。

写在前面:注意FLASH 是有读写寿命的,所以程序上要避免在死循环中对flash进行一直的反复写入。

本文在 vivado2018.3版本上 演示, 其他版本请自行研究

(备注 此章节内容适用于 Smart ZYNQ SP和SL 版的板子,如果是Smart ZYNQ 标准版请看对应板子目录

一、Vivado 部分设计

Vivado 部分工程的创建和之前已经介绍过很多次了,所以这里仅仅介绍重点:

创建一个BLOCK设计

1)IP INTEGRATOR→Create Block Design,在弹出的对话框中输入设计名,最后点击“OK”,如下图所示

2)在右侧的窗口里 ,点击加号,在选择框里搜索ZYNQ,并找到ZYNQ7 PROCESSING SYSTEM ,双击并打开

3)软件自动生成了一个 zynq的block 如下图所示,接下来要做一些相应的设置,双击下图中的ZYNQ核

4)依次在弹窗里找到DDR Configuration→DDR Controller Configuration→DDR3,在Memory Part下拉菜单中根据自己板子上的DDR来选择相应的DDR3,本实验所用到型号:MT41K256M16RE-125,数据位宽选择16bit 最后点击“OK”,如下图所示。

5)在PS的MIO配置选项增加UART部分,使能UART 0 并在IO选项里选择EMIO方式

6)在block design 的设置界面 使能QSPI的功能 如下图所示(当QSPI 时钟大于40MHZ的时候 就需要勾选Feedback clk)

7)因为工程暂时用不到 AXI功能,所以可以先禁用AXI功能

8)随后点OK 保存修改, 点击“Run Block Automation”如下图所示。在弹出的选项中保持默认,点击“OK”,即可完成对ZYNQ7 Processing System的配置

9)引出UART 信号,因为我们增加了EMIO 的UART,所以这里需要将UART的引脚引出 ,右键选择ZYNQ模块的UART_0,然后选择Make External

10) 在source→Design Source ,右键我们创建的BLOCK工程,点击create HDL wrapper,打包BLOCK文件并生成.v代码

在弹出的菜单里直接点选OK

11) 点击绿色箭头RUN 对代码进行编译

12) 增加UART管脚定义,点击RTL 中的SCHEMATIC , 并选择右边出现的 IO Ports 来增加UART 0 EMIO部分的管脚定义(这一步也可以在约束文件中定义, 可看之前的例子)

将 UART 部分的 TX RX 分别设置成 L17,M17 电压属性设置成 LVCMOS33, 之后保存

13) 生成bit文件 :按下Generate Bitstream 完成综合以及生成bit文件,等待弹出综合完成的窗口

 二、SDK部分设计

1)File→Export→Export hardware…在弹出的对话框中勾选“include bitstream”,点击“OK”确认,如下图所示。

2)File→Lauch SDK,在弹出的对话框中,保存默认,点击“OK”,如下图所示。

系统将自动打开SDK开发环境

3)新建一个工程 file→new→Application Project,来新建一个“Application Project”,如下图所示。

4)在新建工程名中输入自己的工程名称,点击NEXT

5)选择空工程,点击完成FINISH

6) QSPI 的调用需要很多底层的函数,对于新手甚至有多年经验的程序员来说都有很大的难度,好在Xilinux 已经帮我们做好可以参考的demo,我们只需要打开demo进行研究即可。

展开工程中的BSP目录,并且双击其中的mss文件, 在右侧 qspips 中点选import Examples

选中qspi示例程序中flash相关的程序: xqspips_flash_polled_example

7) 之后qspi_flash的官方例程被打开,我们打开其中的xqspips_flash_polled_example.c文件查看代码

可以看到,例程本身已经包含了 FlashWrite, FlashRead, FlashErase, FlashReadID(擦除,读,写,读取FLASH ID)等各种功能的函数了

程序的框架也非常简单,主程序进来后,就调用了QspiFlashPolledExample函数

QspiFlashPolledExample 函数的工作流程如下

  • 对QSPI 功能进行初始化 (XQspiPs_CfgInitialize)
  • 对读写 Buffer分别进行初始化(对WriteBuffer数组赋予顺序的初值, 对ReadBuffer进行清零操作)
  • 设置 QSPI的工作模式 (XQspiPs_SetOptions),及分频系数 (XQspiPs_SetClkPrescaler)
  • 使能 FLASH 芯片 (XQspiPs_SetSlaveSelect)
  • 读取 Flash ID (FlashReadID)
  • 使能Flash Quad模式 (FlashQuadEnable) ,及擦除FLASH (FlashErase)
  • 将 write buffer 中的内容逐一通过 (FlashWrite) 函数写入 FLASH
  • 通过(FlashRead)函数(分别用READ_CMD和FAST_READ_CMD两种方式)读出FLASH 中的内容,并存入ReadBuffer中
  • 将ReadBuffer和WriteBuffer进行对比,验证读写数据是否一致

如果对比的内容一致,将在主函数中通过串口输出“Successfully ran QSPI FLASH Polled Example Test\r\n” ,否则将输出“QSPI FLASH Polled Example Test Failed\r\n”

三、下载程序到板子上验证 

1) 先提前打开串口助手(这里用vivado SDK 自带的)

2) 打开Run as -> Run Configurations

如果是第一次打开此页面,之前没有debug过,则双击system debugger选项

3 ) 在右侧 的窗口勾选 Reset entire system ,以及Program FPGA, 这样每次debug 的时候都会预先加载并配置FPGA。

4 ) 之后系统就会自动运行了(fpga也会被自动加载) 。 如果修改程序后 再次要debug,就可以直接点绿色箭头,或者选 Run As –>Launch on Hardware (system debugger即可)

5) 程序工作后, 结果如下图所示,可以看到程序已经读出Flash的ID为 0xEF 0x40 0x18

并且返回了 Successfully ran QSPI FLASH Polled Example Test ,证明写入flash 和从flash 读出的数据对比是一致的,实验成功。

6) 再来查看 READ ID的程序, 我们读取的READ_ID在FLASH上是地址0x9F

根据FLASH的数据手册上描述来看 0X9F 对应的地址 应该是值 EFh 4018h 和我们读出的FlashID=0xEF 0x40 0x18 一致

以上仅仅是调用官方的demo来对读写qspi flash 功能进行讲解和测试, 其他功能大家请自行尝试。

如果项目中 flash 同时需要拿来当作固化程序的存储空间,又要拿来存储其他的数据,请注意不要让存储的区域有交集,否则可能会导致程序运行的过程中,固件被程意外修改,导致下次启动程序无法正常工作。

另外请注意,flash 是有读写寿命的,所以程序上要避免在死循环中对flash进行一直的反复写入。

以下是本次的实验的原始工程,请自行测试

补充 如果要在vitis 里找官方demo 和sdk 中的位置是不同的 详细方法见下图

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注