news 2026/5/20 3:46:35

ZYNQ无SD卡情况下的SPI+EMMC启动

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ZYNQ无SD卡情况下的SPI+EMMC启动

参考

PetaLinux的JTAG启动

前提准备

软件环境准备

Vitis 环境庞大,依赖多,安装慢
若提前用专用工具将BOOT.bin写入QSPI Flash
生产电脑可舍弃 Vitis 环境,TFTP、NFS 用局域网内的服务器;
生产电脑仅需安装串口终端工具

Name作用
Vitis环境烧录BOOT.bin到QSPI Flash
tftp服务器首次启动下载启动各种文件
nfs服务器首次挂载nfs 根文件系统启动
服务器目录
TFTP服务器: IP:192.168.3.4 根目录:/tftpboot 文件: zImage system.dtb system.bit NFS服务器: IP:192.168.3.4 导出目录: /home/wpf/workspace/nfs/z8_rootfs *(rw,sync,no_root_squash)

文件准备

Name作用
BOOT.BINFSBL+U-Boot
boot.cmd.defaultU-Boot 启动命令脚本源码
boot.scrU-Boot启动命令二进制脚本
system.bitbit流
system.dtb设备树
zImageLinux 内核
zynq_fsbl.elf第一阶段启动加载程序
z8_root_fs用于nfs挂载的root_fs
p2_rootfs.img根文件系统镜像
zynq_qspi_program_flash.batjtag烧录boot的脚本
copy_all_to_emmc.sh拷贝文件到emmc的脚本

操作步骤

1. 通过 JTAG 烧录引导程序至 QSPI Flash

使用 JTAG 接口将BOOT.BIN(包含FSBLU-Boot)写入 QSPI Flash,以提供非易失性启动源。

2. 从 QSPI Flash 启动系统

重新上电,使系统从 QSPI Flash 启动,并进入U-Boot 引导环境

3. 下载远程tftp里的启动文件

在 U-Boot 环境下,通过网络TFTP下载远程 NFS 服务器上的启动文件:

  • Linux 内核:zImage
  • 设备树:system.dtb
  • FPGA 配置比特流:system.bit
4. 挂载远程nfs根文件系统并启动

将远程 NFS 根文件系统挂载为系统根目录,实现临时网络启动

5. 对 eMMC 存储器进行分区

进入 Linux 系统后,将 eMMC 分为两个分区:

  • 分区1(FAT32):存放启动文件
  • 分区2(EXT4):存放根文件系统
6. 拷贝启动文件及根文件系统至 eMMC
  • 将 NFS 上的启动文件复制至 eMMC 分区1。
  • 将NFS 上的根文件系统解压至 eMMC 分区2
7. 修改 U-Boot 启动参数并保存

重新上电后,从 eMMC 启动;在 U-Boot 中修改bootargs指向 eMMC 根文件系统,并执行saveenv保存,以确保系统能够直接从本地存储引导。

文件处理

制作z8_root_fs的压缩包,用于拷贝到emmc第二分区

# 进入准备到的根文件系统执行tarczpvf../z8_rootfs_clean.tar.gz --numeric-owner --one-file-system.

z8_root_fs里的关键文件

wpf@minglie:~/workspace/nfs/z8_rootfs/opt$ tree.├── image │ ├── burn_qspi.sh │ ├── copy_boot_to_qspi.sh │ ├── copy_net_boot_to_qspi.sh|├── copy_all_to_emmc.sh │ ├── copy_sd_to_emmc.sh │ └── emmc_partition.sh ├── z8_boot │ ├── BOOT.BIN │ ├── boot.scr │ ├── system.bit │ ├── system.dtb │ └── zImage └── z8_root_fs └── z8_rootfs_clean.tar.gz

u-boot 启动脚本 boot.cmd.default

# mkimage -c none -A arm -T script -d boot.cmd.default boot.scr#################ming_mmc_devnum=1forboot_targetin${boot_targets};doiftest"${boot_target}"="jtag";thenbootm 0x00200000 0x04000000 0x00100000exit;fiiftest"${boot_target}"="mmc0"||test"${boot_target}"="mmc1";thenecho" AAAAAAAAAAAAAWPF Booting from SD (zImage)...${boot_target}--${devtype}-${devnum}-${distro_bootpart}"iftest-e${devtype}${devnum}:${distro_bootpart}/zImage;thenfatload${devtype}${devnum}:${distro_bootpart}0x00200000 zImage;;fiiftest-e${devtype}${devnum}:${distro_bootpart}/system.dtb;thenfatload${devtype}${devnum}:${distro_bootpart}0x00100000 system.dtb;fiiftest-e${devtype}${devnum}:${distro_bootpart}/rootfs.cpio.gz.u-boot;thenfatload${devtype}${devnum}:${distro_bootpart}0x04000000 rootfs.cpio.gz.u-boot;bootm 0x00200000 0x04000000 0x00100000exit;fiiftest-e${devtype}${devnum}:${distro_bootpart}/system.bit;thenfatload${devtype}${devnum}:${distro_bootpart}0x00800000 system.bit;fpga loadb0${fileaddr}${filesize}fibootz 0x00200000 - 0x00100000exit;fiiftest"${boot_target}"="xspi0"||test"${boot_target}"="qspi"||test"${boot_target}"="qspi0";thenecho"BBBBBBBCCCCCCKYLV1 Booting from QSPI (zImage)...${boot_target}--${devtype}-${ming_mmc_devnum}-${distro_bootpart}"iftest-z"${bootargs}";thensetenv bootargs'console=ttyPS0,115200 root=/dev/mmcblk1p2 rw rootwait rootfstype=ext4 earlyprintk'fifatload${devtype}${ming_mmc_devnum}:${distro_bootpart}0x00200000 zImage||echo"zImage not found"fatload${devtype}${ming_mmc_devnum}:${distro_bootpart}0x00100000 system.dtb||echo"system.dtb not found"fatload${devtype}${ming_mmc_devnum}:${distro_bootpart}0x00800000 system.bit&&fpga loadb00x00800000${filesize}bootz 0x00200000 - 0x00100000exitfiiftest"${boot_target}"="nand"||test"${boot_target}"="nand0";thennand infoiftest"image.ub"="image.ub";thennandread0x10000000 0x1000000 0x6400000;bootm 0x10000000;exit;fiiftest"image.ub"="uImage";thennandread0x00200000 0x1000000 0x3200000;nandread0x04000000 0x4600000 0x3200000;bootm 0x00200000 0x04000000 0x00100000exit;fifidone
对emmc进行分区 emmc_partition.sh

分区1 fat32 100M ,剩余部分为ext4
/dev/mmcblk1p2 7.0G 744.5M 5.9G 11% /media/sd-mmcblk1p2
/dev/mmcblk1p1 98.5M 8.1M 90.3M 8% /media/sd-mmcblk1p1

#!/bin/sheMMC_DEVICE="/dev/mmcblk1"umount"${eMMC_DEVICE}p1"2>/dev/nullumount"${eMMC_DEVICE}p2"2>/dev/nullif[!-b"$eMMC_DEVICE"];thenecho"$eMMC_DEVICEnot found!"exit1fifdisk"$eMMC_DEVICE"<<EOF o n p 1 +100M n p 2 w EOFblockdev--rereadpt"${eMMC_DEVICE}"mkfs.vfat-F32"${eMMC_DEVICE}p1"mkfs.ext4"${eMMC_DEVICE}p2"fdisk-l"$eMMC_DEVICE"
copy_net_boot_to_qspi.sh

把nfs里的z8_boot/BOOT.BIN 拷贝qspiFlash

#!/bin/shecho"##############################################"echo"########## COPY BOOT TO Flash QSPI #########"echo"##############################################"echo""boot=/opt/z8_boot/BOOT.BINif[!-f${boot}];thenecho"ERROR:${boot}file does not exist!"exit1fiecho"Erase partition /dev/mtd0"flash_erase /dev/mtd000flashcp${boot}/dev/mtd0echo"########## Complete ##########"echo"##############################################"

第1步, 用vitis把BOOT.bin 烧录到SpiFlash

这里的BOOT.bin和zynq_fsbl.elf用的是petalinux工程中,用petalinux-build生成的

拷贝一份文件到windows里

cdD:\home\wpf\workspace\output\z82_20260212_outputscp-rwpf@192.168.3.4:/home/wpf/workspace/nfs/output/z82_20260212_output ./ls目录: D:\home\wpf\workspace\output\z82_20260212_output Mode LastWriteTime Length Name ---- ------------- ------ ---- -a----2026/3/3117:06848028BOOT.BIN -a----2026/3/3117:062915boot.scr -a----2026/3/3117:064045674system.bit -a----2026/3/3117:0621501system.dtb -a----2026/3/3117:063617968zImage -a----2026/3/3117:06551764zynq_fsbl.elf
在vitis操作

通过bat脚本操作
zynq_qspi_program_flash.bat
@echo offcd/d D:\Xilinx\Vitis\2020.2\bin program_flash ^-fD:\home\wpf\workspace\output\z82_20260325_output\BOOT.BIN ^-offset0^-flash_typeqspi-x4-single ^-fsblD:\home\wpf\workspace\output\z82_20260325_output\zynq_fsbl.elf ^-blank_check^-verify^-cabletypexilinx_tcf url TCP:127.0.0.1:3121 pause
执行脚本
PS D:\home>.\zynq_qspi_program_flash.bat ****** Xilinx Program Flash ****** Program Flash v2020.2(64-bit)**** SW Build3064766on Wed Nov1809:12:45 MST2020** Copyright1986-2020 Xilinx, Inc. All Rights Reserved. WARNING: Failed to connect to hw_server at TCP:127.0.0.1:3121 Attempting to launch hw_server at TCP:127.0.0.1:3121 Connected to hw_server @ TCP:127.0.0.1:3121 Available targets and devices: Target0:jsn-JTAG-SMT2-C305BBD6ABCD Device0: jsn-JTAG-SMT2-C305BBD6ABCD-4ba00477-0 Retrieving Flash info... Initialization done, programming the memory Using default mini u-boot imagefile- D:/Xilinx/Vitis/2020.2/data\xicom\cfgmem\uboot\zynq_qspi_x4_single.bin=====mrd->addr=0xF800025C,data=0x00000000=====BOOT_MODE REG=0x00000000 Downloading FSBL... Running FSBL... Finished running FSBL.=====mrd->addr=0xF8000110,data=0x000FA220=====READ: ARM_PLL_CFG(0xF8000110)=0x000FA220=====mrd->addr=0xF8000100,data=0x00028008=====READ: ARM_PLL_CTRL(0xF8000100)=0x00028008=====mrd->addr=0xF8000120,data=0x1F000200=====READ: ARM_CLK_CTRL(0xF8000120)=0x1F000200=====mrd->addr=0xF8000118,data=0x001452C0=====READ: IO_PLL_CFG(0xF8000118)=0x001452C0=====mrd->addr=0xF8000108,data=0x0001E008=====READ: IO_PLL_CTRL(0xF8000108)=0x0001E008 Info: Remapping 256KB of on-chip-memory RAM memory to 0xFFFC0000.=====mrd->addr=0xF8000008,data=0x00000000==========mwr->addr=0xF8000008,data=0x0000DF0D=====MASKWRITE:addr=0xF8000008,mask=0x0000FFFF,newData=0x0000DF0D=====mwr->addr=0xF8000910,data=0x000001FF==========mrd->addr=0xF8000004,data=0x00000000==========mwr->addr=0xF8000004,data=0x0000767B=====MASKWRITE:addr=0xF8000004,mask=0x0000FFFF,newData=0x0000767B U-Boot2020.01-00107-g4a29a62(Oct132020-16:46:21 -0600)Model: Zynq CSE QSPI SINGLE Board DRAM:256KiB WARNING: Caches not enabled In: dcc Out: dcc Err: dcc Zynq>sf probe000Warning: SPI speed fallback to100kHz SF: Detected w25q32 with page size256Bytes, erase size64KiB, total4MiB Zynq>Sector size=65536. f probe000Performing Erase Operation... sf erase0D0000 SF:851968bytes @ 0x0 Erased: OK Zynq>Erase Operation successful. INFO:[Xicom50-44]Elapsedtime=3sec. Performing Blank Check Operation...0%...sfreadFFFC0000010000Total of61596byte(s)were the same Zynq>INFO:[Xicom50-44]Elapsedtime=5sec. Verify Operation successful. Flash Operation Successful

第2步, SPI模式启动,进入u-boot

U-Boot2020.01(Apr242025- 00:46:36 +0000)CPU: Zynq 7z020 Silicon: v3.1 DRAM: ECC disabled1GiB Flash:0Bytes NAND:0MiB MMC: mmc@e0100000:0, mmc@e0101000:1Loading Environment from SPI Flash... SF: Detected w25q32 with page size256Bytes, erase size4KiB, total4MiB OK In: serial@e0000000 Out: serial@e0000000 Err: serial@e0000000 Net: ZYNQ GEM: e000b000, mdio bus e000b000, phyaddr -1, interface rgmii-id Warning: ethernet@e000b000 MAC addresses don't match: AddressinDT is 00:0a:35:00:1e:53 Addressinenvironment is 00:0a:35:00:1e:56 eth0: ethernet@e000b000 ZYNQ GEM: e000c000, mdio bus e000c000, phyaddr -1, interface gmii Could not get PHYforeth1: addr-1Hit any key to stop autoboot:0Zynq>

第3步, tftp下载必要文件并挂载nfs启动

setenv ipaddr192.168.3.211 setenv serverip192.168.3.4 setenv gatewayip192.168.3.1 setenv netmask255.255.255.0 setenv bootargs"console=ttyPS0,115200 root=/dev/nfs rw nfsroot=192.168.3.4:/home/wpf/workspace/nfs/z8_rootfs,nfsvers=3 ip=192.168.3.211:192.168.3.4:192.168.3.1:255.255.255.0::eth0:off"tftpboot 0x00200000 zImage tftpboot 0x00100000 system.dtb tftpboot 0x00800000 system.bit fpga loadb00x00800000$filesize;bootz 0x00200000 - 0x00100000

第4步 emmc分区

/opt/image/emmc_partition.sh

第5步 拷贝文件到emmc

把 /opt/z8_boot/* 拷贝到 emmc第1分区

cp/opt/z8_boot/* /media/sd-mmcblk1p1/

把根文件系统解压到emmc第2分区

在板子上解压(极慢可行)

tar-zxvf/opt/z8_root_fs/z8_rootfs_clean.tar.gz-C/media/sd-mmcblk1p2/sync

拷贝emmc第2分区的优化方案

制作 p2_rootfs.img镜像直接 dd全量写入emmc第二个分区

p2_rootfs.img的制作(PC上)
# 1. 创建空镜像mkdir-p/home/wpf/workspace/nfs/imagessudoddif=/dev/zeroof=/home/wpf/workspace/nfs/images/p2_rootfs.imgbs=1Mcount=2000# 2. 格式化sudomkfs.ext4 /home/wpf/workspace/nfs/images/p2_rootfs.img# 3. 挂载sudomkdir-p/mnt/p2_tmpsudomount-oloop /home/wpf/workspace/nfs/images/p2_rootfs.img /mnt/p2_tmp# 4. 复制rootfssudocp-a/home/wpf/workspace/nfs/z8_rootfs/. /mnt/p2_tmp/\--exclude=proc\--exclude=sys\--exclude=dev\--exclude=run# 5. 卸载sudoumount/mnt/p2_tmp# 6. 确认ls-lh/home/wpf/workspace/nfs/images/p2_rootfs.img# 检查制作的镜像init是否存在,两个文件都存在再继续。sudomount-oloop /home/wpf/workspace/nfs/images/p2_rootfs.img /mnt/p2_tmpls-la/mnt/p2_tmp/sbin/initls-la/mnt/p2_tmp/bin/shsudoumount/mnt/p2_tmp
nfs启动后在板子上执行
# 卸载p2umount/dev/mmcblk1p2# dd写入ddif=/opt/p2_rootfs.imgof=/dev/mmcblk1p2bs=4M# 挂载p2mount/dev/mmcblk1p2 /media/sd-mmcblk1p2ls/media/sd-mmcblk1p2sync# 重启reboot

第5步的一键脚本

copy_all_to_emmc.sh
#!/bin/shEMMC=/dev/mmcblk1umount${EMMC}p12>/dev/nullumount${EMMC}p22>/dev/null# 1. 分区fdisk"$EMMC"<<EOF o n p 1 +100M n p 2 w EOFblockdev--rereadpt$EMMC# 2. 格式化p1mkfs.vfat-F32${EMMC}p1# 3. dd写p2ddif=/opt/p2_rootfs.imgof=${EMMC}p2bs=4M# 4. 扩展p2 ext4到7GBresize2fs /dev/mmcblk1p2# 5. 挂载p1,拷贝boot文件mkdir-p/media/sd-mmcblk1p1mount${EMMC}p1 /media/sd-mmcblk1p1cp/opt/z8_boot/* /media/sd-mmcblk1p1/syncecho"success, restart"

第6步 在u-boot里更正bootargs

setenv bootargs'console=ttyPS0,115200 root=/dev/mmcblk1p2 rw rootwait rootfstype=ext4 earlyprintk'saveenv
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/20 3:46:34

深度解析:数据挖掘核心任务与实战应用场景

深度解析&#xff1a;数据挖掘核心任务与实战应用场景前言一、数据挖掘核心定义二、数据挖掘标准执行流程&#xff08;CRISP-DM 流程图&#xff09;流程节点说明&#xff1a;三、数据挖掘的主要任务&#xff08;6大核心分类&#xff09;1. 分类分析&#xff1a;预测已知类别2. …

作者头像 李华
网站建设 2026/5/20 3:46:33

ESP32防止函数被优化解决方案

ESP32防止函数被优化解决方案一、解决方案1、__attribute__((used))2、KEEP()2、WHOLE_ARCHIVE二、详解1、__attribute__((used))1.1、作用机制1.2、典型应用场景1.3、与 section 属性配合使用1.4、注意事项1.5、示例代码1.6、总结2、KEEP()2.1、 KEEP() 的作用2.2、KEEP() 的使…

作者头像 李华
网站建设 2026/5/20 3:46:35

从安装到实战:基于快马AI生成openclaw的网站内容监控应用项目

最近在做一个网站内容监控的小工具&#xff0c;尝试用openclaw框架来实现自动化采集和变更检测。这个项目从环境搭建到功能实现踩了不少坑&#xff0c;记录下完整过程给有类似需求的同学参考。 环境准备与openclaw安装 openclaw的安装其实挺简单&#xff0c;直接用pip就能搞定…

作者头像 李华
网站建设 2026/5/20 3:46:18

5个技巧让你在Linux上无缝管理OneNote笔记:P3X OneNote完全指南

5个技巧让你在Linux上无缝管理OneNote笔记&#xff1a;P3X OneNote完全指南 【免费下载链接】onenote &#x1f4da; Linux Electron Onenote - A Linux compatible version of OneNote 项目地址: https://gitcode.com/gh_mirrors/on/onenote Linux用户如何高效管理OneN…

作者头像 李华
网站建设 2026/5/19 17:38:24

一文聊清楚Redis主从复制原理

在技术领域&#xff0c;我们常常被那些闪耀的、可见的成果所吸引。今天&#xff0c;这个焦点无疑是大语言模型技术。它们的流畅对话、惊人的创造力&#xff0c;让我们得以一窥未来的轮廓。然而&#xff0c;作为在企业一线构建、部署和维护复杂系统的实践者&#xff0c;我们深知…

作者头像 李华
网站建设 2026/4/20 1:29:02

JAVA之路(11)——抽象类

当父类的某些方法需要声明&#xff0c;但又不确定如何实现时&#xff0c;就将其声明为抽象方法&#xff0c;包含抽象方法的类就是抽象类。1. 抽象方法用abstract修饰的方法&#xff0c;只有方法声明&#xff0c;没有方法体&#xff08;{}&#xff09;&#xff0c;语法格式&…

作者头像 李华