1. DMA基础概念:什么是DMA、DMA的工作原理、DMA与CPU的数据搬运对比

各位同学,咱们今天聊聊DMA。说实话,我做了十几年嵌入式开发,DMA这玩意儿几乎天天打交道。很多刚入行的朋友总觉得DMA很神秘,其实说白了,它就是硬件层面的「数据搬运工」。

1.1 什么是DMA

DMA,全称Direct Memory Access,直接存储器访问。我习惯叫它「数据快车道」。

你想想看,没有DMA的时候,CPU得亲自把数据从外设搬到内存,或者从内存搬到外设。这就像一个大老板亲自去搬砖,效率能高吗?DMA就是专门干这个的硬件模块,它不需要CPU插手,自己就能完成数据搬运。

核心要点:DMA是一个独立的硬件控制器,可以在没有CPU参与的情况下,完成外设与内存之间的数据传输。

1.2 DMA的工作原理

DMA的工作流程其实不复杂,我给大家拆解一下:

  1. 请求阶段:外设(比如UART、SPI、ADC)产生数据,向DMA控制器发送请求信号。
  2. 仲裁阶段:DMA控制器向CPU请求总线控制权。CPU在总线空闲时让出控制权。
  3. 传输阶段:DMA接管总线,直接在外设和内存之间搬运数据。
  4. 结束阶段:传输完成,DMA释放总线,通知CPU「活干完了」。

嗯,这里要注意一个细节:DMA传输期间,CPU其实是被「挂起」的,不能访问总线。但现代处理器有缓存和流水线,影响没那么大。

个人经验:我在做某款工业相机项目时,用DMA搬运图像数据,CPU占用率从85%直接降到12%。那感觉,就像给系统装了个涡轮增压。

1.3 DMA与CPU的数据搬运对比

咱们直接上对比表,一目了然:

对比项 CPU搬运 DMA搬运
控制方式 软件指令控制 硬件自动控制
速度 受限于指令执行周期 接近总线极限速度
CPU占用 100%占用,无法做其他事 几乎零占用
适用场景 小数据量、非实时 大数据量、实时性要求高
灵活性 高,可随时修改逻辑 低,需预先配置
功耗 较高(CPU持续运行) 较低(专用硬件完成)

说白了,CPU搬运就像你亲自去快递站取件,DMA搬运就像让快递小哥直接送到家门口。一个费时费力,一个省心省力。

避坑指南:我曾经在一个项目中,用CPU轮询方式读取ADC数据,结果CPU忙得连系统心跳都跑不准了。后来换成DMA + 中断方式,问题迎刃而解。记住:能用DMA的地方,别让CPU干苦力活。

1.4 实际代码示例

咱们看一个简单的DMA配置代码,以STM32为例:

// DMA传输配置示例
void DMA_Config(void)
{
    // 1. 使能DMA时钟
    RCC->AHBENR |= RCC_AHBENR_DMA1EN;
    
    // 2. 配置DMA通道
    DMA1_Channel6->CPAR = (uint32_t)&USART1->DR;  // 外设地址
    DMA1_Channel6->CMAR = (uint32_t)rx_buffer;     // 内存地址
    DMA1_Channel6->CNDTR = BUFFER_SIZE;            // 传输数据量
    
    // 3. 配置传输方向:外设到内存
    DMA1_Channel6->CCR |= DMA_CCR_DIR;
    
    // 4. 使能DMA通道
    DMA1_Channel6->CCR |= DMA_CCR_EN;
}

这段代码看着简单,但背后涉及的东西不少。外设地址、内存地址、传输方向、数据宽度...每一个参数都直接影响系统稳定性。

1.5 什么时候该用DMA?

我给大家总结几个典型场景:

  • 大数据量传输:比如音频播放、视频采集、文件读写
  • 周期性数据搬运:比如ADC连续采样、定时器触发传输
  • 实时性要求高:比如电机控制、传感器数据采集
  • 低功耗场景:CPU可以进入休眠,DMA默默干活

反过来,如果只是传几个字节的数据,或者数据量很小,用DMA反而得不偿失。为什么?因为DMA的配置开销可能比直接CPU搬运还大。这个道理,就像你叫个外卖只买一瓶水,配送费比水还贵。

我的建议:刚开始接触DMA时,先从简单的UART接收开始练手。配置简单,效果明显,出了问题也好排查。等熟悉了再挑战复杂场景。

好了,这一章的内容就到这里。DMA的概念其实不复杂,关键是要理解它「解放CPU」的核心思想。下一章咱们聊聊DMA在设备树中的描述方式,那才是真正实战的开始。