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,可以实现高效的数据采集、处理和传输,是嵌入式开发中不可或缺的技术之一。