ZYNQ 程序固化与升级指南

文章目录

    • 前言
    • [一、ZYNQ 烧录文件的组成](#一、ZYNQ 烧录文件的组成)
      • [1.1 裸机/裸跑程序](#1.1 裸机/裸跑程序)
      • [1.2 Linux 系统](#1.2 Linux 系统)
    • [二、核心概念:FSBL 是什么?](#二、核心概念:FSBL 是什么?)
      • [2.1 FSBL 的定义](#2.1 FSBL 的定义)
      • [2.2 FSBL 的核心职责](#2.2 FSBL 的核心职责)
      • [2.3 FSBL 的生成时机](#2.3 FSBL 的生成时机)
    • 三、更底层的起点:BootROM
      • [3.1 BootROM 是什么?](#3.1 BootROM 是什么?)
      • [3.2 BootROM 的核心职责](#3.2 BootROM 的核心职责)
      • [3.3 为什么需要 BootROM?](#3.3 为什么需要 BootROM?)
      • [3.4 BootROM 与 FSBL 的分工](#3.4 BootROM 与 FSBL 的分工)
    • 四、完整的程序加载流程
      • [4.1 启动链路全景图](#4.1 启动链路全景图)
      • [4.2 简化版流程图](#4.2 简化版流程图)
    • 五、常见问题与解答
      • [Q1:什么情况需要烧录 .elf?](#Q1:什么情况需要烧录 .elf?)
      • [Q2:既然 .elf 被打包在 BOOT.bin,为什么还要每次固化 .elf?](#Q2:既然 .elf 被打包在 BOOT.bin,为什么还要每次固化 .elf?)
      • [Q3:XSA文件不变,是不是就不需要更换 .elf?](#Q3:XSA文件不变,是不是就不需要更换 .elf?)
      • Q4:升级过程会自动校验吗?
    • 六、升级文件的产生流程
      • [6.1 完整的文件生成链路](#6.1 完整的文件生成链路)
      • [6.2 不同场景下的升级文件](#6.2 不同场景下的升级文件)
    • 七、实践:一键烧录脚本
      • [7.1 使用说明](#7.1 使用说明)
      • [7.2 运行日志](#7.2 运行日志)
      • [7.3 U-Boot 命令详解](#7.3 U-Boot 命令详解)
    • 八、总结
    • [附录:常用 Flash 类型参数](#附录:常用 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 的定义

FSBLFirst 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.binfsbl.elf 可以视为一个固定不变的烧录"驱动"

Q4:升级过程会自动校验吗?

是的,升级过程会自动进行校验。

校验分为两个层面:

  1. 烧录过程校验program_flash 工具):
    • 使用 -verify 选项,写入后自动读取Flash内容并比对
  2. 启动过程校验 (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

七、实践:一键烧录脚本

以下是一个带详细打印信息的烧录脚本,将所需文件放在同一文件夹,双击即可完成升级:

bash 复制代码
@echo off
chcp 65001 > nul
title Zynq QSPI Flash 烧录工具
color 0A

echo ========================================
echo   Zynq QSPI Flash 一键烧录脚本
echo ========================================
echo.

:: 设置Xilinx工具路径(请根据实际安装路径修改)
set PATH_XILINX=C:\Softwares\Xilinx\Vitis\2021.1\bin

:: 检查工具路径是否存在
if not exist "%PATH_XILINX%\program_flash" (
    echo [错误] 找不到 program_flash
    echo 请检查路径: %PATH_XILINX%
    pause
    exit /b 1
)
echo [1/5] Xilinx 工具路径检测: 通过
echo.

:: 检查当前目录下的文件
echo [2/5] 检查烧录文件...
set BIN_FILE=
set ELF_FILE=

for %%f in (*.bin) do (
    set BIN_FILE=%%f
    echo       找到 BIN 文件: %%f
)
for %%f in (*.elf) do (
    set ELF_FILE=%%f
    echo       找到 ELF 文件: %%f
)
echo.

:: 检查 .bin 文件是否存在
if "%BIN_FILE%"=="" (
    echo [错误] 当前文件夹下没有找到 .bin 文件
    echo 请确保 BOOT.bin 或其它 .bin 文件在此目录下
    pause
    exit /b 1
)

:: ========== 新增:强制要求 .elf 文件 ==========
if "%ELF_FILE%"=="" (
    echo [错误] 当前文件夹下没有找到 .elf 文件
    echo 烧录空白 Flash 时必须提供 fsbl.elf 文件
    echo 请将 fsbl.elf 复制到当前目录后重试
    echo.
    echo 提示:如果 Flash 中已有 FSBL 且无需更新,
    echo       请手动移除本脚本中的 .elf 检查逻辑
    pause
    exit /b 1
)
:: ============================================

echo [3/5] 文件校验通过
echo       将烧录 BIN: %BIN_FILE%
echo       使用 FSBL: %ELF_FILE%
echo.

:: 用户确认
echo [4/5] 请确认以下事项:
echo       1. 板卡已设置为 JTAG 模式
echo       2. 下载器已连接并上电
echo       3. 即将烧录文件: %BIN_FILE%
echo.
set /p confirm="确认继续烧录?(Y/N): "
if /i not "%confirm%"=="Y" (
    echo 用户取消烧录
    pause
    exit /b 0
)

:: 开始烧录
echo.
echo [5/5] 正在烧录 QSPI Flash...
echo       请勿断开电源或 USB 连接...
echo.

call "%PATH_XILINX%\program_flash" -f "%BIN_FILE%" -offset 0 -flash_type qspi-x4-single -fsbl "%ELF_FILE%" -verify

:: 检查结果
if %errorlevel% neq 0 (
    echo.
    echo [错误] 烧录失败!错误代码: %errorlevel%
    echo       请检查:
    echo       - 下载器是否连接正常
    echo       - 板卡是否上电
    echo       - flash_type 参数是否正确
    pause
    exit /b %errorlevel%
)

:: 烧录成功
echo.
echo ========================================
echo   烧录成功完成!
echo ========================================
echo.
echo 下一步操作:
echo   1. 断开电源
echo   2. 将板卡启动模式切换到 QSPI
echo   3. 重新上电,程序应从 Flash 启动
echo.
pause

7.1 使用说明

  1. 将上述脚本保存为 program_qspi.bat
  2. 修改脚本中的 PATH_XILINX 为你的实际安装路径
  3. BOOT.binfsbl.elf 放在同一文件夹
  1. 板卡设置 JTAG 模式,连接下载器并上电
  2. 双击 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)

        模式 说明
        0 CPOL=0, CPHA=0(最常用)
        1 CPOL=0, CPHA=1
        2 CPOL=1, CPHA=0
        3 CPOL=1, CPHA=1
    • 说明:U-Boot 中用于初始化和探测 SPI Flash 设备 的命令。这是执行任何 Flash 操作(读、写、擦除)前必须首先运行的命令

  • sf erase

    • 格式:sf erase <偏移地址> <长度>
      • 偏移地址:Flash 中的起始位置(十六进制)
      • 长度:要擦除的字节数(十六进制)
    • 说明:U-Boot 中用于擦除 SPI Flash 数据的命令。由于 Flash 的物理特性,必须先擦除才能写入数据。
  • sf write

    • 格式:sf write <内存地址> <Flash偏移地址> <长度>
      • 内存地址:数据在 DDR 内存中的源地址
      • Flash偏移地址:写入 Flash 的目标起始地址
      • 长度:要写入的字节数(十六进制)
    • 说明:U-Boot 中用于将数据写入 SPI Flash 的命令。在执行此命令前,必须先执行 sf probe 初始化 Flash,并且目标区域必须已经被擦除。
  • sf read

    • 格式:sf read <内存地址> <Flash偏移地址> <长度>
      • 内存地址:数据要写入的 DDR 内存目标地址
      • Flash偏移地址:Flash 中读取的起始位置
      • 长度:要读取的字节数(十六进制)
    • 说明:U-Boot 中用于从 SPI 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+ 系列原理相同,具体参数请参考对应文档。

相关推荐
ALINX技术博客3 小时前
【黑金云课堂】FPGA技术教程:PLL锁相环实验和MIO应用
fpga开发·fpga
Byron Loong3 小时前
【常识】通俗易懂的讲CPU,GPU,MCU,FPGA,DSP的区别和特点
单片机·嵌入式硬件·fpga开发
gaoxcv1 天前
TDC相关的一些方法
fpga开发
我爱C编程1 天前
【3.4】双口RAM模块的FPGA实现
fpga开发·fpga·fft·双口ram
三万棵雪松1 天前
【嵌入式刷题硬件设计基础(一)】
fpga开发·嵌入式·硬件基础
扣脑壳的FPGAer1 天前
Xilinx远程更新之watchdog Timer1/ Timer2
fpga开发
ALINX技术博客1 天前
【黑金云课堂】FPGA技术教程Linux开发:Petalinux安装
linux·运维·fpga开发
豆包公子2 天前
虚拟机配置共享文件&烧录FPGA bit文件
fpga开发
c-u-r-ry302 天前
pll/mmcm输入时钟配置页面警告
经验分享·fpga开发