Zynq FPGA UART程序固化完整流程文档
一、概述
本文档详细记录了将UART循环打印程序固化到Zynq FPGA开发板的完整流程。通过FSBL(First Stage Boot Loader)引导程序,实现上电后自动运行UART打印程序。
二、固化前准备
2.1 硬件准备
- Zynq开发板(如ZedBoard、ZCU102等)
- USB-JTAG下载器
- USB转串口线
- 存储介质(SD卡或QSPI Flash)
- 电源适配器
2.2 软件准备
- Vivado Design Suite(包含Vitis)
- 串口调试助手(如Putty、SecureCRT)
- 硬件描述文件(.xsa文件)
三、文件系统结构
3.1 所需文件清单
text
固化项目/ ├── fsbl_platform/ # FSBL平台工程 ├── uart_app/ # UART应用程序工程 ├── hardware/ │ └── system.bit # 硬件比特流文件 └── output/ ├── fsbl.elf # FSBL引导程序 ├── uart_app.elf # UART应用程序 ├── system.bit # 硬件比特流 ├── boot.bif # 引导镜像描述文件 └── boot.bin # 最终固化文件
3.2 文件说明
| 文件名 | 后缀 | 作用 | 来源 |
|---|---|---|---|
| fsbl.elf | .elf | 第一阶段引导程序 | Vitis生成 |
| uart_app.elf | .elf | UART应用程序 | Vitis编译 |
| system.bit | .bit | 硬件配置比特流 | Vivado导出 |
| boot.bif | .bif | 引导镜像描述文件 | 手工创建 |
| boot.bin | .bin | 最终固化文件 | bootgen生成 |
四、详细操作步骤
4.1 步骤1:创建FSBL引导程序
4.1.1 在Vitis中创建Platform Project
- 打开Vitis软件
- File → New → Platform Project
- 输入项目名称:
fsbl_platform - 选择硬件描述文件(.xsa文件)
- 点击Finish
4.1.2 编译FSBL
- 在Project Explorer中右键点击
fsbl_platform - 选择Build Project
- 等待编译完成
4.1.3 获取fsbl.elf文件
编译完成后,文件位于:
text
fsbl_platform/export/fsbl_platform/sw/fsbl_platform/boot/fsbl.elf
4.2 步骤2:创建UART应用程序
4.2.1 创建Application Project
- File → New → Application Project
- 项目名称:
uart_app - 选择平台:
fsbl_platform - 选择模板:Hello World(自动生成main.c)
- 点击Finish
4.2.2 替换代码
- 打开
uart_app/src/main.c - 删除原有代码,粘贴以下UART测试代码:
c
#include <stdio.h> #include "xil_printf.h" #include "xil_types.h" #include "xparameters.h" #include "xuartps.h" // 全局变量 XUartPs UartInst; u8 data_buffer[64]; u32 counter = 0; // 初始化UART int init_uart() { XUartPs_Config *Config; int Status; // 查找UART配置 Config = XUartPs_LookupConfig(XPAR_PS7_UART_0_DEVICE_ID); if (Config == NULL) { return XST_FAILURE; } // 初始化UART Status = XUartPs_CfgInitialize(&UartInst, Config, Config->BaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } // 设置波特率115200 XUartPs_SetBaudRate(&UartInst, 115200); // 自检 Status = XUartPs_SelfTest(&UartInst); if (Status != XST_SUCCESS) { return XST_FAILURE; } return XST_SUCCESS; } // 主函数 int main() { int i; // 初始化UART if (init_uart() != XST_SUCCESS) { return -1; } // 发送启动信息 XUartPs_Send(&UartInst, (u8*)"\r\n=== UART Test Application ===\r\n", 34); XUartPs_Send(&UartInst, (u8*)"Starting continuous transmission...\r\n", 39); // 主循环 while (1) { // 填充数据 for (i = 0; i < 64; i++) { data_buffer[i] = (counter + i) & 0xFF; } counter++; // 发送数据 XUartPs_Send(&UartInst, data_buffer, 64); // 发送换行 XUartPs_Send(&UartInst, (u8*)"\r\n", 2); // 延时约1秒 for (i = 0; i < 10000000; i++); } return 0; }
4.2.3 验证链接地址
- 打开
uart_app/lscript.ld链接脚本 - 确认关键配置:ldMEMORY { ps7_ddr_0 : ORIGIN = 0x00100000, LENGTH = 0x1FF00000 /* ... */ } .text : { *(.text) } > ps7_ddr_0 /* 确保.text段在DDR中 */
- 关键点:应用程序起始地址必须是 0x00100000
4.2.4 编译应用程序
- 右键点击
uart_app项目 - 选择 Build Project
- 验证编译成功(无错误)
4.3 步骤3:验证应用程序地址
4.3.1 方法一:使用objdump命令
bash
# 在Vitis Terminal中执行 arm-none-eabi-objdump -h uart_app.elf | grep ".text"
正确输出示例:
text
.text 00000500 00100000 00100000 00001000 2**2
关键检查:第三列(VMA)必须是 00100000
4.3.2 方法二:查看.map文件
- 打开
uart_app/Debug/uart_app.map - 搜索
.text查看地址
4.4 步骤4:生成BOOT.BIN文件
4.4.1 准备三个必需文件
- fsbl.elf - 从FSBL项目复制
- system.bit - 从Vivado硬件工程导出
- uart_app.elf - 从UART项目编译得到
将三个文件复制到同一目录(如 output/)
4.4.2 创建BIF描述文件
在 output/ 目录下创建 boot.bif 文件,内容:
text
the_ROM_image: { [bootloader] fsbl.elf system.bit uart_app.elf }
4.4.3 生成BOOT.BIN
方法A:使用Vitis GUI
- 菜单栏:Xilinx → Create Boot Image
- 点击 Add 依次添加:
fsbl.elf(类型选择bootloader)system.bituart_app.elf
- 设置输出路径
- 点击 Create Image
方法B:使用命令行
bash
cd output bootgen -image boot.bif -arch zynq -o boot.bin -w on
4.4.4 验证生成结果
- 生成的文件:
boot.bin - 文件大小:约3-5MB
- 如果失败,检查文件顺序和类型设置
4.5 步骤5:烧写到存储设备
4.5.1 方法一:SD卡启动(测试用)
- 格式化SD卡为FAT32格式
- 复制boot.bin到SD卡根目录
- 设置开发板为SD卡启动模式(跳线设置)
- 插入SD卡,连接串口线
- 上电启动
4.5.2 方法二:QSPI Flash固化(永久)
- 连接JTAG和串口线
- 打开Vivado → Hardware Manager
- Open Target → Auto Connect
- 右键开发板 → Add Configuration Memory Device
- 选择Flash型号(常见:
mt25ql256aba) - 选择
boot.bin文件 - 点击 Program,等待完成
- 重要:烧写完成后
- 断开JTAG
- 关闭电源
- 设置为QSPI启动模式
- 重新上电
4.6 步骤6:测试验证
4.6.1 串口设置
- 串口软件:Putty/SecureCRT
- 波特率:115200
- 数据位:8
- 停止位:1
- 校验位:None
- 流控制:None
4.6.2 预期输出
上电后串口应输出:
text
=== UART Test Application === Starting continuous transmission... [然后是连续的十六进制数据]
4.6.3 成功标志
- 上电后自动运行,无需JTAG
- 串口连续输出数据
- 断电重启后仍然正常运行
五、故障排除
5.1 常见问题及解决
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无串口输出 | 波特率不匹配 | 检查串口设置为115200 |
| 卡在FSBL阶段 | 应用程序地址错误 | 验证.elf文件起始地址为0x00100000 |
| 程序不运行 | BIN文件生成顺序错误 | 确保顺序:fsbl → bit → app |
| 启动失败 | 启动模式设置错误 | 检查开发板跳线设置 |
| 部分运行后停止 | 堆栈大小不足 | 修改链接脚本增加堆栈空间 |
5.2 调试技巧
5.2.1 添加调试信息
在应用程序开头添加:
c
// 在main函数开始处 XUartPs_Send(&UartInst, (u8*)"App Started!\r\n", 14);
5.2.2 验证硬件连接
c
// 强制发送测试字符 volatile u32 *uart = (u32*)0xE0001000; *uart = 'A';
5.3 关键检查点清单
- FSBL编译成功(fsbl.elf存在)
- 应用程序编译成功(uart_app.elf存在)
- 应用程序起始地址为0x00100000
- boot.bif文件顺序正确
- boot.bin生成成功
- SD卡为FAT32格式
- boot.bin在SD卡根目录
- 开发板启动模式正确
- 串口波特率115200
- 串口线TX/RX连接正确
六、进阶配置
6.1 修改启动延时
在FSBL中可修改启动延时,给用户中断引导的机会:
c
// 在fsbl_main.c中添加 int timeout = 3; // 3秒延时 while (timeout-- > 0 && !CheckUartInput()) { fsbl_printf("Booting in %d seconds...\r\n", timeout); Delay(1000); }
6.2 多应用程序支持
可通过修改FSBL实现多应用程序选择:
c
// 根据按键选择不同应用 if (ReadBootPin() == 0) { // 启动UART测试程序 HandoffAddress = 0x00100000; } else { // 启动其他应用程序 HandoffAddress = 0x00200000; }
6.3 安全性增强
- 添加应用程序校验和验证
- 实现安全启动流程
- 加密固件保护
七、注意事项
7.1 重要提醒
- 不要修改FSBL的跳转逻辑,除非你完全理解其工作原理
- 应用程序不能使用地址0x00000000-0x000FFFFF区域(FSBL使用)
- 固化前务必先用SD卡测试,确认程序能正常运行
- QSPI Flash烧写后必须断电重启,不能热复位
7.2 文件管理建议
- 保留每个版本的.elf和.bin文件
- 记录每次固化的配置参数
- 使用版本控制系统管理源码
7.3 性能优化
- 减少启动时间:优化应用程序初始化代码
- 减小固件大小:移除不必要的库和代码
- 提高可靠性:添加看门狗和错误恢复机制
八、附录
8.1 相关命令参考
bash
# 查看ELF文件信息 arm-none-eabi-objdump -h file.elf arm-none-eabi-readelf -a file.elf # 生成反汇编代码 arm-none-eabi-objdump -d file.elf > disassembly.txt # 查看文件大小 arm-none-eabi-size file.elf
8.2 常用内存地址
| 地址范围 | 用途 | 说明 |
|---|---|---|
| 0x00000000-0x0003FFFF | FSBL区域 | 引导程序使用 |
| 0x00100000-0x001FFFFF | 应用程序区 | 主程序放置位置 |
| 0xE0000000-0xE00FFFFF | 外设寄存器 | UART、GPIO等 |
8.3 开发板启动模式设置
| 开发板 | SD卡模式 | QSPI模式 | JTAG模式 |
|---|---|---|---|
| ZedBoard | MIO5-0: 111010 | MIO5-0: 000010 | MIO5-0: 111111 |
| ZCU102 | SW6: 000010 | SW6: 001010 | SW6: 111111 |
| PYNQ-Z2 | J12: SD模式 | J12: QSPI模式 | J12: JTAG模式 |
文档版本: 1.0
最后更新: 2026年01月
适用平台: Xilinx Zynq-7000系列
注意事项: 本流程基于Vitis 2019.2版本,其他版本可能略有差异