news 2026/4/18 5:17:30

图解说明AXI DMA在SoC中的连接方式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
图解说明AXI DMA在SoC中的连接方式

深入理解AXI DMA:从原理到SoC系统中的实战连接

你有没有遇到过这样的场景?CPU明明没做什么复杂计算,系统却卡得不行。查看负载发现,数据搬运占了大头——比如摄像头源源不断地送帧进来,网络包一个接一个地收,每来一包就要中断一次CPU去拷贝……这种“低效搬运”正是嵌入式系统性能瓶颈的常见根源。

这时候,AXI DMA就该登场了。

它不是什么神秘黑盒,而是现代SoC中默默扛起数据洪流的关键角色。特别是在Zynq、Intel SoC FPGA这类异构平台上,搞懂AXI DMA 的连接方式与工作机制,几乎是实现高性能系统的必修课。

今天我们就抛开教科书式的罗列,用“图解+实战视角”的方式,带你真正看懂 AXI DMA 是如何在片上系统里跑起来的。


为什么需要 AXI DMA?

先回到问题的本质:谁在搬数据?怎么搬才高效?

传统做法是让 CPU 亲自下场,外设一有数据就发中断,CPU 响应后从外设寄存器一个个读出来,再写进内存。这个过程看似简单,但代价极高:

  • 每次中断都要保存上下文;
  • 频繁访问外设寄存器消耗大量指令周期;
  • 数据量一大,CPU 直接被拖垮。

而 AXI DMA 的出现,就是为了让硬件自己完成这件事——把数据从A点搬到B点,不需要CPU插手

它的核心依托是 ARM 定义的AMBA AXI 总线协议。AXI 支持突发传输、地址/数据分离通道、乱序响应等特性,天生适合高带宽、低延迟的数据通路设计。将 DMA 控制器嫁接到 AXI 架构上,就形成了我们所说的AXI DMA

简单说:AXI 提供“高速公路”,DMA 是“自动货车”,两者结合,实现外设和内存之间的“零拷贝”直运。


AXI DMA 到底是什么?拆开看看

如果你打开 Xilinx 的 PG021 文档(AXI DMA Product Guide),会看到一堆术语:MM2S、S2MM、SG Engine、AXI4-Stream……别急,我们用人话重新梳理一遍。

三个接口,各司其职

AXI DMA IP 核通常包含三个独立的 AXI 接口

接口类型功能说明
AXI Memory Mapped (MM)负责与 DDR 内存交互,读或写数据块
AXI4-Stream连接高速数据源/目的地,如 ADC、视频输入、以太网 MAC
AXI Lite轻量级控制接口,用于配置寄存器、查询状态

你可以把它想象成一个“智能物流中心”:

  • MM 接口是仓库大门,货物进出都走这里;
  • Stream 接口是传送带,持续不断地送来或送出包裹;
  • Lite 接口是管理员办公室,你在这里下单、查进度。

两大通道:MM2S 和 S2MM

AXI DMA 最核心的部分是两个数据通道:

✅ MM2S(Memory Map to Stream)

从内存读数据 → 发送到 Stream 输出端
典型用途:把图像帧从 DDR 读出 → 发给 HDMI 显示模块

✅ S2MM(Stream to Memory Map)

从 Stream 输入端收数据 → 写入指定内存地址
典型用途:摄像头数据流 → 存入 DDR 缓冲区

这两个通道可以完全并行运行,意味着你能同时做“采集 + 回放”、“接收 + 转发”,真正做到全双工。

而且它们都有自己的控制逻辑、描述符队列、中断机制,互不干扰。


数据是怎么跑起来的?三步走流程

AXI DMA 不是上电就自动干活的,得先告诉它:“你要搬什么?从哪来?到哪去?搬多少?” 整个流程分三步:

第一步:CPU 下达任务(初始化)

通过 AXI Lite 接口,CPU 向 DMA 写入关键参数:

// 示例寄存器操作 dma_write(CMDR, 0x04); // 复位 dma_write(SA, src_phys_addr); // 源地址(物理) dma_write(DA, dst_phys_addr); // 目标地址 dma_write(LEN, data_size); // 数据长度 dma_write(CMDR, 0x01); // 启动

注意:这里的地址必须是物理连续且 cache 一致的内存,否则可能因缓存污染导致数据错乱。Linux 下推荐使用dma_alloc_coherent()分配。


第二步:DMA 自动执行搬运

一旦启动,DMA 控制器就开始自主工作:

  • MM2S 通道发起 AXI 读事务,从 DDR 取数据;
  • 数据被打包成 AXI4-Stream 格式,送往 PL 中的功能模块;
  • S2MM 通道接收外部 Stream 数据,按描述符写回内存;
  • 所有过程无需 CPU 干预。

如果启用了Scatter-Gather(分散-聚集)模式,DMA 还能自动加载下一个任务描述符,形成“流水线式”连续传输,极大减少中断次数。


第三步:完成通知(中断上报)

当一帧数据传完,DMA 会产生中断信号,通过 IRQ_F2P 引脚送至 PS 端的 GIC(通用中断控制器)。

应用层捕获中断后,即可调度后续处理,例如:
- 图像处理线程开始分析新帧;
- 网络协议栈解析刚收到的数据包;
- 触发下一帧采集。

⚠️ 小贴士:频繁中断也会累。建议启用中断合并(Interrupt Coalescing),比如每 4 帧报一次中断,平衡实时性与 CPU 占用。


在 Zynq SoC 中,它是怎么连的?

现在我们进入重头戏:AXI DMA 在典型的 SoC 架构中到底怎么连接?

以下以 Xilinx Zynq-7000 或 Zynq UltraScale+ 为例,画一张“文字拓扑图”,帮你建立空间感:

[Application Processor Unit (APU)] ↓ [AXI GP0 / GP1] ←→ [GIC, Timer, UART...] ↗ ↘ (Control) (Interrupt) ↓ ↓ [AXI Interconnect] ←→ [DDR Ctrl] ←→ [L3 Cache / OCM] ↑ ↑ (High-Performance Port) (Shared Memory) ↓ [Programmable Logic (PL)] ↓ [AXI DMA Core] ↙ ↘ [MM2S] [S2MM] ↓ ↑ [data out] [data in] ↓ ↑ [FIFO / Video IP] [Sensor / MAC / ADC]

关键路径详解

🌐 MM2S 数据路径(内存 → 外设)
  1. CPU 配置 MM2S 源地址(DDR 地址)、长度;
  2. DMA 发起 AXI 读请求 → 经 AXI HP 接口 → DDR 控制器返回数据;
  3. 数据经 FIFO 缓冲 → 转为 AXI4-Stream → 送给 PL 中的输出模块(如 HDMI TX);
📥 S2MM 数据路径(外设 → 内存)
  1. 外设(如摄像头)发送 AXI4-Stream 数据流进入 S2MM 接口;
  2. DMA 接收数据并缓存于内部 FIFO;
  3. 当满足突发条件时,发起 AXI 写事务 → 将数据写入 DDR 指定地址;
  4. 写完成成后触发中断,通知 CPU。
🔧 控制与中断路径
  • 控制通道:CPU 通过 AXI GP 主端口访问 AXI Lite 接口,进行配置;
  • 中断通道:DMA 的中断信号接入 IRQ_F2P[n],由 PS 端 GIC 统一管理。

实战代码:用户空间也能玩转 AXI DMA

很多人以为操作 DMA 必须写内核驱动,其实对于快速验证,完全可以使用UIO(Userspace I/O)框架在用户态直接控制。

下面是一个精简版的 C 程序,展示如何通过/dev/uio0控制 AXI DMA 发起一次 S2MM 传输:

#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> #define DMA_BASE 0x40400000 #define S2MM_CTRL 0x30 #define S2MM_DA 0x48 #define S2MM_LENGTH 0x58 int main() { int fd; void *reg_base; fd = open("/dev/uio0", O_RDWR); if (fd < 0) { perror("open uio"); return -1; } reg_base = mmap(NULL, 64*1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); // 1. 复位 *((volatile uint32_t*)(reg_base + S2MM_CTRL)) = 0x04; usleep(1000); *((volatile uint32_t*)(reg_base + S2MM_CTRL)) = 0x00; // 2. 设置目标地址(需提前分配DMA一致性内存) uint32_t buf_phys = 0x18000000; *((volatile uint32_t*)(reg_base + S2MM_DA)) = buf_phys; // 3. 设置传输长度(1MB) *((volatile uint32_t*)(reg_base + S2MM_LENGTH)) = 1024 * 1024; // 4. 启动 *((volatile uint32_t*)(reg_base + S2MM_CTRL)) |= 0x01; printf("S2MM transfer started, waiting for interrupt...\n"); // 5. 等待中断(read阻塞直到中断发生) read(fd, NULL, 0); printf("Transfer completed!\n"); munmap(reg_base, 64*1024); close(fd); return 0; }

📌重点提醒
- 物理地址必须真实存在且可写;
- 使用uio_pdrv_genirq驱动绑定设备;
- 内存要用dma_alloc_coherentcma分配,避免 cache 问题;
- 中断只能等待一次,循环传输需重新映射或使用 epoll。

这套方法非常适合原型开发、算法验证,甚至某些对延迟要求不极端的工业场景。


设计中常见的“坑”与应对策略

即便理论清晰,实际落地时仍有不少陷阱。以下是几个高频问题及解决方案:

❌ 坑点1:数据丢包 or 错位

现象:图像花屏、音频断续、采样点丢失
原因
- 外设时钟与系统时钟不同步(如视频 148.5MHz vs 系统 100MHz)
- 没加异步 FIFO,导致跨时钟域亚稳态

对策:在 Stream 接口前插入ASYNC_FIFO,深度至少 2~4 倍于最大突发长度。


❌ 坑点2:带宽不够,传输卡顿

计算示例
4K@30fps YUV422 视频 ≈ 3840×2160×2×30 ≈497 MB/s

若 AXI 总线为 64-bit @ 100MHz → 带宽 = 800 MB/s,勉强够用;
但若有多个通道并发,很容易挤爆总线。

对策
- 升级到 128-bit 总线;
- 使用 AXI ACE 接口支持缓存一致性;
- 合理设置 QoS 优先级,保障关键流。


❌ 坑点3:Cache 污染导致数据看不到

经典错误:DMA 写完了,CPU 读内存却发现全是旧数据!

这是因为 CPU 缓存了之前的副本,而 DMA 修改的是实际物理内存。

正确做法
- 使用dma_alloc_coherent()分配内存(自动 uncached & non-buffered);
- 或手动调用__builtin___clear_cache()/__cpuc_flush_dcache_area()
- 在多核环境下尤其要注意 SMP barrier。


✅ 最佳实践清单

项目推荐做法
内存分配dma_alloc_coherent()或预留 CMA 区域
传输模式高吞吐选 Scatter-Gather,低延迟选 Circular Buffer
中断管理启用 Interrupt Coalescing(如 coalescing_count=4)
跨时钟域所有 Stream 接口前加 ASYNC_FIFO
QoS 设置对视频/实时流设置更高 ARQoS/AWQoS
调试手段使用 ILA 抓波形,确认 TVALID/TREADY 是否拉满

它都在哪些地方发光发热?

AXI DMA 看似低调,实则无处不在。以下是几个典型应用场景:

🎥 场景1:机器视觉采集系统

  • CMOS Sensor → Video-In IP → AXI DMA (S2MM) → DDR
  • GPU / NPU 从 DDR 读取 → AI 推理
  • 实现“采集-推理” pipeline,全程零拷贝

📡 场景2:智能网卡加速

  • Ethernet MAC 收包 → AXI DMA → 报文池
  • 用户态程序(如 DPDK-like)直接消费
  • 避免 Linux 协议栈拷贝开销,提升吞吐

🔊 场景3:高速数据采集(DAQ)

  • ADC @ 100MSPS → LVDS → PL → AXI DMA → DDR
  • 持续录制数分钟原始信号,供后期分析
  • 支持环形缓冲,永不丢点

🖥️ 场景4:图形显示合成

  • 多个图层渲染结果 → 分别通过 MM2S 写入显存
  • DisplayPort/HDMI 控制器读取显存 → 输出
  • 支持动态切换分辨率、刷新率

写在最后:AXI DMA 的未来不止于“搬运工”

今天的 AXI DMA 已不仅仅是“搬数据”的工具。随着边缘计算、AIoT 的发展,它正在演变为更智能的数据通路中枢:

  • 结合SMMU实现安全隔离的 DMA 访问;
  • 集成AXI Firewall防止非法内存访问;
  • 支持虚拟化环境下的多租户 DMA 调度
  • 与 NoC(Network-on-Chip)融合,构建片上海量数据交换网络。

可以说,掌握 AXI DMA,不只是学会了一个IP核的使用,更是掌握了现代SoC数据流设计的核心思维

下次当你面对一个高吞吐需求的设计时,不妨先问问自己:

“这部分数据,真的需要CPU来搬吗?能不能交给 AXI DMA 去做?”

也许答案,就在那条静静流淌的 AXI 总线上。

如果你在项目中用到了 AXI DMA,欢迎留言分享你的架构设计或踩过的坑!

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

trace.moe技术深度解析:如何实现秒级动漫场景精准搜索

trace.moe技术深度解析&#xff1a;如何实现秒级动漫场景精准搜索 【免费下载链接】trace.moe trace.moe - 一个动漫场景搜索引擎&#xff0c;能够识别动漫截图中的场景并提供具体出自哪一集的信息。 项目地址: https://gitcode.com/gh_mirrors/tr/trace.moe 在动漫爱好…

作者头像 李华
网站建设 2026/4/16 16:35:52

STM32离线烧写器实战指南:告别电脑束缚的终极烧写方案

STM32离线烧写器实战指南&#xff1a;告别电脑束缚的终极烧写方案 【免费下载链接】OfflineSWD STM32系列离线烧写器 项目地址: https://gitcode.com/gh_mirrors/of/OfflineSWD 在嵌入式开发的世界里&#xff0c;你是否曾因现场无法连接电脑而束手无策&#xff1f;是否在…

作者头像 李华
网站建设 2026/4/16 15:20:37

One Dark Pro主题完全指南:打造专业级VS Code编码环境

One Dark Pro主题完全指南&#xff1a;打造专业级VS Code编码环境 【免费下载链接】OneDark-Pro Atoms iconic One Dark theme for Visual Studio Code 项目地址: https://gitcode.com/gh_mirrors/on/OneDark-Pro 还在为代码编辑器单调的配色而苦恼吗&#xff1f;每天面…

作者头像 李华
网站建设 2026/4/11 1:28:54

数字人应用开发完整指南:轻松实现跨平台部署

在人工智能技术快速发展的今天&#xff0c;数字人技术正在重塑人机交互的未来。duix.ai作为硅基智能开源的高性能数字人SDK&#xff0c;为开发者提供了简单易用的跨平台解决方案。无论您是技术新手还是经验丰富的开发者&#xff0c;都能通过本指南快速掌握数字人应用开发的核心…

作者头像 李华
网站建设 2026/4/17 10:47:29

风险管理框架:软件资产管理中的风险控制

风险管理框架&#xff1a;软件资产管理中的风险控制作为一名常年从事软件资产管理工作的技术专家&#xff0c;我经常会遇到一个棘手的问题——如何在复杂的软件管理体系中有效识别、评估和控制系统风险&#xff1f;是在企业数字化转型加速、软件资产数量和种类不断膨胀的当下&a…

作者头像 李华
网站建设 2026/4/17 21:00:36

LabelPlus:5个关键功能让你的漫画翻译效率提升300%

LabelPlus&#xff1a;5个关键功能让你的漫画翻译效率提升300% 【免费下载链接】LabelPlus Easy tool for comic translation. 项目地址: https://gitcode.com/gh_mirrors/la/LabelPlus 在漫画翻译领域&#xff0c;LabelPlus作为一款专业的开源漫画翻译工具&#xff0c;…

作者头像 李华