使用Microblaze和AXI_Quad_SPI调用范例读写FLASH
使用Microblaze和AXI_Quad_SPI读写FLASH的使用
使用VIVADO生成Microblaze硬件平台
创建 Block 设计
点击 Create Block Design
可以更改或者保持设计名称为默认值,点击“OK”
添加Microblaze和clock软核
Microblaze IP核
点击添加 IP 快捷按钮,搜索“Microblaze”,双击下拉列表中“Microblaze
Clocking Wizard IP核
添加时钟,搜索“clock”,双击“Clocking Wizard”添加一个时钟向导 IP 核(PLL)
修改时钟参数:输入时钟手动修改为200MHz,差分输入,低电平复位、输出两路100MHz时钟,一路时钟供给给microblaze处理器,另一路时钟给后续添加的AXI_quad_spi核。设置完后确认
点击“Run Block Automation”完成一些自动设置,需要注意,这个选项不会一直都有,一旦设置完成,可能不会再有机会通过这种方式进行一些自动设置。弹出窗口里完成一些 microblaze 参数设置,在“Preset”选项中保持默认“None”,这个选项些选项是用来配置MicroBlaze处理器的预设配置。每个预设针对特定类型的应用进行了优化,根据您的应用需求,无论是微控制器功能、实时响应性还是高计算性能。“Local Memory”选择 最大128KB,因为没有使用外部存储器,这里不能选择太小,否则程序无法运行。“Interrupt Controller”使能中断控制。“Clock Connection”时钟选择时钟向导输出的 100Mhz 时钟作为 CPU 时钟。其余保持不变。
添加外设IP核
AXI_Quad SPI IP核
添加AXI_Quad SPI软核,用于控制Quad Flash芯片。
设置AXI_Quad SPI软核:使用Quad模式,设备选择Micron厂家的,使能STARTUP原语,原语功能是如果外部的Flash挂在FPGA的专用配置管脚上就要使能该原语,使用普通IO则不能使能。勾选上后指SPI的clk就会从FPGA专用的CCLK引脚输出时钟。其余保持不变。
此外将clock IP核的时钟输出2输出的100MHz,连接到AXI_Quad SPI软核的外部时钟输入引脚上,此时AXI_Quad SPI软核与FLASH的工作时钟是100MHz/Frequency Ratio = 50MHz。
GPIO IP核
添加2个GPIO核,修改ip核名称位axi_led、axi_key;一个用于LED输出,一个用于按键Key输出,分别修改IP核,设置位全输出和全输入、GPIO Width”填写 1,这里只控制 1 位 LED和1位Key。使能Enable interrupt中断,开启GPIO中断
Uartlite IP核
添加Uartlite 核,修改波特率为 115200,这是嵌入式系统比较常用的波特率,这里波特率是固定值,无法在程序中动态修改,点击 OK 完成配置。
配置Concat中断选项,Concat是Microblaze时钟中断控制器后才会有,本次设计共有4个中断需要控制,包括1个AXI_Quad_SPI中断2个AXI_GPIO中断 AXI_Uartlite中断,所以配置Concat核的端口数量为4
分别把个IP核的中断线连接到Concat IP核。
点击“Run Connection Automation”,来自动连线,选择“All Automation”,自动连接所有的线,点击“OK”开始自动连线
删除“rst_clk_wiz_0_100M”模块上的端口“reset_rtl_0_0”,选中,按“delete”按键可以 删除。连接“rst_clk_wiz_0_100M”模块上的“ext_reset_in”到“clk_wiz_0”的“resetn”,让 2 个模块共用一个复位,需要注意,这 2 个模块都是低电平复位有效。
修改各端口名称,默认端口名称比较长,不好记。“diff_clock_rtl_0”修改为“diff”,“reset_rtl_0”修改为“reset_n”、“gpio_rtl_1”修改为“keys”,“gpio_rtl_0”修改为“leds”,“uart_rtl_0”修改为“uart”。
“spi_rtl_0”修改为qspi。举例
检测设计并分配IO
保存设计,然后按“F6”检查设计,提示设计中没有错误和警告则可以继续下一步。
选择“design_1.bd”文件,右键选择“Create HDL Wrapper...”创建一个 Verilog 或 VHDL 顶层文件, 选择“Let Vivado manage wrapper and auto-update”,让 Vivado 自动更新 Verilog 或 VHDL 文件
双击打开生成的“design_1_wrapper.v”,可以看到一些端口,下面为这些端口分配 IO
点击“Open Elaborated Design”,在弹出窗口中点击“OK”
运行完成后,点击“Windows -> I/O Ports”,点击“Expand All”,可以看到 IO 都没有分配,在“Package Pin”列分配 IO,在“I/O Std” 列分配电平标准。
根据原理图配置端口位置和电平标准,配置完成后入下图。
点击保存按钮,提示创建一个新的 xdc 文件,名称这里填写IO,点击 OK
点击“PROJECT MANAGER”回到工程管理窗口,双击“IO.xdc”文件可以查看内容
编译
点击“Run Implementation”
如果出现下面窗口,点击“OK”即可
在弹出窗口中有运行路径选择,这里默认,“Number of jobs”线程数量可以可以根据自己
CPU 选择,数字越大,编译越快。
bitstream 设置
bitstream 设置是为了配置从Flash启动时速率。
在“PROGRAM AND DEBUG”选项,右键选择“Bitstream Setting...”
在“Setting”窗口点击“Configure additional bitstream settings”
在“General”选项卡中,“Enable Bitstream Compression”选择“TRUE”,压缩 Bitstream 文 件,让 Bitstream 文件体积变小
在“Configuration”选项卡,修改“Configuration Rate(MHz)”为 50,数值太大可能无法
正确加载配置文件,数值太小可能加载时间过长。“Configuration Voltage”配置电压选择 3.3,
“Configuration Bank Voltage Selection”选择 VCCO,这些配置是硬件设计决定,这里不做解
释。在“SPI Configuration”选择“Bus width”为 4,其他保持默认,点击“OK”完成 Bitstream 设置
点击保存按钮,将配置信息保存到 xdc 文件中
打开 xdc 文件可以发现多出一段 Bitstream 配置相关代码
点击“Generate Bitstream”生成 bit 流文件,生成完成以后,点击“Cancel”,不做任何操作。
导出硬件
在“File -> Export -> Export Hardware...”导出硬件
在弹出窗口中选择“Include bitstream”包含 Bitstream 文件
至此,已经完成再vivado生成Microblaze控制q_flash的硬件平台。
使用SDK生成Microblaze软件代码
点击 File Launch SDK 进入 SDK 操作
新建工程
设置工程名为“micro_flash”,再Hardware Platform选择刚才生成的硬件平台,Processor选择刚才生成的硬件平台中的microblaze,一般默认就选择了。
模板选择“Hello World”,点击“Finish”
工程建立完成以后就会自动编译,等待编译完成就可以调试运行。(这时开发板要上电,并且 JTAG 连接),整个工程完成后会有三个文件,其中,第一个design_1_wrapper…是之前再vivado上生成的硬件文件,下面的程序都是在此硬件平台上运行;第二个micro_flash是刚生成的应用程序,软件运行在这里;第三个micro_flash_bsp是SDK提供的班级支持包,里面含有各种参数核封装好的API供第二个中的应用程序使用。
选择“micro_flash”工程,右键选择“Run As -> Run Configuration...”
勾选“Reset entire system”和“Program FPGA”复位整个系统并下载 FPGA,
这样Run As每次运行程序都会复位并下载程序到FPGA
SDK运行AXI_Quad_SPI范例实现FLASH读写
导入范例
双击 BSP 目录里的“system.mss”文件,点击 axi_quad_spi 旁的“Import Examples”
有很多范例,但由于使用的开发板搭载的是Micro(numonyx)的qflash,所以选择第6个
范例写FLASH代码
打开范例,现在只看整个代码读写FLASH部分
写FLASH的过程主要有四步骤
- 使用SpiFlashWriteEnable函数写使能从设备flash。
- 使用SpiFlashSectorErase函数使能从设备flash擦除FLASH的扇区,通过发送扇区擦除指令擦除地址Address所在扇区。
- 使用SpiFlashWriteEnable函数重新写使能从设备flash
- 使用SpiFlashWrite函数,发送XSPI结构体指针、地址、数据大小,命令进行页写操作。
具体代码如下
函数具体页写过程如下
- 根据传入的XSPI结构体指针得到设备的状态信息,等待设备退出忙状态,
- 准备写入页写命令和地址,在写缓冲数组中的首字节写入页写命令,后面三个字节写入地址
- 准备写入的数据,在写缓冲数组中的后续字节写入具体要写入的值,首值为0x20,后续依次加一
- 通过Xspi_Transfer写入数据
范例读FLASH代码
写FLASH的过程主要有2步骤
- 清空读缓存数组,向数组写0
- 使用SpiFlashRead函数,发送读XSPI结构体指针、地址、数据大小,命令进行读操作。
具体代码如下
函数具体页写过程如下
- 根据传入的XSPI结构体指针得到设备的状态信息,等待设备退出忙状态,
- 准备写入读命令和地址,在写缓冲数组中的首字节写入页写命令,后面三个字节写入地址
- 判断那种读命令添加空字节
- 通过Xspi_Transfer读取数据
Debug判断是否读写成功
1、运行Debug,查看数组内的值是否符合预期
2、进入Debug在写完数据之后,读数据之前设置断点
3、此时写数组以写入命令0x20地址0x00,和从0x20开始递增的数据,显示的是ASCII
4、此时读缓冲数组还没有开始读,此时读缓冲数组内的数据还是之前的数据和写缓冲数组内的数据完全不同。
将断点放在读FLASH命令之后
此时前四位对应的是写的命令和地址,不需要读,返回0,后面就是写入falsh地址的数据,可以和写缓冲数组一一对应