当前位置: 首页 > news >正文

保姆级教程十:软硬大闭环!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 传数据。这一整套丝滑的连招,就是目前工业界(医疗影像、机器视觉、雷达信号处理)最主流的开发范式!

http://www.jsqmd.com/news/493693/

相关文章:

  • 腾讯云澄清高额费用系历史调用,但普通用户如何分清安装免费和使用收费的界限?这是否存在误导用户的嫌疑?
  • 【什么是服务器?10分钟彻底理解服务器的原理与作用(小白必看)】
  • 告别重复劳作!n8n:技术团队的工作流自动化神器
  • 麦轮 AGV 小车电机选型指南
  • 告别云端延迟:用TensorFlow Lite Micro在STM32上跑通你的第一个AI模型(附完整代码)
  • StructBERT中文句子相似度实测:200字符长句、中英混排处理效果展示
  • 【人工智能】向量数据库全生命周期数据安全防护体系:破解向量化与检索双环节泄露风险
  • 好写作AI:硕士论文初稿完成后如何用AI进行自检——从“写完”到“写好”的最后一道关卡
  • OpenClaw 最热门使用技能 TOP 10
  • qt系统字体方案
  • AutoGen Studio快速入门:无需代码基础玩转AI智能体
  • 破除医疗流程图协作壁垒:drawio-desktop的格式桥接技术与实践指南
  • 直流电机特性仿真:调压、弱磁、串电阻启动的Matlab GUI界面设计
  • 快速上手all-MiniLM-L6-v2:轻量级句子嵌入模型实战指南
  • 告别复杂配置!SGLang-v0.5.6 Docker镜像快速部署,小白也能轻松搭建LLM服务
  • Maye Nano v2.2.0.260313 丨 Windows 高效启动工具
  • ISTA6A电商标准,ISTA 6A亚马逊包装测试(Type A)全面介
  • 190.Vue3 + OpenLayers 实战:实现地图旋转移动动画 + CSS缩放动画(详解 animate 用法)
  • HunterPie配置系统深度解析:现代游戏覆盖层的智能管理架构
  • 当心!你选的访客系统正悄悄出卖公司隐私
  • Git误操作急救手册:拯救代码全攻略
  • MinerU入门教程:3步学会使用智能文档理解,提升工作效率
  • 互联网大厂Java面试:水货程序员的搞笑经历
  • 基于code-server打造私有AI编程工作站
  • 深入理解 Spring 中的 @Primary 与 @Qualifier
  • 不止调亮度!晚上玩手机的 “护眼全链路” 设置指南
  • 电动汽车高压平台采用率持续上升
  • 基于PP-DocLayoutV3的VMware虚拟机文档自动化管理
  • 机械毕业设计选题指南:从工程问题到技术实现的选题方法论
  • Qwen2-VL-2B-Instruct保姆级部署教程:Windows系统下Docker环境配置详解