跳到主要内容

STM32 DMA 外设到存储器

介绍

DMA(Direct Memory Access,直接存储器访问)是 STM32 微控制器中一种高效的数据传输机制。它允许外设与存储器之间直接传输数据,而无需 CPU 的干预。这种方式可以显著减少 CPU 的负担,提高系统的整体性能。

在本教程中,我们将重点介绍如何使用 STM32 的 DMA 功能实现外设到存储器的数据传输。我们将通过一个具体的例子来展示如何配置 DMA,并解释每个步骤的含义。

DMA 的基本概念

DMA 是一种硬件功能,它允许数据在外设和存储器之间直接传输,而不需要 CPU 的参与。DMA 控制器负责管理数据传输的整个过程,包括地址的递增、数据大小的控制以及传输完成后的中断处理。

在 STM32 中,DMA 可以用于多种外设,如 ADC、SPI、I2C、USART 等。通过 DMA,这些外设可以直接将数据传输到存储器中,或者从存储器中读取数据。

外设到存储器的 DMA 传输

外设到存储器的 DMA 传输是指数据从外设(如 ADC)直接传输到存储器(如 SRAM)的过程。这种传输方式通常用于需要高速数据传输的场景,例如数据采集、音频处理等。

配置步骤

  1. 启用 DMA 时钟:首先需要启用 DMA 控制器的时钟。
  2. 配置 DMA 通道:选择 DMA 通道,并配置传输方向、数据大小、地址递增等参数。
  3. 配置外设:配置外设以使用 DMA 传输。
  4. 启动 DMA 传输:启动 DMA 传输,并等待传输完成。

代码示例

以下是一个简单的代码示例,展示了如何配置 DMA 从 ADC 传输数据到存储器。

c
#include "stm32f4xx.h"

#define BUFFER_SIZE 100

uint16_t adc_buffer[BUFFER_SIZE];

void DMA_Config(void) {
// 启用 DMA2 时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

// 配置 DMA2 Stream0 通道0
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_Channel = DMA_Channel_0;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);
DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)adc_buffer;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStruct.DMA_BufferSize = BUFFER_SIZE;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &DMA_InitStruct);

// 启用 DMA2 Stream0
DMA_Cmd(DMA2_Stream0, ENABLE);
}

void ADC_Config(void) {
// 启用 ADC1 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

// 配置 ADC1
ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStruct.ADC_ScanConvMode = ENABLE;
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;
ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStruct);

// 配置 ADC1 通道0
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);

// 启用 ADC1 DMA
ADC_DMACmd(ADC1, ENABLE);

// 启用 ADC1
ADC_Cmd(ADC1, ENABLE);
}

int main(void) {
// 配置 DMA 和 ADC
DMA_Config();
ADC_Config();

// 启动 ADC 转换
ADC_SoftwareStartConv(ADC1);

while (1) {
// 等待 DMA 传输完成
if (DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TCIF0)) {
// 处理数据
// ...

// 清除传输完成标志
DMA_ClearFlag(DMA2_Stream0, DMA_FLAG_TCIF0);
}
}
}

代码解释

  • DMA_Config 函数:配置 DMA2 Stream0 通道0,使其从 ADC1 的数据寄存器(DR)传输数据到 adc_buffer 数组中。
  • ADC_Config 函数:配置 ADC1 以使用 DMA 传输,并启用 ADC1。
  • main 函数:启动 ADC 转换,并在主循环中等待 DMA 传输完成。

实际应用场景

数据采集系统

在数据采集系统中,ADC 需要以高速率采集数据,并将数据传输到存储器中进行处理。使用 DMA 可以显著减少 CPU 的负担,使系统能够同时处理其他任务。

音频处理

在音频处理应用中,音频数据需要从外设(如 I2S)传输到存储器中进行处理。DMA 可以确保数据传输的实时性,避免音频数据的丢失或延迟。

总结

通过本教程,您已经了解了 STM32 的 DMA 功能,特别是外设到存储器的数据传输。我们详细介绍了 DMA 的配置步骤,并通过一个具体的代码示例展示了如何实现 ADC 数据的 DMA 传输。

提示

在实际应用中,DMA 的配置可能会更加复杂,具体取决于外设和系统的需求。建议您参考 STM32 的参考手册和库函数文档,以获取更多详细信息。

附加资源

练习

  1. 修改代码示例,使其从 SPI 外设传输数据到存储器。
  2. 尝试配置 DMA 以使用双缓冲模式,并观察数据传输的效果。
  3. 在数据传输完成后,使用中断处理函数来处理数据,而不是在主循环中等待。

通过完成这些练习,您将更深入地理解 STM32 的 DMA 功能,并能够在实际项目中灵活应用。