3. Zynq启动与PS端最小系统
Zynq-7000 的启动过程与纯 FPGA 或纯 ARM 处理器都不同:它是一颗把 PS(Processing System,双核 Cortex-A9 + 存储控制器 + 外设)和 PL(Programmable Logic)集成在同一芯片上的 SoC。上电后,PS 是"主控者",PL 默认处于未配置状态,必须由 PS 主动加载比特流才能工作。因此理解 Zynq 的启动链,是搭建任何 PS 端最小系统的前提。
一、启动阶段划分:从 BootROM 到操作系统
Zynq 的启动是严格分阶段的,每一级只负责把下一级搬进内存并跳转过去。上电复位后,芯片内部固化的 BootROM(约 128 KB,不可修改)首先运行,它根据 MIO[5:2] 引脚(启动模式选择)判断从哪里读取 Boot Header:QSPI Flash、NAND、NOR、SD 卡或 JTAG。BootROM 只做一件事——把 Boot Header 和 FSBL 从所选介质搬到 OCM(On-Chip Memory,256 KB)中,然后跳转到 FSBL 入口。
FSBL(First Stage Boot Loader)是用户可修改的第一段代码,由 Xilinx 提供源码(fsbl 工程),通常基于官方模板修改。它承担四项关键任务:初始化 DDR 控制器与时钟、配置 PL(若启动镜像中包含 bitstream)、加载第二阶段引导程序(U-Boot 或裸机应用)、最后跳转执行。FSBL 运行在 OCM 中,因此其代码体积必须控制在 192 KB 以内(OCM 中留给 FSBL 的部分)。
第二阶段通常是 U-Boot(用于 Linux 启动)或直接是裸机应用(bare-metal)。U-Boot 负责加载 Linux 内核、设备树和根文件系统,最终把控制权交给内核。整个链条可以概括为:BootROM → FSBL → U-Boot → Linux Kernel,裸机场景则简化为 BootROM → FSBL → 应用。
二、FSBL 的关键配置与常见问题
FSBL 工程在 Vitis(或旧版 SDK)中创建时,会自动生成 fsbl_debug.h、fsbl.h 等文件。真正需要关注的是 fsbl.h 中的几个宏:FSBL_DEBUG_INFO 打开后会在串口输出详细日志,调试阶段建议开启;FSBL_DEBUG_DETAILED 更啰嗦,仅在定位 DDR 初始化失败时使用。FSBL 的 DDR 初始化参数来自 Vivado 导出的 ps7_init.c/h,这些文件由 PS 配置界面中的 DDR 型号、位宽、时序参数自动生成,因此 DDR 配置必须在 Vivado 中正确设置,否则 FSBL 会在 DDR 初始化处卡死。
一个典型现象是:串口只打印 BootROM 的 "Xilinx First Stage Boot Loader" 后就没有下文。这通常意味着 FSBL 在 DDR 初始化或 PL 配置阶段失败。排查顺序是:先确认 ps7_init 是否与硬件匹配,再检查启动镜像(BOOT.bin)中是否包含了正确的 bitstream,最后确认 FSBL 是否被正确打包进 BOOT.bin。
三、设备树:硬件描述与内核的桥梁
设备树(Device Tree)是 Linux 内核识别硬件的唯一依据。Zynq 的设备树源文件(.dts/.dtsi)描述了 PS 端所有外设的基地址、中断号、时钟、引脚复用等信息。对于 PS 端最小系统,关键节点包括:uart1(串口)、gem0(以太网)、sdhci0(SD 卡)、qspi(Flash)、memory(DDR 大小)。
设备树中 chosen 节点的 bootargs 决定了内核启动参数,例如 console=ttyPS0,115200 root=/dev/mmcblk0p2 rw rootwait 表示串口控制台、根文件系统在 SD 卡第二分区。如果串口没有输出,首先要检查 bootargs 中的 console 设备名是否与设备树中 UART 节点一致。
四、U-Boot 与启动镜像打包
U-Boot 在 Zynq 上通常使用 xilinx_zynq 配置。它从 FSBL 手中接过控制权后,会读取环境变量(保存在 QSPI 或 SD 卡中),执行 bootcmd。典型流程是:从 FAT 分区加载 image.ub(FIT 镜像,包含内核+设备树)或分别加载 zImage 与 system.dtb,然后 bootm 启动。
启动镜像 BOOT.bin 由 Bootgen 工具打包,输入是一个 .bif 文件,内容形如:
the_ROM_image:
{
[bootloader] fsbl.elf
system.bit
u-boot.elf
}
其中 [bootloader] 标记 FSBL 为第一阶段,system.bit 是 PL 比特流,u-boot.elf 是第二阶段。Bootgen 会按顺序把它们拼接成 BootROM 能识别的格式。注意:如果使用裸机应用,则把 u-boot.elf 替换为应用 elf 即可。
五、串口调试:观察启动链的窗口
PS 端最小系统调试几乎完全依赖串口。硬件上,UART1 通过 MIO48/49 引出,需在 Vivado 中使能并分配引脚。PC 端使用串口工具(如 PuTTY、minicom、screen)连接,参数固定为 115200-8-N-1。上电后应依次看到:BootROM 无输出(正常)、FSBL 打印版本与 DDR 初始化信息、U-Boot 打印版本与倒计时、内核打印启动日志。如果某一级没有输出,就说明问题出在该级或前一级。
FSBL_DEBUG_INFO,并在 U-Boot 中设置 bootdelay=3,这样可以在串口上看到完整的启动链日志,快速定位是 DDR、PL 配置还是内核加载的问题。六、裸机运行环境
如果不需要 Linux,可以直接用 FSBL 加载裸机应用。裸机应用在 Vitis 中创建,链接脚本通常把代码放在 DDR 或 OCM 中。对于简单控制任务,可以只使用 OCM(256 KB),这样无需初始化 DDR,启动更快。裸机应用的入口是 main(),Xilinx 提供的 BSP 会初始化 UART、定时器等基础外设。串口打印使用 xil_printf(),它比标准 printf 更轻量,适合资源受限场景。
无论 Linux 还是裸机,PS 端最小系统的核心都是:正确的启动模式引脚、匹配硬件的 FSBL、完整的 BOOT.bin、以及一个能观察启动过程的串口。把这四件事做对,Zynq 就能稳定地从上电走到应用入口。