2. DMA传输模式:单次、块、链传输

DMA传输模式,说白了就是决定「一次搬运多少数据、搬完后怎么办」。我当年刚接触DMA时,觉得能传输就行,模式什么的无所谓。直到有一次项目功耗超标,才发现选错了模式,CPU被拖累得够呛。

搞懂这三种模式,你就能精准控制CPU负载。咱们一个一个看。

2.1 单次传输模式

这是最基础的DMA模式。一次请求,只传输一个数据单元(比如一个字节或一个字)。传输完就停,等着下一个请求。

我曾经在音频采集项目里用过单次传输,结果CPU每秒要响应几千次中断。你说这DMA还有什么意义?

工作流程:

  • CPU配置源地址、目的地址、传输大小(1单元)
  • DMA搬运1个单元
  • 触发中断,通知CPU处理
  • CPU重新配置下一次传输

你想想看,每次传输都要CPU介入。这跟CPU自己搬数据有什么区别?唯一的好处是,传输本身不占CPU时钟周期。但中断开销全在CPU头上。

特性 描述
中断频率 极高(每个数据单元一次)
适用场景 极低速外设(如按键、传感器采样)
CPU负载 高(被频繁中断淹没)

我个人习惯,只有在传输频率低于1KHz时才考虑单次模式。否则CPU光伺候中断就够呛了。

2.2 块传输模式

块传输模式,也叫突发传输。它把多个数据单元打包成一个「块」,一次请求就把整个块搬完。

举个例子:

  • 配置块大小为1024字节
  • DMA连续搬运1024次(每次1字节)
  • 全部完成后触发一次中断

这里的关键是「连续搬运」——DMA独占总线,一口气把数据搬完。中间不释放总线控制权。

我在处理高速数据采集卡时遇到过一个问题:块传输虽然减少了中断次数,但总线被DMA占着不放,CPU在传输期间无法访问内存。如果传输块太大,CPU响应会延迟。

核心权衡:块越大,中断次数越少,但CPU内存访问延迟越高。

块大小 中断次数(1MB数据) 总线占用持续时间
64字节 16384次 极短
1KB 1024次 中等
16KB 64次 较长

块传输适用场景:

  • 连续数据流(如音频、视频)
  • 外设速度匹配(如SPI、I2C)
  • CPU可以忍受短时总线延迟的场景

2.3 链传输模式

链传输,这是真正的大杀器。它把多个传输任务连成一条「链」,DMA自动执行下一个,CPU全程不用管。

核心原理:每个传输任务称为一个「描述符」,描述符中除了配置信息,还包含指向下一个描述符的指针。

// 描述符结构示意
struct dma_descriptor {
    uint32_t src_addr;      // 源地址
    uint32_t dst_addr;      // 目的地址
    uint32_t transfer_size; // 传输大小
    uint32_t next_desc;     // 指向下一个描述符
    uint32_t control;       // 控制字段
};

// 链式描述符示例
struct dma_descriptor desc1, desc2, desc3;
desc1.next_desc = &desc2;
desc2.next_desc = &desc3;
desc3.next_desc = NULL;  // 链尾

为什么要把多个块串起来?我举个实际案例:图像采集系统中,一帧图像分布在3个不同缓冲区。如果用块传输,CPU得配置3次;用链传输,配置一次,DMA自动搞定三个缓冲区。

链传输的三大优势:

  • 零CPU干预:配置完链后,CPU可以睡大觉
  • 复杂传输场景:分散-聚集(Scatter-Gather)轻松实现
  • 极低中断频率:整条链执行完才中断一次

我曾经在工业相机项目中使用链传输,200个描述符串成一链,连续采集10秒图像,CPU只在结束时刻收到一次中断。你说这负载优化得有多痛快?

2.4 三种模式对比与选型

选哪种模式,取决于你的系统对CPU负载和实时性的要求。我通常按这个思路判断:

  • 数据量小(< 10字节)、频率低 → 单次传输
  • 数据量大、可接受短暂总线延迟 → 块传输
  • 数据量大、需要CPU空闲、多个不连续缓冲区 → 链传输

2.5 知识结构图

下面这张图把三种模式的核心关系和适用场景串起来了。

DMA传输模式对比 单次传输 一次传输1个数据单元 中断频率:极高 CPU负载:高 块传输 一次传输多个数据单元 中断频率:中 CPU负载:中 链传输 多个块自动串联执行 中断频率:极低 CPU负载:极低 适用场景速查 极低速外设 连续数据流 多缓冲区、Scatter-Gather (按键、传感器) (音频、视频、SPI) (图像采集、网络包处理) 选型核心:CPU负载 vs 实时性需求

嗯,这张图你看懂了,选型基本不愁。我个人建议,只要硬件支持,优先考虑链传输。它带来的CPU负载降低,是立竿见影的。

避坑提醒:链传输虽然强大,但描述符链必须保证在物理内存中连续(或通过硬件自动取指)。我见过有人把描述符放在堆里,结果DMA读取时内存碎片化导致指针断裂,系统直接挂掉。

2.6 小结

三种模式,从单次到链传输,CPU负载逐步降低,但配置复杂度逐级升高。做项目时,我习惯先看系统对CPU空闲率的要求,再决定模式。如果要求CPU在数据传输期间能干别的事,别犹豫,上链传输。