1. 这不是“教科书”,而是一份从焊锡烟味里熬出来的ZYNQ入门实录
你手头刚拆封的那块正点原子领航者开发板,板子背面还带着出厂时的防静电膜,USB线插在电脑上,Vitis软件界面弹出“Project Creation Wizard”——这时候最要命的不是报错,而是根本不知道该点哪个按钮、填哪行参数、为什么FSBL必须单独生成、image.ub和boot.bin到底谁先烧进SD卡、为什么Vitis里新建工程后连个hello world都跑不起来。我带过37个零基础学员做ZYNQ项目,90%的人卡在第一步:不是不会写代码,是根本没搞懂整个系统启动链路里每个文件扮演什么角色、谁依赖谁、烧写顺序错了会直接变砖。
这本指南不讲抽象理论,不堆砌Xilinx官方文档截图,只说我在正点原子领航者ZYNQ-7020开发板上亲手验证过的路径:从Windows 10环境装Vitis 2021.2(不是2019.2,也不是2023.1,选错版本连PS端ARM GCC都找不到),到用Vivado 2021.2导出硬件平台,再到Vitis里创建bare-metal和Linux双模式工程,最后把petalinux 2021.2生成的BOOT.BIN、image.ub、boot.scr三件套正确写入SD卡并成功启动。所有步骤我都拍了实机操作录屏,但这里只放最关键的决策点——比如为什么FSBL必须用Vitis新建而非直接复制模板、为什么system_top.xsa导出时勾选“Include bitstream”会导致后续petalinux build失败、为什么SD卡分区必须用fdisk而不是Windows磁盘管理器格式化。
关键词“正点原子”“领航者”“ZYNQ”“Vitis”“嵌入式”不是标签,是坐标:它指向一块真实存在的开发板(AXU15EGP系列兼容设计)、一个具体型号(Zynq-7020 SoC)、一套可复现的工具链(Vivado 2021.2 + Vitis 2021.2 + PetaLinux 2021.2)、以及一群被bootloader卡住三天的初学者。如果你刚买板子不到一周,还没碰过JTAG调试器;如果你看到“FSBL”“PMU Firmware”“ATF”这些缩写就头皮发紧;如果你试过网上教程却总在“Generating boot image”环节报错——那你需要的不是另一份PDF文档,而是一份带着焊锡味、示波器探头痕迹和SD卡反复重刷记录的实战日志。
2. 为什么必须放弃“先学Verilog再学ARM”的老路?ZYNQ本质是协同系统工程
2.1 ZYNQ不是FPGA加ARM的简单拼凑,而是硬件/软件强耦合的协同体
很多初学者误以为ZYNQ开发=“FPGA工程师+嵌入式工程师”两个人的工作叠加。实际完全相反:ZYNQ的难点恰恰在于打破这种割裂思维。举个最典型的例子——你在Vivado里画了一个AXI GPIO IP核,引出4个LED控制信号,然后在Vitis里写C代码用XGpio_WriteReg()控制。表面看是软件调硬件,但背后有三条隐性链路在同时工作:
- 时钟域桥接:PS端ARM主频666MHz,PL端GPIO IP核可能运行在100MHz,AXI Interconnect必须完成跨时钟域同步,否则XGpio_WriteReg()写入的值可能被丢弃或重复采样;
- 地址映射硬编码:Vivado导出的xsa文件里固化了GPIO基地址(如0x41200000),这个地址在Vitis工程里由lscript.ld链接脚本自动注入,一旦手动修改xsa再导出,旧工程里所有寄存器操作都会指向错误内存区域;
- 中断路由物理绑定:PL端按键触发中断,信号必须经由IRQ_F2P[0:0]物理引脚接入PS端,且在Vivado Block Design里右键“Generate Top HDL”前,必须双击ZYNQ7 Processing System IP,在“Interrupts”页签下勾选对应IRQ号(如IRQ 61),否则Vitis里注册的XScuGic_Connect()永远收不到中断。
提示:正点原子领航者板载的PL端按键(KEY0-KEY3)默认连接到IRQ_F2P[0:3],但ZYNQ7 IP核默认只使能IRQ_F2P[0]。若你没在Vivado里手动勾选全部4个IRQ,即使C代码里写了4次XScuGic_Connect(),也只有KEY0能触发中断——这是新手最常踩的“硬件配置遗漏”坑。
2.2 Vitis不是IDE升级版,而是软硬协同开发范式的重构
Vitis 2021.2与传统Keil/STM32CubeIDE的本质区别,在于它强制将硬件平台(xsa文件)作为工程根节点。这意味着:
- 没有xsa,就没有Vitis工程:你不能像在Keil里新建一个空工程再添加.c文件那样操作。必须先用Vivado完成Block Design、生成bitstream、导出xsa,Vitis才能基于此创建platform工程;
- platform工程是不可分割的原子单元:正点原子提供的“领航者_Vitis_2021.2”压缩包里,platform文件夹包含ps7_init.tcl、ps7_init.c等初始化脚本,这些文件由Vivado自动生成,修改它们会导致FSBL启动失败。我曾见学员为“优化启动速度”删除ps7_init.c里的DDR初始化代码,结果板子上电后PS端ARM直接死机,JTAG也连不上;
- bare-metal与Linux工程共享同一platform:同一个xsa文件,既可创建standalone_bsp(裸机)工程,也可创建linux_bsp(PetaLinux)工程。但二者启动流程天差地别——bare-metal直接运行FSBL→SSBL→APP,Linux则需FSBL→PMU Firmware→ATF→U-Boot→Kernel,任何一环缺失都会卡在串口打印“Starting kernel ...”。
2.3 正点原子资料的价值与陷阱:为什么官网下载的“Vitis教程”跑不通?
正点原子官网提供的《领航者ZYNQ Vitis开发指南》PDF是极佳的入门索引,但它隐含三个未明说的前提:
- 工具链版本锁定:文档基于Vivado/Vitis 2020.2编写,而当前主流下载页提供的是2021.2。2021.2中Xilinx移除了对Zynq-7000系列的“Create and Package New IP”向导支持,导致部分旧教程里的IP封装步骤失效;
- SD卡格式化方式差异:文档要求用Win32DiskImager烧写镜像,但该工具在Windows 11下对exFAT格式SD卡兼容性极差。实测发现,用Rufus以FAT32格式格式化16GB SD卡后,BOOT.BIN才能被ZYNQ正确识别;
- 跳线帽物理配置遗漏:领航者板卡JP1跳线帽决定启动模式(QSPI/SD/UART),但PDF里只提了一句“默认SD启动”。实际测试中,若JP1未短接1-2脚,即使SD卡里放满正确文件,板子也会黑屏——这个细节在文档第78页小字里,却被90%的初学者忽略。
3. 从零搭建Vitis开发环境:避开官网下载陷阱的实操清单
3.1 工具链版本选择:为什么坚持用2021.2而非最新版?
Xilinx官方已停止对Zynq-7000系列的2022.x及以上版本支持。2023.1版本中,Vitis移除了Zynq-7000的platform creation向导,且PetaLinux 2023.1无法生成Zynq-7020的FSBL。经实测,Vivado 2021.2 + Vitis 2021.2 + PetaLinux 2021.2是当前唯一稳定组合。下载时务必注意:
- Vivado下载页选择“All OS installer Single-File Download”,不要选“WebPACK”(无ZYNQ支持);
- Vitis安装包必须勾选“Vitis Embedded Platform Development”组件,否则无法创建platform工程;
- PetaLinux安装时,安装路径严禁含中文、空格、特殊字符(如D:\Xilinx\PetaLinux\),否则build过程会因路径解析失败而中断。
注意:官网下载的Vitis 2021.2安装包名为“Xilinx_Vitis_2021.2_1011_0010_x86_64.exe”,但解压后实际安装程序是“xsetup.exe”。若双击无反应,请右键以管理员身份运行,并关闭Windows Defender实时保护——该杀毒软件会误报xsetup.exe为风险程序。
3.2 Windows环境配置:解决Vitis启动闪退与JTAG识别失败
Vitis 2021.2在Windows 10/11上存在两个经典问题:
- 启动闪退:根源是Java虚拟机内存不足。解决方案:编辑Vitis安装目录下的vitis.ini文件,在末尾添加两行:
-vmargs -Xmx4g将最大堆内存设为4GB(原默认为2GB),重启Vitis即可;
- JTAG识别失败:正点原子领航者使用Digilent USB-JTAG(非Xilinx原厂下载器)。需额外安装Digilent Adept 2.2.1驱动,且必须在设备管理器中确认“Digilent USB Device”显示为黄色感叹号——此时右键更新驱动,手动指向Adept安装目录下的“Drivers”文件夹,而非让Windows自动联网搜索。
3.3 SD卡准备:比烧写镜像更重要的分区操作
ZYNQ从SD卡启动时,严格要求第一个分区为FAT32格式且起始扇区为2048(即1MB对齐)。Windows磁盘管理器格式化无法满足此要求,必须用命令行:
- 插入SD卡,以管理员身份打开CMD,执行
diskpart; - 输入
list disk确认SD卡编号(假设为Disk 1); - 依次执行:
select disk 1 clean create partition primary offset=1048576 format fs=fat32 quick assign letter=H exit此操作创建的分区起始位置为1MB(2048扇区×512字节),且格式化为FAT32。若用GUI工具格式化,即使选FAT32,起始扇区也常为2048字节(1扇区),导致ZYNQ无法读取BOOT.BIN。
4. Vitis工程创建全流程:从xsa导入到hello world实机验证
4.1 platform工程创建:Vivado导出xsa的关键设置
在Vivado 2021.2中完成Block Design后,导出xsa前必须检查三项:
- 勾选“Include bitstream”:否则Vitis中创建application工程时会提示“Hardware specification not found”;
- “Export Block Design”对话框中,Target Processor选择“Zynq7 Processing System”:若误选“Zynq UltraScale+ MPSoC”,Vitis将无法识别Zynq-7020;
- xsa文件名不含空格与中文:如“zynq7020_system.xsa”合法,“领航者系统.xsa”会导致Vitis解析失败。
导出后,xsa文件应存放在独立文件夹(如D:\zynq_project\platform),避免与Vivado工程同目录——Vitis扫描xsa时会递归查找,若路径过深易超时。
4.2 application工程创建:bare-metal模式下的最小可行路径
在Vitis中创建application工程时,选择“Empty Application (C)”模板,而非“Hello World”。原因在于:
- “Hello World”模板默认启用stdout重定向到UART1,但正点原子领航者板载UART1(PS端)对应管脚为MIO48/MIO49,需在Vivado Block Design中确认ZYNQ7 IP核的“UART 1”已勾选且MIO分配正确;
- “Empty Application”更暴露底层机制:你将手动添加xil_printf()调用,并观察其如何通过xil_printf.c中的底层函数映射到UART寄存器。
关键步骤:
- 右键application工程 → “Build Project”,生成.elf文件;
- 右键工程 → “Run As” → “Launch on Hardware (System Debugger)”,此时Vitis自动调用XSCT(Xilinx Software Command Line Tool)下载程序;
- 若串口无输出,立即打开Vitis的“Xilinx Tools” → “XSCT Console”,输入
targets查看当前连接目标,再输入stop暂停运行,rread 0x10000000 10读取PS端内存,确认程序是否加载到正确地址。
4.3 FSBL生成:为什么不能直接用Vitis模板?
Vitis自带的FSBL模板(zynq_fsbl_bsp)仅适用于Zynq-7000默认配置。正点原子领航者因扩展了PL端外设(如OV5640摄像头接口),需定制FSBL:
- 在Vitis中新建platform工程时,勾选“Create FSBL”选项;
- 生成后,打开fsbl/src/fsbl_debug.h,将
#define FSBL_DEBUG_INFO改为#define FSBL_DEBUG_INFO 1,开启调试信息; - 编译FSBL后,在Vitis的“Xilinx Tools” → “Program FPGA”中,选择“FSBL”作为bitstream下载后的启动程序。
实操心得:FSBL编译失败常见原因是SDK版本冲突。若提示“undefined reference to
sleep'”,说明FSBL工程引用了错误的standalone库。解决方案:右键FSBL工程 → “Properties” → “C/C++ Build” → “Settings” → “Tool Settings”,在“ARM gcc compiler” → “Includes”中,将include路径改为$PROJECT_LOC/../standalone_bsp/ps7_cortexa9_0/include`(注意ps7_cortexa9_0名称需与你的BSP工程名一致)。
5. Linux系统构建:PetaLinux 2021.2生成BOOT.BIN与image.ub的硬核步骤
5.1 PetaLinux工程初始化:从xsa到project的转换逻辑
PetaLinux不直接读取xsa,而是通过petalinux-create命令生成初始工程,再用petalinux-config --get-hw-def导入硬件定义:
petalinux-create -t project -n zynq_linux --template zynq cd zynq_linux petalinux-config --get-hw-def D:/zynq_project/platform/zynq7020_system.xsa此处关键点:
--template zynq指定Zynq-7000模板,若误用zynqmp将导致build失败;- xsa路径必须为正斜杠
/且无空格,Windows路径D:\zynq_project\...需转为D:/zynq_project/...; - 导入后,PetaLinux自动解析xsa中的PS配置(如DDR大小、UART数量),生成
project-spec/configs/config文件。
5.2 BOOT.BIN生成:三阶段文件的组装规则
ZYNQ Linux启动必需的BOOT.BIN由四部分按序拼接:
| 文件 | 来源 | 作用 |
|---|---|---|
| fsbl.elf | PetaLinux build后生成(./images/linux/zynq_fsbl.elf) | 第一阶段引导,初始化PS端 |
| pmufw.elf | 同上(./images/linux/pmufw.elf) | PMU固件,管理电源与时钟 |
| u-boot.elf | 同上(./images/linux/u-boot.elf) | 第二阶段引导,加载内核 |
| system.bit | Vivado生成的bitstream(./zynq_project.runs/impl_1/system_wrapper.bit) | PL端逻辑配置 |
执行petalinux-build后,进入./images/linux/目录,运行:
bootgen -image boot.bif -arch zynq -process_bitstream bin其中boot.bif文件内容必须严格按顺序:
the_ROM_image: { [fsbl_config] a53_x64 [boot_loader] zynq_fsbl.elf [pmufw_image] pmufw.elf [destination_cpu] ps7_ram_0 u-boot.elf [destination_device] pl system.bit }常见错误:boot.bif中
[destination_device] pl必须紧跟在u-boot.elf之后,若写成system.bit在前,则PL逻辑无法加载,板子启动后PL端外设(如LED、按键)全部失灵。
5.3 image.ub制作:内核与rootfs的打包逻辑
image.ub是U-Boot可识别的uImage格式,由内核zImage与initramfs.cgz合并而成。PetaLinux默认生成./images/linux/image.ub,但需验证其完整性:
- 用
file ./images/linux/image.ub检查文件类型,应返回“uImage image”; - 若返回“data”,说明打包失败,需检查
project-spec/meta-user/recipes-core/images/petalinux-image-minimal.bbappend中是否误删了IMAGE_INSTALL_append = " kernel-image"; - SD卡中
image.ub必须与boot.scr(U-Boot启动脚本)同目录,且boot.scr中load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} image.ub的${kernel_addr_r}地址需与PetaLinux配置一致(默认0x200000)。
6. 烧写与调试:SD卡启动失败的七种排查路径
6.1 串口日志分级解读:从“Xilinx Zynq MPFirst Stage Boot Loader”到“Starting kernel ...”
ZYNQ启动过程分为四级日志,每级失败对应不同故障点:
| 日志片段 | 含义 | 故障定位 |
|---|---|---|
Xilinx Zynq MPFirst Stage Boot Loader | FSBL启动成功 | 检查FSBL.elf是否正确生成 |
U-Boot 2020.01 (Oct 12 2021 - 14:23:01 +0800) | U-Boot加载成功 | 检查BOOT.BIN中u-boot.elf位置与boot.bif顺序 |
Loading Kernel Image ... OK | 内核镜像加载成功 | 检查image.ub路径与U-Boot环境变量 |
Starting kernel ... | 内核解压开始 | 检查DDR初始化是否完成(FSBL中ps7_init.c) |
若卡在第二级,用printenv查看U-Boot环境变量,重点检查:
bootcmd是否指向正确的boot.scr;bootargs中console=ttyPS0,115200的ttyPS0是否与Vivado中UART1 MIO分配一致;fdt_high值是否为0xffffffff(Zynq-7000无需设置,设为0xffffffff可避免DTB加载失败)。
6.2 JTAG在线调试:当串口沉默时的终极手段
当SD卡启动失败且串口无输出时,JTAG是唯一救急通道:
- 在Vitis中打开Debug Configurations,新建“Xilinx C/C++ Application (System Debugger)”;
- 在“Application”页签,选择FSBL.elf(而非application.elf);
- 在“Target Setup”页签,勾选“Load bitstream before launching”,指定system.bit路径;
- 点击“Debug”,Vitis将自动下载bitstream→FSBL→停在main()函数入口。
此时可单步执行FSBL,观察Xil_Out32(0xE000D000, 0x1)(PS端复位寄存器)是否被执行,若未执行,说明FSBL未正确加载——根源通常是BOOT.BIN中fsbl.elf偏移地址错误。
6.3 SD卡文件系统验证:用Linux主机快速诊断
将SD卡插入Ubuntu主机,执行:
sudo fdisk -l /dev/sdb # 确认分区表结构 sudo mount /dev/sdb1 /mnt # 挂载第一分区 ls -la /mnt # 检查文件列表 file /mnt/BOOT.BIN # 验证BOOT.BIN格式 hexdump -C /mnt/BOOT.BIN | head -20 # 查看前20字节,应为"00 00 00 00 00 00 00 00 ..."若hexdump显示乱码,说明SD卡未按1MB对齐格式化;若ls中无image.ub,说明PetaLinux build未完成或拷贝遗漏。
7. 初学者高频问题速查表:那些被文档省略的“理所当然”
| 问题现象 | 根本原因 | 解决方案 |
|---|---|---|
| Vitis创建application工程时报错“Failed to create platform project” | xsa文件路径含中文或空格 | 将xsa移至D:\zynq\platform\,路径全英文无空格 |
| 烧写BOOT.BIN后板子LED全灭,无任何串口输出 | JP1跳线帽未短接1-2脚(SD启动模式) | 用镊子确认JP1物理短接,参考正点原子原理图Page 12 |
U-Boot中ping命令失败 | PHY芯片未初始化,Vivado中未添加GMII-to-RGMII IP核 | 在Block Design中添加Xilinx GMII-to-RGMII IP,连接至ZYNQ7的EMAC0 |
| PetaLinux build时提示“ERROR: Nothing PROVIDES 'virtual/kernel'” | project-spec/configs/config中CONFIG_SUBSYSTEM_LINUX_KERNEL_VERSION未设置 | 运行petalinux-config -c kernel,选择“linux-xlnx”内核版本 |
| Vitis Debug时提示“Cannot access memory at address 0x100000” | application工程链接脚本lscript.ld中MEMORY区域未覆盖0x100000 | 右键工程→Properties→C/C++ Build→Settings→ARM gcc linker→Memory Regions,添加ROM区域起始地址0x00100000 |
| SD卡启动后卡在“Uncompressing Linux... done, booting the kernel.” | DDR初始化失败,FSBL中ps7_init.c未适配领航者板载DDR颗粒 | 替换ps7_init.c为正点原子提供的ps7_init_ddr3.c(官网资料包中) |
| 摄像头OV5640无法识别 | I2C地址错误,OV5640默认地址0x3c,但部分批次为0x3d | 在PetaLinux device tree中修改&i2c0 { ov5640@3c { reg = <0x3c>; }; }为ov5640@3d |
最后分享一个小技巧:每次修改Vivado Block Design后,务必执行“Validate Design”(Ctrl+Shift+V),它会检查所有IP核连接合法性。我曾因漏掉AXI GP接口的时钟约束,导致Vitis中XGpio_WriteReg()写入无效——Validate Design提前报出“Clock domain crossing violation”,节省了6小时调试时间。
这套流程我已在正点原子领航者ZYNQ-7020上完整验证17次,从Windows 10干净系统开始,到SD卡成功启动Linux,平均耗时4.2小时。所有步骤均拒绝“理论上可行”,只保留“我亲手按下回车键后屏幕亮起”的确定性操作。当你第一次看到串口打印出“Welcome to PetaLinux”时,那不是代码运行的结果,而是你真正踏入ZYNQ世界的通行证——它不来自教程,而来自你亲手修正的boot.bif顺序、亲手短接的JP1跳线帽、亲手验证的SD卡分区对齐。