2. 裸机开发环境搭建:Vivado + SDK安装、创建第一个Hello World工程、工程结构解析

做Zynq开发,第一步就是把家伙事儿备齐。很多新手卡在环境搭建这一步,其实没那么玄乎。我刚开始用Vivado时也被它那庞大的安装包吓到过,但用顺手了就会发现,这套工具链的设计逻辑其实挺清晰的。

2.1 开发工具概览

Zynq的裸机开发,说白了就是“硬件设计 + 软件编程”两条腿走路。你需要两套工具:

工具 作用 我的评价
Vivado 硬件平台设计:配置PS、添加PL外设、生成比特流 核心工具,绕不开
Vitis (旧称SDK) 软件应用开发:写C代码、编译、调试、下载 基于Eclipse,上手快
Xilinx USB Cable驱动 让PC能识别下载器(如JTAG) 最容易出幺蛾子的地方

我个人习惯把Vivado和Vitis装在同一台机器上。版本一定要匹配,否则各种奇怪报错会让你怀疑人生。目前主流是Vivado 2020.x到2022.x系列,我建议用2021.1或2022.1,社区资料最多,遇到问题好搜。

2.2 安装避坑指南

安装过程其实就三步:下载、解压、点下一步。但有几个坑我得提前说:

⚠ 路径不能有中文和空格
我曾经在一个项目里把Vivado装在了“D:\开发工具\Xilinx”路径下,结果综合时报了个莫名其妙的路径错误。排查了两小时,最后发现是“开发工具”里的中文惹的祸。老老实实用全英文路径,省心。
  • 安装包大小:完整版大约40-60GB。别慌,你不需要全装。选“Vivado” + “Vitis”即可,那些7系列、UltraScale+的器件库按需勾选。Zynq-7000系列选“7 Series”就行。
  • License:Xilinx提供免费WebPack License,功能足够你学完这门课。申请后加载到Vivado里就行。
  • USB Cable驱动:装完Vivado后,插上JTAG下载器,如果设备管理器里显示黄色感叹号,手动去安装目录下找drivers\cable_drivers里的驱动。我遇到过好几次Win10自动更新把驱动搞挂了,得重装。

2.3 创建第一个Hello World工程

环境装好了,咱们来跑个灯……哦不,跑个Hello World。Zynq的Hello World不是打印到PC屏幕,而是通过串口打印出来。所以你需要一块Zynq开发板(比如ZedBoard、PYNQ-Z2、或者你们公司的自制板),一根Micro USB线连到串口。

步骤很简单,我拆解给你看:

  1. 打开Vivado,创建工程:选RTL Project,勾选“Do not specify sources at this time”。器件选你板子上的具体型号,比如XC7Z020-1CLG484C。
  2. 创建Block Design:在IP Integrator里创建一个新的Block Design。添加Zynq Processing System IP核。
  3. 配置PS:双击Zynq IP核,进入配置界面。这里要做的关键配置是:
    • 使能UART1(对应板子上的串口)
    • 配置DDR型号(跟你的板子硬件一致,错了起不来)
    • 配置时钟频率(一般默认667MHz或533MHz)
  4. 连线并生成顶层:自动连接FCLK_CLK0和复位,右键Create HDL Wrapper。然后Generate Bitstream。
  5. 导出硬件到Vitis:File → Export → Export Hardware,勾选“Include bitstream”。然后Launch Vitis。
  6. 在Vitis里创建应用工程:File → New → Application Project。选择刚才导出的硬件平台,模板选“Hello World”。
  7. 编译、下载、看结果:右键工程Build,然后右键Debug As → Launch on Hardware。打开串口助手(波特率115200),你会看到板子打印出“Hello World”。
💡 小技巧
第一次下载时如果提示“No cable connected”,检查一下JTAG驱动。我习惯在Vivado里先打开Hardware Manager,连上板子确认识别到了,再切回Vitis下载。这样能快速定位是硬件连接问题还是软件配置问题。

2.4 工程结构解析

Hello World跑起来了,但你知道Vitis工程里那些文件夹都是干嘛的吗?我见过不少工程师,工程一复杂就找不到文件在哪。咱们捋一捋:

hello_world/
├── src/                  # 源代码目录
│   ├── helloworld.c      # 主函数,打印Hello World
│   ├── platform.c        # 板级初始化代码(串口、中断等)
│   └── platform.h        # 平台头文件
├── _ide/                 # IDE配置文件,别手动改
├── Debug/                # 编译输出目录
│   ├── hello_world.elf   # 可执行文件,下载到板子上的就是这个
│   └── ...               # 各种中间文件
├── lscript.ld            # 链接脚本,定义内存布局
└── Makefile              # 编译规则,一般不用管

这里面最值得关注的是lscript.ld。它决定了你的代码和数据放在DDR的哪个位置。裸机程序默认从0x00000000开始,但Zynq的BootROM会先执行,所以实际应用入口在0x00100000附近。如果你以后做更复杂的工程,比如要划分内存给PL的DMA用,就得改这个文件。

另一个是platform.c。它里面有个init_platform()函数,负责初始化串口、中断控制器等。我刚开始做Zynq时,以为这些初始化是自动的,结果自己写了个外设驱动怎么都跑不通,最后发现是init_platform()里没使能对应的时钟。嗯,这里要注意,platform.c不是摆设。

2.5 知识体系:从代码到硬件的完整链路

为了让你更直观地理解整个流程,我画了张图。从你写C代码,到板子上的LED闪烁或串口打印,中间经历了什么:

Zynq裸机开发:从代码到硬件的完整链路 用户C代码 helloworld.c ARM GCC编译 生成 .elf 文件 链接脚本 lscript.ld .elf 可执行 JTAG下载 Vitis → 板子 Zynq硬件平台 PS (Processing System) ARM Cortex-A9 双核 DDR控制器 / UART / GPIO PL (Programmable Logic) FPGA逻辑 自定义IP / 加速器 板级外设 串口 / LED / 按键 以太网 / HDMI 裸机程序直接运行在PS的ARM核上,通过AXI总线与PL交互

这张图把整个链路串起来了。你写的C代码经过编译、链接生成.elf文件,通过JTAG下载到Zynq的DDR里,然后ARM核从DDR里取指令执行。执行过程中,它通过UART外设把“Hello World”发到串口线上,你的PC串口助手收到后显示出来。

你想想看,这中间任何一个环节出问题,结果都出不来。所以排查问题时,按这个链路倒着查:串口线通了吗?驱动装了吗?.elf下载成功了吗?编译报错了吗?代码写对了吗?

2.6 常见问题与排查

最后,我把这些年遇到最多的几个问题列出来,你遇到了直接对照着查:

现象 可能原因 解决办法
Vivado识别不到JTAG USB Cable驱动没装好 手动更新驱动到cable_drivers目录
串口打印乱码 波特率不匹配 检查Vitis里UART配置和串口助手是否都是115200
下载后板子没反应 DDR配置与硬件不符 核对板子原理图上的DDR型号,重新配置PS
编译报错“undefined reference” BSP库没包含 右键工程 → Properties → C/C++ Build → Settings → Libraries,添加对应库
🔑 核心要点
环境搭建的核心就三件事:
1. 装对版本(Vivado + Vitis匹配)
2. 配好硬件(DDR、UART、时钟)
3. 理解链路(代码 → 编译 → 下载 → 执行)
这三件事搞定了,后面写驱动、调外设就是水到渠成的事。