news 2026/9/28 14:57:04

Zynq-7020 Vitis程序固化实战:从FSBL到QSPI Flash全流程详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Zynq-7020 Vitis程序固化实战:从FSBL到QSPI Flash全流程详解

1. 为什么7020的Vitis程序固化值得单独拿出来讲

Xilinx Zynq-7000系列里的XC7Z020,也就是大家常说的7020,是很多工业控制、图像采集、通信设备的主力芯片。它内部集成了双核ARM Cortex-A9处理器和FPGA可编程逻辑,软硬协同的设计让它在嵌入式领域非常吃香。但很多朋友在Vitis里把程序调通之后,一到固化这一步就卡住了——JTAG在线调试跑得好好的,断电重启就什么都没了。

这个问题的本质是:在线调试时,程序是通过JTAG直接加载到DDR或者OCM里运行的,掉电即失。要让7020上电后自动运行你的程序,必须把启动镜像写入非易失性存储介质,通常是QSPI Flash或者SD卡。而Vitis环境下生成BOOT.bin并烧录到Flash的流程,和早期ISE/SDK时代有不少差异,工具链的更新也让很多老教程不再适用。

这篇文章面向的是已经能在Vitis里完成基本开发和在线调试、但对固化流程还不够熟悉的嵌入式工程师。我会把从工程配置、FSBL生成、BOOT.bin打包,到最终烧录进QSPI Flash的完整链路拆开讲清楚,包括每一步背后的原理和实际踩过的坑。不管你是刚接触Zynq的新手,还是从SDK迁移过来的老手,应该都能从中找到有用的东西。

2. 固化前的核心概念与整体思路拆解

2.1 Zynq启动流程到底是怎么走的

要理解固化,先得搞清楚7020上电之后发生了什么。Zynq的启动分三个阶段:

Stage 0是芯片内部的BootROM,这段代码是出厂固化在芯片里的,改不了。上电后BootROM会根据MIO引脚的电平状态判断启动模式——QSPI、SD卡、NAND、JTAG。判断完启动设备后,BootROM会去对应设备里找启动镜像,也就是BOOT.bin。

Stage 1是FSBL(First Stage Boot Loader),这是用户自己生成的。BootROM把FSBL加载到OCM(On-Chip Memory)里执行。FSBL做的事情包括:初始化DDR控制器、配置时钟、加载PL的bitstream、加载SSBL(通常是U-Boot)或者直接加载裸机应用。

Stage 2就是你的应用程序或者U-Boot。如果是裸机程序,FSBL直接把它加载到DDR里跳转执行;如果是Linux系统,FSBL加载U-Boot,U-Boot再加载内核和文件系统。

所以BOOT.bin里面至少包含两样东西:FSBL的ELF文件和你的应用程序ELF文件。如果用到PL逻辑,还要加上bitstream文件。

2.2 为什么BOOT.bin的组成文件顺序不能乱

BOOT.bin本质上是一个按照特定格式打包的镜像文件,BootROM和FSBL会按照分区顺序去解析它。标准的顺序是:

  1. FSBL.elf——必须放在第一个分区,BootROM第一个找的就是它
  2. system.bit——PL的配置文件,如果有的话
  3. 应用程序.elf——裸机程序或者U-Boot

这个顺序不是随便定的。BootROM的代码逻辑就是读取第一个分区作为FSBL来执行,FSBL再去处理后续分区。如果你把应用程序放在第一位,BootROM会把它当FSBL加载,结果就是跑不起来。

注意:在Vitis中创建Boot Image时,工具会自动识别文件类型并排序,但如果你手动指定顺序,一定要确保FSBL在第一位。

2.3 Vitis和旧版SDK在固化流程上的关键差异

很多朋友之前用SDK 2015.4、2016.4做固化很熟练,换到Vitis之后发现界面全变了,找不到原来的Create Boot Image选项。这里梳理一下主要差异:

对比项旧版SDKVitis
工程结构独立WorkspaceWorkspace+Platform概念
FSBL生成新建FSBL工程通过Platform或模板创建
Boot Image工具Xilinx Tools菜单Vitis菜单或命令行
Flash烧录Program FlashProgram Flash(路径不同)
命令行工具bootgenbootgen(参数兼容)

Vitis把平台(Platform)的概念引入进来,FSBL的生成方式变成了基于平台创建。这个变化一开始确实让人不太适应,但理解了平台的概念之后,操作反而更清晰。

2.4 整体固化流程的四个阶段

我把整个固化流程分成四个阶段,后面会逐一展开:

  • 第一阶段:确认硬件启动模式——检查MIO引脚配置,确保QSPI启动模式正确
  • 第二阶段:生成FSBL——在Vitis中创建FSBL工程并编译
  • 第三阶段:制作BOOT.bin——用Create Boot Image工具打包
  • 第四阶段:烧录到Flash——通过JTAG将BOOT.bin写入QSPI Flash

每个阶段都有各自的注意事项,下面逐个拆解。

3. 核心细节解析与实操要点

3.1 FSBL工程的创建与关键配置

FSBL是整个启动链条的枢纽,它负责初始化DDR、加载bitstream、加载应用程序。在Vitis中创建FSBL的步骤如下:

首先,确保你已经创建了一个Platform工程,并且这个Platform包含了你的硬件设计(.xsa文件)。然后通过File → New → Application Project,在模板选择页面找到Zynq FSBL模板。Vitis会自动生成FSBL的源码工程。

FSBL里有几个关键配置需要关注:

DDR初始化参数。FSBL会根据你的硬件设计自动生成DDR的初始化代码,这些参数来自Vivado中的DDR配置。如果你在Vivado里改了DDR型号或者时序参数,一定要重新导出.xsa并更新Platform,否则FSBL初始化DDR会失败。

调试打印输出。FSBL默认会通过UART输出调试信息,这对于排查启动问题非常有帮助。在fsbl_debug.h中可以调整调试级别:

#define FSBL_DEBUG_INFO // 或者更详细的 #define FSBL_DEBUG_DETAILED

看门狗处理。FSBL默认会关闭看门狗,如果你的系统需要在启动阶段保持看门狗开启,需要修改fsbl_hooks.c中的相关代码。

编译FSBL工程后,会在Debug或Release目录下生成fsbl.elf文件,这个文件就是后面打包BOOT.bin要用的。

实操心得:FSBL编译时如果报错找不到xil_cache.h之类的头文件,通常是因为Board Support Package(BSP)没有正确配置。检查BSP设置中的standalone操作系统是否包含了必要的库。

3.2 应用程序ELF文件的生成注意事项

应用程序就是你实际要跑的业务代码。在Vitis中,应用程序工程会依赖一个BSP工程,BSP里包含了驱动库和硬件相关的配置。

生成应用程序ELF时需要注意几点:

链接地址的确认。裸机程序的链接地址通常是DDR的起始地址(比如0x00100000),这个地址必须和FSBL加载地址一致。在Vitis中,链接脚本(.ld文件)会自动生成,但如果你手动修改过,要确保没有冲突。

优化等级的选择。Release模式下编译器会做更多优化,生成的ELF文件更小,但有时候优化会导致一些时序敏感代码出问题。如果Release模式下程序跑飞了,先试试降到-O1或者-O0。

BSP的匹配。应用程序的BSP必须和FSBL使用同一个硬件平台,否则寄存器地址可能对不上。在Vitis中,同一个Platform下的所有工程共享硬件信息,这一点比SDK时代更清晰。

3.3 bitstream文件的准备与格式要求

如果你的7020设计中用到了PL逻辑,那么BOOT.bin里还需要包含bitstream文件。Vivado生成的bitstream文件是.bit格式,但BOOT.bin需要的是.bin格式。

转换方法有两种:

第一种是在Vivado中直接导出bin格式。在Generate Bitstream之后,通过File → Export → Export Bitstream选择Bin格式。

第二种是用bootgen命令行工具转换:

bootgen -image design.bif -arch zynq -process_bitstream bin

其中design.bif是一个描述文件,内容大致如下:

all: { design.bit }

执行后会生成design.bit.bin文件。

注意:bitstream文件在BOOT.bin中的位置必须在FSBL之后、应用程序之前。如果顺序放错了,FSBL加载PL配置时会找不到文件。

3.4 BOOT.bin打包的BIF文件编写

BIF(Boot Image Format)文件是bootgen工具的输入描述文件,它定义了BOOT.bin中包含哪些分区、每个分区的类型和属性。

一个典型的BIF文件内容如下:

the_ROM_image: { [bootloader] fsbl.elf system.bit application.elf }

[bootloader]标记告诉bootgen这个文件是FSBL,会被放在第一个分区。如果没有这个标记,bootgen会按照文件顺序排列,但不会做FSBL的特殊处理。

如果需要加密或者认证,BIF文件还可以添加更多属性,比如:

the_ROM_image: { [bootloader, authentication=rsa] fsbl.elf [authentication=rsa] system.bit [authentication=rsa] application.elf }

对于大多数普通应用场景,不需要加密认证,保持最简单的格式就行。

3.5 QSPI Flash的型号匹配与分区规划

7020开发板上常见的QSPI Flash型号有W25Q256、S25FL256等,容量一般是32MB或者64MB。烧录之前要确认Flash型号和Vitis中配置的是否一致。

在Vitis的Program Flash界面中,需要选择Flash类型。如果列表里没有你的Flash型号,可以选择兼容的通用配置,或者手动添加Flash参数。

Flash的分区规划也值得考虑。BOOT.bin通常放在Flash的起始地址(0x00000000),如果还有文件系统或者其他数据,需要规划好各自的偏移地址。对于裸机应用,一般整个Flash都给BOOT.bin用就够了。

4. 实操过程与核心环节实现

4.1 硬件启动模式的确认与设置

在开始烧录之前,先确认板子上的启动模式跳线或拨码开关设置正确。7020的启动模式由MIO[5:2]引脚决定:

MIO[5:2]启动模式
0000JTAG
0001QSPI
0010SD卡
0100NAND

烧录到QSPI Flash时,通常先把模式设为JTAG(方便烧录),烧录完成后再切换到QSPI模式。有些板子设计的是拨码开关,有些是跳线帽,具体看原理图。

实操心得:我遇到过一块板子,拨码开关标注的ON/OFF和实际电平是反的,导致一直启动不了。后来拿万用表量了MIO引脚的电压才确认。所以不要完全信丝印,关键时候用万用表确认一下。

4.2 在Vitis中创建Boot Image的完整步骤

打开Vitis,确保你的Platform和Application工程都已经编译通过。然后按照以下步骤操作:

第一步:菜单栏选择Xilinx → Create Boot Image。

第二步:在Boot Image Format页面,选择Zynq架构。

第三步:添加分区文件。点击Add按钮,依次添加:

  • FSBL的ELF文件(fsbl.elf),Partition Type选择bootloader
  • bitstream的bin文件(如果有),Partition Type选择datafile
  • 应用程序的ELF文件,Partition Type选择datafile

第四步:确认输出路径和文件名,默认是BOOT.bin。

第五步:点击Create Image,等待工具生成BOOT.bin。

生成成功后,可以在输出目录看到BOOT.bin文件,大小通常在几MB左右(取决于应用程序和bitstream的大小)。

4.3 通过JTAG烧录BOOT.bin到QSPI Flash

烧录这一步是整个流程中最容易出问题的环节。Vitis中烧录Flash的入口在Xilinx → Program Flash。

具体操作:

第一步:选择硬件平台。Vitis会自动检测连接的JTAG下载器,确认芯片型号是XC7Z020。

第二步:选择要烧录的文件,即刚才生成的BOOT.bin。

第三步:配置Flash类型。在Flash Type下拉框中选择你的QSPI Flash型号。如果找不到完全匹配的,选一个容量相同、指令集兼容的型号。

第四步:设置偏移地址。默认是0x00000000,如果BOOT.bin不是从Flash起始位置开始存放,需要修改。

第五步:点击Program,等待烧录完成。

烧录过程中,Vitis会先通过JTAG加载一个Flash编程器(Flash Programmer)到FPGA的OCM中运行,然后由这个编程器去操作QSPI控制器,把数据写入Flash。

注意:烧录时间取决于BOOT.bin的大小和Flash的写入速度。一个8MB的BOOT.bin,烧录时间大概在1到2分钟。如果超过5分钟还没完成,可能是Flash型号选错了或者硬件连接有问题。

4.4 烧录后的验证与启动测试

烧录完成后,不要急着断电。先通过Vitis的串口终端观察FSBL的输出信息。如果FSBL正常启动,你会看到类似下面的打印:

Xilinx First Stage Boot Loader Release 2023.1 Jan 15 2024-10:30:00 Devcfg driver initialized Silicon Version 3.1 Boot mode is QSPI Flash Base Address: 0xFC000000 ...

看到这些信息说明FSBL已经成功从Flash加载并运行了。接下来FSBL会加载应用程序,如果应用程序有串口输出,也应该能看到。

确认一切正常后,断电,把启动模式切换到QSPI,重新上电。如果程序自动运行了,说明固化成功。

4.5 命令行方式生成BOOT.bin的备选方案

除了Vitis的图形界面,也可以直接用bootgen命令行工具生成BOOT.bin。这在自动化构建或者CI/CD流程中很有用。

命令格式:

bootgen -image boot.bif -arch zynq -o BOOT.bin -w on

参数说明:

  • -image:指定BIF文件
  • -arch:指定架构,7020是zynq
  • -o:输出文件名
  • -w:覆盖已存在的输出文件

BIF文件的内容和前面说的一样。命令行方式的好处是可以写进Makefile或者脚本里,每次编译完自动生成BOOT.bin。

5. 常见问题与排查技巧实录

5.1 Flash烧录失败的典型原因与解决方法

烧录失败是固化过程中最常见的问题,表现五花八门。我整理了一个速查表:

错误现象可能原因解决方法
Cannot load flash device descriptionFlash型号未配置手动添加Flash参数或选择兼容型号
Failed to communicate with flash chipJTAG连接不稳定检查下载器连接,降低JTAG时钟频率
Flash download failed - target dll cancelledFlash编程器加载失败重新上电,确保芯片处于JTAG模式
Cannot load flash programming algorithm算法文件不匹配确认Vitis版本和芯片型号匹配
烧录完成但启动无输出启动模式不对检查MIO引脚电平,确认QSPI模式

5.2 FSBL启动卡死的排查思路

FSBL跑不起来,串口没有任何输出,这种情况要从几个方面排查:

DDR初始化失败。这是最常见的原因。FSBL在初始化DDR时如果参数不对,会卡在ps7_init函数里。解决方法是用Vivado重新导出.xsa,确保DDR配置和实际硬件一致。

时钟配置错误。如果输入时钟频率和Vivado中配置的不一样,PLL锁定不了,FSBL也会卡死。检查晶振频率和Vivado中的设置是否匹配。

Flash中的BOOT.bin损坏。重新烧录一次,烧录时勾选Verify选项,确保数据写入正确。

串口波特率不对。FSBL默认波特率是115200,确认串口终端设置正确。

5.3 程序在JTAG下能跑但固化后不运行的经典问题

这个问题困扰过很多人。JTAG调试正常说明硬件和程序逻辑没问题,固化后不运行通常是以下几个原因:

启动模式没切换。烧录时是JTAG模式,烧录完忘了切到QSPI模式。这个低级错误我犯过不止一次。

BOOT.bin分区顺序错误。FSBL没有放在第一个分区,BootROM找不到有效的启动镜像。

应用程序链接地址冲突。应用程序的链接地址和FSBL使用的内存区域重叠了,导致FSBL加载应用程序时把自己覆盖了。

PL配置未加载。如果应用程序依赖PL逻辑,但bitstream没有正确打包进BOOT.bin,程序跑起来也会异常。

5.4 QSPI Flash型号不识别时的处理技巧

Vitis的Flash型号列表里不可能包含所有市面上的QSPI Flash。遇到不认识的型号时,可以尝试以下方法:

选择兼容型号。大多数QSPI Flash的指令集是兼容的,比如W25Q256和S25FL256的读写指令基本一致。选一个容量相同的型号通常能正常工作。

手动添加Flash参数。在Vitis的Flash配置目录下可以添加自定义的Flash描述文件,格式参考已有的配置文件。

用通用SPI模式。有些Flash支持标准SPI模式,可以尝试用通用的SPI Flash配置来烧录,虽然速度慢一些但兼容性更好。

实操心得:我手上有一批板子用的是GD25Q256,Vitis列表里没有这个型号。后来发现选W25Q256完全兼容,烧录和启动都正常。所以遇到不认识的Flash,先查数据手册对比指令集,大概率能找到替代型号。

5.5 固化后启动时间过长的优化方向

有些朋友反馈固化后启动要十几秒甚至更久。启动时间主要消耗在以下几个环节:

FSBL的调试打印。如果FSBL开启了详细调试输出,每个打印都要等UART发送完成,会显著增加启动时间。量产版本应该关闭调试输出。

DDR训练。FSBL每次启动都会做DDR初始化,这个过程需要一些时间。如果DDR参数已经稳定,可以考虑跳过部分训练步骤。

bitstream加载。PL配置文件的加载时间取决于bitstream大小和QSPI时钟频率。提高QSPI时钟频率可以加快加载速度,但要确保Flash支持。

应用程序初始化。如果应用程序本身初始化就很慢,那和固化无关,需要优化应用代码。

6. 几个容易被忽略的细节和进阶建议

6.1 Flash寿命与写入策略

QSPI Flash的擦写次数是有限的,通常标称10万次左右。调试阶段频繁烧录问题不大,但量产或者现场升级时要注意写入策略。比如可以先擦除再写入,避免不必要的全片擦除。另外,如果只是更新应用程序部分,可以考虑只烧录应用程序分区,而不是整个BOOT.bin重写。

6.2 多启动镜像的备份机制

对于可靠性要求高的场景,可以在Flash中存放两个BOOT.bin,一个主镜像一个备份镜像。FSBL启动失败时可以跳转到备份镜像。Zynq的BootROM支持多启动镜像机制,通过设置MIO引脚或者使用BootROM的fallback功能来实现。这个机制在工业控制领域特别实用,能有效降低现场设备变砖的风险。

6.3 从SDK迁移到Vitis的注意事项

如果你之前用SDK 2015.4或者更早版本做固化,迁移到Vitis时要注意:

  • 工程文件格式变了,不能直接导入,需要重新创建
  • FSBL的生成方式从独立工程变成了基于Platform
  • BIF文件的语法基本兼容,但bootgen的版本更新了,某些参数可能有变化
  • Flash编程器的路径和界面变了,但底层机制一样

我个人的建议是,如果旧项目还在用SDK维护,没必要强行迁移到Vitis。但如果新项目开始,直接用Vitis,熟悉之后效率更高。

6.4 调试阶段快速迭代的技巧

固化调试最烦的就是每次改代码都要重新生成BOOT.bin、重新烧录Flash,一次下来好几分钟。有几个方法可以加速迭代:

先用JTAG调试确认功能。功能没问题了再固化,避免反复烧录。

用SD卡启动做快速验证。把BOOT.bin放到SD卡里,改启动模式为SD卡,这样每次只需要替换SD卡里的文件,不用烧录Flash。

只烧录应用程序分区。如果FSBL和bitstream没变,只更新应用程序ELF对应的分区,烧录时间会短很多。

用Vitis的Program FPGA功能单独加载bitstream。调试PL逻辑时,不需要每次都打包BOOT.bin,直接用JTAG加载bitstream到PL就行。

这些技巧在实际项目中能省下大量时间。我自己在做7020项目时,前期基本都用SD卡启动来验证,等所有功能稳定了,最后才做一次QSPI固化。

6.5 关于7020使用JTAG固化Flash时是否需要DDR的疑问

这个问题在社区里经常被问到。答案是:FSBL在烧录过程中确实会初始化DDR,但Flash编程器本身不一定需要DDR。

具体来说,Vitis的Program Flash流程是:先通过JTAG把Flash编程器加载到OCM中运行,编程器负责擦除和写入Flash。FSBL在这个过程中也会被加载,用于初始化系统时钟和DDR控制器。但如果你的设计中没有使用DDR,或者DDR初始化有问题,可以尝试使用不依赖DDR的Flash编程流程。

不过在实际操作中,大多数7020设计都会用到DDR,所以FSBL初始化DDR是正常流程的一部分。如果DDR初始化失败导致烧录失败,那说明硬件设计或者FSBL配置有问题,需要先解决DDR的问题。

6.6 版本兼容性问题的处理经验

Xilinx工具链的版本兼容性一直是个让人头疼的问题。Vitis 2020.1和2023.1在Flash烧录界面上就有不少差异。我的经验是:

  • Vivado和Vitis的版本必须匹配,不能混用
  • .xsa文件的格式在不同版本间可能有变化,升级工具后建议重新导出
  • bootgen的BIF语法在大版本间基本稳定,但新版本可能增加新属性
  • Flash编程器的算法文件随版本更新,旧版算法可能不支持新Flash型号

如果遇到莫名其妙的烧录失败,先检查工具版本是否匹配,这能排除掉一大半问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 14:55:59

Win11下Fastboot驱动装不上?从设备管理器到成功识别全攻略

玩转Android刷机的朋友&#xff0c;最怕的不是变砖&#xff0c;而是电脑上那个黄色感叹号。尤其是换到Win 11之后&#xff0c;Fastboot驱动装不上、设备管理器里设备反复横跳、命令行卡在< waiting for any device >&#xff0c;这些问题几乎成了每个搞机人的必经之劫。我…

作者头像 李华
网站建设 2026/9/28 14:53:46

YOLOv5+LPRNet车牌检测识别实战:CCPD数据集训练与边缘部署

简介&#xff1a;这份资源面向计算机、电子信息、数学等专业的大学生及算法初学者&#xff0c;提供一套基于YOLOv5s与LPRNet的轻量级中文车牌检测与识别完整方案&#xff0c;可用于课程设计、期末大作业或毕业设计参考。项目以CCPD数据集为基础&#xff0c;YOLOv5s负责车牌定位…

作者头像 李华
网站建设 2026/9/28 14:53:25

蛋壳裂缝检测数据集VOC+YOLO双格式对齐指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 14:53:20

LLM长期记忆实战:用hindsight+Dify让Agent真正记住用户

1. 先从“失忆”说起&#xff1a;为什么每个聊天机器人都让人想翻白眼如果你做过一阵子LLM应用&#xff0c;一定遇到过这种场面&#xff1a;用户周一跟你的Agent说“我对花生过敏&#xff0c;帮我点菜时注意”&#xff0c;周五又问“你记得我有什么过敏吗”&#xff0c;Agent一…

作者头像 李华
网站建设 2026/9/28 14:53:19

HC32F460串口IAP实战:从Flash分区到APP跳转全链路实现

1. 项目概述&#xff1a;为什么HC32F460的串口IAP值得花时间啃透&#xff1f;华大半导体的HC32F460系列&#xff0c;是国产32位MCU里少有的“性能与成本平衡得特别稳”的选手——Cortex-M4F内核、浮点单元、1MB Flash、192KB SRAM、双路CAN、USB Device、丰富的模拟外设&#x…

作者头像 李华
网站建设 2026/9/28 14:52:23

mRNA-LNP重塑CD38靶向治疗:三条技术路线与临床前要点

CD38 这个靶点这几年的热度&#xff0c;很大程度上是被 daratumumab 抬起来的。2015 年它作为多发性骨髓瘤&#xff08;MM&#xff09;的四线用药获批&#xff0c;之后一路推进到一线联合方案&#xff0c;直接证明了一件事&#xff1a;CD38 是一个可成药、且临床获益明确的靶点…

作者头像 李华