1. 为什么7020的Vitis程序固化值得单独拿出来讲做过Zynq开发的人都有一个共识调试阶段跑得通不算本事能把程序稳稳当当地固化到板子上、断电重启还能自己跑起来才算真正交付。Xilinx 7020这颗芯片在工业控制、图像采集、通信网关里出镜率极高PS端带双核Cortex-A9PL端逻辑资源够用又不算贵很多中小批量项目直接拿它当主力。但偏偏就是“固化”这一步卡住了不少人——Vitis工程和早年SDK工程的流程差异、BOOT.bin的组成结构、Flash型号匹配、QSPI还是SD卡启动模式的选择每一环都有坑。这篇内容就是把我自己在7020上反复烧录、反复翻车的经验整理出来。从Vitis里怎么配置FSBL和应用程序、怎么生成BOOT.bin、怎么用JTAG间接烧写到QSPI Flash到烧完之后不启动怎么排查整个链路走一遍。适合已经能在7020上跑通Hello World、但一到固化就抓瞎的工程师也适合从ISE/SDK时代迁移过来、对Vitis这套新工具链还不熟的老手。核心关键词就几个Xilinx、Vitis、7020、BOOT.bin、Flash围绕它们把流程讲透。我见过太多人卡在“烧录成功但启动失败”上最后发现是FSBL里没加正确的硬件配置或者BOOT.bin的生成顺序搞反了。这些细节官方文档里都有但散落在各个UG里真到操作的时候没人给你串起来。下面我按实际动手的顺序一步步拆。2. 固化前的整体思路与方案选型2.1 先搞清楚7020的启动链路到底怎么走Zynq 7020的启动不是“上电直接跑你的main函数”这么简单。上电后芯片内部有一段BootROM它是固化在硅片里的改不了。BootROM会先看启动模式引脚MIO[5:2]或者MIO[8:7]取决于具体配置决定从哪里找启动镜像。常见的就是QSPI Flash、SD卡、NAND、JTAG几种。找到镜像之后BootROM把FSBLFirst Stage Boot Loader加载到OCM里跑起来FSBL再去初始化DDR、配置PL、把应用程序搬到DDR里最后跳转到应用程序。所以BOOT.bin里至少要有三样东西FSBL的elf、PL的bitstream如果用到PL的话、应用程序的elf。顺序不能乱FSBL必须在最前面因为BootROM第一个找的就是它。这个顺序在Vitis里生成BOOT.bin的时候会自动处理但你要知道它为什么是这个顺序出问题的时候才知道从哪查。2.2 为什么选QSPI Flash而不是SD卡实际项目里SD卡启动适合调试和快速迭代拔插方便换程序不用重新烧Flash。但量产设备上SD卡是活动部件振动、氧化、误拔都是隐患。QSPI Flash焊在板子上可靠性高得多。7020常见的QSPI Flash容量从16MB到64MB都有放一个BOOT.bin绰绰有余。我一般建议调试阶段用SD卡定型之后固化到QSPI。选QSPI的时候要注意Flash型号。不同厂家的QSPI Flash扇区大小、擦除命令、写使能时序都有差异。Vitis里烧录Flash需要对应的Flash编程算法Flash Programming Algorithm这个算法文件通常在Vitis安装目录下的data/xicom/cfgmem/里能找到。如果板子上的Flash型号不在列表里要么找相近的替代要么自己改算法配置。这一步后面会细说。2.3 Vitis和旧SDK在固化流程上的关键差异从SDK迁移到Vitis的人最容易在这里翻车。SDK里生成BOOT.bin是在Xilinx菜单下直接点“Create Boot Image”Vitis里这个功能被挪到了更隐蔽的地方而且工程结构变了。Vitis里一个Platform工程对应硬件一个或多个Application工程对应软件。生成BOOT.bin的时候FSBL是一个独立的Application工程需要单独创建和编译。另一个差异是Vitis默认用vitis -b命令行或者GUI里的“Create Boot Image”来打包但GUI有时候会抽风特别是路径里有中文或者空格的时候。我后来养成习惯关键步骤用命令行跑日志清楚出错也好查。命令行方式后面会给具体命令。3. 核心细节拆解从FSBL到BOOT.bin的每一步3.1 FSBL工程的创建与关键配置FSBL不是随便建个空工程就能用的。在Vitis里创建Application工程的时候模板要选“Zynq FSBL”。选完之后Vitis会自动从Platform工程里拉取硬件信息生成xparameters.h之类的配置文件。这里有个坑如果你的Platform工程里PL部分没有正确导入bitstream或者没有配置好FSBL编译的时候可能不报错但跑起来会在配置PL的阶段卡死。FSBL的源码里main.c会依次调用InitPlatform、DDRInit、LoadBitstream如果有PL、LoadApplication。如果你不需要PL可以在FSBL的编译选项里把FSBL_DEBUG_INFO打开这样串口会打印详细的启动日志排查问题的时候非常有用。打开方式是在FSBL工程的fsbl_debug.h里把FSBL_DEBUG_INFO的宏定义取消注释或者在编译选项里加-DFSBL_DEBUG_INFO。还有一个容易忽略的点FSBL里DDR的初始化参数是从ps7_init.c里来的这个文件由Vivado导出硬件时生成。如果你在Vivado里改了DDR的时钟或者时序参数一定要重新导出硬件、更新Platform工程否则FSBL用的还是旧的DDR配置跑起来可能不稳定甚至起不来。3.2 应用程序工程的编译与elf文件确认应用程序就是你的业务代码编译完之后在Debug或Release目录下会生成.elf文件。这里要注意Vitis默认编译出来的是带调试信息的elf体积比较大。固化到Flash的时候建议用Release版本体积小、启动快。但Release版本有时候优化级别太高会把一些你依赖的变量优化掉调试阶段还是用Debug定型再换Release。确认elf文件的时候用arm-none-eabi-size看一下各个段的大小确保DDR的分配够用。7020的DDR通常挂512MB或者1GB一般应用够用但如果你的程序里有大数组或者图像缓冲区要算清楚。FSBL加载应用程序的时候是把elf里的各个段按地址搬到DDR里如果地址重叠了跑起来就是随机崩溃。3.3 bitstream的导入与PL配置时机如果你的设计里PL部分有逻辑bitstream必须打包进BOOT.bin。在Vitis里创建BOOT.bin的时候会有一个步骤让你指定bitstream文件.bit。这里有个选择FSBL是在加载应用程序之前配置PL还是之后默认是之前。如果你的应用程序依赖PL先配置好才能跑那就保持默认。如果应用程序自己会去配置PL比如用PCAP或者devcfg那就要在FSBL里把LoadBitstream跳过否则会冲突。bitstream文件在Vivado里生成的时候注意要选“Bin File”格式还是“Bit File”格式。Vitis的BOOT.bin生成工具通常吃.bit文件但有些版本对.bin支持更好。我一般用.bit没出过问题。如果生成BOOT.bin的时候报错说bitstream格式不对试试在Vivado里导出.bin格式。3.4 BOOT.bin的组成结构与生成顺序BOOT.bin本质上是一个容器里面按顺序放了多个分区partition。第一个分区必须是FSBL第二个通常是bitstream第三个是应用程序。每个分区都有一个头部描述了加载地址、大小、校验和等信息。BootROM读第一个分区加载FSBLFSBL读后续分区加载bitstream和应用程序。在Vitis里生成BOOT.binGUI操作是菜单栏Xilinx - Create Boot Image。然后依次添加FSBL的elf、bitstream、应用程序的elf。注意顺序FSBL在最上面bitstream在中间应用程序在最下面。添加完之后输出格式选BIN输出路径不要有中文和空格。点Create Image如果一切正常会在指定目录生成BOOT.bin。命令行方式更可靠vitis -b -image BOOT.bin -fsbl fsbl.elf -bit system.bit -app app.elf具体参数名可能随Vitis版本略有差异用vitis -b -help查一下。命令行生成的好处是可以在脚本里自动化而且出错信息比GUI详细。4. 实操过程JTAG间接烧录QSPI Flash全记录4.1 硬件连接与启动模式设置烧录之前先把板子的启动模式拨到JTAG模式。7020的启动模式由MIO引脚决定具体拨码位置看板子原理图。通常JTAG模式是MIO[5:2] 0000或者类似。拨好之后连接JTAG下载器Platform Cable USB或者兼容的给板子上电。在Vitis里确认能识别到芯片如果识别不到先检查JTAG线序、驱动、以及Vivado/Vitis的版本是否匹配。注意有些板子的JTAG和QSPI共用引脚烧录的时候要确保没有其他设备干扰。如果JTAG识别不到芯片先量一下TCK、TDO、TDI、TMS的对地阻抗排除硬件问题。4.2 在Vitis里配置Flash编程器Vitis里烧录Flash的入口在Xilinx - Program Flash。打开之后需要指定几个东西硬件平台Platform工程、BOOT.bin文件路径、Flash类型、Flash编程算法。Flash类型选“qspi_single”或者“qspi_dual”取决于你的Flash是单线还是双线。7020通常用qspi_single四线的话选qspi_quad。Flash编程算法文件在Vitis安装目录下找比如/tools/Xilinx/Vitis/2021.2/data/xicom/cfgmem/。里面有一堆.mcs和.prm文件对应不同厂家的Flash。如果你的Flash型号是Micron的N25Q系列找n25qxxx.mcs如果是Spansion的S25FL系列找对应的。找不到完全匹配的选一个容量和扇区结构相近的通常也能用但擦除和写入的地址范围要手动确认。4.3 烧录过程与日志解读配置好之后点ProgramVitis会先擦除Flash的对应扇区然后把BOOT.bin写进去最后校验。整个过程在控制台有日志输出。正常的话会看到类似“Erasing flash...”、“Programming flash...”、“Verifying flash...”、“Flash programming completed successfully”的字样。如果卡在“Erasing flash”不动大概率是Flash型号选错了或者Flash硬件有问题。如果卡在“Programming”阶段可能是Flash的写保护没解除或者供电不稳。如果校验失败可能是Flash有坏块或者写入过程中被中断。烧录完成后把启动模式拨回QSPI断电再上电。如果一切正常串口会打印FSBL的启动日志然后应用程序开始跑。如果没反应先别急着重新烧按下面的排查步骤走。4.4 烧录后的启动验证与串口日志分析串口是排查启动问题的第一工具。FSBL如果编译时开了FSBL_DEBUG_INFO启动时会打印类似Xilinx First Stage Boot Loader Release 2021.2 Mar 10 2024-15:30:22 Devcfg driver initialized Silicon Version 3.1 Boot mode is QSPI Flash Base Address: 0xFC000000 ...看到这些说明FSBL跑起来了。如果卡在某一行不动那一行对应的初始化步骤就是问题所在。比如卡在“DDR init”就是DDR配置有问题卡在“Loading bitstream”就是bitstream有问题。如果串口完全没输出先确认串口线接对了、波特率是115200、串口终端没被占用。再确认启动模式拨对了。还不行就用JTAG连上在Vitis里跑FSBL的调试看卡在哪。5. 常见问题与排查技巧实录5.1 烧录成功但上电不启动的典型原因这是最常见的问题没有之一。烧录日志显示成功校验也过了但拨回QSPI启动就是没反应。按概率从高到低排启动模式引脚没拨对有些板子的拨码开关丝印和实际逻辑是反的或者MIO[5:2]的映射和你想的不一样。拿万用表量一下引脚电平对照UG585里的启动模式表确认。BOOT.bin里FSBL不是第一个分区用bootgen -dump BOOT.bin看一下分区顺序FSBL必须在最前面。Flash的地址映射不对7020的QSPI Flash通常映射在0xFC000000但有些板子用了不同的片选或者地址译码。在FSBL的xparameters.h里确认XPS_QSPI_LINEAR_BASEADDR的值。DDR初始化失败FSBL跑起来了但加载应用程序的时候挂了。串口日志会停在“Loading application”附近。检查Vivado里的DDR配置和实际板子的DDR颗粒是否匹配。5.2 Flash型号不匹配导致的烧录失败Vitis的Flash编程算法列表里没有你的Flash型号这是很常见的情况。比如有些板子用国产的QSPI Flash或者用比较新的型号。解决办法有几个找Flash厂家提供的编程算法文件通常是.mcs格式放到Vitis的cfgmem目录下。用相近型号的算法但手动调整擦除地址范围和扇区大小。比如你的Flash是16MB但算法是按8MB写的那只能烧前8MB。用flashrom或者openocd之类的开源工具自己写烧录脚本。这个门槛高一些但灵活。提示改Flash算法之前先用flashrom -p ft2232_spi:type...之类的命令读一下Flash的ID确认型号和容量。读出来是0xEF4018就是Winbond的W25Q12816MB。5.3 JTAG识别不到芯片的排查路径JTAG识别不到芯片先分清楚是硬件问题还是软件问题。硬件方面JTAG线有没有断、下载器有没有坏、板子有没有供电、TCK频率是不是太高试试降到1MHz。软件方面Vitis/Vivado的版本和下载器固件是否匹配、驱动有没有装好、有没有其他程序占用了JTAG。在Linux下可以用lsusb看下载器有没有被识别。Windows下看设备管理器。如果下载器识别到了但Vitis里连不上试试在Vivado里先连一下有时候Vivado的JTAG驱动更稳。还不行就换一个下载器试试Platform Cable USB的兼容性最好但山寨的容易出问题。5.4 启动时间过长或看门狗复位的处理有些应用对启动时间有要求比如工业控制里要求上电后几百毫秒内开始响应。7020的FSBL默认会做一些冗余的初始化比如等待PLL锁定、扫描所有启动设备。可以在FSBL里裁剪掉不需要的步骤比如跳过NAND、SD的扫描只保留QSPI。具体是在fsbl.h里把对应的宏关掉。看门狗复位是另一个坑。FSBL里默认会启动看门狗如果应用程序启动时间太长看门狗会复位。解决办法是在FSBL里把看门狗喂狗或者关掉或者在应用程序里尽早接管看门狗。我一般是在FSBL的main.c里把RegisterWDT相关的调用注释掉简单粗暴但有效。5.5 常见问题速查表现象可能原因排查方法烧录时卡在ErasingFlash型号选错确认Flash ID换对应算法烧录成功但不启动启动模式不对量MIO引脚电平对照UG585串口无输出波特率/线序/启动模式换串口线确认115200拨码卡在DDR initDDR配置不匹配检查Vivado DDR设置和板子颗粒卡在Loading bitstreambitstream格式或PL配置冲突换.bit/.bin格式检查FSBL配置JTAG识别不到硬件连接/驱动/频率降TCK频率换下载器查驱动启动后看门狗复位看门狗未处理FSBL里关看门狗或应用里喂狗6. 几个容易被忽略的实操心得6.1 关于BOOT.bin的版本管理BOOT.bin是二进制文件没法用git直接看diff。但项目迭代的时候BOOT.bin会频繁更新。我的做法是每次生成BOOT.bin的时候在文件名里带上日期和git commit号比如BOOT_20240310_a1b2c3d.bin。同时在项目根目录放一个bootgen.bif文件记录生成BOOT.bin的配置。这样回溯的时候用bif文件重新生成就行不用去翻旧的二进制。bif文件的格式大概是这样the_ROM_image: { [bootloader] fsbl.elf system.bit app.elf }用bootgen -image bootgen.bif -o BOOT.bin -w on就能生成。-w on是覆盖已有文件。6.2 用SD卡启动来快速验证BOOT.bin在固化到QSPI之前先用SD卡验证BOOT.bin是否正确。把BOOT.bin拷到SD卡根目录启动模式拨到SD上电。如果能正常启动说明BOOT.bin本身没问题固化到QSPI只是烧录环节的事。如果SD卡也启动不了那就是BOOT.bin生成有问题回去查FSBL和分区顺序。这个方法能省很多时间。因为QSPI烧录一次要几十秒到几分钟SD卡换程序就是拔插的事。我一般是在SD卡上验证通过之后才去烧QSPI。6.3 关于Vitis版本的坑Vitis的版本和Vivado的版本必须匹配2021.2的Vivado配2021.2的Vitis不能混。混了之后Platform工程可能导不进去或者BOOT.bin生成的时候报奇怪的错。另外Vitis 2020.1之前的版本和之后的版本在工程结构上有变化从旧版本迁移过来的工程可能需要重建。如果遇到Vitis里识别不到芯片先确认Vivado能不能识别。Vivado能识别但Vitis不能通常是Vitis的JTAG驱动没装好或者Vitis的版本和下载器固件不兼容。试试在Vitis的安装目录下找install_drivers脚本重新装一下驱动。6.4 Flash寿命与擦写次数QSPI Flash的擦写次数是有限的通常10万次左右。调试阶段频繁烧录虽然不至于把Flash写坏但也没必要。我一般调试用SD卡只有定型或者需要验证QSPI启动的时候才烧Flash。另外烧录的时候尽量用整片擦除还是扇区擦除整片擦除快但伤Flash扇区擦除慢但只擦用到的部分。Vitis默认是扇区擦除够用了。6.5 关于启动时间的优化如果项目对启动时间敏感可以从几个方面优化FSBL里关掉不必要的调试输出FSBL_DEBUG_INFO关掉能省几十毫秒、跳过不需要的启动设备扫描、把应用程序的elf压缩Vitis支持压缩启动镜像但会增加解压时间看情况用。实测下来一个简单的Hello World应用从FSBL到应用程序跑起来大概200到300毫秒。加上PL配置可能到500毫秒。如果要求更高就得考虑用更轻量的FSBL或者直接跳过FSBL不推荐除非你很清楚自己在做什么。7. 最后再分享几个排查小技巧串口日志是最直接的排查手段但有时候串口没输出不代表FSBL没跑。可以用JTAG连上在Vitis里attach到正在跑的FSBL看PC指针停在哪里。或者用Vivado的ILA抓一下QSPI的片选和时钟信号看BootROM有没有去读Flash。这些手段在硬件调试阶段很有用。另外BOOT.bin生成之后用bootgen -dump BOOT.bin看一下分区信息确认每个分区的加载地址和大小。有时候应用程序的elf里某个段地址和bitstream的地址重叠了跑起来就是随机崩溃但编译和烧录都不报错。这种问题最难查提前dump一下能避免。Flash烧录的时候如果板子上有多个QSPI Flash比如双片选要确认烧的是哪一个。有些板子用两个Flash做乒乓或者容量扩展Vitis里选错片选就会烧到另一个上去。量一下片选信号或者看原理图确认。我个人在实际操作中的体会是固化这件事流程本身不复杂但细节特别多。每一步都确认清楚比出了问题再回头查要省时间。尤其是BOOT.bin的分区顺序和Flash型号匹配这两个地方不出错基本就成功了一大半。剩下的就是耐心看日志、量信号没有查不出来的问题。