做Zynq开发的同学十有八九都会遇到这个时刻JTAG在线调试一切正常代码跑得飞起但只要一断电整个系统就像失忆一样回到原点。想要让Zynq上电就自动运行程序必须把启动镜像固化到非易失存储里。W25Q256FV就是Zynq开发板上非常常见的一颗SPI NOR Flash容量256Mbit也就是32MB通过QSPI接口和Zynq相连。这篇文章就来聊聊怎么用Vitis自带的Program Flash功能给这块Flash烧写程序顺便把我在几个不同板子上踩过的高频报错和解决办法做个完整整理。不管你是刚接触Zynq的新手还是已经被Flash烧写折磨过几次的开发者这篇文章应该都能给你一些参考。我会尽量把每一步操作背后为什么这么做讲清楚而不是只丢给你一串“点这里、点那里”的操作步骤。毕竟烧写Flash这件事出问题往往不是你不会点按钮而是不懂工具背后的工作流程出了报错就两眼一抹黑。1. 烧写前的全局认知Vitis烧Flash到底干了什么1.1 一条简洁命令背后的三段接力第一次用Vitis的Program Flash时很多人以为这会像用普通烧录器一样直接把文件从JTAG灌进Flash。实际上完全不是这么回事。Zynq的QSPI Flash烧写其实是一个“接力赛”先是JTAG接口把一小段引导代码加载到Zynq的内存里然后由这段代码初始化DDR和QSPI控制器再配合上位机软件把镜像数据一笔一笔写到Flash里。这个在内存里运行的临时程序就是FSBLFirst Stage Boot Loader。这就能回答那个被问烂了的问题Zynq 7020使用JTAG固化Flash时必须使用DDR吗答案是只要你用的是Vitis/SDK自带的Program Flash功能就必须要有一块可用的DDR。逻辑不复杂FSBL本身要运行在内存里而Zynq的BootROM能用的OCM只有256KB既要放引导代码又要放烧写协议栈根本放不下。所以工具链默认先把FSBL加载到DDR里再由它在DDR里跑起来完成QSPI控制器初始化、扇区擦除、数据写入这一整套动作。你可以把它类比成用电脑刻录光盘光盘本身不能自己启动刻录软件必须靠另一台电脑先跑起来才能把数据写进去。DDR就是那台“临时电脑”的内存条。理解了这条链路很多现象就说得通了。比如烧写时板子必须处于JTAG启动模式因为只有JTAG模式下BootROM才不会尝试从其他介质启动而是安静地等调试器把FSBL塞进来避免烧写过程中发生总线冲突。再比如为什么烧写到一半突然报dll cancelled很多情况下就是DDR没初始化好、JTAG链抖动或者FSBL根本没跑起来。工具表面上是在“烧Flash”实际上它先完成了一遍“在内存里启动临时程序”的过程。1.2 先认识W25Q256FV这颗FlashW25Q256FV是Winbond的256Mbit SPI NOR Flash换算下来是32MB容量。Zynq-7000系列内置的QSPI控制器和它就是天生一对标准SPI、Dual SPI、Quad SPI都支持硬件上只需要一根片选加4根数据线。它的供电电压是3.3VJEDEC ID是0xEF4019其中0xEF是Winbond的厂商ID0x40是内存类型0x19是容量代码。烧写工具全靠这个ID来识别芯片所以后面排查“failed to communicate with the flash chip”时第一个动作就是确认读回来的ID是不是这串数。这颗Flash有个很重要的特性默认工作在3字节地址模式一次最多寻址16MB。要访问完整的32MB空间必须切到4字节地址模式。用在Zynq上时BootROM通常只认Flash前16MB的内容所以启动镜像一定要放在0偏移处并且整个BOOT.BIN别太大塞进前16MB以内最稳妥。烧写工具内部会自己在3字节和4字节地址模式之间切换不需要你手动敲指令但如果哪天你脱离Vitis用裸机代码直接操作这颗Flash就要格外当心地址模式这个坑。1.3 为什么推荐用Vitis自带烧写功能当然给W25Q256FV烧写不是只有Vitis这一条路不同场景下选择也不同。我把常见的三种方案放在一起对比过方案优点缺点适用场景Vitis Program Flash图形界面、和工程集成、不需要额外硬件必须有DDR、速度一般、Flash型号受工具支持列表限制日常开发调试、单板少量烧写外部SPI Flash编程器不依赖Zynq能否运行、支持空板和量产需要额外买设备、板载Flash可能要拆芯片或飞线无DDR板卡、量产、维修备件U-Boot下sf命令烧写传输速度快、可反复操作、不挑电脑环境得先把U-Boot从SD或JTAG启动起来板子能启动U-Boot时的常规更新如果你手里的板子有DDR日常开发阶段完全没必要折腾外部编程器。Vitis自带的烧写功能虽然速度不算快但胜在稳定、链路清晰出问题也好排查。这篇文章后面的步骤也是围绕这个方案写的。2. 硬件与软件准备动手前先做好这些检查2.1 硬件连接和启动模式设置烧写Flash之前先把硬件环境过一遍能省掉后面一大半的报错排查时间。我这里列的是一个通用检查清单具体到某块板子时以板卡手册为准JTAG下载器接到板卡的JTAG口。常见的有Xilinx Platform Cable USB II、Digilent JTAG-HS3以及其他兼容的调试器。USB线尽量选短而粗的带磁环更好。烧写32MB Flash是个持续几分钟的活儿USB链路不稳定是最容易踩的坑。板卡要独立供电。JTAG接口只提供电平参考不负责给目标板供电。启动模式拨码开关拨到JTAG boot。Zynq-7000的boot mode引脚是MIO[5:2]JTAG模式对应0000但不同板卡的拨码位置不一样务必看手册。如果你用的是定制板确认一下Flash的WP写保护引脚有没有被正确拉高HOLD引脚有没有被拉高这两个引脚处理不好烧写时会出现写不进去或者通信失败。强调一下启动模式这件事。有次我在一块板子上烧写一直报target dll cancelled排查半天发现是拨码开关停留在QSPI模式。板子上电后BootROM拼命去读FlashJTAG链路被干扰FSBL加载不进去烧写自然失败。把拨码拨到JTAG模式再上电一切就正常了。所以烧写前拨码检查真的不能省。2.2 Vitis版本、驱动与Flash描述支持软件环境方面第一件事是确认驱动。Windows下如果设备管理器里看不到Xilinx USB Cable设备HW Server就连不上JTAG调试器。Vitis或者Vivado安装的时候会附带Cable Drivers也可以单独从Vivado安装目录下安装装完记得重新插拔一次USB线。第二件事是Vitis版本。建议至少用2020.1以上的版本新版本对W25Q256FV这类大容量Quad SPI Flash的支持完整很多。老版本SDK在Flash Type下拉框里可能只给你几个老型号找不到qspi-x4-single强行选其他型号烧写极易出问题。第三件事是确认Flash描述。打开Program Flash对话框时如果Flash Type下拉列表里能找到qspi-x4-single那没问题。如果找不到说明工具安装目录里的flash device description文件缺了。处理方法有三个升级Vitis从新版本安装目录里拷贝对应的描述文件到老版本路径或者应急选一个参数接近的型号烧完务必重新上电验证。最后这条纯属应急不推荐长期使用因为不同Flash的擦除指令和地址模式命令有差异临时凑合容易埋雷。2.3 创建BOOT.BIN镜像到了准备镜像的环节新手最容易问我直接烧应用程序的elf不行吗不行。Zynq上电后BootROM不认识普通ELF文件它只认带Boot Image Header的镜像格式。BOOT.BIN就是一个把FSBL、bitstream、应用程序打包在一起的容器每个分区都记录了加载地址和长度BootROM按表加载缺一个环节启动就失败。在Vitis里创建BOOT.BIN的操作如下菜单选择Xilinx → Create Boot Image。选择Create new BIF file给文件起个名字。按顺序添加分区第一个分区放FSBL的elf必须放在0x0第二个分区放bitstream如果工程有PL逻辑第三个分区放应用程序elf。输出文件名写BOOT.BIN点击Create Image生成。如果用文本方式看生成的BIF文件大概是这样的结构arch zynq; fsbl fsbl.elf; partition system.bit; partition app.elf;这里有个容易被忽略的坑如果工程里生成了PL bitstream但创建Boot Image时忘了加进去烧写后PS部分能跑PL逻辑起不来。别问我是怎么知道的我第一次给一块带PL的板子烧写调试了半小时才发现bitstream压根没打进去。3. 手把手烧写流程实操3.1 连接目标板并确认器件准备工作做完可以正式操作了。先把板卡上电确认启动模式在JTAG然后在Vitis菜单栏选择Xilinx → Hardware Manager打开硬件管理器。点击Open Target选择本地hw_server正常情况下连接后能看到目标器件列表比如xc7z020。这一步能确认JTAG链路通不通如果这里就看不到芯片直接跳到4.5节排查。芯片能被识别是一个好信号但不代表Flash通信没问题。烧写之前工具会在后台初始化QSPI控制器并读取Flash ID。如果你在日志里看到Found flash: W25Q256FV类似的信息说明从Zynq到Flash这一段的通路也是通的。看到这行字基本上可以放心往下走。3.2 打开Program Flash并设置参数器件确认无误后在Vitis菜单栏选择Xilinx → Program Flash弹出烧写对话框。这里有四个字段需要认真填Image File选择刚才生成的BOOT.BIN。Offset保持0x0。这个字段千万别乱改Zynq BootROM上电后就是去Flash的0地址找Boot Header写在别处等于没写。Flash Type选择qspi-x4-single。W25Q256FV是一颗单芯片的Quad SPI Flash如果硬件上只连了单根数据线也可以选qspi-x1-single但速度会慢不少。x4和dual的区别也要搞清楚dual一般指两颗Flash并联普通板子用不上。FSBL File新版Vitis会自动带出来如果界面有这个字段且是空的手动选工程里生成的fsbl.elf。设置完成后点击Program烧写开始。整个流程是擦除、编程、校验三个阶段齐头并进的工具会在日志里一步步打印进度。烧写过程中不要动USB线不要按复位键更不要直接断电。W25Q256FV整片擦除时间不短你要是烧到一半断电轻则烧写失败重则Flash里原有的内容都没了。3.3 烧写日志怎么看烧写过程中Console窗口会打印类似这样的日志****** Program Flash ****** ... Opening target... Enumerating flash devices... Found flash: W25Q256FV Image File: /home/user/workspace/BOOT.BIN Offset: 0x0 Erasing... Programming... Flash programming completed successfully.几行关键信息需要会读。Found flash后面跟着的ID如果就是W25Q256FV说明Flash识别正常Erasing阶段工具在擦除扇区如果Flash里已经写过内容这一步会稍微久一些Programming阶段在逐页写入大镜像需要多等一会儿最后出现Flash programming completed successfully恭喜你烧写成功。如果你的日志停在某个阶段不动或者出现Error、Warning字样别慌第4章整理了常见报错的排查方法对着看就行。3.4 切换到QSPI启动验证烧写成功不等于万事大吉最终还要验证从Flash启动是不是真的能跑起来。操作步骤在Vitis里断开硬件连接或者直接给板卡断电。把启动模式拨码开关从JTAG切到QSPI。Zynq常见的QSPI模式配置是MIO[5:2]0100具体以你板卡手册为准。重新上电打开串口终端波特率看你工程代码里的配置裸机程序大多数是115200。观察串口输出。如果能看到FSBL的启动打印然后是U-Boot或你的应用日志说明固化成功。如果上电后串口一点反应都没有先别怀疑Flash没烧进去。按4.4节的顺序检查拨码、偏移、串口配置再决定要不要重新烧一遍。我自己就干过烧写成功但串口助手的波特率配错结果以为启动失败折腾了一晚上的蠢事。4. 高频报错排查实录4.1 报错信息一error: flash download failed - target dll has been cancelled这个报错是在论坛里出现频率最高的Zynq烧写报错没有之一。它直译过来是“目标DLL已被取消”听起来像Windows DLL文件出了问题实际上在Vitis/SDK的环境里它表示上位机调试器与目标板之间的连接在烧写过程中被中断了。常见诱因有三个第一hw_server进程不稳定。烧写到一半hw_server崩溃或者被杀掉连接直接断开。这种情况优先重启Vitis重新启动hw_server再试。第二USB链路问题。USB线质量差、接口接触不良、使用过长的延长线在烧写大镜像时都容易导致连接中断。第三目标板异常复位。板子的看门狗复位、电源抖动、有人手痒按了复位键都会让JTAG链路断掉。排查时按这个顺序走换一根短而粗的USB线直接插主机后置USB口查看Windows设备管理器里JTAG设备有没有在烧写过程中消失关闭杀毒软件等可能干扰后台进程的程序检查板卡供电是否稳定。还有一个Windows特有的坑USB控制器会默认开启选择性暂停节能烧写到一半USB设备休眠就会报dll cancelled。去电源管理里把USB选择性暂停设置关掉这个问题能消掉一大半。4.2 报错信息二warning: failed to communicate with the flash chip, read/write operations wi...这一条报错的关键词是“communicate with the flash chip”——JTAG链路是通的目标芯片也连着但FSBL尝试访问Flash时没有得到预期响应。碰到这个报错先看能不能读到Flash ID读回来全是FF大概率是Flash没上电或者片选信号没拉对。用万用表量一下Flash供电引脚和片选看有没有跳变。读回来的ID不是0xEF4019先检查Flash Type选没选对。比如板载是qspi-x4-single你在工具里选了qspi-x4-dualID匹配不上就会报通信失败。ID正确但还是通信失败检查WP和HOLD引脚。这两个引脚如果没拉好Flash可能被写保护或者命令时序被打断报错表现就是读写操作不允许。还有一类情况是SPI时钟频率过高。手工焊接的板子、飞线连接的Flash或者走线过长导致信号质量差SPI时钟跑太快容易通信失败。Vitis的烧写配置里可以尝试降低QSPI时钟频率虽然烧得慢一点但至少能稳定写完。4.3 报错信息三cannot load flash device description这个报错说明Vitis安装目录里缺少对应Flash型号的描述文件纯粹是工具支持列表的问题不是你的板子坏了。解决思路有几种升级Vitis到更新版本新版本一般会补充更多Flash型号从高版本安装目录拷贝flash描述文件到旧版本对应路径应急情况下选一个参数接近的型号先烧但烧完必须重新上电完整验证。这条报错其实在提醒我们一个工作习惯烧写前先检查工具里有没有你板载Flash的型号。W25Q256FV在新版Vitis里基本都收录了但一些冷门Flash、或者很老的Vitis版本就容易触发这个问题。提前检查比报错后再折腾更省时间。4.4 报错信息四烧写成功但上电启动不了烧写报告completed successfully但切到QSPI启动后板上没有任何反应。这个情况反而比直接报错更让人头疼因为问题被藏在了运行阶段。我排查这类问题会按这个顺序走第一步确认启动模式真的切到QSPI了。很多板子有多个拨码开关经常有人只拨了一个剩下的还留在JTAG模式。第二步检查烧写时的Offset。如果填的不是0BootROM去0地址找Boot Header会扑空。第三步确认镜像大小。刚才说过W25Q256FV超过16MB的部分需要4字节地址模式老一点的BootROM可能不认所以BOOT.BIN要保证在Flash前16MB以内。第四步串口配置有没有问题。波特率不对、串口接错都可能导致你以为系统没启动。第五步用JTAG模式启动一遍确认镜像本身没问题。按这个顺序排查大部分启动失败的问题都能定位。要特别提醒的是不要一上来就怀疑Flash烧坏了。SPI NOR Flash即使写错内容也只是数据问题重新擦除再写就行别动不动就把芯片判死刑。4.5 报错信息五Vitis下载调试时识别不到芯片这个问题和烧写Flash强相关因为烧写前必须先把调试器连上。连接不上后面什么都无从谈起。常见原因和检查方式我整理成了一张表检查项操作常见结论驱动在设备管理器里看有没有Xilinx USB Cable设备缺驱动就装Vivado安装目录下的Cable Drivers电源确认目标板供电正常JTAG接口的Vref电压约3.3VJTAG检测不到目标电压就会连接失败JTAG链路在Vivado Hardware Manager里看链路上有没有器件只有下载器没有Zynq查TMS/TCK连接和线序复位信号按一下板卡复位键再重新Open Target有些板子需要先复位再握手PS复位检查PS_POR_B上电复位是否释放复位拉低时JTAG能识别但无法初始化这里有个偏门但实际碰到过的情况Zynq的PS_POR_B被外部电路一直拉低JTAG能识别到下载器但目标器件始终初始化不了。测一下复位引脚电平往往能快刀斩乱麻。4.6 报错速查表把上面的报错汇总成一张速查表方便你烧写的时候放在手边对照报错信息最可能原因第一处理方法flash download failed - target dll has been cancelledJTAG连接中断、hw_server崩溃、USB节能换USB线/口关闭USB节能重启hw_serverfailed to communicate with the flash chipFlash ID不匹配、WP/HOLD引脚异常、供电问题读ID查引脚核对Flash Typecannot load flash device description工具缺少Flash型号描述升级Vitis或拷贝flash描述文件烧写成功但启动不了拨码没切、Offset错误、镜像16MB按4.4节顺序排查下载调试不识别芯片驱动、电源、JTAG链路、复位按4.5节表格逐项检查5. 容易被忽略的细节、备选方案与我的实操心得5.1 烧写前的备份习惯很多开发板出厂时Flash里已经带了测试程序或者硬件检测镜像烧写前先把原厂内容读出来备份是个值得养成的好习惯。Vitis的Program Flash除了写也提供读Flash的功能可以在界面里指定读取大小和保存路径读取速度虽然不快但胜在方便。或者从U-Boot里用sf read命令也能把内容导出来。这个习惯在开发阶段无所谓但等到板子量产、维修、或者需要恢复出厂状态时就知道备份有多重要了。我就见过有人把带校准数据的板载Flash整片刷掉最后花了两天时间重新校准才写回来教训挺深刻的。5.2 没有DDR的板子怎么固化程序前面说过Vitis烧写必须有DDR那没有DDR的板子怎么办如果你的板子完全没有DDR有以下几条路可以走第一用外部SPI Flash编程器。把Flash拆下来放到编程器里烧写或者用夹子直接夹在板载Flash上编程。这种方案不依赖Zynq能不能跑适合空板、量产和维修。第二如果板子有SD卡可以从SD启动一个运行在OCM里的裸机程序由这个程序通过QSPI驱动把镜像写进Flash。OCM只有256KB程序的能力受限制但只要镜像规划好烧写是可行的。第三最不推荐用飞线接树莓派这类方法去给Flash刷写SPI时序和电平匹配很容易出问题得不偿失。5.3 几条实操心得最后分享几条我在反复烧写W25Q256FV过程中沉淀下来的经验这些细节在官方文档里基本不会写同一块板子连续烧写多次后偶尔会报dll cancelled这种时候不要怀疑板子坏了拔掉USB线重插、重启一次hw_server绝大多数都能解决。烧写大镜像的时候不要开着大量占用USB带宽的软件串口工具的自动重连、大文件同步这些都会干扰JTAG链路的稳定性。另外烧写文件路径里千万不要有中文和空格Vitis对中文路径的兼容性很一般这个老毛病从SDK时代就有我踩过不只一次。最后一次烧写完我习惯把启动模式拨回JTAG再做一次在线确认。这样做有两个好处一是确认板子本身没被烧坏二是下次开发调试时不用再折腾拨码开关。这个习惯保持了很久帮我躲过了好几次低级错误。希望这篇文章能让你少走点弯路烧写顺利。
