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)的过程。这种传输方式通常用于需要高速数据传输的场景,例如数据采集、音频处理等。
配置步骤
- 启用 DMA 时钟:首先需要启用 DMA 控制器的时钟。
- 配置 DMA 通道:选择 DMA 通道,并配置传输方向、数据大小、地址递增等参数。
- 配置外设:配置外设以使用 DMA 传输。
- 启动 DMA 传输:启动 DMA 传输,并等待传输完成。
代码示例
以下是一个简单的代码示例,展示了如何配置 DMA 从 ADC 传输数据到存储器。
#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 的参考手册和库函数文档,以获取更多详细信息。
附加资源
练习
- 修改代码示例,使其从 SPI 外设传输数据到存储器。
- 尝试配置 DMA 以使用双缓冲模式,并观察数据传输的效果。
- 在数据传输完成后,使用中断处理函数来处理数据,而不是在主循环中等待。
通过完成这些练习,您将更深入地理解 STM32 的 DMA 功能,并能够在实际项目中灵活应用。