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线连到串口。
步骤很简单,我拆解给你看:
- 打开Vivado,创建工程:选RTL Project,勾选“Do not specify sources at this time”。器件选你板子上的具体型号,比如XC7Z020-1CLG484C。
- 创建Block Design:在IP Integrator里创建一个新的Block Design。添加Zynq Processing System IP核。
- 配置PS:双击Zynq IP核,进入配置界面。这里要做的关键配置是:
- 使能UART1(对应板子上的串口)
- 配置DDR型号(跟你的板子硬件一致,错了起不来)
- 配置时钟频率(一般默认667MHz或533MHz)
- 连线并生成顶层:自动连接FCLK_CLK0和复位,右键Create HDL Wrapper。然后Generate Bitstream。
- 导出硬件到Vitis:File → Export → Export Hardware,勾选“Include bitstream”。然后Launch Vitis。
- 在Vitis里创建应用工程:File → New → Application Project。选择刚才导出的硬件平台,模板选“Hello World”。
- 编译、下载、看结果:右键工程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闪烁或串口打印,中间经历了什么:
这张图把整个链路串起来了。你写的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. 理解链路(代码 → 编译 → 下载 → 执行)
这三件事搞定了,后面写驱动、调外设就是水到渠成的事。