跳到主要内容

STM32 DMA配置案例

介绍

DMA(Direct Memory Access,直接内存访问)是STM32微控制器中一个强大的功能,它允许外设与内存之间直接传输数据,而无需CPU的干预。这种方式可以显著提高数据传输效率,尤其是在处理大量数据时,例如音频流、图像处理或通信协议(如UART、SPI、I2C等)。

通过DMA,CPU可以专注于其他任务,而数据传输则由DMA控制器自动完成。本文将逐步讲解如何配置STM32的DMA,并通过一个实际案例展示其应用。


DMA的基本概念

DMA的核心思想是减少CPU的负担。它通过以下步骤实现数据传输:

  1. 源地址:数据从哪里来(例如外设寄存器或内存)。
  2. 目标地址:数据到哪里去(例如内存或外设寄存器)。
  3. 传输大小:需要传输的数据量(字节、半字或字)。
  4. 传输模式:单次传输或循环传输。

DMA控制器会根据配置自动完成数据传输,并在传输完成后触发中断(如果需要)。


STM32 DMA配置步骤

以下是配置STM32 DMA的基本步骤:

  1. 启用DMA时钟:在使用DMA之前,需要启用DMA控制器的时钟。
  2. 配置DMA通道:选择DMA通道并设置传输方向、数据大小、地址增量等参数。
  3. 配置外设:将外设与DMA关联,例如UART、SPI等。
  4. 启动DMA传输:使能DMA通道并开始传输。
  5. 处理中断(可选):如果需要,可以配置DMA传输完成中断。

实际案例:使用DMA实现UART数据传输

以下是一个使用DMA实现UART数据传输的案例。我们将通过DMA将内存中的数据发送到UART,并在传输完成后触发中断。

硬件配置

  • 使用STM32F4系列微控制器。
  • UART1用于数据传输。
  • DMA1的通道4用于UART1的发送。

代码实现

c
#include "stm32f4xx.h"

#define BUFFER_SIZE 128

uint8_t txBuffer[BUFFER_SIZE] = "Hello, DMA!";

void DMA_Config(void) {
// 1. 启用DMA时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

// 2. 配置DMA通道
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_Channel = DMA_Channel_4;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)txBuffer;
DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
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_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
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(DMA1_Stream4, &DMA_InitStruct);

// 3. 启用DMA中断
DMA_ITConfig(DMA1_Stream4, DMA_IT_TC, ENABLE);
NVIC_EnableIRQ(DMA1_Stream4_IRQn);

// 4. 启用DMA流
DMA_Cmd(DMA1_Stream4, ENABLE);
}

void USART_Config(void) {
// 启用USART1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

// 配置USART1
USART_InitTypeDef USART_InitStruct;
USART_InitStruct.USART_BaudRate = 115200;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Tx;
USART_Init(USART1, &USART_InitStruct);

// 启用USART1 DMA请求
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

// 启用USART1
USART_Cmd(USART1, ENABLE);
}

void DMA1_Stream4_IRQHandler(void) {
if (DMA_GetITStatus(DMA1_Stream4, DMA_IT_TCIF4)) {
// 清除中断标志
DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_TCIF4);

// 传输完成后的处理
// 例如:点亮LED或打印日志
}
}

int main(void) {
// 初始化DMA和USART
DMA_Config();
USART_Config();

// 启动DMA传输
DMA_Cmd(DMA1_Stream4, ENABLE);

while (1) {
// 主循环
}
}

代码说明

  1. DMA_Config:配置DMA通道,设置源地址(内存中的txBuffer)和目标地址(UART1的数据寄存器)。
  2. USART_Config:配置UART1并启用DMA请求。
  3. DMA1_Stream4_IRQHandler:DMA传输完成中断处理函数,用于在传输完成后执行特定操作。

总结

通过本文,我们学习了如何配置STM32的DMA功能,并通过一个实际案例展示了如何使用DMA实现UART数据传输。DMA是STM32中一个非常强大的工具,能够显著提高系统性能,尤其是在处理大量数据时。

提示

练习:尝试修改代码,使用DMA实现UART接收数据,并将接收到的数据存储到内存中。


附加资源