ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

ZYNQ程序固化到Flash完整指南:启动流程、QSPI/NAND烧写与常见报错排查

ZYNQ程序固化到Flash完整指南:启动流程、QSPI/NAND烧写与常见报错排查 搞过ZYNQ的朋友应该都有这种体验在Vivado里把硬件工程跑通了、SDK里应用程序也编译过了仿真一切正常结果到了要把程序固化到flash这一步突然卡住。网上搜一圈要么是零零散散的截图要么是只说“点Program Flash就行”的教程真到自己动手各种报错扑面而来。这篇文章我就把自己实际烧写ZYNQ程序到flash的完整过程、踩过的坑、排查思路都整理出来从启动流程到FSBL的作用从QSPI和NAND的选择到具体的烧写命令一次性讲透。这里要说明一下这篇文章面向的是所有用ZYNQ做开发的朋友不管是刚上手的新手还是被烧写问题折磨的老手应该都能从中找到自己需要的东西。内容以Xilinx官方工具链Vivado SDK/Vitis为主线覆盖QSPI Flash和NAND Flash两种最常见的固化场景同时也会提到SD卡启动的替代方案以及在工程实践中经常碰到的几个典型报错。1. 烧写之前必须搞清楚的启动流程很多人在烧写flash这一步翻车根源不是操作不对而是对整个启动流程理解不够。ZYNQ的启动机制和单片机完全不一样别拿STM32那套思路往上面套。1.1 ZYNQ的启动镜像到底由什么组成先看一个最核心的问题ZYNQ从flash启动时硬件上电后到底执行了什么答案不是你的应用程序而是一级引导程序后面跟着FSBL、bitstream、SSBL通常是U-Boot和应用程序。整个镜像文件被称为BOOT.bin它的内部结构大致是启动头Boot Header包含镜像描述信息、加密选项、校验值等是BootROM解析镜像的入口。FSBLFirst Stage Boot Loader由Xilinx提供模板负责初始化DDR、时钟、MIO等并加载后续镜像。硬件比特流bitstream如果PL端有逻辑比特流由FSBL加载到PL。第二阶段引导程序或应用程序U-Boot或裸机程序最终交到用户程序执行。上电时ZYNQ片内的BootROM会先运行根据MIO引脚的电平配置决定从哪个接口启动比如QSPI、NAND、SD或者JTAG。BootROM把BOOT.bin开头的一段代码读入片上RAM然后跳转执行也就是进入FSBL流程。所以你会看到SDK里烧写flash时强制要求先选择一个FSBL文件提示“A valid FSBL file is required for flash operation”。这不是Xilinx故意为难你而是烧写工具必须用FSBL来完成flash的初始化和擦写操作。1.2 QSPI、NAND和SD卡启动介质怎么选ZYNQ支持的启动介质主要是这几种QSPI Flash、NAND Flash、SD卡还有JTAG调试模式。选哪个取决于你的应用场景。QSPI NOR Flash是最常用的。它的优点在于接口简单、读取速度快、可靠性高而且Xilinx的IP核支持得很完善。容量一般在16MB到128MB之间对于中小型工程绰绰有余。大部分开发板比如米尔、正点原子、黑金这些板载的都是QSPI Flash。如果是裸机程序或者Linux系统比较精简QSPI完全够用。NAND Flash的优势在容量动辄512MB甚至更大适合存放大的文件系统、视频数据等。但NAND本身有坏块管理、ECC校验等一堆问题而且ZYNQ支持的NAND型号有限在Xilinx官方文档UG585里有详细的兼容列表。买芯片前一定要查一下型号在不在支持范围内否则就算烧写成功也可能启动异常。SD卡启动是另一条路严格来说不算烧写flash但也经常被用来运行Linux系统。SD卡容量大、方便更换开发阶段尤其好用。很多基于ZYNQ的bootloader在线升级设计就是SD卡启动Linux配合应用程序去更新QSPI里的镜像。我的建议是产品量产用QSPI固化开发调试用SD卡NAND除非有容量刚需否则尽量避开。理由很简单QSPI在工具链支持上最成熟出问题的概率最低这一点在后面的烧写步骤里会有体现。2. 烧写方案选型与工具分析搞清楚启动流程之后接下来要选烧写方案。ZYNQ烧写flash的途径主要有三条SDK/Vitis图形界面烧写、命令行工具烧写、第三方烧写器烧写。三者各有适用场景不能一概而论。2.1 SDK图形界面烧写和命令行烧写怎么取舍图形界面烧写是入门首选。在Vitis旧版SDK里连接开发板右键点击FSBL工程选择Run As → Launch on Hardware先把FSBL下载到板上跑起来然后选择Xilinx → Program Flash填写flash类型、镜像路径等参数点Program就完事。命令行烧写用的是program_flash工具它支持更灵活的脚本化操作适合产线批量烧写和自动化集成。比如可以写成一条命令program_flash -f BOOT.bin -offset 0 -flash_type qspi-x4-single -fsbl fsbl.elf -cable type xilinx_tcf url TCP:127.0.0.1:3121这条命令的效果和图形界面是一样的但可以放进CI脚本里或者封装成产线工具效率和可维护性都高得多。另外还有一个更新一点的方案是用xsdb programmer命令行。xsdb是Xilinx的调试服务器配合tcf agent可以实现远程烧写这在板卡不在手边的时候特别有用。2.2 JTAG、串口、第三方烧写器到底有什么区别烧写通道的选择同样关键。ZYNQ最常用的烧写通道是JTAG因为JTAG直接链到CPU的调试访问端口DAP可以控制CPU执行任意代码包括FSBL。通过JTAG加载FSBL后FSBL再对接flash读写这就是“JTAG烧写”的本质。串口烧写则是另一种思路它不着眼于JTAG链而是通过UART把镜像传给一个已经运行起来的引导程序比如U-Boot由U-Boot把数据写入flash。这种方式在现场升级时用得比较多因为现场不一定有JTAG调试器。但你搜“串口烧写失败”会发现一堆帖子原因主要集中在波特率不匹配、流控打开、镜像带校验头导致U-Boot拒绝写入等方面。我个人建议是能用JTAG就用JTAG串口烧写适合用在产品已经交付后的现场升级场景。第三方烧写器比如之前相关搜索里出现的BeeProg2属于通用编程器直接夹在flash芯片引脚上烧。这种方案通常用于空板贴片前的预烧写或者flash焊在板上但JTAG链路被占用的情况。用编程器烧写要特别注意芯片封装适配器和电压匹配稍有疏忽就可能损伤芯片。3. 详细实操编译BOOT.bin并烧写QSPI Flash现在进入正题以QSPI Flash烧写为例完整走一遍从构建镜像到烧写验证的流程。3.1 从硬件工程到BOOT.bin的完整构建流程第一步在Vivado里完成硬件工程的综合、实现并导出硬件平台。注意勾选“Include bitstream”这样导出的XSA文件里才会包含PL端配置。如果你只需要PS端跑裸机不需要PL逻辑那XSA里也可以没有bitstream但FSBL会跳过PL初始化这个没关系。第二步打开Vitis基于XSA创建platform工程然后创建一个FSBL工程。FSBL可以从Xilinx提供的模板生成在Vitis里新建Application Project时模板列表里找到“Zynq FSBL”直接生成即可。第三步创建你的应用程序工程。如果是裸机程序编译生成ELF如果是Linux系统这一步就要用PetaLinux生成U-Boot和image.ub然后把FSBL、bitstream、U-Boot打包。第四步生成BOOT.bin。在Vitis的Xilinx菜单下选择Create Boot Image界面里按顺序添加分区1FSBL类型选bootloader文件为fsbl.elf分区2bitstream文件为design_1_wrapper.bit分区3应用程序或U-Boot文件为app.elf或u-boot.elf生成后得到一个BOOT.bin。如果用PetaLinux可以用以下命令一条龙生成petalinux-package --boot --fsbl --fpga --u-boot --force这条命令会自动把FSBL、比特流和U-Boot打包成BOOT.bin。3.2 使用Vitis图形界面烧写QSPI Flash烧写前先准备硬件环境开发板通电JTAG调试器Digilent JTAG-HS2/3或Xilinx Platform Cable USB连接到PC板卡上启动模式跳线设为JTAG模式。注意如果跳线设成了QSPI启动JTAG链路可能被BootROM引导流程干扰导致下载失败。打开Vitis连接目标板。可以先运行一个空的FSBL到板上确保JTAG链路和DDR初始化正常。然后在菜单栏选择Xilinx → Program Flash弹窗里这样配置Image File选择BOOT.bin路径Offset填0x0Flash Type选qspi-x4-single或qspi-x1-single依据原理图上的连接方式FSBL File选择fsbl.elf勾选Verify after flash点击Program工具会自动通过JTAG把FSBL加载到片上RAM运行然后FSBL初始化QSPI控制器执行擦除、编程、校验。QSPI Flash容量不大比如16MB整个流程通常在一两分钟内完成。如果镜像比较大比如几十MB时间会明显变长这时候不要误以为卡死了看右下角log进度就行。烧写完成后把启动模式跳线改到QSPI重新上电。如果一切正常程序会自己跑起来。如果板子没有反应优先检查BOOT.bin里的FSBL分区是不是放在第一个以及启动模式引脚的电平组合是否和板卡手册一致。3.3 命令行烧写与u-boot下烧写NAND FlashQSPI用图形界面够了但NAND Flash的烧写情况复杂一些因为NAND有坏块、页大小、OOB区等概念Xilinx的图形界面支持度不如QSPI好。到这一步我建议转用命令行工具或者U-Boot来烧写。用program_flash命令烧写NAND的典型用法program_flash -f BOOT.bin -offset 0x0 -flash_type nand-x8 -fsbl fsbl.elf -verify需要注意flash_type参数必须与硬件实际使用的NAND颗粒规格一致x8还是x16是否带ECC这些参数在UG585或者Vitis文档里有明确说明。烧写NAND时FSBL里也需要正确配置NAND驱动否则擦写会失败。另一种常见做法是通过U-Boot烧写。先让板子从SD卡启动进入U-Boot然后用tftp把镜像下载到DDR再用nand erase、nand write命令写入。流程如下setenv ipaddr 192.168.1.100 setenv serverip 192.168.1.10 tftp 0x3000000 BOOT.bin nand erase 0x0 0x800000 nand write 0x3000000 0x0 0x800000这种方式的好处是不依赖JTAG调试器现场只需要网线和串口线就能完成升级。这个思路其实就是很多“基于ZYNQ的bootloader在线升级设计”的核心——系统运行起来之后通过自定义应用程序读取新镜像然后调用flash驱动完成在线更新。这里有个大坑写入长度必须是页大小的整数倍NAND的页大小常见是2KB或4KB算错的话末尾数据会丢失。3.4 制作SD卡启动盘并合理规避flash烧写风险有时候flash烧写频繁出错或者你只是想快速验证Linux系统我会建议干脆先用SD卡启动。SD卡启动的镜像文件不是BOOT.bin而是需要一张包含BOOT.bin由FSBLbitstreamU-Boot组成和image.ub的SD卡。制作SD卡启动盘的一般步骤用分区工具把SD卡分成两个分区第一个分区格式化为FAT32放BOOT.bin和boot.scr第二个分区格式化为ext4放image.ub和根文件系统。将PetaLinux生成的BOOT.bin、boot.scr、image.ub复制到对应分区。插入SD卡开发板跳线设为SD启动上电。SD卡启动非常适合开发阶段反复调试不会磨损板载flash也不怕烧错变砖。很多ZYNQ在线升级方案就是利用SD卡启动Linux在Linux里跑一个升级服务接收新的固件包然后把固件写入QSPI Flash实现不拆机升级。这种方案绕开了直接烧flash的风险升级失败还可以回退到SD卡系统容错性很好。4. 常见问题与排查技巧实录这部分我直接整理成速查表的形式每个问题都附上排查思路和解决方法。下面这些报错基本覆盖了90%以上的人会遇到的场景。4.1 Error: Flash Download Failed - Target DLL has been cancelled这个报错太经典了几乎每个用Vitis烧写的人都会碰上一次。它的含义是烧写过程中目标DLL被中止通常是JTAG链路出现异常或者FSBL运行崩溃导致烧写进程中断。排查顺序按下面的来检查JTAG连接确认调试器被PC识别并检查板卡JTAG链路是否完整部分开发板JTAG和QSPI/其他外设共用引脚看板卡手册确认是否有跳线冲突。检查启动模式烧写时跳线务必设在JTAG模式如果设成了QSPI或SD启动BootROM的启动流程可能干扰FSBL的执行。检查FSBL是否选对Program Flash对话框里FSBL File一栏必须指向与当前硬件匹配的FSBL。如果FSBL是别的板子的初始化DDR或QSPI时就会崩然后报这个错。检查电源稳定性ZYNQ对电源纹波比较敏感尤其是DDR供电异常时FSBL初始化DDR会卡住表现就是Target DLL cancelled。4.2 A valid FSBL file is required for flash operation这个提示是Vitis在Program Flash时弹出的很多新手会问“我明明选了BOOT.bin为什么还要FSBL”原因前面讲过——BOOT.bin里的FSBL在烧写过程中不一定会被重新执行而Program Flash功能需要FSBL来初始化flash控制器并执行驱动。注意BOOT.bin里已经有FSBL了但你仍然需要在Program Flash对话框里单独指定fsbl.elf。这是工具的设计要求不是可以省掉的选项。如果找不到fsbl.elf回到platform工程旁边的FSBL工程里找Debug或Release目录。4.3 Cant perform JTAG flash, because OpenOCD server is not running这个报错常见于新版Vitis或使用第三方调试器如SEGGER J-Link、OpenOCD的环境。OpenOCD本身是一个开源的调试工具Vitis工程里如果检测不到调试服务器就会报这个错。解决思路有两个方向。一是用Xilinx官方调试器Digilent JTAG-HS系列等此时Vitis会启动自带的hw_server和target manager不会依赖OpenOCD二是你确实要用OpenOCD那么先启动OpenOCD服务openocd -f interface/ftdi/jtagkey2.cfg -f target/zynq.cfg确保OpenOCD进程保持运行再回到Vitis或命令行执行烧写。这个场景在Linux主机上比较常见Windows下多数还是用官方驱动居多。4.4 串口烧写失败的问题排查串口烧写失败的原因我在实际支持中见到的可以归为三类。波特率不匹配U-Boot默认波特率常见为115200如果你串口终端软件那边设成9600或其他值看着就是乱码收到的数据全是坏的。镜像格式不对U-Boot烧写时通常要求镜像带头部信息比如mkimage生成的镜像。如果直接把BOOT.bin通过串口发给U-BootU-Boot会拒收因为它期待的可能是它认识的image格式。文件传输协议问题串口烧写常用ymodem或xmodem协议。有些终端工具对超大文件支持不好传输到一半就断。尽量把镜像控制在几MB以内或者换一个成熟的终端工具。如果条件允许串口烧写只作为备用方案。优先JTAG其次是U-Boot网口tftp最后才是串口。4.5 烧写完成后板子无反应这个问题的原因就要结合启动流程来查了。先看电源指示灯和时钟是否正常。ZYNQ板卡上一般有PS_CLK用示波器量一下如果时钟没有起振PS端根本没跑起来。再确认启动模式引脚设置。ZYNQ的启动模式由MIO[5:2]的电平决定每一种组合对应一种启动介质比如0110对应QSPI。如果跳线设置和实际烧录介质不一致BootROM读了错误的介质自然启动不了。还有一种情况是BOOT.bin中分区顺序错了。FSBL必须排在第一个分区如果bitstream排在了第一个BootROM会把它当成FSBL执行结果当然是异常。最后检查是否烧到了正确的offset。QSPI Flash一般从0地址开始但有些板卡设计会在flash开头留一段空间给别的用途比如存放保护配置或BootROM参数。这种情况下BOOT.bin的offset不一定是0要按板卡手册来。4.6 NAND Flash型号兼容性排查前面多次提到Xilinx对ZYNQ支持的NAND Flash型号有明确限制。这个限制不是芯片引脚兼容的问题而是ZYNQ内部NAND控制器驱动所支持的页大小、块大小、ECC算法有限制。所以就算你找了一颗物理上兼容的NAND但不在Xilinx支持列表里FSBL初始化时也可能读取不到正确的芯片参数导致擦写失败。UG585里有一张NAND Flash支持列表的表格选型时直接对照。如果不确定手上的颗粒是否支持最稳妥的方式是用SDK里的QSPI/NAND驱动自带的Flash ID查询功能把芯片ID读出来比对。这个问题在NAND方案里非常普遍建议提前规避。5. 实际项目中烧写方案的落地经验前面聊了具体操作最后这部分我想分享一些项目层面经验尤其是烧写和多分区布局、在线升级搭配相关的思路。5.1 flash分区规划与启动方案设计产品开发到后期一定会遇到flash分区规划的问题。比如QSPI 16MB不能把BOOT.bin从头占到尾因为还要留空间给应用程序升级。常规的做法是做一个分区表举例如下分区名称起始地址大小存放内容Bootloader区0x0000001MBBOOT.binFSBLbitstreamU-Boot内核区0x1000004MBimage.ub文件系统区0x5000008MBrootfs/image用户数据区0xD00000剩余应用程序、配置、日志这样划分的好处是升级时只需要更新其中一个分区不需要整片擦除。配合在线升级设计应用程序收到新包后写入用户数据区然后重启切换启动指针既降低了升级风险也缩短了升级时间。如果你用的是裸机程序同样可以分两个APP区做A/B升级。写一个简单的引导逻辑在FSBL或用户引导程序里判断哪个分区的版本号更高就从哪个分区启动。这个方案我在好几个产品里用过稳定可靠而且实现起来并不复杂。5.2 在线升级降级与回滚策略基于ZYNQ的bootloader在线升级设计在实际产品里通常还要考虑回滚。最直接的办法是保留出厂固件分区升级时先擦除临时分区写入新固件校验通过后再把启动标志指向新分区。如果校验失败或运行异常看门狗会触发回滚启动到旧版本。这个思路听着简单真正落地时有一堆细节。比如flash的写入尽量按扇区对齐否则擦除操作会波及邻近数据校验采用CRC32或SHA256不能只靠长度判断升级过程中的意外断电必须有应对措施通常是在flash头部存一个升级状态标记引导程序判断标记来决定是否继续升级。我在实际项目中的经验是任何flash写操作都先备份旧镜像、再写新镜像、最后更新标志位顺序不能搞反。否则一旦断电落在“新镜像只写了一半、标志位已经更新”的状态系统就起不来了。5.3 产线批量烧写的效率提升办法如果你的产品要小批量试产一个个开Vitis点Program Flash显然不现实。针对产线我有几个建议。第一用program_flash命令行工具封装一个批处理脚本只传镜像路径和flash型号操作员双击执行。这样即使不是研发人员也能完成烧写。第二JTAG链上可以串联多块板卡一次烧写多块。前提是每块板卡的JTAG链IDCODE要能区分脚本里针对不同位置的目标执行烧写即可。第三如果是裸板没有JTAG座子或者不想接调试器可以采用“预烧写”模式也就是贴片前用编程器把flash芯片烧好再贴到板上。这样速度快、成本低缺点是一旦硬件改版flash里的程序要重新烧。很多量大的产品都是这么干的。写在最后ZYNQ烧写程序到flash看起来只是一个简单的操作背后涉及启动流程、FSBL机制、flash选型、工具链使用和可靠性设计。我自己在第一次烧写QSPI时也被“Target DLL has been cancelled”折腾了一整天最后发现只是跳线帽没接对。后来项目做多了才慢慢意识到烧写这件事本身不难难的是对整个启动链路有清晰的认知。如果你正在被烧写问题困扰我的建议是不要急着点按钮先花半天时间把启动流程读一遍把BOOT.bin里每个分区的作用搞清楚。接下来再对照这篇文章的排查清单一项项过大部分问题都能解决。如果还不行就用最笨的办法先确保JTAG能连上、FSBL能跑再一步步增加环节定位问题会快得多。最后再分享一个小技巧烧写QSPI之前先把整片flash的读保护、写保护状态检查一遍很多板卡出厂时flash被软件保护了擦除命令根本不生效表现就是烧写时一直报错。用烧写工具先执行一次blank check或chip erase往往能解决一半的“莫名其妙”现象。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表