Zynq7000混合启动方案:QSPI引导+eMMC根文件系统部署全解析
发布时间:2026/9/19 14:52:19 锦皓数字建站

很多搞Zynq的工程师第一块板子都是QSPI启动起步做着做着就会发现一个问题根文件系统放哪QSPI NOR Flash容量再大也就几十上百MB塞一个完整的Linux发行版根本不现实用SD卡吧工业现场掉电频繁接口和卡座又容易出问题。把eMMC挂上去之后最顺手的方案就是我现在要聊的“混合启动”——QSPI Flash管第一级引导eMMC管内核和ext4根文件系统。这套方案在Zynq7000系列上非常成熟既能保证上电启动的确定性又能用上eMMC的大容量、高可靠性和块设备特性。这篇文章会从启动链路原理、硬件信号、镜像制作、U-Boot环境变量、eMMC分区部署到故障排查完整走一遍适合正在做Zynq Linux产品化、想把系统从SD卡迁到板载eMMC的嵌入式工程师。1. 启动链路拆解为什么非要用“混合启动”这套组合1.1 Zynq7000的上电启动顺序从BootROM到U-BootZynq7000是一颗异构芯片内部有PSProcessing System和PLProgrammable Logic两部分。上电后PS内部固化的BootROM先运行它会根据BOOT_MODE引脚的电平状态决定从哪个介质读取启动镜像。BootROM只认一种镜像格式就是通过bootgen打包生成的BOOT.BIN里面最核心的是FSBLFirst Stage Boot Loader。BootROM把FSBL加载到片上OCMOn-Chip Memory运行后FSBL负责初始化DDR、PLL、MIO等基础外设如果需要位流文件还会配置PL最后把第二级引导程序——也就是U-Boot——从启动介质拷贝到DDR里跳转执行。从BootROM到U-Boot整个阶段都发生在操作系统接管之前这个阶段里可用的硬件资源非常有限能用的存储介质完全取决于BootROM的支持列表。Zynq7000的BootROM支持QSPI、SD、NAND、NOR等常见启动源也有JTAG调试模式。这里有个关键点eMMC在BootROM眼里只是一个挂在SDIO接口上的设备BootROM确实有可能直接从eMMC启动的但实际应用中很少人这么干。原因有两个一是eMMC的初始化时序和SD卡不完全一样BootROM对它的兼容性处理没那么细致二是一旦把整个启动链都压在eMMC上后续做分区调整、镜像备份、启动模式切换都会变得束手束脚。所以我更推荐把QSPI固定作为第一级启动介质把eMMC留给内核和文件系统这也是“混合启动”最核心的思路。1.2 单QSPI方案的瓶颈和eMMC的补位逻辑单独用QSPI启动的方案构建起来最省事BOOT.BIN和内核都塞进一片QSPI NOR里就行。但代价也很直观一片常见的QSPI Flash8MB、16MB、32MB算是主流64MB就要挑型号了。放到现在的Linux系统里一个带完整驱动的内核Image加上设备树大概10MB到20MB如果还要放ramdisk或者多个版本备份QSPI容量立刻见底。更要命的是NOR Flash的写入寿命和写入速度拿它当rootfs介质用频繁的日志写入会让坏块管理压力非常大而且NOR是MTD设备文件系统选型只能用jffs2、ubifs这类专门给Flash设计的方案改造起来麻烦。eMMC的出现恰好补上了这个短板。它是BGA封装、板载固定、不用考虑卡座松脱容量从4GB到128GB随便挑。eMMC内部有完整的FTLFlash Translation Layer主机层看到的是一个标准块设备坏块管理、磨损均衡、ECC纠错全部由芯片内部的控制器完成。这意味着可以像操作普通硬盘一样直接在上面创建ext4文件系统可靠性和性能都远胜NOR。所以“QSPI引导 eMMC根文件系统”这个混合方案本质是把“启动的确定性”和“存储的大容量”两个优点结合到一起各管一段互不拖累。1.3 BOOT_MODE引脚设定把启动源钉死在QSPI上要让Zynq7000每次上电都老老实实从QSPI加载BOOT.BINBOOT_MODE引脚必须配置正确。Zynq7000的启动模式引脚通常是MIO[6:2]这5根线具体封装不同引脚编号会有差异设计硬件时务必对照对应型号的数据手册和UG821、UG1085这些官方文档确认。给一个通用原则把BOOT_MODE[4:0]按QSPI启动方式对应的电平组合通过上下拉电阻固定到QSPI模式把选择权留给硬件而不是每次通过JTAG手动指定。有个容易踩坑的细节是BOOT_MODE引脚是上电瞬间采样采样完成后这些引脚仍然可以复用为普通MIO功能但硬件设计上还是建议不要把BOOT_MODE位用到的MIO再接其他大负载外设避免上电瞬间的毛刺导致采样错误。我就见过一块板子把MIO[6:2]中的一根既拉成启动模式配置又接了外设中断线结果10次上电有2次启动到SD卡模式查了半天才发现是复用冲突。2. 硬件视角QSPI和eMMC在板级设计上的分工与关键信号2.1 eMMC为什么可以被ext4直接管理很多刚从NOR Flash转过来的工程师会对“eMMC上挂ext4”产生疑虑潜意识里总觉得Flash上应该用Flash专用文件系统。这个观念需要更新eMMC是一颗带管理控制器的Flash不是裸Flash。裸NAND和NOR的擦写、坏块管理都要主机软件来做所以需要UBI、JFFS2这些方案eMMC内部已经把这些逻辑全部消化掉了对主机暴露的是LBALogical Block Address接口协议层走的是类似SD卡的命令响应机制主机只需要通过CMD和DAT线读写扇区就行。由于具备这个特性eMMC的驱动层级和SD卡几乎一致Linux内核和U-Boot都把它当块设备处理。内核识别后生成 /dev/mmcblk0U-Boot里用mmc命令直接访问。所以ext4这种为块设备设计的通用日志文件系统在eMMC上是非常合适的选型。实际使用中ext4的日志机制配合eMMC的掉电保护抗异常断电能力明显强于直接在NOR上挂文件系统。2.2 BGA153封装关键信号与硬件检查点板载eMMC最常见的封装是BGA153也就是热词里提到的“153ball eMMC”芯片底部153个焊球间距0.5mm。虽然我们做软件的人一般不看原理图细节但调试启动问题时硬件信号检查是绕不开的一步。eMMC的关键信号可以分三组电源组VCC是主电源一般3.3V给内部NAND供电VCCQ是接口电源决定IO电平可以是1.8V或3.3V必须和相连的SDIO控制器电压匹配。接口信号组CLK时钟、CMD命令线、DAT[7:0]数据线。低功耗模式可以只走DAT0-3高速模式一般用8位总线也就是DAT0-7全接。控制信号组RST_n复位脚低电平有效这个脚非常关键DS数据选通脚在HS400模式下才会用到很多板子可以不接。调试时第一件事就是量RST_n的时序。常见坑是RST_n直接接地或者用一个大电容慢慢充电造成eMMC复位释放太晚U-Boot初始化时报Card did not respond to voltage select。正确做法是RST_n由一个GPIO或复位芯片控制上电时先保证VCC和VCCQ稳定再释放复位释放后等待一小段时间再开始发命令。另外CMD和DAT线需要在板上配上拉电阻阻值10kΩ到50kΩ之间具体看芯片手册我习惯用10kΩ配合HS200模式实测稳定。2.3 存储介质的职责划分容量和地址规划建议混合启动方案里QSPI和eMMC各自承担什么角色要在一开始就规划清楚后面做镜像才不抓瞎。我的建议是QSPI至少8MB起步如果板子成本允许16MB最稳。QSPI里放BOOT.BIN、U-Boot环境变量区、一份冗余备份镜像基本就占了3-4MB。eMMC的分区按“小系统区 大文件系统区”划分具体大小参考后缀的实操章节先给总体职责表介质存放内容文件系统/格式加载者QSPI FlashBOOT.BIN含FSBLbitU-Boot、env备份裸分区由bootgen打包BootROM、FSBLeMMC分区1内核Image、设备树ext4或FATU-BooteMMC分区2根文件系统ext4Linux内核QSPI地址从0x0开始烧BOOT.BIN这个地址是BootROM硬性要求的不能改。U-Boot环境变量区域放在BOOT.BIN之后比如0x400000地址大小给1MB就够。eMMC第一个分区放内核和DTB好处是内核升级时直接替换分区里的文件而不是重新烧QSPI第二分区放rootfs用ext4格式化这是整个方案存储能力的主要来源。3. QSPI侧镜像制造从FSBL到U-Boot的整体打包3.1 用Vitis生成FSBL别只把它当HelloWorldFSBL的代码量其实不大Vitis里提供了现成的FSBL模板工程。打开VitisFile - New - Application Project选好对应的Zynq型号后在模板列表里找到Zynq FSBL点击生成。生成的工程会包含BOOT.BIN所必需的第一阶段引导代码包括DDR初始化、MIO配置、PL位流下载和跳转逻辑。很多人拿到FSBL后不会去看它的源码但实际排查启动问题时FSBL打印的日志非常关键默认工程会把XFSBL_*这类打印信息输出到串口通过日志能快速判断DDR初始化是否通过。FSBL编译产物是fsbl.elf后面打包BOOT.BIN时它必须作为第一个镜像。如果你不需要PL逻辑参与启动可以不放位流文件如果放了位流FSBL会在跳转U-Boot之前先把PL配置完成。这里要注意一个编译细节FSBL工程的内存链接脚本默认把代码放在OCM里如果你的FSBL改得比较大或者DDR初始化逻辑有定制要确认链接脚本和DDR地址没有冲突否则会出现“FSBL跑飞”的现象串口上根本看不到任何输出。3.2 U-Boot配置启动eMMC必须打开的四个开关U-Boot是整个启动链路里最灵活的一环也是很多人觉得最复杂的地方。我用的是Xilinx维护的u-boot-xlnx分支编译Zynq7000目标时先确认默认配置里有没有开这几个关键选项CONFIG_MMCy CONFIG_MMC_SDHCIy CONFIG_MMC_SDHCI_ZYNQy CONFIG_CMD_MMCy CONFIG_CMD_EXT4y CONFIG_CMD_FATy CONFIG_CMD_SFy CONFIG_CMD_SPIy CONFIG_CMD_BOOTIy CONFIG_ENV_IS_IN_SPI_FLASHyCONFIG_MMC和CONFIG_MMC_SDHCI_ZYNQ是驱动层没有它们eMMC在U-Boot阶段就是一块不存在的硬件。CONFIG_CMD_EXT4是读取ext4分区的关键后续用ext4load命令从eMMC加载内核就靠它。CONFIG_CMD_SF和CONFIG_CMD_SPI对应QSPI Flash操作环境变量保存也要用到。最后CONFIG_ENV_IS_IN_SPI_FLASH把U-Boot环境变量存到QSPI的专用区域这样才能让saveenv之后的配置在重启后保留。配置的方法是在U-Boot源码目录下先执行make xilinx_zynq_virt_defconfig这类板级配置再用make menuconfig逐一确认上述选项。编译产物中需要的是u-boot.elf这个文件会作为BOOT.BIN的最后一个镜像块被bootgen打包进去。3.3 bootgen的bif文件与烧写验证BOOT.BIN的打包依赖bif文件这是bootgen的描述输入。我常用的bif内容如下the_ROM_image: { [bootloader] ./fsbl.elf ./bitstream.bit ./u-boot.elf }如果不需要位流把中间的bitstream.bit这一行去掉就行。打包命令在Vitis的XSCT控制台或者命令行里执行bootgen -image boot.bif -o i BOOT.BIN生成的BOOT.BIN需要写到QSPI Flash的0x0地址。我比较喜欢在U-Boot命令行里直接用sf命令烧写因为速度快、依赖少。先把BOOT.BIN加载到DDR我一般是让板卡先从SD卡或网络tftp下载到DDR地址0x1000000然后执行sf probe sf erase 0x0 0x800000 sf write 0x1000000 0x0 0x800000擦除和写入的大小根据BOOT.BIN实际大小调整我这里的0x8000008MB是保守值实际烧写前先看文件大小。写完后sf read再读回来对比一下确认数据没问题再断电复位。这一步的严谨程度直接决定后面所有调试是否顺利BOOT.BIN写错位置是新手最常见的坑。4. U-Boot环境变量把加载源从QSPI切到eMMC4.1 先搞清mmc设备编号0还是1U-Boot启动后会枚举MMC控制器Zynq7000一般有两个SDIO控制器一个接SD卡一个接eMMC具体哪个对应mmc0、哪个对应mmc1由硬件连接决定没有绝对固定的规律。启动U-Boot后先执行mmc list输出类似sdhcie0100000: 0 (SD) sdhcie0101000: 1 (eMMC)先看哪一行后面写着eMMC。然后执行mmc dev 1切换到eMMC再执行mmcinfo确认容量、总线位宽、速度等级能够正确打印出这些信息说明eMMC在U-Boot阶段已经可用。这个“先确认设备号”的习惯一定要养成很多启动失败都是因为环境变量里写死了mmc dev 0但硬件上eMMC其实是mmc1。4.2 bootcmd环境变量一条条写出完整的启动链U-Boot启动内核的整个过程可以浓缩成几条环境变量。我习惯把所有加载命令写成独立变量再用bootcmd把它们串起来。下面是一个我在Zynq7000上验证过的boot.cmd脚本内容setenv loadkernel ext4load mmc 1:1 ${kernel_addr_r} Image setenv loadfdt ext4load mmc 1:1 ${fdt_addr_r} system.dtb setenv bootargs consolettyPS0,115200 root/dev/mmcblk0p2 rw rootwait setenv bootcmd run loadkernel; run loadfdt; booti ${kernel_addr_r} - ${fdt_addr_r} saveenv注意ext4load mmc 1:1的含义mmc是接口类型1是设备号1是分区号后面的Image和system.dtb是文件在eMMC分区1里的名字。kernel_addr_r和fdt_addr_r是U-Boot预设的DDR加载地址不用改但可以通过env print kernel_addr_r查看确认。booti用于启动ARM64的Image格式镜像——准确说Zynq7000是32位ARMU-Boot里booti也能引导Image格式如果用的是zImage则用bootz这是两个常见差异点。把这些命令写进文件后用mkimage打包成U-Boot可执行的脚本mkimage -A arm -T script -C none -n Boot Script -d boot.cmd boot.scr然后把boot.scr放到eMMC或QSPI中U-Boot启动时执行source命令加载它。生产环境我推荐用boot.scr比开机后手工敲命令靠谱得多。4.3 内核cmdline里rootwait和PARTUUID的取舍root/dev/mmcblk0p2是直接指定块设备节点的方式优点是直观缺点是设备节点号不稳定。当系统里同时存在SD卡、eMMC、USB存储时内核枚举顺序变化会造成mmcblk0和mmcblk1互换根文件系统就可能挂错。我在实际项目里更推荐用PARTUUID分区格式化后可以通过blkid查看分区的PARTUUID然后bootargs改成rootPARTUUIDxxxxxxxx-01 rw rootwaitPARTUUID是跟分区走的不管mmcblk编号怎么变都能正确找到根分区。另外rootwait这个参数一定不能省。eMMC这类块设备的初始化是异步完成的内核启动阶段访问根分区时mmc驱动可能还没来得及把设备准备好没有rootwait就直接panicrootwait让内核死等块设备就绪再挂载代价只是启动多等几百毫秒但对稳定性影响巨大。4.4 环境变量存储QSPI里的env分区怎么留如果你把CONFIG_ENV_IS_IN_SPI_FLASH打开了U-Boot默认会在QSPI Flash里划分一块区域存放环境变量。这个区域的起始地址和大小由CONFIG_ENV_OFFSET和CONFIG_ENV_SECT_SIZE决定。一般建议把env区域放在BOOT.BIN之后比如BOOT.BIN只有2MBenv起始地址可以设在0x400000大小为0x40000256KB左右。设计分区时留足余量避免以后BOOT.BIN体积增长把env区域覆盖掉。env区域损坏的典型症状是U-Boot启动时报Warning: env area is invalid然后回到默认环境变量遇到这种情况先别急着怀疑Flash坏了重新saveenv一次就能恢复。5. eMMC上的ext4根文件系统分区、镜像制作与写盘验证5.1 分区规划给8GB eMMC的实用分法分区方案直接影响后续升级维护的便利程度。以一个8GB eMMC为例我会在设备上建两个主分区尽量不用扩展分区MBR分区表就够。分区1大小512MB格式化成ext4用来放内核Image、设备树和boot.scr这相当于一个独立的boot分区分区2用掉剩余的7.5GB格式化成ext4作为根文件系统分区。两个分区都用ext4的好处是U-Boot和主机的常用命令都能无缝访问不用引入FAT工具链。在U-Boot命令行里分区比较麻烦我一般先在Linux侧分区或者用读卡器在PC上分好再焊回板子。用parted命令在Linux下对 /dev/mmcblk0 操作时关键是分区起始扇区要按1MiB对齐减少跨页访问带来的性能损失parted /dev/mmcblk0 mklabel msdos parted /dev/mmcblk0 mkpart primary ext4 1MiB 513MiB parted /dev/mmcblk0 mkpart primary ext4 513MiB 100%分区完成后分别mkfs.ext4格式化两个分区分区1可以加个卷标叫boot分区2叫rootfs方便后续识别。5.2 在主机上制作ext4根文件系统镜像用命令说话在PC上制作rootfs镜像的体积可控、检验方便是我推荐的方式。以在Ubuntu主机上为例假设根文件系统内容都在/path/to/rootfs目录下先创建空镜像文件dd if/dev/zero ofrootfs.ext4 bs1M count2048 mkfs.ext4 -L rootfs rootfs.ext4 mkdir /mnt/rootfs mount -o loop rootfs.ext4 /mnt/rootfs然后把rootfs内容复制进去。如果用从发行版官方的rootfs tar包解压时注意保留属主和权限tar xf ubuntu-base-22.04-base-armhf.tar.gz -C /mnt/rootfs --numeric-owner这里呼应一个热词Ubuntu 22.04的base文件系统解压后再配合QEMU chroot可以安装更多软件包但Zynq7000是32位ARM根基文件系统选armhf版本。如果是自己构建的buildroot或busybox系统直接把_install目录下的内容拷进去就行。复制完成后卸载镜像并做一次文件系统检查umount /mnt/rootfs e2fsck -f rootfs.ext4e2fsck这一步不能跳它是发现镜像问题的最后一道防线。检查通过后就可以用dd把镜像写到eMMC的分区2里。5.3 dd烧写的注意事项别把设备号搞错把镜像写到eMMC分区用dd就能完成但操作前必须反复确认设备节点。在板卡Linux系统下eMMC通常是 /dev/mmcblk0分区2就是 /dev/mmcblk0p2如果系统里还有SD卡节点号可能往后排写之前用lsblk看一眼确认容量和分区表是不是目标eMMC。烧写命令dd ifrootfs.ext4 of/dev/mmcblk0p2 bs1M statusprogress convfsync写完后先别急着上电用sync确保数据落盘。如果镜像大小和分区大小不一致可能出现两种情况镜像小于分区文件系统没有占满整个分区启动后执行resize2fs /dev/mmcblk0p2扩展镜像大于分区dd会报空间不足这时要么重做更小的镜像要么重新分区。我个人的习惯是把镜像做得比分区略小启动后用resize2fs自动扩展到满这样以后换更大容量的eMMC也不用重新制作文件系统。5.4 挂载参数与ext4维护工具清单rootfs部署好之后eMMC的ext4挂载参数值得花点心思。在 /etc/fstab 里给根分区设置挂载参数主要关注discard和noatime。discard使能TRIM命令让FTL及时回收空闲块但实时discard在部分场景下会降低性能如果对IO时延敏感可以改成定期fstrimnoatime避免每次读文件都更新访问时间减少不必要的写放大。举一个fstab配置示例/dev/mmcblk0p2 / ext4 defaults,noatime,discard 0 1日常维护中tune2fs -l /dev/mmcblk0p2查看inode数和块信息dumpe2fs看文件系统详细信息resize2fs调整大小e2fsck在异常断电后进行修复。这些命令在板卡上的util-linux和e2fsprogs包里都有属于根文件系统的基本工具裁剪系统时不要漏掉。6. 实测启动与高频故障排查从日志定位到根因6.1 一份可对照的启动日志从U-Boot到login一个正常的启动过程串口输出大致长这样。我把关键节点标注出来方便你对照自己的板卡U-Boot 2018.3 (Apr 28 2024 - 10:00:00) DRAM: 1 GiB MMC: sdhcie0100000: 0, sdhcie0101000: 1 SF: Detected n25q128 with page size 256 Bytes, erase size 4 KiB, total 16 MiB In: serial Out: serial Err: serial Net: eth0 Hit any key to stop autoboot: 0 switch to partitions #0, OK mmc1 is current device ext4load mmc 1:1 0x2080000 Image 4012928 bytes read in 153 ms (25 MiB/s) ext4load mmc 1:1 0x2000000 system.dtb 21480 bytes read in 10 ms (2 MiB/s) ## Flattened Device Tree blob at 0x2000000 Booting using the fdt blob at 0x2000000 Working FDT set to 0x2000000 Kernel image 0x2080000 [ 0x000000 - 0x400000 ] Starting kernel ... [ 0.000000] Booting Linux on physical CPU 0x0 [ 1.234567] mmc0: new high speed SDIO card at address 0001 [ 2.345678] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null) [ 3.456789] systemd[1]: systemd 249 running in system mode ... Ubuntu 22.04 LTS ttyPS0 zynq login:看到EXT4-fs挂载成功再看到login提示符整套链路就通了。如果卡在某个阶段日志会停留在对应的位置这就是排查的起点。6.2 高频故障速查表现象、原因、排查方向我在多个项目里遇到过的问题整理成表格对你应该很有帮助现象可能原因排查方向上电后串口完全无输出启动模式引脚配置错误、BOOT.BIN未烧写、DDR初始化失败检查BOOT_MODE引脚电平确认QSPI上有数据用JTAG连接查看FSBL是否运行FSBL输出完但U-Boot无启动信息u-boot.elf损坏、DDR加载地址错误、位流配置PL失败重新打包BOOT.BIN确认bif文件镜像顺序检查FSBL日志最后一行U-Boot启动后mmc dev 1报错eMMC供电或复位时序问题、VCCQ电压不匹配、上拉电阻缺失用示波器量RST_n上电波形量CLK和CMD信号检查 eMMC 封装焊接ext4load找不到文件分区号或文件名不对、分区没有格式化为ext4、U-Boot未开CONFIG_CMD_EXT4ext4ls mmc 1:1查看分区内容逐个核对文件名大小写内核启动但挂不上rootfsroot参数错误、rootwait缺失、rootfs镜像损坏、分区设备节点号变了检查bootargs核对PARTUUID用initramfs临时进入系统查看分区文件系统以只读方式挂载异常断电导致ext4错误标记、eMMC进入只读保护执行e2fsck修复检查eMMC的RST_n和电源排查硬件保护机制启动过程非常慢eMMC工作在1-bit模式、SDIO时钟频率低、rootwait等待时间过长mmcinfo查看总线位宽设备树里确认bus-width和no-1-8-v属性每一行的排查方向都很关键但实际项目中往往是几个问题叠加出现。比如eMMC的RST_n接法有误会先导致U-Boot阶段不稳定好不容易启动到内核又因为设备树里没有配好总线位宽、速度跑不上去整个系统启动慢到让人怀疑人生。6.3 按信号链排查从BootROM到rootfs挂载遇到启动问题我的排查习惯是“顺着信号链路一步步隔离”。第一步看串口有没有BootROM阶段的输出如果没有问题在硬件和BOOT_MODE配置不是软件能解决的如果FSBL的日志出来了但很快中断用JTAG连上去看PC指针跑到哪里通常能定位是DDR初始化还是位流加载的问题如果U-Boot起来了问题收敛到存储和启动参数。U-Boot阶段是一个天然的边界。在这个阶段可以用命令逐个验证硬件。先mmc list确认设备识别再mmc dev切换用mmcinfo读容量用mmc read直接读DDR地址并比对数据确认eMMC读写通道有没有问题。确认eMMC没问题之后用ext4ls列出分区内容验证文件系统是否可读。这样一步步推进每一步都有明确结论问题很快就能定位到具体环节而不是在整个链路里瞎猜。6.4 混合启动的另一种组合内核放QSPI、rootfs放eMMC最后再说一种变体。如果产品对启动速度要求很高或者内核升级频率低可以把内核Image和设备树也放到QSPI Flash里QSPI容量够大就行。这样U-Boot阶段用sf命令代替ext4load从eMMC读文件setenv loadkernel sf read ${kernel_addr_r} 0x1000000 0x400000 setenv loadfdt sf read ${fdt_addr_r} 0x800000 0x100000好处是内核从NOR读比从eMMC读快启动时间能缩短几百毫秒而且即使eMMC上的文件系统完全损坏U-Boot还是能用QSPI里的内核进入紧急维护模式恢复手段更多。坏处是每次升级内核要重新烧QSPI稍微麻烦。我在量产产品里偏好这种组合开发阶段则选择内核放eMMC方便反复替换调试。这个方案里还有一个经常被忽略的点无论内核和rootfs怎么分布eMMC的RST_n引脚和供电时序一定要在项目早期就验证到位。我吃过一次亏开发板用eMMC裸片RST_n被一个10kΩ电阻直接拉到VCC上电瞬间eMMC内部还没准备好命令就发出去了导致偶发性初始化失败后来改成由FPGA GPIO分时控制复位问题彻底消失。如果你在硬件设计阶段建议把这根线用一个RC延时电路或者GPIO拉高保证VCC稳定后至少再等5ms释放复位。整个混合启动方案跑通之后产品化的后续工作就顺畅多了。升级系统只需要替换eMMC分区里的文件或者在Linux下做在线升级出厂烧录也简单QSPI用JTAG烧一次BOOT.BINeMMC用SD卡启动后dd镜像进去两条路径都稳定可靠。这应该就是Zynq7000平台上最实用、最不容易出问题的一套启动与存储组合了。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。