ZYNQ双启动模式配置全攻略:SD卡与QSPI Flash从原理到实操

发布时间:2026/10/3 1:49:26
ZYNQ双启动模式配置全攻略:SD卡与QSPI Flash从原理到实操 得又有人在群里问ZYNQ启动模式的问题了。每次看到新手在SD卡启动和QSPI Flash启动之间来回折腾最后卡在“为啥我的板子就是不跑”这种问题上我是真想隔着屏幕把配置文件给他甩过去。借着这个机会我干脆把ZYNQ双启动模式的配置流程完整梳理一遍从原理到实操再到排错一步到位。这篇东西无论你是刚拿到开发板的纯小白还是已经玩过一阵子但没系统搞过启动配置的工程师都能直接照着抄作业。ZYNQ这个芯片比较特殊它是ARM Cortex-A9处理器和FPGA逻辑放在一颗芯片里的异构SoC。正因为这种架构它的启动流程就比单纯的单片机或者FPGA都麻烦一些既要管PSProcessing System侧的ARM核启动又要管PLProgrammable Logic侧的FPGA配置。搞懂它的启动模式是玩转ZYNQ的第一道关卡也是后面做系统移植、跑Linux、搞裸机程序的基础。1. 内容整体设计与思路拆解1.1 核心需求解析先搞清楚我们到底要解决什么问题。典型的ZYNQ开发场景里工程师往往面临两种需求一是产品量产阶段需要把最终固件固化到板载Flash里上电就自动运行不需要外部存储介质这叫QSPI Flash启动。QSPI Flash焊接在PCB上容量通常在16MB到128MB之间优点是集成度高、可靠性好、上电启动快适合固定功能的工业设备和仪器仪表。二是开发调试阶段Linux内核和根文件系统可能有好几百MBQSPI Flash容量根本装不下。这时候就需要用SD卡来承载整个系统镜像从SD卡启动这叫SD卡启动。SD卡容量大、读写方便、修改系统只需要替换文件非常适合频繁编译、烧写、测试的开发节奏。双启动模式配置就是把这套东西理解透了让板子既能从Flash启动做产品验证也能从SD卡启动做开发调试两条路都走得通。这里要提醒一句ZYNQ的启动模式是由硬件管脚决定的软件只是配合所以真正的双启动是指“理解两种模式、随时切换”而不是同一时刻既从SD卡又从Flash启动。1.2 方案选型与可行性分析为什么选SD卡加QSPI Flash这套组合而不是其他存储方案这是由ZYNQ芯片本身的启动架构决定的。ZYNQ的BootROM固化在芯片内部上电后第一件事就是读取Boot Mode引脚的电平状态然后根据引脚配置决定从哪个设备加载FSBLFirst Stage Bootloader。BootROM支持的启动源包括QSPI Flash、SD卡SD0/SD1、NAND Flash、JTAG等这几类里最适合双启动组合的就是QSPI和SD卡。NAND Flash虽然容量比QSPI大但接口速度慢烧写麻烦而且ZYNQ对NAND型号的支持比较挑剔。JTAG启动只适合调试不能作为产品启动方式。相比之下QSPI Flash接口简单、速度快、寿命长SD卡通用性极强、容量几乎不受限制两者在硬件资源上互不冲突引脚也不共用非常适合做成一个双启动系统。硬件层面的选型确定后软件层面的核心任务就清晰了编译生成FSBL、生成BOOT.bin、配置SD卡分区格式、处理U-Boot环境变量、烧写QSPI Flash。这几步前后有严格的依赖关系很考验对整个启动链路的理解。我后面会一步步拆开讲每一步该做什么、为什么这么做、有什么坑都给你交代清楚。2. 核心细节解析与实操要点2.1 Boot Mode引脚配置机制ZYNQ的启动模式选择不是由软件配置的而是由芯片上的Boot Mode引脚MIO[6:2]在复位结束时的电平状态决定的。这些引脚属于MIOMultiplexed I/O的第0组硬件设计时直接通过上下拉电阻接到板上的拨码开关上或者直接固定电平。常见的几种启动模式对应的引脚状态启动模式MIO[6]MIO[5]MIO[4]MIO[3]MIO[2]JTAG00000QSPI00100SD卡SD001000SD卡SD111010NAND100000表示低电平1表示高电平。具体的电平组合以对应芯片型号的数据手册为准不同系列的ZYNQ如Z-7010、Z-7020、ZU系列引脚定义会有差异但基本原理一致。我强烈建议你拿到开发板之后先找到板子的原理图把Boot Mode对应的拨码开关位置确认好再动手做后面的步骤。很多新手其实配置文件、烧写步骤全对就是拨码开关拨错了位置导致启动失败。这里有一个关键细节Boot Mode引脚状态只在复位释放的时刻被采样一次。所以如果你在系统运行过程中拨动拨码开关是没有任何效果的必须按一下复位按键或者重新上电新的模式才会生效。实测中经常有人拨了开关以后不按复位对着串口终端干瞪眼以为板子坏了其实就差这一步。2.2 FSBL与BOOT.bin的核心作用从高层次看ZYNQ的启动是一个“接力跑”BootROM芯片固化→ FSBL第一阶段引导加载程序→ U-Boot第二阶段引导加载程序→ 内核/应用。BootROM是芯片出厂时写死的我们改不了它的任务是初始化存储控制器如SD控制器、QSPI控制器、从选定的启动介质中读取FSBL、把FSBL加载到片上RAMOCM中并跳转执行。FSBL由Xilinx提供的工具生成它的任务是初始化DDR内存控制器、把BOOT.bin里包含的FPGA bitstream加载到PL侧、然后跳转到U-Boot或者裸机应用继续执行。BOOT.bin是一个容器文件里面按照特定格式打包了FSBL、FPGA bitstream、以及SSBL如U-Boot。它排在最前面的永远是FSBL的镜像BootROM也是根据这个结构去解析的。理解这个容器结构对排查启动问题非常重要——如果你看到的报错是Invalid boot image之类的说明BOOT.bin的生成或者烧写出了问题而没有报错直接死掉往往是FSBL本身没跑起来。2.3 双启动方案中的分区与布局策略SD卡启动方式和QSPI Flash启动方式在文件系统的布局上有本质区别。QSPI Flash的存储介质是线性地址空间CPU可以直接映射访问所以BOOT.bin、内核镜像、设备树、根文件系统都可以按照固定偏移烧写到Flash的不同区域由U-Boot通过地址去加载。QSPI Flash的容量一般是16MB到128MB除去BOOT.bin占用的几MB空间剩余的空间如果塞不下完整的Linux根文件系统一般需要几十MB到几百MB就需要用只读的ramdisk或者最小化根文件系统方案。SD卡的布局则自由得多因为SD卡有完整的块设备和文件系统支持。标准做法是把SD卡分成两个分区第一个分区格式化为FAT32大小几百MB存放BOOT.bin、boot.scr、image.ub等启动相关的文件第二个分区格式化为ext4是整个Linux的根文件系统。U-Boot从FAT32分区读取内核和设备树挂载ext4分区作为根文件系统。这套布局方案是Xilinx官方推荐的也是petalinux工具链默认生成的镜像布局。好处是调试阶段只需要替换SD卡里的文件就能完成系统更新根文件系统的读写也方便。缺点也比较明显SD卡的文件系统如果损坏整个系统就起不来了所以在工业环境中SD卡方案往往只用于开发调试量产还是得回到QSPI Flash方案。3. 实操过程与核心环节实现3.1 环境准备与工具链构建开始动手之前先把环境搭好。Xilinx的开发工具链是Vivado Vitis老版本叫SDK如果你的目标是跑Linux那就还需要PetaLinux工具链。我用的是Vivado 2024.1 PetaLinux 2025.1的组合下面讲到的操作在2020版本以上的工具链基本都通用。安装完Vivado之后确保环境变量已经加载好source /opt/Xilinx/Vivado/2024.1/settings64.sh source /opt/Xilinx/Vitis/2024.1/settings64.shPetaLinux如果需要source /opt/Xilinx/petalinux/2025.1/settings.sh然后准备一块ZYNQ开发板一个8GB以上的SD卡一根Micro USB转串口线一个用于读取和烧写SD卡的USB读卡器以及电脑端可以访问开发板串口终端的软件我用的是MinicomWindows下用MobaXterm也可以。3.2 QSPI Flash启动配置全流程3.2.1 生成FSBL、bitstream和BOOT.bin在Vivado中完成硬件工程综合、布局布线并导出硬件描述文件XSA文件之后就可以开始生成启动镜像了。如果只用裸机程序直接在Vitis中创建FSBL工程和应用程序工程编译后选择“Create Boot Image”生成BOOT.bin。如果使用PetaLinux则是在PetaLinux工程里执行petalinux-package --boot --fsbl --fpga --u-boot --force这个命令会把PetaLinux自动生成的FSBL、FPGA的bitstream文件、U-Boot一起打包成BOOT.bin。生成的文件位于images/linux/目录下大小一般在几MB到十几MB之间。另一个需要确认的文件是boot.scr这是U-Boot的启动脚本。在PetaLinux中默认已经生成它的内容是告诉U-Boot在启动时去哪里找内核和设备树fatload mmc 0:1 0x2000000 image.ub bootm 0x2000000这段脚本的意思是从SD卡的第一个分区的FAT文件系统中把名为image.ub的文件加载到内存地址0x2000000处然后跳转到该地址执行启动。image.ub是一个复合镜像里面打包了Linux内核镜像和设备树。3.2.2 使用Vitis烧写QSPI Flash烧写QSPI Flash有两种常用方式。第一种是直接在Vitis中烧写这种方式非常简单适合新手。先把开发板配置为JTAG启动模式连接好JTAG下载器在Vitis中进入“Xilinx → Program Flash”菜单BRAM Config选择“Fallback”Image File选择刚才生成的BOOT.binFlash Type选择你板子上实际的QSPI Flash型号常见的有S25FL256S、N25Q256A、IS25LP256等这个信息在板子的原理图或者元器件清单上能找到然后在Operation中选择“Program”点击Program按钮等待烧写完成。第二种方式是通过U-Boot烧写这个我在实际项目中也经常用到。其流程是先让板子从SD卡启动进入U-Boot命令行然后把BOOT.bin放到SD卡的FAT32分区中在U-Boot里执行sf probe fatload mmc 0:1 0x3000000 BOOT.bin sf erase 0x0 0x1000000 sf write 0x3000000 0x0 0x1000000这三条命令的意思是初始化QSPI Flash控制器从SD卡加载BOOT.bin到内存0x3000000然后擦除Flash的整个16MB区域再把内存中的数据写入Flash。这种方式在量产时可以配合脚本批量烧写效率比Vitis图形界面高不少。3.2.3 验证QSPI启动结果烧写完成后把开发板的Boot Mode拨码开关拨到QSPI启动模式对应MIO[6:2]为00100按一下复位按键。打开串口终端如果一切正常你会看到U-Boot的启动日志然后授入Linux内核启动最终出现登录提示符。如果没有出现任何串口输出优先检查拨码开关位置是不是确确实实拨到了QSPI其次检查串口线连接的是不是UART0对应的那个串口ZYNQ开发板通常有多个串口引脚容易接错。3.3 SD卡启动配置全流程3.3.1 制作SD卡启动盘制作SD卡启动盘的第一步是分区和格式化。在Linux系统下操作最方便如果用的是Windows可以用Rufus或者balenaEtcher实现类似功能但格式以Linux下为准。把SD卡插入读卡器连接到电脑先确定设备名称lsblk假设设备名是/dev/sdb用fdisk分区sudo fdisk /dev/sdb在fdisk交互界面中依次输入d删除已有分区反复执行直到全部删除n新建分区p主分区回车使用默认的起始扇区500M设置第一个分区大小为500MBt更改分区类型c设置为FAT32 / W95 FAT32 LBA类型。然后再次输入n创建第二个分区直接回车使用全部剩余空间t设置第二个分区类型为83Linux最后输入w保存。分区完成后格式化sudo mkfs.vfat -F 32 -n BOOT /dev/sdb1 sudo mkfs.ext4 -L ROOTFS /dev/sdb2把BOOT.bin、boot.scr、image.ub拷贝到第一个FAT32分区sudo mount /dev/sdb1 /mnt/boot sudo cp images/linux/BOOT.BIN /mnt/boot/BOOT.bin sudo cp images/linux/boot.scr /mnt/boot/boot.scr sudo cp images/linux/image.ub /mnt/boot/image.ub sudo umount /mnt/boot把根文件系统解压到第二个ext4分区sudo mount /dev/sdb2 /mnt/rootfs sudo tar -xzf images/linux/rootfs.tar.gz -C /mnt/rootfs sudo umount /mnt/rootfs3.3.2 避坑指南SD卡分区常见误区关于SD卡启动有不少新手遇到过“显示没有文件”或者“无法挂载分区”这类问题。原因大部分出在分区操作上。第一个坑是分区类型没有设置正确。BOOT分区必须是FAT32文件系统而且分区类型标识要设置成cW95 FAT32 LBA否则U-Boot的fatload命令无法识别文件系统。用lsblk -f查看分区信息确认FSTYPE列显示的是vfat或者ext4不能是空的。第二个坑是FAT32分区容量太大。FAT32文件系统在大多数Linux发行版中用mkfs.vfat格式化时有分区大小限制如果分区大于32GB格式化会失败或者格式化成FAT16/其他格式。因为第一个分区只有几百MB这个问题不太容易踩到但是在做单分区的大容量SD卡时就会暴露。第三个坑是BOOT.bin文件名的大小写。U-Boot的fatload命令是对文件名大小写敏感的如果BOOT.bin被拷贝成了boot.binU-Boot就会报Unable to read file boot.bin。这是新手最常犯的错误之一我见过不下五次。3.3.3 U-Boot环境变量与启动参数配置SD卡启动上电后U-Boot会先被FSBL加载执行然后U-Boot读取SD卡第一个分区中的boot.scr按照里面的内容去加载内核和设备树。如果你在启动时看到U-Boot报错Invalid boot script或者No boot script found说明boot.scr缺失或者格式有问题。boot.scr是由boot.cmd文件通过mkimage工具生成的如果你需要自定义启动参数比如指定根文件系统所在分区可以修改boot.cmd再重新生成。boot.cmd的一个典型内容setenv bootargs consolettyPS0,115200 root/dev/mmcblk0p2 rw rootwait fatload mmc 0:1 0x2000000 image.ub bootm 0x2000000生成boot.scr的命令mkimage -A arm -T script -C none -n Boot Script -d boot.cmd boot.scr这里的root/dev/mmcblk0p2表示根文件系统在SD卡的第二个分区mmcblk0对应SD卡p2代表第二个分区。如果根文件系统在QSPI Flash的某个偏移地址这里就要改成root/dev/mtdblockX或者用initramfs方案这也是两种启动模式差异最大的地方之一。3.3.4 验证SD卡启动结果把拨码开关拨到SD卡启动模式SD0对应01000按复位键。串口终端上应该先出现BootROM的初始化日志然后进入U-Boot命令行界面自动执行boot.scr中的指令加载内核和设备树启动到Linux登录提示符。看到Starting kernel ...之后一般等3到8秒就能看到Linux的启动日志了。如果启动卡在Starting kernel ...之后没有反应最常见的原因是设备树里PL侧的驱动和实际硬件不匹配导致内核在初始化FATAL错误这种情况需要回头检查设备树并重新编译image.ub。3.4 双启动模式切换与优先级管控配置好两种启动方式之后切换模式的操作就是非常机械的事了拨码开关切到对应模式按复位键即可。但实际项目中还有几个细节值得注意。开发阶段建议把默认模式设为SD卡启动因为开发中要频繁修改内核和文件系统SD卡模式修改文件最灵活也不需要反复擦写Flash。当开发完成后、准备交付测试时再切到QSPI Flash模式验证固化系统的运行稳定性。在生产阶段如果产品需要支持远程升级经常采用的做法是量产时烧写QSPI Flash作为主启动介质同时在SD卡预留一个升级分区。系统正常运行时从Flash启动检测到SD卡上有升级标志文件后把新的镜像写入Flash然后重启。这样既兼顾了Flash启动的可靠性又实现了现场维护的便利性。这算是双启动模式的一个进阶玩法等基础配置熟练之后可以尝试。4. 常见问题与排查技巧实录4.1 启动模式不生效排查现象可能原因排查方法切换拨码开关后启动模式没变没有按复位键切换后务必按复位键或重新上电配置到SD启动但串口无输出Boot Mode引脚被外设占用检查硬件设计确认Boot Mode引脚没有复用冲突配置到QSPI启动但串口无输出Flash型号选择错误Vitis中重新选择正确的Flash型号并烧写上电后串口只有一堆乱码串口波特率不对确认终端波特率设为115200与U-Boot配置一致4.2 QSPI Flash烧写失败问题烧写QSPI Flash的典型报错是a valid fsbl file is required for flash operation。这个报错字面意思是“需要有效的FSBL文件”但实际上它还有个隐性的触发条件Vitis在烧写Flash之前要求BRAM Config设置为“Fallback”模式这样烧写工具才会先把FSBL加载到BRAM中运行然后通过FSBL去驱动QSPI控制器完成烧写。如果你选择的是“None”模式Vitis就无法加载FSBL就会报这个错。解决办法在Program Flash对话框中把BRAM Config从None改成Fallback选择好FSBL文件然后再执行烧写。如果还报错检查FSBL工程是否使用的是和当前硬件一致的XSA文件FSBL版本不匹配也会导致烧写失败。4.3 启动失败与日志分析做ZYNQ启动调试看串口日志是最基本的功夫。日志从BootROM开始输出你可以从中判断启动流程走到了哪一步。整理一个启动日志排查的思路如果串口完全没有输出先确认供电、时钟、复位电路正常再检查Boot Mode引脚电平是否确实处于预期状态。用万用表量一下Boot Mode引脚的电压验证拨码开关是不是真的把对应引脚拉到了正确电平。如果串口输出停在FSBL相关报错比如FSBL status 0x...后面卡住一般是FSBL初始化DDR失败。常见原因是硬件上的DDR型号和Vivado中的DDR控制器配置不一致或者FSBL使用的XSA文件与实际板卡型号不符。如果U-Boot打印完版本信息就停住不执行boot.scr排查boot.scr文件或者尝试在U-Boot命令行手动输入fatload mmc 0:1 0x2000000 image.ub bootm 0x2000000手动方式能跑起来说明boot.scr有问题重新生成它。如果内核开始启动但中途崩溃报Kernel panic - not syncing: VFS: Unable to mount root fs这是根文件系统挂载失败。先确认bootargs里的root参数指向了正确的设备节点/dev/mmcblk0p2再确认该分区中确实有可用的根文件系统。用串口进入U-Boot命令行输入mmc list和mmc part查看SD卡分区情况确认mmcblk0p2存在。4.4 硬件相关的常见问题ZYNQ开发板的SD卡和Flash接口在硬件设计上也有一些容易出问题的点。SD卡电路要特别注意上拉电阻和去耦电容SDIO信号线的上拉电阻一般在10K到47K之间如果信号完整性不良高速读写时会随机失败。QSPI Flash的片选、时钟、数据线在PCB走线时要尽量等长避免高频反射导致通信不稳定。如果遇到Flash烧写一半报错、或者偶发启动失败硬件上优先检查这两个地方。对纯软件方向的新手可能没条件重新打板但开发板上这些都已经是定好的。遇到硬件相关的问题确认开发板硬件正常即可最直接的方法是找同型号的开发板做交叉验证——如果别人的板子能跑你的镜像而你的不行那基本确定是板子硬件层面的问题了。5. 实操心得补充文章写到这儿我回顾了一下这些年做ZYNQ项目踩过的坑有几个体会特别想分享。第一一定要养成修改硬件配置后重新生成全套镜像的习惯。很多疑难杂症的背后都是“改了XSA文件忘了重新生成BOOT.bin”这种低级问题。XSA文件里包含FPGA bitstream和FSBL的参数只要硬件设计有变化必须重新走一遍petalinux-build和petalinux-package的完整流程。第二调试阶段尽量保留JTAG启动模式作为兜底。就算你调好了SD卡和QSPI启动也把JTAG作为一种备用手段。当板子启动完全没反应、怀疑Flash内容损坏时切到JTAG模式可以重新烧写和调试是最重要的“救命稻草”。第三建议保存一份完整的工程流程图。每个版本的BOOT.bin对应哪个Vivado工程、哪个PetaLinux配置、哪个XSA文件这些信息不能靠记忆管理。我曾经过了一个月回来看项目对着两个版本的镜像想不起来哪个是量产版本、哪个是测试版本最后只能通过烧录对比来验证白白浪费了大半天时间。这是血泪教训。如果你是按部就班照着我上面写的步骤来操作走到这一步应该已经能熟练切换SD卡和QSPI Flash两种启动方式了。接下来可以考虑自己定制U-Boot环境、调整内核设备树、把QSPI Flash剩余空间利用起来放用户数据这些都是水到渠成的下一步。祝大家都能少踩坑一次点亮。