ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ZYNQ Flash烧写全攻略:从BOOT.bin到在线升级的避坑指南

ZYNQ Flash烧写全攻略:从BOOT.bin到在线升级的避坑指南 在ZYNQ的开发流程里把程序固化到Flash这步几乎每个人都会栽几次跟头。哪怕你已经把PL端和PS端的工程调得稳稳当当只要没把镜像写进Flash板子一断电就回到解放前一切都得重新来过。这篇东西不聊虚的就从“为什么烧写老失败”和“到底该怎么烧”这两个角度把ZYNQ烧写Flash这件事拆开揉碎讲清楚。这篇内容适合刚拿到ZYNQ开发板、准备从JTAG调试转向固化启动的工程师也适合那些已经烧过几次但偶尔还会被“Target DLL has been cancelled”这类报错折磨的老手。我会把镜像组成、烧写方式选型、完整实操步骤、NAND与QSPI的差异、高频报错排查以及在线升级的扩展思路都过一遍。你可以把它当成一份可以直接抄作业的手册遇到问题回来翻对应章节就行。1. 烧写之前先搞清楚ZYNQ启动镜像里装了什么很多人上来就点“Program Flash Memory”烧完发现板子起不来然后开始怀疑Flash坏了、怀疑焊接虚了、怀疑人生。其实大部分情况下不是硬件问题而是根本没搞清楚ZYNQ的启动流程和镜像结构。这块必须先从根上讲明白。1.1 一条完整的启动链BootROM、FSBL、SSBL与AppZYNQ-7000的启动流程是固定的三段式。芯片上电后片内固化的BootROM会先根据MIO引脚上的启动模式设置决定从QSPI、NAND、SD还是JTAG加载下一级镜像。BootROM本身只有192KB左右它干不了太多事只负责把第一级引导程序搬进片内OCMOn-Chip Memory通常只有256KB并跳转过去。这第一级引导程序就是我们常说的FSBLFirst Stage Boot Loader。FSBL由Xilinx提供源码在SDK里编译工程时会自动生成。它完成的工作很明确初始化PS端的必要外设比如MIO、DDR、GIC中断控制器等加载PL端的bitstream如果需要的话然后把SSBLSecond Stage Boot Loader一般是U-Boot或者裸机App从启动介质搬运到DDR里最后跳转执行。后面的事就看你的系统设计了。跑Linux的话SSBL就是U-Boot再由U-Boot引导内核和设备树跑裸机或RTOSFSBL可以直接跳转到你的应用程序。整个链条里任何一环出了问题板子就表现为“没反应”“串口无输出”或者“启动到一半卡死”。1.2 BOOT.bin是怎么生成的Bootgen与BIF文件烧写之前必须先把多个镜像打包成一个文件。Xilinx的工具叫Bootgen在Vivado SDK里通过“Create Boot Image”界面操作本质上是在调用一条bootgen命令行。打包所需的输入至少包含FSBL的elf文件再加上你想加载的bitstream和应用程序elf或U-Boot输出结果就是BOOT.bin。如果你不想每次都在GUI里点来点去可以直接写BIF文件然后用命令打包。一个典型的BIF文件长这样the_ROM_image: { [bootloader] ./fsbl.elf ./system.bit ./u-boot.elf }然后在命令行执行bootgen -image boot.bif -o i BOOT.BIN -w on-w on表示覆盖已存在的同名文件。这个流程在PetaLinux里也被封装好了平时我们生成BOOT.bin其实就是同一套逻辑。关键是理解BOOT.bin不是单个程序而是一个按BootROM和FSBL约定格式组织起来的镜像容器顺序、地址、校验都不能乱。1.3 启动模式选择QSPI、NAND、SD与JTAGZYNQ的启动模式是通过MIO[6:2]引脚电平组合决定的。不同板子可能拉高拉低的配置不一样但只要明白一点硬件上把启动模式设置成什么BootROM就从什么介质去读镜像。QSPI模式从片外QSPI Flash读取BOOT.bin适合量产和小型系统。NAND模式从NAND Flash读取适合大容量存储需求的场景。SD模式从SD卡启动开发阶段非常方便改完镜像直接换卡或者重新拷入即可。JTAG模式不加载非易失存储直接用JTAG把FSBL和App灌进芯片用于调试。开发阶段建议先做SD卡启动或JTAG调试把逻辑和软件都调稳了最后再做Flash固化。千万别一上来就往Flash烧否则每次改一点都要擦写一次浪费时间不说Flash的擦写次数虽然多但没必要这么糟蹋。2. 烧写方式选型不是只有JTAG一条路“烧写到Flash”这个动作本身在实际工程里有好几种实现路径。每种方式的适用场景、前置条件和风险都不一样选错了会非常难受。2.1 JTAG烧写最直接、最适合开发阶段JTAG烧写就是通过Xilinx的Vivado Hardware Manager或者SDK的“Program Flash Memory”功能把镜像文件直接写进连接在ZYNQ上的Flash芯片。这种方式不需要先在板子上跑任何程序只要JTAG链路通、Flash型号被工具识别就能写。它的优点是操作简单、无需预先烧入引导程序非常适合开发初期验证镜像。缺点是速度慢尤其大容量Flash写起来非常磨人另外它对Flash型号和连接有要求不是所有板子都能被工具自动识别。我见过有人用JTAG烧写128Mb的QSPI Flash光写镜像就花了快二十分钟中途还因为USB线接触不良断了一次整个人心态都崩了。2.2 U-Boot下烧写量产与现场恢复的利器如果板子上已经有一份能正常启动的U-Boot那后续的Flash烧写就简单多了。U-Boot里自带Flash操作命令配合TFTP或者FAT文件系统可以把新镜像下载到DDR再从DDR写入Flash。整个过程不用重新连接JTAG甚至可以通过网络远程操作。在U-Boot命令行里QSPI Flash的常见操作是这组命令的组合# 探测QSPI Flash确认型号和大小 sf probe # 通过TFTP下载BOOT.bin到DDR地址0x10000000 tftp 0x10000000 BOOT.bin # 擦除从0地址开始、大小1MB的Flash区域 sf erase 0x0 0x100000 # 把DDR里的数据写入Flash sf write 0x10000000 0x0 0x100000这套流程看起来简单但有几个细节要注意。sf erase的地址和长度必须按照Flash的扇区或块大小对齐不同型号的擦除粒度不一样。另外TFTP下载前要在U-Boot里设好IP地址、掩码和服务器地址否则文件拉不下来。2.3 系统内升级在线升级设计的基础再进一步如果设备已经部署到现场总不能每次升级都拆机接JTAG这时候就需要设计一套在线升级机制。常见做法是让运行中的系统Linux或RTOS接收升级包写入一个固定的升级分区然后重启进入U-Boot由U-Boot判断升级标志并把新镜像搬到启动分区。在线升级的复杂度等级比普通烧写高不少但它几乎是量产产品的必经之路。这块我在第6节再展开讲现在先记住一个结论JTAG烧写是手段U-Boot烧写是效率在线升级才是量产正解。3. 完整实操Vivado SDK JTAG烧写QSPI Flash一步步来现在进入正题讲一套我从头到尾实测过多次的操作流程。这套流程适用于绝大多数ZYNQ-7000开发板Flash型号以常见的Winbond W25Q128、Micron N25Q128、ISSI IS25LP128等QSPI Nor Flash为例。3.1 环境准备与硬件检查动手之前先把环境和硬件状态确认一遍这能省掉后面九成的问题。软件方面Vivado和SDK的版本要对应我目前常用Vivado 2020.2和2023.1两种版本的SDK界面略有差异但核心操作逻辑一致。目标板通过JTAG仿真器连到电脑常见的有Xilinx原厂Platform Cable USB II、Digilent JTAG-HS3或者板载的FTDI芯片大多数国产开发板是这个方案。硬件方面重点检查三件事板子供电正常核心电压、DDR电压、IO电压都稳定。如果板子上有电流表养成上电后看一眼电流的习惯ZYNQ空载跑FSBL时的电流一般在几百毫安级别电流异常偏低说明DDR都没初始化直接烧写大概率失败。JTAG链路通畅。打开Vivado Hardware Manager能看到设备列表里有xc7z010、xc7z020之类的芯片编号同时能看到连接的Flash型号老版本SDK需要把Flash型号也加入扫描链。如果这里看不到设备先别急着烧查USB线、驱动和仿真器供电。启动模式跳线设置在正确的位置。如果你的板子当前启动模式在SD卡或者NAND而你要烧QSPI最好把跳线拨到QSPI模式再操作。这不是烧写动作本身需要而是为了避免烧完后验证时启动介质不对让人误以为烧写失败。3.2 打开Program Flash Memory并选择镜像在Vivado SDK中点击菜单栏Xilinx - Program Flash Memory会弹出烧写对话框。这个对话框里的选项就是整个烧写动作的核心参数。第一个要选的是Image File也就是你要烧写的镜像文件。它可以是BOOT.bin也可以是MCS文件甚至可以是单独的BIN文件。我的习惯是直接烧BOOT.bin因为它包含FSBL、bitstream和U-Boot一次烧完省事。第二个要选的是Flash Type。SDK会根据JTAG链上的设备自动识别常见的是qspi-x4-single如果工具识别不出来就需要手动选择。这里要注意如果你的硬件设计里QSPI Flash连接在MIO1-6上且使用了x4模式就选qspi-x4-single如果只用了single模式选qspi-x1-single。选错的话烧写可能能完成但启动时BootROM读不到正确数据。第三个必选的是FSBL File。SDK烧写Flash时并不像烧写裸机程序那样直接把镜像扔进Flash而是需要一个中间代理程序先把FSBL加载到OCM里运行起来由FSBL来初始化PS端的外设尤其是QSPI控制器然后再由运行在PS上的FSBL把镜像数据写入Flash。所以这里选择的FSBL文件必须和当前硬件匹配。它可以是SDK里任何能编译通过且用到了当前硬件的fsbl工程生成的elf。如果选择错误烧写过程会报各种莫名其妙的错误比如第5节会讲的“Target DLL has been cancelled”十有八九就出在这个FSBL上。3.3 关键参数地址、擦除与校验策略Flash起始地址默认是0x0通常不需要改。如果你的设计里把BOOT.bin放在了Flash的非零偏移处那你要确保BootROM的相应启动模式支持这个偏移否则就是自己给自己挖坑。做开发时一律从0地址开始最稳妥。烧写操作里还有几个选项需要注意Blank Check空检查烧写前检查目标区域是否为空可以提前发现Flash擦除是否彻底。Erase Before Programming擦除后再编程建议勾选。Flash只能从1写0如果不先擦除直接写入会残留旧数据导致校验失败。Verify After Programming烧写后校验强烈建议勾选。烧写完成后回读Flash数据与原始镜像逐字节比对能从硬件层面确认镜像完整。我遇到过一次烧写过程显示完成但板子死活起不来的情况后来发现是忘记了勾选Verify而实际上Flash的某个扇区因为坏块导致数据写入失败。从那以后我的烧写参数都固定勾选Erase和Verify一次烧写多花几十秒但换来的是可靠的结果值。3.4 顺利烧写时你会看到的日志点击OK后SDK的Console窗口会输出一系列信息。正常流程大致是这样Connecting to target... -----开始烧写----- FSBL文件加载成功 Offset: 0x00000000, Size: 0x000A0000 擦除Flash... 编程Flash... 校验Flash... Flash编程完成。注意中间如果出现任何红色的Error都别继续往下走了先停下来分析原因。有一类错误是Flash ID没被识别到可能是因为Flash型号不在Xilinx的列表里也可能是因为板子的Flash供电没给上。遇到这类错误先确认硬件再折腾软件顺序别搞反。4. 换个介质NAND Flash烧写要点与型号适配QSPI Nor Flash是ZYNQ开发板最常见的配置但在实际产品里NAND Flash也开始用得越来越多。原因很简单同样是几十块钱的成本NAND能买到几Gb甚至几十Gb的容量而QSPI Nor通常到128Mb16MB就差不多到头了。如果你的系统需要存储大量数据比如嵌入式数据库、本地缓存、历史记录等NAND几乎是必然选择。4.1 ZYNQ对NAND的支持情况与型号选择ZYNQ-7000系列内部集成了NAND控制器支持ONFI 1.0兼容的SLC NAND Flash。这里要划重点是SLC不是MLC也不是TLC。虽然市面上一些MLC型号物理上也能用但Xilinx的FSBL和驱动并没有针对MLC做完整的坏块管理、位翻转处理和ECC校验支持强行使用风险极高现场出了问题非常难查。选型上推荐Micron的MT29F系列、Winbond的W29N系列、Spansion现Cypress/Infineon的S34ML系列。容量方面256MB到1GB范围的产品在ZYNQ系统里用得最多太大容量反而会引入页映射和分区管理复杂度收益不大。另外要注意NAND对FSBL的要求比QSPI高不少。QSPI模式下FSBL只要能把镜像读出来就行简单粗暴NAND模式下FSBL必须处理ECC校验和坏块跳过Xilinx提供的FSBL源码里默认带了这些功能但前提是你选了正确的BSP配置。如果在创建FSBL工程时没有选对NAND驱动参数烧写出来的镜像即使写进Flash启动时也会因为ECC校验失败而卡住。4.2 NAND烧写的坑用Vivado SDK的Program Flash Memory烧写NAND整体流程和烧QSPI几乎一样都是先加载FSBL再写Flash但有几个非常折磨人的差异点。首先是速度NAND的编程单位是页Page典型页大小是2KB或4KB虽然单页编程时间只有几百微秒但批量写入时要不断照管ECC和坏块实测下来速度往往只有QSPI的几分之一。其次是擦除和写入的粒度不同。不管QSPI还是NAND操作前都要擦除但NAND的擦除单位是块Block一个块通常是64页或128页即128KB或256KB。如果你只想更新部分数据也必须整块擦除再整体写入这对在线升级的分区设计有很大影响。第三是坏块处理。NAND出厂就可能有坏块使用过程中还会产生新坏块。SDK烧写NAND时如果遇到坏块会报错终止不会自动跳过这意味着你烧写前必须确保目标区域没有坏块否则就要用专门的烧写工具或U-Boot下的nand命令来写。我实际工作中烧NAND基本都是走U-Boot很少直接用SDK。在U-Boot下烧写NAND的命令组合长这样# 从TFTP下载镜像到DDR tftp 0x20000000 BOOT.bin # 擦除NAND从0地址开始、大小1MB的区域 nand erase 0x0 0x100000 # 写入NAND nand write 0x20000000 0x0 0x100000NAND的ECC模式一般由FSBL或U-Boot在启动时配置好烧写前用nand info确认当前ECC方式与Flash颗粒匹配避免校验失败。4.3 大容量Flash的分区规划建议NAND容量大了以后必然要涉及分区规划。我的建议是整个Flash按用途分成三个区启动镜像区存放BOOT.bin大小1-2MB内核与设备树区如果采用U-Boot从NAND引导内核需要单独划分大小几十MB用户数据区剩余全部空间按文件系统或裸数据管理。分区规划这件事最好在设计阶段就定下来别等软件写完了再补否则后面一次升级就要重新设计方案改起来牵一发动全身。5. 高频报错实录与排查方法这部分是整篇文章里我最有底气的地方因为下面这些错误我基本都亲手踩过有的坑踩完还特意复现了几次就是为了搞清楚根因。按出现频率从高到低我把最典型的几个报错和排查思路整理出来。5.1 ErrorFlash download failed - Target DLL has been cancelled这个报错在SDK烧写时出现频率极高而且原因非常多。Target DLL被取消本质上是烧写过程中JTAG链路或目标芯片状态出现了异常导致工具无法继续控制目标。我总结下来最常见的原因是FSBL文件有问题。前面说过烧写Flash时SDK会先把FSBL加载到OCM运行由FSBL初始化QSPI/NAND控制器。如果你的FSBL不匹配芯片初始化到一半就卡死了JTAG自然无法继续操作于是报Target DLL cancelled。排查顺序是这样确认JTAG能正常连接目标芯片单独用Hardware Manager做一次设备扫描如果扫描都失败先解决连接问题。确认选择的FSBL文件正确。最稳妥的做法是在SDK里专门创建或打开一个与当前硬件对应的fsbl工程编译一次然后选这个elf文件。检查板子的启动模式引脚。有些板子在JTAG模式下会禁用某些时钟导致FSBL加载后初始化外部存储失败。把启动模式临时切到QSPI或者SD往往能绕开这个问题。用示波器或逻辑分析仪看Flash的片选信号和时钟确认FSBL运行过程中确实产生了预期的读写时序。5.2 ErrorA valid FSBL file is required for flash operation这个报错就直白多了SDK在烧写Flash前必须有一个FSBL文件作为代理你没给或者给的文件无效它就罢工。正常情况下在Program Flash Memory对话框里选择FSBL File为fsbl.elf即可。但有几种情况要注意如果SDK工程被build过一次后又改了硬件平台旧的fsbl.elf可能引用了已经不存在的硬件描述直接报错还有就是把不同版本的fsbl.elf混用比如Vivado 2019.2生成的elf拿到2023.1里用大概率也会报错。解决办法就是重新编译一份当前工程对应的fsbl.elf。5.3 擦除失败或超时QSPI Flash的擦除是按扇区通常4KB或块通常64KB进行的。如果你的镜像跨了多个扇区边界SDK会逐步擦除在这个过程中如果Flash电压不稳或时钟频率过高擦除操作可能超时或失败。这类问题一个非常常见的诱因是电源质量。ZYNQ开发板上3.3V给Flash供电如果板上电源波动大Flash在擦除过程中进入低电压锁定状态就会表现为擦除失败。排查方法很简单擦除时用示波器监测3.3V电源轨看有没有掉坑。另一个因素是JTAG频率过高。SDK里可以设置JTAG时钟频率如果冗余太少把频率从默认的15MHz降到6MHz或者3MHz往往能解决很多莫名其妙的失败。别嫌慢Flash烧写本来就不是一个追求速度的操作。5.4 烧完了却启动不了烧写完成后启动失败这个是排查难度最大的问题因为烧写环节一切正常报错却在启动阶段。按我的经验检查优先级如下启动模式引脚设置是否正确。最常见的情况就是跳线还留在JTAG模式或者SD模式BootROM根本不会去读Flash。镜像内容是否完整。用Hardware Manager读回Flash数据和原始BOOT.bin比对看有没有漏数据。如果用的是旧版SDK有时候擦除后写入的数据会在尾部截断比对能直接发现。FSBL里DDR初始化是否匹配。如果你的BOOT.bin里的FSBL是从某个模板工程生成的而模板的DDR颗粒和实际板子不一样FSBL在初始化DDR时失败后续的U-Boot或App根本没法跑起来。bitstream是否真正被加载。有的设计里PL被配置成user modeFSBL加载完bitstream后继续跑软件如果bitstream本身有问题可能系统看起来启动了但外设不工作。这种情况可以单独烧一个只含bitstream的镜像来验证PL部分。5.5 制作SD卡启动镜像的补充说明不少人一看到“flash烧写”就以为只能往Flash里写其实ZYNQ从SD卡启动也是开发调试阶段的常用手段。制作SD卡启动卡的过程实际上也是把BOOT.bin、boot.scr、image.ub等文件放进FAT分区和“烧写”概念上类似只是介质变了。用PetaLinux时一条命令就能完成打包petalinux-package --boot --fsbl --fpga --u-boot --force生成BOOT.bin之后把BOOT.bin、boot.scr、image.ub拷贝到SD卡第一个FAT分区把启动模式拨到SD上电就能启动。这套流程对调试内核配置特别方便改内核只需要替换image.ub几十秒就能完成一轮启动测试比反复擦写Flash高效太多。5.6 高频错误速查表错误现象最可能原因首要排查动作Flash download failed - Target DLL cancelledFSBL不匹配或JTAG链路不稳确认FSBL并降低JTAG频率A valid FSBL file is required未选或选错FSBL选择当前工程的fsbl.elf烧写完成但校验失败Flash擦除不彻底或写入时序问题勾选Erase Before Programming启动无反应Boot模式引脚错误或镜像不完整检查跳线并回读比对FlashU-Boot下sf probe失败QSPI Flash型号不支持或硬件连接错误检查原理图和Flash供电6. 进阶思路基于ZYNQ的Bootloader在线升级设计聊完烧写本身我再延伸一个每个产品化项目都躲不开的话题在线升级。调试阶段用JTAG烧写、用SD卡启动都没问题但产品一旦部署出去在线升级就是刚需。下面这套方案是我在多个项目里落地过的直接参考即可。6.1 为什么要做在线升级设备部署在现场以后不可能每次更新固件都派人拆机接JTAG。哪怕只是改一个参数如果系统架构不支持在线升级工程师就得背着电脑、仿真器和一把螺丝刀出差成本极高。在线升级的本质是让运行中的系统自己把新镜像写进Flash然后在下次启动时切换到新版本。这个需求的工程难点在于可靠性。升级过程中如果掉电、断网、镜像损坏设备就变砖了。所以设计在线升级方案时核心要解决的不是“能不能升级”而是“升级失败后能不能恢复”。6.2 一个实用的分区方案我常用的分区方案是这样的QSPI或NAND的起始区域放一个固定不变的Boot区里面是BootROM所需的FSBL和U-Boot。这个区域平时不参与升级除非是重大架构调整否则永远不动。Boot区之后划分两个App区A区和B区交替存放应用程序镜像。当前运行在A区新版本就写到B区写入完成后置一个升级标志重启后U-Boot读取标志引导B区。如果B区启动失败U-Boot回滚引导A区设备回到旧版本依然可用。这个方案在业界叫A/B分区或双备份系统实现起来不复杂但对启动流程的理解要求比较高U-Boot需要能从环境变量或特定Flash地址读取“下次启动哪个分区”的标志。6.3 实现要点升级流程的落地路径大概是这样的运行在Linux或RTOS中的应用从服务器下载新镜像到文件系统写入换一个分区写镜像然后设置启动标志最后触发重启。U-Boot侧需要定制启动脚本读取标志位并引导对应分区的镜像。有几个细节容易踩坑。第一个是镜像完整性校验。下载下来的镜像写入Flash之前一定要做校验CRC32或MD5校验通过才允许写入否则直接丢弃。第二个是断电保护写Flash的过程中掉电是最危险的最稳妥的办法是先把镜像写到DDR里确认完整后再一次性写入Flash虽然不能完全避免掉电风险但能大幅缩短Flash写窗口。U-Boot侧的关键命令是这样的# 设置下次启动分区为B区 setenv boot_part b saveenv # 引导逻辑 if test $boot_part b; then run boot_b else run boot_a fi6.4 风险控制与实测建议在线升级的测试不能只在实验室里做“正常流程”必须刻意制造异常场景来验证恢复能力。我自己测试时最常用的一种方法是在升级写到一半的时候直接断电然后重新上电看设备能不能自动回滚到旧版本。如果回滚逻辑写得不健壮这种测试一两次就会暴露问题。另外要强调的是Boot区的FSBL和U-Boot虽然不参与常规升级但它们本身也有需要更新的场景比如调整DDR时序、增加启动参数所以架构上还是要预留一个“特殊升级模式”通过按键或串口命令进入专门更新Boot区内容。这个模式一定要有明显的标志位和保守策略否则一旦Boot区写坏整块板子就只能返厂用JTAG恢复。最后分享一点个人经验烧写Flash这件事看着是小事但每个环节都藏着坑。我最早做ZYNQ项目时因为FSBL文件选错连续报同样的Target DLL错误折腾了两天才发现是在另外一个工程目录里Build的FSBL和当前硬件根本不匹配。从那以后我养成了一个习惯每块板子建一个专门的fsbl工程名字里带硬件版本号改版就重新Build绝不沿用旧文件。还想提醒的是如果你的板子支持多种启动方式建议在Flash里放一份稳定版本之后日常开发切到SD卡启动。这样Flash里的固件始终是“最后可用状态”就算SD卡里的新版本改坏了也能随时切回Flash版本救砖。这个习惯帮我避免过好几次项目延期在这里一并写出来希望对你有用。
返回列表