Skip to content

DMA(Direct Memory Access,直接存储器访问)是一种微控制器中的硬件模块,允许外设直接与存储器(SRAM、Flash 等)之间传输数据,而无需经过 CPU 的参与。DMA 的存在极大提升了数据传输的效率,并降低了 CPU 的负载。

以下是关于 DMA 的理论知识详细讲解:


1. DMA 的基本概念 ​

  1. 什么是 DMA?

    • DMA 是一种硬件模块,用于在微控制器的外设(如 ADC、DAC、USART、SPI、I2C 等)和存储器之间进行数据传输,而不需要 CPU 直接干预。
    • 数据传输由 DMA 控制器完成,CPU 只需配置 DMA 控制器即可。
  2. DMA 的作用

    • 减轻 CPU 的负担:DMA 模块可以在后台完成数据传输,CPU 可以专注于其他任务。
    • 提升数据传输效率:DMA 可以以硬件级别直接完成数据传输,速度快且延迟低。
    • 提供高吞吐量:通过 DMA,可以实现大批量数据的快速传输,例如 ADC 的连续采样、串口数据的高效收发等。
  3. DMA 的数据传输方式

    • 外设到存储器:例如 ADC 采样数据传输到内存。
    • 存储器到外设:例如从内存发送数据到串口(USART)。
    • 存储器到存储器:例如从一个内存区域复制数据到另一个内存区域。

2. DMA 的工作原理 ​

  1. 基本工作流程

    • CPU 配置 DMA 控制器,定义数据源、目的地址、数据大小、传输方向等。
    • 当外设产生事件(如数据准备好)时,触发 DMA 请求。
    • DMA 控制器将数据从源地址传输到目的地址,并更新传输计数器。
    • 当所有数据传输完成后,DMA 控制器通知 CPU(通过中断或标志)。
  2. 关键组件

    • 源地址:数据传输的起始地址。
    • 目的地址:数据传输的目标地址。
    • 传输计数器:记录需要传输的数据量。
    • 模式控制器:控制传输方向、数据大小、传输方式等。
    • 触发事件:由外设或软件触发 DMA 数据传输。
  3. 触发机制

    • DMA 的触发事件可以是外设产生的硬件请求(如 ADC 完成采样、中断信号等),也可以是由软件手动触发。

3. DMA 的传输模式 ​

DMA 支持多种传输模式,常见的有以下几种:

  1. 普通模式(Normal Mode)

    • DMA 传输完成后停止,不会重复传输。
    • 适用于一次性传输固定长度的数据。
  2. 循环模式(Circular Mode)

    • 当传输完成后,自动从起始地址再次开始传输。
    • 适用于需要连续传输的数据,例如 ADC 的连续采样。
  3. 双缓冲模式(Double Buffer Mode,部分 MCU 支持)

    • 配置两个缓冲区,DMA 在传输一个缓冲区的数据时可以准备另一个缓冲区。
    • 能有效减少数据丢失,适用于实时性要求较高的场景。

4. DMA 的传输方向 ​

DMA 传输的数据方向可以是以下三种:

  1. 外设到存储器

    • 例如从 ADC 获取采样数据并存储到内存。
    • 使用场景:ADC 连续采样、UART 接收数据。
  2. 存储器到外设

    • 例如从内存中读取数据并发送到外设(如 USART、SPI)。
    • 使用场景:UART 发送数据、DAC 输出波形。
  3. 存储器到存储器

    • 例如从一个内存区域复制数据到另一个内存区域。
    • 使用场景:快速数据复制或内存初始化。

5. DMA 的优点和局限性 ​

5.1 优点 ​

  1. 减轻 CPU 的负担:DMA 模块在后台运行,CPU 可以处理其他任务。
  2. 快速传输:DMA 传输速度比 CPU 控制更快,尤其是在大数据量传输时。
  3. 低延迟:DMA 的硬件传输机制相比软件更高效。
  4. 支持多种外设和传输模式:如 ADC、USART、SPI 等。

5.2 局限性 ​

  1. 配置复杂:DMA 的初始化和配置需要注意多个参数。
  2. 数据传输粒度有限:DMA 不能直接处理复杂的数据结构,只能传输原始字节或简单数组。
  3. 数据一致性问题:DMA 的传输是异步的,可能需要额外的措施确保数据一致性。
  4. 需要硬件支持:并非所有微控制器外设都支持 DMA。

6. STM32 DMA 的硬件结构 ​

在 STM32 微控制器中,DMA 控制器通常包括以下硬件模块:

  1. DMA 通道

    • 每个 DMA 控制器有多个通道,每个通道可以独立配置和运行。
    • 每个外设(如 ADC、USART 等)通常与特定的 DMA 通道绑定。
  2. 优先级

    • DMA 通道可以配置优先级(高、中、低),当多个通道同时请求时,高优先级的通道会被优先处理。
  3. 数据宽度

    • 数据传输的宽度可以是字节(8 位)、半字(16 位)或字(32 位)。
  4. 中断支持

    • DMA 支持传输完成中断、传输错误中断等。

7. DMA 的配置步骤 ​

以 STM32 HAL 库为例,以下是配置 DMA 的基本步骤:

7.1 初始化 DMA ​

  1. 使用 CubeMX 或手动配置 DMA 通道。
  2. 设置 DMA 的数据源、目标地址、数据大小、传输方向等。

7.2 启动 DMA ​

  1. 启动外设(例如 ADC、USART)。
  2. 启动 DMA 传输。

7.3 数据传输 ​

DMA 会根据配置自动完成数据传输。

7.4 中断处理(可选) ​

如果启用了中断,可以在中断回调函数中处理传输完成事件。


8. DMA 的实际应用场景 ​

  1. ADC 数据采集

    • 使用 DMA 将 ADC 的采样数据连续存储到内存中,适合高频信号采样。
  2. USART 数据收发

    • 使用 DMA 实现串口数据的高效发送和接收。
  3. SPI 数据传输

    • 使用 DMA 快速传输大批量数据到 SPI 外设,适合屏幕显示、数据传输等。
  4. DAC 波形输出

    • 使用 DMA 将波形数据从内存传输到 DAC,生成实时波形。
  5. 存储器数据复制

    • 使用 DMA 在存储器之间快速复制数据,例如初始化大数组。

9. DMA 的简单代码示例 ​

以下是一个使用 DMA 配合 ADC 的简单代码示例:

c
#include "stm32f4xx_hal.h"

ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
uint32_t adc_buffer[100];  // 存储 ADC 数据

void ADC_DMA_Init(void)
{
    // 初始化 ADC
    hadc1.Instance = ADC1;
    hadc1.Init.Resolution = ADC_RESOLUTION_12B;
    hadc1.Init.ScanConvMode = ENABLE;
    hadc1.Init.ContinuousConvMode = ENABLE;
    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    HAL_ADC_Init(&hadc1);

    // 配置 DMA
    hdma_adc1.Instance = DMA2_Stream0;
    hdma_adc1.Init.Channel = DMA_CHANNEL_0;
    hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
    hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_adc1.Init.Mode = DMA_CIRCULAR;  // 循环模式
    hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
    HAL_DMA_Init(&hdma_adc1);

    // 将 DMA 与 ADC 关联
    __HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);

    // 启动 ADC 和 DMA
    HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, 100);
}

10. 总结 ​

DMA 是嵌入式系统中非常重要的硬件模块,它通过硬件级别的直接数据传输,显著提高了数据传输效率并降低了 CPU 的负担。通过合理使用 DMA,可以实现高效的数据采集、处理和传输,是嵌入式开发中不可或缺的技术之一。