2、Vitis开发环境搭建:Vitis统一软件平台安装、创建HLS组件、创建嵌入式工程
好,咱们直接进入正题。这一章我带你亲手把Vitis这套工具链搭起来。说实话,很多初学者卡就卡在环境搭建这一步,不是装不上就是版本对不上。我当年第一次装Vitis的时候,折腾了整整一个下午,最后发现是JDK版本不对。嗯,这些坑我会一个个帮你填平。
2.1 Vitis统一软件平台安装
Vitis这个平台,说白了就是Xilinx把以前的SDK和SDAccel整合到了一起。你装一个Vitis,就等于同时拥有了嵌入式开发、加速计算和HLS三套能力。我个人习惯装Vitis Unified Software Platform,而不是单独装Vivado再装Vitis——那样容易出依赖问题。
Vitis 2023.2 需要搭配 Vivado 2023.2 使用。我曾经见过有人装了Vitis 2023.1却用Vivado 2022.2,结果HLS组件死活编译不过。血的教训。
安装步骤其实不复杂,我列个清单给你:
- 下载安装包:去Xilinx官网下载Vitis Unified Software Platform。大约20GB,建议用下载工具,别用浏览器直接下。
- 运行安装程序:双击xsetup.exe,选择“Vitis”安装选项。注意,它会自动勾选Vivado,别取消。
- 选择器件支持:咱们做按键消抖,选个Artix-7或者Zynq-7000系列就够了。全选的话硬盘会哭的——我第一台电脑256GB SSD,装完Vitis直接红了。
- 设置安装路径:路径不要有中文,不要有空格。我习惯用
C:\Xilinx\Vitis\2023.2这种结构。 - 等待安装完成:去泡杯咖啡,大概40分钟到1小时。
安装完成后,记得把
C:\Xilinx\Vitis\2023.2\bin加到系统PATH里。这样你在命令行直接敲vitis就能启动,不用每次都去点图标。
2.2 创建HLS组件
HLS组件是啥?说白了,就是用C/C++写硬件逻辑,然后让工具帮你转成RTL。咱们的按键消抖算法,完全可以用HLS来实现。我个人觉得,对于这种控制逻辑,HLS比手写Verilog快得多。
创建HLS组件的步骤:
- 启动Vitis:双击桌面图标,或者命令行敲
vitis。 - 创建工作空间:选一个干净的目录,比如
D:\FPGA_Projects\key_debounce。记住,工作空间路径也不能有中文。 - 创建HLS组件:点击
File → New → HLS Component。 - 填写组件信息:组件名我建议用
debounce_hls,函数名用debounce。这样后面调用的时候一目了然。 - 选择器件:选
xc7a35tcsg324-1(Artix-7)或者你板子对应的型号。 - 添加源文件:把咱们的C代码加进去。代码我稍后会贴。
这里贴一下咱们的HLS核心代码。嗯,代码不长,但逻辑要讲清楚:
#include <ap_int.h>
#define DEBOUNCE_CNT_MAX 1000000 // 20ms @ 50MHz
void debounce(
bool raw_btn,
bool &debounced_btn
) {
static ap_uint<20> counter = 0;
static bool stable_state = 0;
if (raw_btn == stable_state) {
counter = 0;
} else {
counter++;
if (counter >= DEBOUNCE_CNT_MAX) {
stable_state = raw_btn;
counter = 0;
}
}
debounced_btn = stable_state;
}
ap_uint<20>:20位宽的计数器,够数到1,048,575,咱们只用到1,000,000。static变量:HLS里用static实现寄存器,相当于Verilog里的reg。- 判断逻辑:输入和稳定状态一致就清零计数器,不一致就累加。累加到阈值就翻转状态。
写完之后,点击Run C Simulation验证一下功能。我习惯先写个简单的testbench:
#include <stdio.h>
#include <stdbool.h>
extern void debounce(bool raw_btn, bool &debounced_btn);
int main() {
bool result;
// 模拟按键抖动:高低电平快速切换
for(int i=0; i<5; i++) {
debounce(1, result);
debounce(0, result);
debounce(1, result);
debounce(0, result);
}
// 然后保持高电平
for(int i=0; i<2000000; i++) {
debounce(1, result);
}
printf("Final result: %d\n", result);
return 0;
}
仿真通过后,点击Run C Synthesis进行综合。综合完成后,你会看到资源使用报告。咱们这个消抖逻辑,LUT只用了几十个,FF用了二十多个——几乎不占资源。
重点关注
Latency和Interval。咱们这个设计是组合逻辑+时序逻辑混合,Latency是1个时钟周期,Interval也是1。说白了就是每个时钟周期都能处理一次输入。
2.3 创建嵌入式工程
HLS组件搞定了,接下来要把它集成到嵌入式工程里。这一步很多人会搞混——HLS生成的是IP核,你得把它挂到PS(处理系统)的AXI总线上。
创建嵌入式工程的步骤:
- 创建平台工程:在Vitis里点击
File → New → Platform Project。平台名用zynq_platform。 - 导入硬件描述:选择你的Vivado导出的.xsa文件。如果没有,可以用Vitis自带的Zynq模板。
- 创建应用工程:点击
File → New → Application Project。选择刚才创建的平台。 - 选择模板:选
Empty Application(C),咱们从头写。 - 添加HLS组件:右键工程 →
Add Hardware Component→ 选择刚才综合好的HLS组件。
工程建好后,你会看到自动生成的驱动文件。在src目录下创建main.c:
#include <stdio.h>
#include "xparameters.h"
#include "xdebounce_hls.h"
XDebounce_hls debounce_inst;
int main() {
int status;
u32 raw_btn, debounced_btn;
// 初始化HLS IP核
status = XDebounce_hls_Initialize(&debounce_inst, XPAR_DEBOUNCE_HLS_0_DEVICE_ID);
if(status != XST_SUCCESS) {
printf("Init failed!\n");
return -1;
}
while(1) {
// 读取原始按键值(假设接在GPIO上)
raw_btn = XGpio_DiscreteRead(&gpio_inst, 1);
// 写入HLS IP
XDebounce_hls_Set_raw_btn(&debounce_inst, raw_btn);
// 启动处理
XDebounce_hls_Start(&debounce_inst);
// 等待完成
while(!XDebounce_hls_IsDone(&debounce_inst));
// 读取消抖结果
debounced_btn = XDebounce_hls_Get_debounced_btn(&debounce_inst);
// 输出到LED
XGpio_DiscreteWrite(&gpio_inst, 2, debounced_btn);
}
return 0;
}
HLS IP核的地址在
xparameters.h里定义。如果你发现XPAR_DEBOUNCE_HLS_0_DEVICE_ID找不到,八成是地址没对上。去xparameters.h里搜一下DEBOUNCE,看看实际定义的名字是啥。
编译工程:右键工程 → Build Project。第一次编译会慢一些,因为要编译BSP和驱动库。后面就快了。
下载到板子:连接好JTAG,点击Run → Run As → Launch on Hardware (Single Application Debug)。如果一切顺利,你会看到LED随着按键按下而稳定亮起,不再闪烁。
用手快速抖动按键(或者用信号发生器给一个带抖动的方波),观察LED是否稳定。如果LED偶尔还会闪一下,说明消抖时间不够长,可以调大
DEBOUNCE_CNT_MAX。
2.4 本章知识体系
下面这张图帮你理清整个流程:
嗯,整个流程走下来,你会发现Vitis其实没那么可怕。关键就是三步:装对版本、写好HLS、配好地址。我当年第一次调通的时候,看着LED稳稳地亮起来,心里那个爽啊——就跟修好了一台老收音机似的。
如果你在搭建过程中遇到问题,别急。大概率是下面几个原因:
- 版本不匹配:Vitis和Vivado版本必须一致,别混着用。
- 路径有中文:Xilinx工具对中文路径支持很差,全用英文。
- HLS综合失败:检查一下代码里有没有用
printf——HLS不支持标准库的打印函数。 - 地址没对上:去
xparameters.h里搜一下IP核的名字,确认宏定义存在。
我习惯在main函数里加个串口打印,每处理一次按键就输出一次。这样不用看LED,直接看串口数据就知道消抖有没有生效。串口初始化代码可以在BSP里找到模板。
好了,环境搭好了,HLS组件也建好了,嵌入式工程也能跑了。下一章咱们会深入讲按键消抖的算法原理,以及怎么根据实际硬件调整参数。不过那是后话了——先把今天的内容消化掉,动手试试看。
可可精品资料库