ZYNQ 和诸多FPGA一样,从JTAG 下载的二进制文件,断电后是丢失的,为了让程序断电重启后仍然可以工作,需要对程序进行固化,本文将演示,如何把代码固化到板子的QSPI FLASH 芯片上,让系统每次开机从FLASH 芯片加载程序启动
(备注 一般调试不需要固化程序,当程序需要永久保存时候 可以考虑将程序进行固化)
本工程在第7章的基础上进行修改,可选择性查看
本文在 vivado2018.3版本上 演示, 其他版本请自行研究
(备注 此章节内容适用于 Smart ZYNQ SP和SL 版的板子,如果是Smart ZYNQ 标准版请看对应板子目录)
1. ZYNQ启动流程
1.首先了解ZYNQ的启动过程, ZYNQ的启动过程以 ARM核为主, 上电后 硬件先读取ARM核PS端特定引脚的电平状态以确定 系统从NAND ,QSPI ,SD Card还是 JTAG 启动系统。 启动的方式可以通过板子的拨码开关进行调整
2.ARM的普通FPGA(非ZYNQ)固化是直接将BIT文件通过QSPI写入FLASH就行的,但是对于 ZYNQ 来说,必须要有 PS 端的配合才能固化程序
2. 实际操作演示
具体的启动方式如下图所示, 我们的最小系统板只有 QSPI 和TF的硬件,所以只需要关注QUAD-SPI ,SD,JTAG 三种启动方式就好。也就是看系统上电瞬间MIO5和MIO4两个管脚的电平状态,用来区分不同的上电方式。
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-52.png)
在电路上 设计的过程中已将MIO5和MIO4分别接到了 拨动开关上了,也就是按照拨动开关在上电瞬间的状态即可控制系统的启动方式 ,具体可参考板子上的丝印标注
操作,让系统从JTAG 方式启动,以进入调试模式
要想对FLASH 芯片进行程序的固化,我们需要让板子临时从JTAG调试模式进行启动(临时性的) ,只需要在上电前让板子拨码开关保持在S1和S2都在ON的状态再执行上电操作。 如下图所示
![](http://www.hellofpga.com/wp-content/uploads/2023/01/image-71.png)
2.1软件部分配置
本工程在工程7的基础上 演示固化功能,大部分内容重复 选择性观看
创建一个BLOCK设计
1)IP INTEGRATOR→Create Block Design,在弹出的对话框中输入设计名,最后点击“OK”,如下图所示
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-1.png)
2)在右侧的窗口里 ,点击加号,在选择框里搜索ZYNQ,并找到ZYNQ7 PROCESSING SYSTEM ,双击并打开
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-2.png)
3)软件自动生成了一个 zynq的block 如下图所示,接下来要做一些相应的设置,双击下图中的ZYNQ核
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-3.png)
4)依次在弹窗里找到DDR Configuration→DDR Controller Configuration→DDR3,在Memory Part下拉菜单中根据自己板子上的DDR来选择相应的DDR3,本实验所用到型号:MT41K256M16RE-125,数据位宽选择16bit 最后点击“OK”,如下图所示。
![](http://www.hellofpga.com/wp-content/uploads/2023/01/image-70.png)
在PS的MIO配置选项的GPIO栏里,增加两路EMIO(因为本次测试的是两个,如果需要增加按键或者其它IO 这里可以对应的调整(这里两路GPIO是为了点亮LED灯看效果演示用的,非固化必须)
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-41.png)
5). 重要的一步在block design 的设置界面 使能QSPI的功能 如下图所示(当QSPI 时钟大于40MHZ的时候 就需要勾选Feedback clk)
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-56.png)
6)最后 点击“Run Block Automation”如下图所示。在弹出的选项中保持默认,点击“OK”,即可完成对ZYNQ7 Processing System的配置
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-43.png)
7)将刚才添加EMIO GPIO 引出 右键GPIO_0—->Make External
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-44.png)
8)用线将M_AXI_GP0_ACLK与 FCLK_CLK0连接起来
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-47.png)
9)source→Design Source ,右键我们创建的BLOCK工程,点击create HDL wrapper如下图所示。
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-12.png)
10)在弹出的对话框里保持默认
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-13.png)
11)软件自动为我们生成HDL文件
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-14.png)
2.2创建约束文件,并且定义管脚
1)Add Source → Add or create constraints 点Next
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-15.png)
因为这个项目没有创建过约束文件 所以这里创建一个约束文件,并在File name 里设置约束文件的名称,并且点击FINISH 完成约束文件的创建
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-16.png)
2)Sources → Constraints 里找到刚才创建的约束文件 双击并打开该XDC约束文件
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-17.png)
在约束文件里面复制下面代码来对输出的GPIO进行管脚(所有的管脚转接板上丝印都有实际标注对应的IO)
set_property IOSTANDARD LVCMOS33 [get_ports GPIO_0_0_tri_io[0]] set_property IOSTANDARD LVCMOS33 [get_ports GPIO_0_0_tri_io[1]] set_property PACKAGE_PIN P20 [get_ports GPIO_0_0_tri_io[0]] set_property PACKAGE_PIN P21 [get_ports GPIO_0_0_tri_io[1]]
2.3 综合布线和生成bit文件
按下绿色箭头对工程进行编译
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-19.png)
按下Generate Bitstream 完成综合以及生成bit文件
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-18.png)
2.4 SDK程序编写
1)File→Export→Export hardware…,在弹出的对话框中勾选“include bitstream”,点击“OK”确认,如下图所示。
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-20.png)
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-24.png)
2)File→Lauch SDK,在弹出的对话框中,保存默认,点击“OK”,如下图所示。
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-21.png)
系统将自动打开SDK开发环境
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-22.png)
3)新建一个工程 file→new→Application Project,来新建一个“Application Project”,如下图所示。
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-23.png)
4)在新建工程名中输入自己的工程名称,点击NEXT
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-37.png)
5)选择空工程,点击完成FINISH
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-26.png)
6) 在工程中添加main.c文件 src—>New—>Source File 如下图所示
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-48.png)
7)在弹出的窗口中填入main.c 并且保存
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-49.png)
8).打开刚才创建的main.c
然后 写入以下代码(代码是在 例程的基础上进行精简的) 有一个地方值得注意 EMIO的 IO口编号 是从54开始的,也就是我VIVADO 下创建的 EMIO端口,在PS端都是从54-55-56 依次排序的(小贴士 小于54的是MIO 也就是芯片PS的硬件IO口)
#include "xparameters.h" #include "xgpiops.h" #include "xstatus.h" #include "xplatform_info.h" #define LED1 54 #define LED2 55 #define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID XGpioPs Gpio; void Gpio_Init(void){ XGpioPs_Config *ConfigPtr; ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID); XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr); XGpioPs_SetDirectionPin(&Gpio, LED1, 1); XGpioPs_SetOutputEnablePin(&Gpio, LED1, 1); XGpioPs_SetDirectionPin(&Gpio, LED2, 1); XGpioPs_SetOutputEnablePin(&Gpio, LED2, 1); XGpioPs_WritePin(&Gpio, LED1, 0); XGpioPs_WritePin(&Gpio, LED2, 0); } #define LED_DELAY 10000000 volatile int Delay; int main(void) { Gpio_Init(); while(1){ XGpioPs_WritePin(&Gpio, LED1, 1); XGpioPs_WritePin(&Gpio, LED2, 0); for (Delay = 0; Delay < LED_DELAY; Delay++); XGpioPs_WritePin(&Gpio, LED1, 0); XGpioPs_WritePin(&Gpio, LED2, 1); for (Delay = 0; Delay < LED_DELAY; Delay++); }; return 0; }
3.下载到板子上进行验证
选中工程中的硬件平台,并点击右键→Program FPGA,在弹出的对话框中选择默认,点击“program”,完成FPGA PL部分的Program工作
![](http://www.hellofpga.com/wp-content/uploads/2021/08/image-42.png)
2)选中我们生成的GPIO工程 展开绿色箭头(RUN)右边的图标,选择Run As→1 Launch on Hardware(System Debugger)
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-50.png)
可以看到板子上的LED1灯在闪烁
备注 :如果 RUN 的时候弹出错误 可以按照下面的操作 进行设置 再进行DEBUG
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-51.png)
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-39.png)
之后点 APPLY 然后 再选择Run As→1 Launch on Hardware(System Debugger)看是否下载成功(如果仍然不行,请对板子进行断电后重试,一般发生这种问题的原因是因为debug的时候跟之前运行的程序产生冲突导致的)
备注 这里的调试下载是没有固化的,断电后 程序会丢失。
以上内容除了BLOCK DESIGN 里设置QSPI的部分和 第七个工程不同外,其他过程几乎相同, 接下来才是 PS部分的固化设置
4. 进行固化的操作
程序固化分为两步1. 创建FSBL模块,2.创建image(boot.bin)文件
在zynq上运行程序的时候,加载过程中肯定需要用到一个文件,那就是fsbl,是zynq启动第一阶段的加载程序,经过了fsbl这一阶段,后面系统才能够运行裸奔程序或者是引导操作系统的u-boot
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-60.png)
1)创建FSBL:在SDK中新建工程如下
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-61.png)
设置工程名fsbl,点next选择FSBL模板
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-62.png)
![](http://www.hellofpga.com/wp-content/uploads/2021/12/image-2.png)
2)制作BOOT.bin用于固化到FLASH。
BOOT.bin由fsbl.elf文件 vivado生成的fpga 的bit文件 app工程的elf文件(这里为led工程的elf)三个文件组成。在生成image的时候要分别填入三个文件的路径, 这里也有个偷懒的方法,就是在点 create boot image之前先选中 我们的APP工程,这样系统会自动为我们添加路径。如下所示
a) 先选中 我们的APP工程目录,这里是LED_CODE( 不是FSBL 也不是BSP 和 platform) 如果一开始已经被选中了,请先用鼠标选择上下任意一个目录,再选择回APP目录,否则路径可能不自动加载
![](http://www.hellofpga.com/wp-content/uploads/2022/10/image-63.png)
b) 点xilinx –>create boot image
![](http://www.hellofpga.com/wp-content/uploads/2021/12/image-3.png)
在界面里分别设置 boot.bin的输出路径,以及生成boot.bin需要的三个文件的路径(这里有一个偷懒的方法,就是在点下Create Boot Image 之前先选中我们的APP工程),如下图所示,如果没有出现三个文件的路径,请重试上一步。 如果有三个文件路径,则直接点create image生成镜像
![](http://www.hellofpga.com/wp-content/uploads/2023/04/image-24-1024x603.png)
3) 烧录 镜像
生成完boot.bin后,下一步将boot.bin 下载到QSPI flash 中
点Program Flash
![](http://www.hellofpga.com/wp-content/uploads/2022/11/image-222.png)
![](http://www.hellofpga.com/wp-content/uploads/2023/04/image-25-1024x450.png)
按上图操作 导入 boot镜像 文件,和fsbl.elf文件(需要自己导入路径),将flash type 设置为 qspi-x4-sig ,然后将板子拨码开关调整到JTAG模式,并重新上电(或者按下POR RST键),之后再点击PROGRAM 开始下载(必须在JTAG模式下,拨码开关调整到JTAG 模式 并且重启板子或者按下POR RST键)
![](http://www.hellofpga.com/wp-content/uploads/2023/01/image-71.png)
点击PROGRAM
待程序下载成功后,将跳线位置换回到QSPI上
![](http://www.hellofpga.com/wp-content/uploads/2023/01/image-75.png)
重新上电(或者按下POR RST键), 正常的话两个LED 会开始闪烁,说明板子的FPGA 已经正常初始化完整,flash 下载成功
如果下载过程中出现下图所示,说明系统上电时没有正常进入JTAG 调试模式,请进入JTAG模式后再尝试下载
![](http://www.hellofpga.com/wp-content/uploads/2021/12/image-10.png)
以下是完整工程:
您好,我按这个教程弄完后,POR RST键已经不起作用了,只有重新插拔线才可以让板子成功重启(即Done灯亮,绿LED灯闪烁)
你好,这种情况是因为你 vivado 里也连接着设备, vivado 里连接的设备退出后,就没问题了
系统默认和vivado 连接了导致 启动失败