ZYNQ 程序固化与升级指南
文章目录
- 前言
- 一、ZYNQ 烧录文件的组成
- 1.1 裸机/裸跑程序
- 1.2 Linux 系统
- 二、核心概念:FSBL 是什么?
- 2.1 FSBL 的定义
- 2.2 FSBL 的核心职责
- 2.3 FSBL 的生成时机
- 三、更底层的起点:BootROM
- 3.1 BootROM 是什么?
- 3.2 BootROM 的核心职责
- 3.3 为什么需要 BootROM?
- 3.4 BootROM 与 FSBL 的分工
- 四、完整的程序加载流程
- 4.1 启动链路全景图
- 4.2 简化版流程图
- 五、常见问题与解答
- Q1:什么情况需要烧录 .elf?
- Q2:既然 .elf 被打包在 BOOT.bin,为什么还要每次固化 .elf?
- Q3:XSA文件不变,是不是就不需要更换 .elf?
- Q4:升级过程会自动校验吗?
- 六、升级文件的产生流程
- 6.1 完整的文件生成链路
- 6.2 不同场景下的升级文件
- 七、实践:一键烧录脚本
- 7.1 使用说明
- 7.2 运行日志
- 7.3 U-Boot 命令详解
- 八、总结
- 附录:常用 Flash 类型参数
前言
在 ZYNQ 开发过程中,程序如何固化、如何升级是每个开发者都会遇到的问题。本文将以问答形式,系统梳理 ZYNQ 程序烧录相关的核心知识点,帮助你从原理到实践全面掌握。
一、ZYNQ 烧录文件的组成
1.1 裸机/裸跑程序
ZYNQ 的烧录文件通常打包成一个BOOT.bin文件,包含三个核心部分:
| 组成部分 | 文件格式 | 作用 |
|---|---|---|
| FSBL | .elf | 第一阶段引导加载程序,初始化PS端硬件 |
| 硬件逻辑 | .bit | 配置FPGA逻辑电路 |
| 用户程序 | .elf | 在ARM上运行的应用程序 |
这三部分按照FSBL → BIT → ELF的顺序打包成 BOOT.bin,顺序错误会导致启动失败。
1.2 Linux 系统
Linux 系统的启动文件更为复杂,通常包含:
- BOOT.bin:FSBL + .bit + U-Boot
- uImage:Linux内核镜像
- devicetree.dtb:硬件描述文件
- uramdisk.image.gz:根文件系统
二、核心概念:FSBL 是什么?
2.1 FSBL 的定义
FSBL是First Stage Boot Loader(第一阶段引导加载程序)的缩写。简单理解:ZYNQ 上电后,ARM 核心执行的第一段用户程序就是 FSBL。
2.2 FSBL 的核心职责
| 职责 | 具体内容 |
|---|---|
| 初始化PS端 | 配置ARM核心、DDR内存、时钟、中断等 |
| 加载PL端 | 把.bit文件配置到FPGA逻辑区域 |
| 加载用户程序 | 从Flash读取程序到DDR,然后跳转执行 |
| 支持安全启动 | 可选:验证镜像签名、解密等 |
2.3 FSBL 的生成时机
FSBL 是在Vitis(旧称 SDK)中生成的,流程如下:
text
Vivado硬件设计 → 导出XSA文件 → Vitis创建FSBL工程 → 编译生成fsbl.elf关键点:只要 Vivado 硬件设计变了(PS配置、DDR参数、引脚分配等),就必须重新生成 FSBL。
三、更底层的起点:BootROM
3.1 BootROM 是什么?
BootROM是 ZYNQ 芯片内部固化、不可修改的一段只读代码,位于芯片的 ROM 中。它是 ZYNQ 上电后执行的第一段代码。
可以把它理解为芯片的“硬件出厂设置”——类似电脑主板的 BIOS,但更底层。
3.2 BootROM 的核心职责
| 职责 | 说明 |
|---|---|
| 初始化基本硬件 | 配置 CPU、时钟等最基础的功能 |
| 读取启动模式 | 检测拨码开关,确定从 QSPI/SD卡/JTAG 等介质启动 |
| 加载 FSBL | 从启动介质读取BOOT.bin头部,加载到芯片内部 RAM(OCM) |
| 验证并跳转 | 检查 CRC 校验和,通过后跳转到 FSBL 执行 |
3.3 为什么需要 BootROM?
没有 BootROM,ZYNQ 上电后不知道该怎么启动。
核心原因:要从外部 Flash 读取代码,必须先有代码来初始化 Flash 控制器——这是一个“先有鸡还是先有蛋”的问题。BootROM 作为芯片内部预置的代码,解决了这个悖论。
3.4 BootROM 与 FSBL 的分工
| BootROM | FSBL | |
|---|---|---|
| 位置 | 芯片内部 ROM(固化) | 外部 Flash(可更新) |
| 是否可修改 | ❌ 不可修改 | ✅ 可以修改 |
| 主要任务 | 加载 FSBL | 初始化 DDR、配置 PL、加载用户程序 |
| 对开发者的影响 | 只需遵守其格式要求 | 需要根据硬件生成 |
一句话总结:BootROM 负责找到并加载 FSBL,然后就把控制权交出去了。开发者无需修改它,只需要按照它的要求打包 BOOT.bin 即可。
四、完整的程序加载流程
4.1 启动链路全景图
┌─────────────────────────────────────────────────────────────┐ │ 1. 上电复位 │ └─────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────┐ │ 2. BootROM(芯片内部固定,不可修改) │ │ - 初始化最基本硬件(CPU、时钟等) │ │ - 读取启动模式拨码开关(QSPI/SD卡/JTAG) │ │ - 从启动介质读取 BOOT.bin 头部 │ │ - 验证 Header 的 CRC 校验和 │ │ - 将 FSBL 加载到 OCM(芯片内部 RAM) │ │ - 跳转到 FSBL │ └─────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────┐ │ 3. FSBL(存储在 Flash 中,用户可以修改) │ │ - 初始化 DDR 内存 │ │ - 配置 PL(加载 .bit 文件到 FPGA) │ │ - 从 Flash 读取用户程序到 DDR │ │ - 验证分区校验和 │ │ - 跳转到用户程序 │ └─────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────┐ │ 4. 用户应用程序 │ │ - 裸机程序:直接运行 │ │ - Linux:运行 U-Boot → 加载内核 → 挂载文件系统 │ └─────────────────────────────────────────────────────────────┘4.2 简化版流程图
上电复位 ↓ ┌─────────────────────────────────────────┐ │ BootROM(芯片固化,不可修改) │ │ 读取启动模式 → 加载FSBL → 验证 → 跳转 │ └─────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────┐ │ FSBL(可更新) │ │ 初始化DDR → 配置PL → 加载用户程序 → 跳转 │ └─────────────────────────────────────────┘ ↓ 用户应用程序五、常见问题与解答
Q1:什么情况需要烧录 .elf?
答案:FSBL(.elf文件)变了,或者 Flash 里没有 FSBL 时才需要。
| 情况 | 是否需要烧录.elf |
|---|---|
| Flash是空白的(第一次烧录) | ✅ 必须 |
| Vivado硬件设计变了 | ✅ 必须 |
| 只改了C代码(app.elf) | ❌ 不需要 |
| 只改了PL逻辑(.bit) | ❌ 通常不需要 |
| 量产时升级固件 | ❌ 不需要 |
Q2:既然 .elf 被打包在 BOOT.bin,为什么还要每次固化 .elf?
这是一个很容易混淆的问题。关键在于:烧录时指定的-fsbl参数,和打包在BOOT.bin里的 FSBL,是两个不同用途的 FSBL。
| 烧录工具使用的FSBL | 打包在BOOT.bin里的FSBL | |
|---|---|---|
| 存放位置 | 电脑硬盘上的.elf文件 | BOOT.bin镜像内部 |
| 运行时间 | 烧录过程中临时运行 | 正常启动时运行 |
| 核心任务 | 为烧录工具提供运行环境 | 初始化系统并启动应用 |
| 是否需要频繁更新 | 不需要 | 看硬件是否变化 |
通俗理解:
- 烧录时的FSBL = U盘启动盘(制作一次可反复使用)
- BOOT.bin里的FSBL = C盘里的系统引导程序(随系统更新而变化)
Q3:XSA文件不变,是不是就不需要更换 .elf?
是的,完全正确。
只要.xsa文件(硬件平台描述文件)没有变化,用于烧录的fsbl.elf就完全不需要更换。
日常固件升级时,你只需要替换BOOT.bin,fsbl.elf可以视为一个固定不变的烧录“驱动”。
Q4:升级过程会自动校验吗?
是的,升级过程会自动进行校验。
校验分为两个层面:
- 烧录过程校验(
program_flash工具):- 使用
-verify选项,写入后自动读取Flash内容并比对
- 使用
- 启动过程校验(BOOT.bin内部机制):
- BootROM检查Header的CRC校验和
- FSBL检查每个分区的校验和
建议:烧录命令中始终添加-verify选项,确保写入数据的完整性。
六、升级文件的产生流程
6.1 完整的文件生成链路
text
Vivado硬件设计 ↓ 导出 XSA文件(硬件平台描述) ↓ Vitis创建工程 FSBL工程 → 编译 → fsbl.elf ↓ 应用工程 → 编译 → app.elf ↓ Boot Image打包工具(bootgen) ↓ BOOT.bin(最终烧录文件)6.2 不同场景下的升级文件
| 升级场景 | 需要替换的文件 | 是否需要换fsbl.elf |
|---|---|---|
| 应用程序更新 | BOOT.bin | 否 |
| FPGA逻辑更新 | BOOT.bin(包含新.bit) | 否(除非接口变化) |
| 硬件配置变化 | BOOT.bin + fsbl.elf | 是 |
| 首次烧录空白板 | BOOT.bin + fsbl.elf | 是 |
七、实践:一键烧录脚本
以下是一个带详细打印信息的烧录脚本,将所需文件放在同一文件夹,双击即可完成升级:
@echo off chcp65001>nul title Zynq QSPI Flash 烧录工具 color 0Aecho========================================echoZynq QSPI Flash 一键烧录脚本echo========================================echo. :: 设置Xilinx工具路径(请根据实际安装路径修改)setPATH_XILINX=C:\Softwares\Xilinx\Vitis\2021.1\bin :: 检查工具路径是否存在ifnot exist"%PATH_XILINX%\program_flash"(echo[错误]找不到 program_flashecho请检查路径: %PATH_XILINX% pauseexit/b1)echo[1/5]Xilinx 工具路径检测: 通过 echo. :: 检查当前目录下的文件echo[2/5]检查烧录文件...setBIN_FILE=setELF_FILE=for%%fin(*.bin)do(setBIN_FILE=%%fecho找到 BIN 文件: %%f)for%%fin(*.elf)do(setELF_FILE=%%fecho找到 ELF 文件: %%f)echo. :: 检查 .bin 文件是否存在if"%BIN_FILE%"==""(echo[错误]当前文件夹下没有找到 .bin 文件echo请确保 BOOT.bin 或其它 .bin 文件在此目录下 pauseexit/b1)::==========新增:强制要求 .elf 文件==========if"%ELF_FILE%"==""(echo[错误]当前文件夹下没有找到 .elf 文件echo烧录空白 Flash 时必须提供 fsbl.elf 文件echo请将 fsbl.elf 复制到当前目录后重试 echo.echo提示:如果 Flash 中已有 FSBL 且无需更新,echo请手动移除本脚本中的 .elf 检查逻辑 pauseexit/b1)::============================================echo[3/5]文件校验通过echo将烧录 BIN: %BIN_FILE%echo使用 FSBL: %ELF_FILE% echo. :: 用户确认echo[4/5]请确认以下事项:echo1. 板卡已设置为 JTAG 模式echo2. 下载器已连接并上电echo3. 即将烧录文件: %BIN_FILE% echo.set/pconfirm="确认继续烧录?(Y/N): "if/i not"%confirm%"=="Y"(echo用户取消烧录 pauseexit/b0):: 开始烧录 echo.echo[5/5]正在烧录 QSPI Flash...echo请勿断开电源或 USB 连接... echo. call"%PATH_XILINX%\program_flash"-f"%BIN_FILE%"-offset0-flash_typeqspi-x4-single-fsbl"%ELF_FILE%"-verify:: 检查结果if%errorlevel% neq0(echo.echo[错误]烧录失败!错误代码: %errorlevel%echo请检查:echo- 下载器是否连接正常echo- 板卡是否上电echo- flash_type 参数是否正确 pauseexit/b %errorlevel%):: 烧录成功 echo.echo========================================echo烧录成功完成!echo========================================echo.echo下一步操作:echo1. 断开电源echo2. 将板卡启动模式切换到 QSPIecho3. 重新上电,程序应从 Flash 启动 echo. pause7.1 使用说明
- 将上述脚本保存为
program_qspi.bat - 修改脚本中的
PATH_XILINX为你的实际安装路径 - 将
BOOT.bin和fsbl.elf放在同一文件夹
- 板卡设置 JTAG 模式,连接下载器并上电
- 双击
program_qspi.bat即可完成烧录
7.2 运行日志
7.3 U-Boot 命令详解
以下是嵌入式开发中最核心、最常用的 U-Boot 命令详解:
sf probe
格式:sf probe <总线编号> [<时钟频率>] [<SPI模式>]
总线编号:SPI 控制器的编号(通常是 0)
时钟频率:设置 SPI 时钟频率(Hz),
0表示使用 Flash 芯片的默认时钟频率(通常是 40-50 MHz)SPI 模式:SPI 工作模式(0-3)
模式 说明 0CPOL=0, CPHA=0(最常用) 1CPOL=0, CPHA=1 2CPOL=1, CPHA=0 3CPOL=1, CPHA=1
说明:U-Boot 中用于初始化和探测 SPI Flash 设备的命令。这是执行任何 Flash 操作(读、写、擦除)前必须首先运行的命令。
sf erase
- 格式:sf erase <偏移地址> <长度>
- 偏移地址:Flash 中的起始位置(十六进制)
- 长度:要擦除的字节数(十六进制)
- 说明:U-Boot 中用于擦除 SPI Flash 数据的命令。由于 Flash 的物理特性,必须先擦除才能写入数据。
- 格式:sf erase <偏移地址> <长度>
sf write
- 格式:sf write <内存地址> <Flash偏移地址> <长度>
- 内存地址:数据在 DDR 内存中的源地址
- Flash偏移地址:写入 Flash 的目标起始地址
- 长度:要写入的字节数(十六进制)
- 说明:U-Boot 中用于将数据写入 SPI Flash的命令。在执行此命令前,必须先执行
sf probe初始化 Flash,并且目标区域必须已经被擦除。
- 格式:sf write <内存地址> <Flash偏移地址> <长度>
sf read
- 格式:sf read <内存地址> <Flash偏移地址> <长度>
- 内存地址:数据要写入的 DDR 内存目标地址
- Flash偏移地址:Flash 中读取的起始位置
- 长度:要读取的字节数(十六进制)
- 说明:U-Boot 中用于从 SPI Flash 读取数据到内存的命令。这是验证烧录结果、备份数据、调试系统时最常用的命令之一。
- 格式:sf read <内存地址> <Flash偏移地址> <长度>
八、总结
| 知识点 | 核心要点 |
|---|---|
| BOOT.bin组成 | FSBL + .bit + app.elf(顺序固定) |
| BootROM的作用 | 芯片内部固化的引导代码,负责加载FSBL |
| FSBL的作用 | 上电后第一段用户程序,初始化硬件、加载FPGA、启动应用 |
| FSBL生成时机 | 在Vitis中从XSA文件编译生成 |
| 何时需要烧录.elf | XSA变化时,或首次烧录空白板 |
| 升级校验机制 | 烧录用-verify + BootROM/FSBL的CRC校验 |
| 日常升级操作 | 只需替换BOOT.bin,fsbl.elf固定不变 |
附录:常用 Flash 类型参数
| Flash类型 | program_flash参数 |
|---|---|
| 单路QSPI(4线) | qspi-x4-single(最常用) |
| 双路QSPI(2线) | qspi-x2-single |
| 双片并联(8线) | qspi-x8-dual_parallel |
本文基于 ZYNQ 7000 系列编写,UltraScale+ 系列原理相同,具体参数请参考对应文档。
