
做FPGA和Zynq开发的朋友几乎都撞见过同一个尴尬场景调试阶段明明一切正常用JTAG把bitstream拉进去点灯、串口、读写DDR全都没问题结果一断电重启板子立刻回到“出厂状态”之前的设计全不见了还得重新开Vivado、重新连下载线、重新把配置文件灌进去。这个现象的根源在于SRAM型FPGA的配置存储是易失的掉电即清零。要让板子通电之后自己把配置加载出来必须把程序和配置文件写到板上的非易失Flash里这个过程圈里人叫“程序固化”。这篇文章我会从Vivado侧导出硬件的环节开始一路讲到在SDK/Vitis里创建FSBL、生成BOOT.BIN再讲到用Hardware Manager或SDK的Program Flash Memory把镜像烧进SPI Flash最后把我这几年在现场踩过的坑和典型报错的排查方法一起整理出来。内容偏纯实操分Zynq SoC和7系列纯FPGA两条主路线讲解适合刚入门FPGA的工程师、第一次做Zynq启动方案的嵌入式开发以及所有被“flash download failed”这类报错折腾过的人。1. 程序固化到底在解决什么问题1.1 为什么FPGA断电就“失忆”先把这个根子上的原理说清楚。市面上绝大多数FPGA比如Xilinx 7系列、UltraScale系列用的是SRAM工艺的配置存储。所谓配置存储就是芯片里那块专门存放bitstream的地方它本质上就是一组SRAM单元。SRAM的特点是速度快、可无限次改写但它是易失的只要断电里面存的东西就全部清零。所以这类FPGA上电之后芯片内部其实是一片空白必须有一个外部来源把配置数据送进来。这个来源可以是JTAG调试时手动下载、可以是板上的Flash、也可以是其他处理器通过SelectMAP之类的接口灌进来。只要配置完成DONE信号拉高FPGA才开始进入用户设计的工作状态。这里要强调一下FPGA芯片本身不“记住”你的设计它只是“临时执行”当前SRAM里那份配置。Zynq的情况更复杂一点。Zynq是ARM双核处理器加FPGA的异构架构PS部分的启动代码运行在DDR里DDR也是易失的掉电同样全没。所以Zynq的固化不仅要管PL的bitstream还要管PS的启动软件这也就是为什么Zynq的固化文件不叫bitstream而叫BOOT.BIN。1.2 固化的本质是一次“搬家”明白了上面的原理“程序固化”这个词就很好理解了把本需要每次手动加载的配置文件提前写进板上的非易失存储器上电之后让芯片自己去读这样看起来程序就被“固定”在板子上了。打个比方调试阶段就像每次开机都拿系统光盘引导电脑而固化相当于把系统装进硬盘开机自动启动。具体到实现上有两个关键动作第一个是把文件写进Flash这个动作就是我们常说的烧录、编程、programming第二个是把启动模式引脚拨到正确的状态比如Zynq要切到QSPI启动7系列要把M[2:0]配置成Master SPI模式这样芯片上电后BootROM或者配置引擎才会主动去Flash里找数据。很多人固化失败往往不是第一步没做对而是第二步忘了。镜像烧进去了但boot mode还在JTAG或者别的状态上电自然不跑。后面我在第6节会重点讲这个。1.3 固化介质怎么选NOR、NAND还是SD卡固化介质的选择直接决定你的工程路数先看一张对比表。介质典型型号容量范围优点缺点适用场景SPI NOR FlashW25Q128、S25FL128、N25Q1281Mbit~256Mbit接口简单、支持XIP、驱动成熟容量偏小、写速度慢7系列纯FPGA、Zynq QSPI启动BPI并行NORPC28Fxxx8Mbit~512Mbit总线读取快引脚多、布局麻烦大容量并行加载、老式FPGANAND FlashMT29Fxxx1Gbit~64Gbit容量大、成本低有坏块、需要管理、不能XIPZynq大容量存储启动SD/eMMC任意SD卡、eMMC数GB以上容量大、方便升级需要协议栈、启动稍慢Zynq Linux系统启动对于纯FPGA最常见的是板载一颗SPI NOR Flash比如很多国产开发板喜欢用W25Q128一颗16MB的Flash存7系列中小型号的bitstream绰绰有余。对于Zynq如果你只是跑裸机小应用QSPI NOR就够了如果要跑完整Linux系统通常会考虑SD卡启动或者NAND启动这种场景下烧录的就不是Flash而是制作启动SD卡流程又不一样。我个人的建议是做固化方案之前先把板卡原理图打开看清楚板上Flash的型号、供电电压、和FPGA/PS的接法再决定走哪条路。很多人踩坑都是从“我觉得板上应该有个Flash”开始的。2. 动手前先想清楚你的平台属于哪种固化路线2.1 纯FPGA只需要把bitstream扔进Flash如果你的工程是纯FPGA没有PS比如Artix-7、Kintex-7这种固化这条链路要简单得多。你只需要准备一个配置用的镜像文件bin或者mcs烧进Flash然后把配置模式引脚设到Master SPI上电之后FPGA的配置引擎就会自动从Flash把数据读进内部SRAMDONE信号拉高设计跑起来。这类工程不需要FSBL、不需要BOOT.BIN因为FPGA自己没有处理器不需要“引导程序”去初始化什么。7系列芯片上有一个SPI控制器专门用来在Master SPI模式下从外部Flash读配置。需要特别注意的是配置模式引脚M[2:0]不同型号的7系列芯片这些引脚位置不一样具体编码要看UG470和你的板卡原理图不同的板卡可能做成拨码开关也可能是固定电平的贴片电阻。不要凭印象硬记某一种编码我见过有人拿A板的配置代码直接套到B板折腾了半天发现只是引脚变了。2.2 Zynq SoC需要BOOT.BIN不是简单一个bitZynq的固化链路是另外一套逻辑。Zynq上电之后片内BootROM先运行BootROM根据启动模式引脚Zynq上是MIO[5:2]的电平组合判断从哪里启动如果判断是从QSPI启动它就把Flash里开头的一段镜像读进来这段镜像就是FSBLFirst Stage Boot Loader第一级引导程序。FSBL的作用是初始化PS侧的时钟、DDR控制器、MIO引脚然后解析BOOT.BIN里的分区表把bitstream分区加载进PL把应用分区的ELF加载到DDR最后把控制权跳转给应用软件。这就是Zynq的标准启动链BootROM → FSBL → bitstream → 应用软件。所以Zynq的固化文件是一个打包体叫BOOT.BIN里面至少包含FSBL、bitstream、应用程序三个分区顺序不能乱。注意整个启动链的源头是BootROM而BootROM是Zynq出厂时就固化的我们不需要也不能改它固化工作真正做的事是生成BOOT.BIN然后把它写进Flash的0地址。2.3 SDK和Vitis的版本关系在动手之前还有一个容易让人困惑的问题为什么有人教程里写Xilinx SDK有人写Vitis这两个其实是同一个东西在不同时期的名字。Vivado 2019.1及之前的版本配套的嵌入式开发环境叫Xilinx SDK从Vivado 2019.2开始SDK被整合进了一个更大的平台叫Vitis。习惯上很多人还是叫它SDKUI界面里很多菜单位置也基本没变。我这篇文章涉及的菜单路径比如Export Hardware、Create Boot Image、Program Flash Memory在SDK和Vitis里基本一致只是Vitis的工程组织方式稍有变化首次启动会让你选workspace创建平台工程时会生成一个Platform Project然后再创建应用工程。如果你用的是老版本比如网上还能搜到的2015.4、2016.4界面可能更老但核心流程是一样的。另外提醒一句不同大版本的Vivado生成的工程后缀不一样老版本的.xmp、.hdf和新版本的.xsa不要混用老老实实装对应版本。3. 固化前的环境准备与硬件导出3.1 先确保bitstream是干净的所有固化流程的起点都是先有一个能正常工作的bitstream。别小看这一步我见过太多人bitstream还没干净就急着固化结果每次怀疑是镜像问题最后发现是源设计就有问题。这里的“干净”指的是综合和实现都无错误通过时序收敛没有大的violationbit文件能正常生成。建议在Vivado的Flow Navigator里依次跑Synthesis、Implementation然后点Generate Bitstream。生成完后打开Implemented Design看一下时序报告如果WNS最差负时序裕量是负的先解决时序问题再继续。Bit文件生成之后记下它的路径一般在工程的proj.runs/impl_1/xxx.bit。另外如果你在工程里设置了Bitstream的加密、压缩或者配置模式相关的属性比如set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4这些属性会实际影响生成的bitstream格式固化时也要注意和Flash烧录接口一致别在属性这里埋雷。3.2 Export Hardware这一步不要漏选bitstream对于Zynq工程Vivado这边要做完的关键一步是导出硬件平台。菜单路径是File Export Hardware在弹出的对话框里一定要勾选Include bitstream然后点OK会生成一个.xsa文件2019.2以后或者.hdf文件老版本。这一步漏勾bitstream是我见到的最高频失误之一。你不勾导出的硬件平台里没有bitstream后面在SDK里创建Boot Image时分区列表里就不会自动带上bitstream最后烧出来的BOOT.BIN其实缺了PL配置上电后PL部分自然不工作。而且这个问题在JTAG调试阶段往往发现不了因为调试时你会单独用Program FPGA把bitstream加载进去看起来一切正常等到固化上电就不行了。导出完硬件平台之后可以直接点File Launch Vitis IDE或者Launch SDK它会自动用刚才导出的xsa创建平台工程。注意workspace路径不要和Vivado工程目录混淆自己建立一个专门的workspace文件夹省得后面文件乱。3.3 JTAG连接与驱动检查固化离不开JTAG先把硬件链路确认好。连接开发板和电脑打开Vivado的Hardware Manager或者Open Target正常情况下能够看到JTAG链路里的设备。7系列纯FPGA会显示对应型号Zynq会显示相应的Zynq系列设备。如果你插上USB下载器之后设备管理器里看不到任何新设备或者Hardware Manager报找不到cable先别急着怀疑板子坏了。优先检查驱动Vivado安装目录下自带USB cable驱动Windows下通常在Vivado安装目录/data/xicom/cable_drivers/nt64手动更新驱动指向这个目录即可。Digilent板卡自带的下载器或者FTDI芯片往往还需要装Digilent的驱动软件。再有就是虚拟机用户很多时候是USB没有直通给虚拟机或者直通后驱动没装这是另一个高发区。JTAG链路上如果有多个设备比如Zynq板上还挂了一颗CPLD或者另一片FPGA烧录前先在Hardware Manager里确认你选中的是目标器件别烧错了。用JTAG链的IDCODE可以核对芯片型号不同IDCODE不同这个动作能帮你确认。4. Zynq固化全流程FSBL、应用工程与BOOT.BIN生成4.1 新建FSBL工程SDK/Vitis打开硬件平台导入成功之后开始建FSBL工程。以SDK为例File New Application Project工程名建议用zynq_fsbl在模板列表里选择Zynq FSBL然后完成。不要小看这个模板工程它生成的FSBL就已经覆盖了启动阶段几乎所有标准工作初始化PS侧的PLL、DDR控制器、配置MIO引脚、解析分区表、加载bitstream和应用镜像。你基本不需要改它的源码。编译之后会生成zynq_fsbl.elf。FSBL源码里有些地方值得扫一眼比如xfsbl_main.c、xfsbl_plat.c。如果你是做自定义DDR或者特殊MIO配置可能需要对FSBL做一些裁剪或修改但不是本文范围。默认情况下直接用模板就好。一个小经验如果你在硬件设计里改了DDR参数导出的xsa会更新FSBL也必须跟着重新生成并重新编译否则可能启动到DDR初始化就挂掉。所以FSBL最好每次硬件更新后都重建一次。4.2 新建并编译应用工程接着创建应用工程。同样File New Application Project取个名字比如hello_app模板选Hello World或者Empty Application。Hello World模板会把串口初始化代码和应用代码都建好适合先跑通链路后面改成自己的应用就行。应用工程会自动关联一个BSP板级支持包BSP里包含了驱动库比如UART、GPIO、DMA等等。如果你的应用需要什么库可以在BSP设置里勾选。编译应用工程生成hello_app.elf。这里有个细节SDK里的应用工程编译时BSP的链接脚本决定了ELF加载到DDR的哪个地址一般默认从DDR0基址开始比如0x00100000左右这个是合理的不需要动。除非DDR配置非常特殊否则别手改链接脚本容易把启动流程搞乱。4.3 先用JTAG整链路验证一次生成BOOT.BIN之前强烈建议先做一次JTAG全链路验证。这一步的目的是把“软件/FSBL问题”和“镜像/Flash问题”分开。如果JTAG下载能跑通说明FSBL和应用本身没问题后面固化失败就锁定在镜像制作或Flash侧。验证方法是先在Vivado Hardware Manager里把bitstream下载进PL或者直接在SDK里点Xilinx Program FPGA选择bit文件然后在SDK里右键应用工程选Run As Launch on Hardware。系统会自动把FSBL和应用一起加载并运行串口终端上能看到Hello World打印。很多人跳过这一步直接去烧Flash结果上电不跑排查时又要回头怀疑FSBL、怀疑应用、怀疑DDR非常消耗时间。先跑通JTAG链路你的问题域就能缩小一半。4.4 Create Boot ImageBOOT.BIN的生成细节全链路验证通过后就可以打包BOOT.BIN。在SDK里点Xilinx Create Boot Image。第一次打开会要求你设置输出路径和文件名默认生成BOOT.BIN。然后在Boot Image Partitions区域按顺序添加三个分区FSBL选择上面编译出的zynq_fsbl.elf并且在分区属性里把它标为bootloader。其他应用分区选择普通elf。bitstream就是你导出的硬件平台里带的top.bit一般会自动出现在列表里如果没有手动添加后选择类型为bitstream。应用选择hello_app.elf。分区的顺序就是FSBL解析时的加载顺序bitstream先于应用这符合启动链逻辑先把PL配置好再加载PS侧应用。创建Boot Image的底层是一个BIF文件格式类似the_ROM_image: { [bootloader]./zynq_fsbl.elf ./top.bit ./hello_app.elf }如果你以后要用命令行批量生成可以直接写BIF文件然后用bootgen工具跑效果一样。GUI方式生成的BOOT.BIN默认放在工程目录/boot/BOOT.BIN或类似路径。生成的BOOT.BIN建议顺手看一眼大小。正常情况下它至少包含bitstream的体积如果BOOT.BIN只有几十KB、几百KB那大概率bitstream没打进去马上回第3.2节检查。5. 纯FPGA固化把bitstream转换成Flash认识的格式5.1 BIN、MCS、HEX到底该选哪个纯FPGA没有BOOT.BIN这套你需要把bitstream转换成Flash能烧的格式。常见三种.bin纯二进制从烧录起始地址开始连续排列最简单Vivado Hardware Manager直接烧它就行。.mcsIntel HEX格式的文本文件里面有地址记录很多第三方编程器、批量烧录工具认它。.hex类似.mcs的另一种文本格式使用场景少一些。如果你就在Vivado里用Hardware Manager烧推荐用.bin体积小、无需解析地址出错概率最低。如果你要把镜像交给产线批量烧录那通常要生成.mcs因为产线用的离线编程器对HEX格式支持更普遍。另外有些烧录器还支持直接加载.bit文件但那只是烧录器自己在解析并不通用。5.2 用write_cfgmem一句命令生成bin文件生成bin文件最直接的办法是在Vivado的Tcl Console里执行write_cfgmem命令。举个例子假设你的工程是Artix-7板载Flash通过SPI x4方式配置bit文件完好的情况命令如下write_cfgmem -force -format bin -interface spix4 -size 32 -loadbit up 0x0 ./top.bit -filename ./top.bin逐个参数说清楚-force输出文件已存在时强制覆盖。-format bin输出二进制格式。-interface spix4指定Flash接口为SPI x4。如果你的电路设计用的是单引脚SPI就写spix1。这个接口要和硬件设计里的配置引脚一致也和后面boot mode一致。-size 32指定Flash容量单位是Mbit。32表示32Mbit也就是4MB。这个参数只需要大于等于bitstream实际占用的空间即可。-loadbit up 0x0 ./top.bit把bitstream放在Flash的0地址开始的位置。up是write_cfgmem固定语法的一部分指定加载的bit文件放在哪个地址。后面如果是多个镜像或者多版本镜像地址可以改为其他值。-filename输出文件名。命令执行成功后会在当前路径下生成top.bin。你可以用十六进制编辑器打开看一眼文件头确认不是全空或者全FF。如果需要生成MCS把-format bin改成-format mcs即可-size记得和实际Flash容量对齐否则MCS文件地址可能会超出Flash范围。5.3 关于SPI x1和x4的影响这里多聊几句SPI接口。7系列FPGA做SPI从Flash启动时可以是x1位宽也可以是x2、x4位宽x4就是常说的Quad SPI需要Flash支持对应的指令。生成bin文件时选择的interface必须和硬件设计一致。硬件上如果板子默认只连了SCK、MOSI、MISO、CS四根线SPI引脚复用的IO2/IO3很可能没有接Flash那你就只能用spix1。如果板子确实利用了Quad模式SPI Flash的IO2/IO3都连到了FPGA并且配置引脚也设成了相应模式那用spix4能显著加快启动配置速度。实际操作中很多低成本的板子虽然用的是Quad Flash芯片但接线只用了x1模式这时你生成bin用spix4反而会出问题。判断标准很简单看原理图里Flash的WP和HOLD引脚是直接接的FPGA IO还是接的电源/地。如果WP和HOLD直接拉死基本就是x1用法。另外如果你在Vivado工程里设置了BITSTREAM.CONFIG.SPI_BUSWIDTH属性这个值也必须和实际硬件匹配它会影响bitstream内部的配置指令序列。6. Flash烧录实操两条主流路线带你写进去6.1 路线一在Vivado Hardware Manager里烧这是最通用的路线适用于纯FPGA也适用于Zynq如果你烧的是BOOT.BIN。步骤打开Vivado Hardware ManagerOpen Target确保设备已连接并识别。右键目标FPGA设备选择Add Configuration Memory Device第一次或Program Configuration Memory Device已有配置记录。如果选择Add会弹出一个搜索框让你选择板上的Flash型号。在搜索框输入Flash型号关键字比如w25q128、s25fl128、n25q128。Vivado的Flash库覆盖了主流厂商的常见型号。如果找不到你的型号先看第7.3节的处理办法。选择好Flash设备后会进入Programming窗口。在这里选择Configuration File也就是刚才生成的top.bin纯FPGA或者BOOT.BINZynq。编程选项里几个关键的勾选项Erase、Blank Check、Program、Verify。建议全勾上工具有默认的擦除和编程策略Verify会在编程后自动回读校验非常有用。注意Programming Frequency编程频率默认值通常是33MHz或者更高。如果你的Flash、板卡走线质量一般或者线又长又没有加阻抗匹配这个频率很可能太高导致烧写失败。实测中很多问题降到15MHz甚至10MHz就解决了。频率降低只是烧录变慢不影响稳定性。点Program之后工具会先擦除Flash再编程再校验。整个过程的进度条在状态栏里显示几分钟不等取决于Flash容量和频率。6.2 路线二在SDK/Vitis里用Program Flash Memory烧如果你做的是Zynq工程SDK里专门提供了一个Program Flash Memory工具路径是Xilinx Program Flash Memory。这个工具的界面会要求你选择Image File选生成的BOOT.BIN。Offset默认0保持0即可Zynq的BootROM就是从Flash 0地址开始读的。Flash Type下拉菜单里通常有qspi-x1、qspi-x2、qspi-x4等选项选择与你的QSPI启动模式一致的类型。Configuration Memory Device这里选择具体的Flash型号有时候工具会根据硬件配置文件自动带出来。Flash Programming Frequency同样可以手动调整遇到下载失败先调低。这个工具的本质和Hardware Manager的Program Configuration Memory Device是一样的底层都是通过JTAG把数据写进Flash只是界面针对Zynq做了封装默认会带上BOOT.BIN和分区结构的支持。如果你已经在Vivado里用过Hardware Manager从任一入口烧都行。我个人的习惯是纯FPGA固定用Hardware ManagerZynq固定用SDK的Program Flash Memory。原因很简单SDK那边会自动处理一些与硬件平台关联的配置比如某些Zynq开发板要求先对FSBL做地址重定位SDK会比较友好。当然这只是习惯两条路本质相同。6.3 烧录之后怎么确认真的固化了烧录完成不等于固化成功最后一步是验证也是最容易出成就感或者最打击人的一步。操作流程把板卡的启动模式切到非JTAG模式。Zynq是QSPI启动纯FPGA是Master SPI。具体拨码开关位置看原理图找不到就翻板卡丝印一般有丝印标注。完全断电等几秒钟再次上电。观察现象Zynq的话串口应该有启动日志或者在应用里打出的Hello World纯FPGA的话DONE指示灯点亮LED、串口等外设开始工作。如果一切正常恭喜你固化完成。以后这块板子不需要再连JTAG上电就跑。有一个细节必须强调切换启动模式后马上上电如果板子卡在某个奇怪状态先检查启动模式拨码是不是真的拨到位了。我用示波器看过不少人其实拨了一格但没到位接触不良非常隐蔽。7. 常见报错与排查技巧实录7.1 flash download failed - target DLL has been cancelled这个报错是固化现场出现频率最高的一条。文字是“flash download failed - target DLL has been cancelled”一般伴随着编程中断让人一头雾水因为提示里完全没有说Flash哪一步出了问题。我遇到的情况里绝大多数是下面几个原因hw_server进程冲突。电脑上开着多个Vivado、多个SDK、甚至残留的hw_server后台进程多个进程抢同一个JTAG目标导致下载被取消。处理办法打开任务管理器把所有hw_server、vivado进程全部结束重新打开Hardware Manager再试。JTAG下载线连接不稳定。USB线接触不良、延长线太长、USB口供电不足都可能导致编程中途掉链子。换个USB口、换根短线、确认下载器供电往往能解决。编程频率过高。前面提到的把频率降到15MHz以下再试成功率明显提升。Flash型号选错。选了型号和板载不一样擦除和编程指令自然对不上也会报这个错。核对型号再试。排错顺序我建议是先杀进程重开再换USB线/口再降频率最后核对型号。按这个顺序排查大部分问题在第一步或第二步就解决了。7.2 warning: failed to communicate with the flash chip, read/write operations will fail这条Warning出现的时候基本等于预告了接下来的烧录会失败。它翻译过来就是JTAG没让Flash芯片正常应答上。常见原因Flash型号不对FW读到的ID和预设不符工具直接放弃。Flash电压域不对。很多Flash是1.8V供电如果板卡设计成3.3V供电或者FPGA的配置Bank电压设置错误通信就会失败。检查CFGBVS引脚和VCCO配置Bank的电压7系列这个比较讲究。Flash的WP写保护和HOLD引脚被拉低。这两个引脚如果硬件上没有处理芯片会进入写保护或者暂停状态通信一塌糊涂。检查原理图必要时把WP和HOLD拉高或者烧录时确认一下板子有没有对应的跳线。SPI时钟频率太高信号完整性差。降低编程频率。板卡上Flash的片选或时钟走线有问题比如CS线上拉电阻缺失。这种情况需要拿示波器看信号了。排查这条警告我的经验是先看原理图把Flash的电压、WP、HOLD、CS、SCK全部过一遍再用示波器量一下SCK和CS确认FPGA/PS侧确实有信号出来。硬件没问题再谈软件配置。7.3 cannot load flash device description这句话出现在你搜索Flash型号、工具却无法加载该设备描述的时候。本质是Vivado的Flash库太老或者库里压根没有你板子上那颗Flash。处理办法换一个同系列相近器件。比如库里没有W25Q128但有一个W25Q64如果引脚和指令兼容你可以先用它顶上。注意这只是为了能跑烧录流程不代表设备描述100%匹配烧录成功的前提是Flash的擦除/编程指令一致。用Custom方式手动创建设备填入Device ID、指令集等参数。这种方式有点门槛需要看Flash手册适合确实找不到任何可用描述的场景。如果库里没有兼容型号去官网看是否有更新的Flash库补丁或者在社区里搜同型号是否有人做过兼容记录。在产线时更常见的办法是绕过Vivado用第三方编程器比如J-Link配合JFlash、或者专用离线编程器直接烧写bin文件到Flash。这种情况Vivado只是用来生成bin烧录工具随便选。这也是我前面强调保存bin文件的价值——不依赖Vivado的Flash库也能烧。7.4 烧录成功但上电之后不运行烧录过程一切正常校验也通过结果断电重启板子毫无反应。这是最让人抓狂的一类问题。我的排查清单如下启动模式没切对。Zynq拨码还在JTAG或者7系列的M[2:0]不对BootROM压根没往Flash看。这是第一嫌疑。BOOT.BIN里缺bitstream。回到第4.4节检查文件大小和分区列表。分区顺序不对。FSBL必须在第一个bitstream其次应用最后。镜像本身没有正确烧到0地址。有些工具默认从某个扇区开始写你如果设了非0的偏移BootROM找不到。检查Offset是不是0。SPI接口位宽不匹配。生成的bin用了spix4但硬件启动模式是x1或者反之启动时读到的数据都是错的。重新用匹配的interface生成镜像。Zynq的DDR初始化失败。FSBL里DDR参数和实际DDR颗粒不匹配启动卡在DDR初始化。这个只能用串口日志来看或者回头用JTAG验证FSBL能正常跑第4.3节。电源和复位问题。板卡上电时序不好、复位信号一直被拉低芯片根本没进入配置过程。用示波器量POWER_GOOD和DONE信号能帮你快速定位。排查这类问题核心思路是把“启动链路”一步一步拆开先是BootROM读Flash再是FSBL运行再是PL配置最后是应用运行。每一步都有对应的观测手段比如量DONE、量Flash的CS片选、看串口日志。不要上来就怀疑镜像先确认链路最前端。7.5 JTAG时不时掉线、识别不到设备这个虽然不是固化专有但会影响固化效率和心态。常见原因和办法驱动没装好。Windows下按第3.3节手动更新cable driver。杀毒软件拦截了驱动或hw_server的通信添加信任或者临时关闭。虚拟机USB直通问题确认USB设备已经直通给虚拟机不要在宿主机和虚拟机之间抢设备。USB线/口质量差。下载器最好直接插主板USB口不要接前置面板或者USB Hub。长线、劣质线、Hub供电不足是三个高频坑。电脑上多个Vivado版本共存各个版本的hw_server相互干扰。尽量一次只打开一个版本的Hardware Manager。Windows驱动签名问题老版本cable驱动在Win10/11下需要禁用驱动签名强制或者在高级启动里选“禁用驱动程序强制签名”装一遍再恢复。7.6 其他环境坑WinPcap、目录、卡死最后补几个环境侧的坑。老版本Xilinx工具链在Windows上安装时有时会提示WinPcap安装失败这个组件主要服务于网络相关的远程调试功能如果你用不到远程下载一般可以忽略。如果确实需要可以单独下载对应版本的WinPcap安装包手动安装然后再重试Vivado的环境检查。工程路径也是一大雷区。Vivado和SDK对中文路径、空格路径、超长路径都比较敏感很多莫名其妙的编译或烧录错误把工程挪到一个纯英文短路径下就消失了。这是我反复强调过的事情仍然每周都有人踩。还有卡死问题。烧录过程中如果进度条长时间不动又没有报错先别急着重启电脑。观察10分钟如果还是不动再考虑强制结束进程然后断电重启板卡再试。强制中断后Flash可能处于半擦除状态重新烧录前最好先手动执行一次完整擦除。8. 固化调试中的几条个人经验文章到最后我分享几条自己踩过多次之后才总结出来的习惯不一定都写在官方文档里但非常实用。第一把常用命令做成脚本。无论是write_cfgmem还是bootgen我都存成了固定的Tcl脚本或者批处理脚本换工程只改文件名和容量参数。这样每次生成镜像都是同一套逻辑能最大程度避免手滑。第二给每块板子建立一份“固化档案”。记录Flash型号、启动模式拨码位置、烧录频率、镜像文件名、板卡硬件版本。项目一多你会发现“上次那个板子是什么Flash来着”这种问题会频繁出现有档案就能秒查。第三烧录前给板子断电再上电。不要从上次烧录失败的半死状态直接开始先把板子和JTAG链路彻底reset一遍。这个习惯帮我减少了很多玄学报错。第四买一个便宜的逻辑分析仪或者示波器放桌上。排查固化问题时量一下CS、SCK、DONE、串口TX比翻半天日志快得多。很多时候固化的坑根本不是软件问题而是硬件接线或时序问题。第五也是最重要的一条固化失败别急躁先拆链路。每次遇到“上电不跑”我都按BootROM→FSBL→PL→应用的顺序逐段定位用可观测的信号把每一段链路单独验证很快就能锁定问题段。与其反复盲试不如一次把观测点布置好。固化这件事说难其实不难流程就那么几步说简单也不简单因为它横跨了Vivado、SDK、硬件电路、启动模式四个维度。希望这篇教程能帮你少走点弯路第一次就把板子固化成功。