4. 第一个裸机程序:Hello World工程创建、串口打印验证、编译与下载流程、启动模式配置
说实话,学Zynq最让人兴奋的一刻,就是看到串口终端里跳出那行"Hello World"。这标志着你的PS端已经跑起来了,硬件链路通了,开发环境也配对了。今天我们就一步步把这个过程走通。
4.1 工程创建:从零搭建一个裸机项目
我个人习惯用Vivado + Vitis这套组合。先打开Vivado,创建一个新的Block Design,把Zynq Processing System IP拖进来。嗯,这里有个关键点——一定要先配置好PS端的时钟和DDR,否则后面跑不起来。
导出硬件描述文件(.xsa)后,打开Vitis。新建一个Application Project,选择刚才导出的.xsa文件,平台选"standalone"——这就是裸机环境。模板里有个"Hello World",直接选它就行。
我曾经遇到过一个问题:新建工程后编译报错,说找不到"xparameters.h"。后来发现是.xsa文件路径有中文,Vitis解析不了。所以工程路径千万别带中文,空格也最好别用。
4.2 串口打印验证:Hello World是怎么出来的
模板生成的代码其实很简单,核心就几行:
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
int main()
{
init_platform();
print("Hello World\n\r");
cleanup_platform();
return 0;
}
这里有个细节——print()函数用的是xil_printf.h里的实现,而不是标准C的printf。为什么?因为裸机环境下没有操作系统帮你管理标准输出,Xilinx自己封装了一个轻量级的打印函数,直接操作UART寄存器。
说白了,print("Hello World\n\r")这行代码,最终会通过Zynq PS端的UART控制器,把字符一个个发出去。串口那边收到后,在终端上显示出来。
\n在Windows终端里需要配合\r才能正确换行。所以记得用\n\r,而不是单独\n。
4.3 编译与下载流程:把程序烧进芯片
编译很简单,在Vitis里右键工程选"Build Project"。第一次编译会慢一些,因为要链接库文件。编译成功后,你会看到.elf文件生成。
下载方式有两种:
| 方式 | 适用场景 | 特点 |
|---|---|---|
| JTAG下载 | 调试阶段 | 直接通过调试器加载,掉电丢失 |
| QSPI Flash烧写 | 量产/脱机运行 | 掉电保留,上电自动加载 |
调试阶段我建议用JTAG。在Vitis里点"Debug"按钮,它会自动把.elf文件通过JTAG链加载到DDR里,然后PC指针跳到main函数入口。这时候打开串口终端(波特率115200,8N1),就能看到输出了。
4.4 启动模式配置:芯片上电后怎么知道该干啥
Zynq的启动模式由硬件引脚决定。说白了,芯片上电后,BootROM会去读这些引脚的电平,然后决定从哪个设备加载第一阶段启动代码(FSBL)。
常见的启动模式有这些:
| 模式 | 引脚配置(MIO[5:2]) | 启动设备 |
|---|---|---|
| JTAG | 0000 | 调试器直接加载 |
| QSPI | 0010 | 板载Flash |
| SD卡 | 0110 | SD0(通常是SD卡槽) |
| NAND | 1000 | NAND Flash |
你想想看,如果板子上电后什么都没反应,很可能就是启动模式引脚没配置对。我遇到过一块板子,SD卡启动死活不行,最后发现是MIO[5:2]的焊接虚焊了,导致BootROM读到了错误的电平。
下面这张图展示了从按下复位键到Hello World打印出来的完整流程:
嗯,到这里,你的第一个裸机程序就跑通了。从工程创建到串口打印,再到启动模式配置,这一套流程是后面所有外设驱动开发的基础。你想想看,如果连Hello World都出不来,后面I2C、SPI、Ethernet就更别谈了。
- 工程路径不要有中文或空格
- 串口打印用
\n\r换行 - JTAG调试时确认PS端初始化完成
- 启动模式引脚配置要跟实际硬件一致