news 2026/8/8 8:35:51

保姆级教程十:软硬大闭环!ZYNQ Linux下联合调用HLS与DMA实现硬件加速(全网最通透)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
保姆级教程十:软硬大闭环!ZYNQ Linux下联合调用HLS与DMA实现硬件加速(全网最通透)

保姆级教程十:软硬大闭环!ZYNQ Linux下联合调用HLS与DMA实现硬件加速(全网最通透)

文章目录

  • 保姆级教程十:软硬大闭环!ZYNQ Linux下联合调用HLS与DMA实现硬件加速(全网最通透)
    • 🛠️ 第一步:把 HLS 硬件导入 Vivado (搭积木)
      • 1. 导入自定义 IP 库
      • 2. 改造 Block Design (插入乘法器)
      • 3. 查看物理地址(极其关键!)
    • 🚀 第二步:PetaLinux 刷新系统配置
    • 🔑 第三步:揭秘 HLS 的启动钥匙(控制寄存器)
    • 💻 第四步:C语言实战(召唤神龙的时刻)
      • 编译与运行:
    • ❓ 终极排雷指南 (FAQ)

一路跟到第十篇的兄弟们,欢呼吧!今天我们将迎来 ZYNQ 嵌入式开发中最具成就感的一战:真正的软硬件协同加速!

以前我们都是用 ARM(PS端)的 CPU 去算乘法、算图像,速度慢得像老牛拉破车。今天,我们要把计算任务丢给上一篇用 HLS 生成的“硬件乘法器”,让 FPGA 瞬间秒杀这些计算,并用 DMA 实现海量数据的高速搬运!

准备好迎接真正的黑科技了吗?发车!


🛠️ 第一步:把 HLS 硬件导入 Vivado (搭积木)

我们先打开第7篇教程中做好的那个“DMA 环回测试”的 Vivado 工程。

1. 导入自定义 IP 库

  1. 在 Vivado 左侧导航栏点击Settings
  2. 展开IP-> 点击Repository
  3. 点击+号,找到你上一篇 Vitis HLS 工程里的solution1/impl/ip文件夹,点击 Select。
  4. 此时 Vivado 会弹出一个窗口告诉你识别到了 1 个 IP(这就是我们的Hw_multiplier),点击 OK。

2. 改造 Block Design (插入乘法器)

  1. 打开你的 Block Design 图纸。
  2. 找到 DMA 发货口(M_AXIS_MM2S)和收货口(S_AXIS_S2MM)之间连着的那根线,选中它,按 Delete 键删掉!(切断原来的直接环回)。
  3. 在空白处右键 ->Add IP-> 搜索hw_multiplier,把它添加进来。
  4. 核心连线
    • 把 DMA 的M_AXIS_MM2S连到乘法器的输入流in_stream
    • 把 乘法器的输出流out_stream连到 DMA 的S_AXIS_S2MM
  5. 控制线连线
    • 乘法器上面有一个s_axi_CTRL_BUS(这是它的控制寄存器)。点击上方的Run Connection Automation,Vivado 会自动帮把它连到 PS 端的主干道上。

3. 查看物理地址(极其关键!)

点击顶部的Address Editor标签页。
你会看到两个重要的外设地址:

  • axi_dma_0:比如是0x40400000
  • hw_multiplier_0:比如是0x40000000把这个地址记在小本本上,一会写 C 语言要用!

老规矩:Generate Bitstream -> Export Hardware 导出包含 bitstream 的.xsa文件。


🚀 第二步:PetaLinux 刷新系统配置

把新的.xsa图纸丢进 Ubuntu 虚拟机里的 PetaLinux 工程。

执行更新命令:

petalinux-config --get-hw-description=/你的xsa路径/

(保存并退出)

因为我们在第7篇已经在设备树(Device Tree)里给 DMA 预留了 16MB 的连续物理内存(0x10000000),所以这里不需要再改设备树了

直接编译打包:

petalinux-build petalinux-package--boot--fsblimages/linux/zynq_fsbl.elf--fpgaimages/linux/system.bit --u-boot--force

把新的BOOT.BINimage.ub拷入 SD 卡,开发板上电开机!


🔑 第三步:揭秘 HLS 的启动钥匙(控制寄存器)

在写 C 语言之前,必须科普一个小白最容易踩的坑:
HLS 生成的 IP 核,通电后默认是“休眠”状态的!你不去踹它一脚,它绝对不干活!

怎么踹?通过刚才记下的0x40000000这个地址。
Xilinx 规定,HLS 生成的 IP,基地址偏移0x00的地方,就是它的总控制寄存器(Control Register)

  • Bit 0 (ap_start):写 1,代表启动运算。
  • Bit 7 (auto_restart):写 1,代表自动重启。

小白神级操作:我们只要往0x40000000写入0x81(二进制的 10000001),这个乘法器就会开启无限续航模式,只要 DMA 送来数据,它立马乘 2 吐出来!


💻 第四步:C语言实战(召唤神龙的时刻)

在 Linux 系统里新建hls_dma_test.c
这段代码将同时控制:DMA 发车+HLS 启动+内存读写

#include<stdio.h>#include<unistd.h>#include<fcntl.h>#include<sys/mman.h>// --- 我们在 Vivado 里查到的物理地址 ---#defineDMA_REG_BASE0x40400000// DMA 控制寄存器#defineHLS_REG_BASE0x40000000// HLS 乘法器控制寄存器#defineDMA_MEM_BASE0x10000000// 设备树里预留的物理内存火车站// --- 内存区划分 ---#defineTX_BUFFER(DMA_MEM_BASE+0x0000000)// 10000000 发送区#defineRX_BUFFER(DMA_MEM_BASE+0x0800000)// 10800000 接收区// --- DMA 寄存器偏移 ---#defineMM2S_CR0x00// TX 控制#defineMM2S_SA0x18// TX 源地址#defineMM2S_LENGTH0x28// TX 长度 (触发发送)#defineS2MM_CR0x30// RX 控制#defineS2MM_DA0x48// RX 目标地址#defineS2MM_LENGTH0x58// RX 长度 (触发接收)intmain(){intmem_fd;void*dma_reg,*hls_reg,*tx_ram,*rx_ram;// 1. 打开 /dev/mem (使用 O_SYNC 避免 Cache 捣乱)mem_fd=open("/dev/mem",O_RDWR|O_SYNC);if(mem_fd<0){printf("打开 /dev/mem 失败!\n");return-1;}// 2. 映射所有的物理地址到虚拟地址dma_reg=mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_SHARED,mem_fd,DMA_REG_BASE);hls_reg=mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_SHARED,mem_fd,HLS_REG_BASE);tx_ram=mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_SHARED,mem_fd,TX_BUFFER);rx_ram=mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_SHARED,mem_fd,RX_BUFFER);volatileunsignedint*dma=(volatileunsignedint*)dma_reg;volatileunsignedint*hls=(volatileunsignedint*)hls_reg;volatileunsignedint*tx_data=(volatileunsignedint*)tx_ram;volatileunsignedint*rx_data=(volatileunsignedint*)rx_ram;// ==========================================// 3. 准备数据 (往 TX 内存放 5 个数字)// ==========================================for(inti=0;i<5;i++){tx_data[i]=i+1;// 放入 1, 2, 3, 4, 5rx_data[i]=0;// 清空接收区}printf("发送前的数据: %d, %d, %d, %d, %d\n",tx_data[0],tx_data[1],tx_data[2],tx_data[3],tx_data[4]);// ==========================================// 4. 点火!启动 HLS 硬件加速器// ==========================================// 往偏移 0x00 写 0x81 (Auto Restart = 1, Start = 1)*hls=0x81;printf("HLS 硬件乘法器已启动待命...\n");// ==========================================// 5. 启动 DMA 传输// ==========================================// 开启 DMA 通道*(dma+(MM2S_CR/4))=1;*(dma+(S2MM_CR/4))=1;// 设置收发物理地址*(dma+(MM2S_SA/4))=TX_BUFFER;*(dma+(S2MM_DA/4))=RX_BUFFER;// 触发传输!长度为 5 个整数 = 20 字节 (必须先开 RX 再开 TX)*(dma+(S2MM_LENGTH/4))=20;*(dma+(MM2S_LENGTH/4))=20;// 等待传输完成 (约几微秒)usleep(100000);// ==========================================// 6. 验证加速结果// ==========================================printf("\n--- DMA 传输完毕 ---\n");printf("接收到的数据: %d, %d, %d, %d, %d\n",rx_data[0],rx_data[1],rx_data[2],rx_data[3],rx_data[4]);// 清理现场munmap(dma_reg,4096);munmap(hls_reg,4096);munmap(tx_ram,4096);munmap(rx_ram,4096);close(mem_fd);return0;}

编译与运行:

arm-linux-gnueabihf-gcc hls_dma_test.c-ohls_dma_testchmod+x hls_dma_test ./hls_dma_test

见证奇迹的时刻到了!你的屏幕上将输出:

发送前的数据: 1, 2, 3, 4, 5 HLS 硬件乘法器已启动待命... --- DMA 传输完毕 --- 接收到的数据: 2, 4, 6, 8, 10

🎉 完美!硬件乘法器不仅收到了数据,而且成功把每个数字乘了 2,并通过 DMA 原封不动地还给了 Linux 内存!


❓ 终极排雷指南 (FAQ)

Q1:程序跑了,但是卡在usleep之后死机,或者 DMA 不返回数据?

  • 神级细节揭秘:这是 AXI-Stream 的TLAST(最后一个数据标志)惹的祸!DMA 接收通道(S2MM)必须看到TLAST信号被拉高,才知道一包数据传完了。
  • 回头看第9篇:我们在 HLS 的 C++ 代码里写了一句val_out.last = val_in.last;。这句话就是魔法!它把进入乘法器的TLAST标志原封不动地传了出去。如果你手写 HLS 时忘了传递TLAST,DMA 就会一直死等,导致总线挂死!

Q2:输出的数据全是 0 是怎么回事?

  • 嫌疑1:你忘了给 HLS 写入0x81启动信号,乘法器还在睡大觉。
  • 嫌疑2:缓存一致性(Cache)问题,记得确认你的open函数带上了O_SYNC标志。

Q3:这个乘 2,我在 C 语言里一个for循环不就算完了吗,干嘛费这么大劲?

  • 对于 5 个数字,确实 C 语言快。但如果是一张1920x1080 的高清图像(200万个像素点)呢?
  • 在 C 语言里,CPU 要循环 200 万次;而在我们搭建的这套“DMA + HLS 纯硬件流水线”里,这 200 万个数据会像水流一样,每个时钟周期(几纳秒)就处理完一个!这才是 FPGA 硬件加速的真正威力!

结语:
兄弟们,当你看到终端里打印出2, 4, 6, 8, 10的那一刻,你已经走完了 ZYNQ 开发者最艰难的一段路。

Vivado 建硬件 -> PetaLinux 编系统 -> HLS 写算法 -> C 语言控寄存器 -> DMA 传数据。这一整套丝滑的连招,就是目前工业界(医疗影像、机器视觉、雷达信号处理)最主流的开发范式!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 15:24:37

ESP8266和电流互感器实现交流电流检测

检测原理电流互感器&#xff08;Current Transformer&#xff0c;CT&#xff09; 是一种用于测量电流的传感器&#xff0c;它利用电磁感应原理将一次侧的大电流按比例转换为二次侧的小电流&#xff0c;从而实现对电流的安全测量和监控。简单来说&#xff0c;电流互感器就像一个…

作者头像 李华
网站建设 2026/7/14 15:24:38

革新性VC运行库全场景解决方案:从根源解决DLL依赖难题

革新性VC运行库全场景解决方案&#xff1a;从根源解决DLL依赖难题 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 问题象限&#xff1a;被忽视的运行库生态危机 …

作者头像 李华
网站建设 2026/7/14 15:24:36

深入解析RK芯片RGB显示驱动的调试流程

1. RK芯片RGB显示驱动调试入门指南 第一次接触RK芯片的RGB显示驱动调试时&#xff0c;我也被各种专业术语和复杂配置搞得晕头转向。经过几个项目的实战积累&#xff0c;我发现只要掌握几个关键步骤&#xff0c;就能快速上手。RK芯片的显示系统主要由VOP&#xff08;视频输出处…

作者头像 李华
网站建设 2026/7/14 15:24:52

造相-Z-Image与3D引擎集成:Unity虚拟场景快速构建

造相-Z-Image与3D引擎集成&#xff1a;Unity虚拟场景快速构建 1. 引言 想象一下&#xff0c;你正在开发一款游戏或虚拟现实应用&#xff0c;需要快速创建各种场景&#xff1a;奇幻森林、未来城市、古代宫殿...传统的美术资源制作流程需要数天甚至数周时间。但现在&#xff0c…

作者头像 李华
网站建设 2026/7/14 15:24:54

YOLOv8与丹青识画融合实践:实时视频流中的艺术画作检测与追踪

YOLOv8与丹青识画融合实践&#xff1a;实时视频流中的艺术画作检测与追踪 你有没有想过&#xff0c;博物馆里的那些名画&#xff0c;如果会自己“说话”该多好&#xff1f;当游客走近时&#xff0c;它就能自动开始讲解自己的故事。这听起来像是科幻电影里的场景&#xff0c;但…

作者头像 李华