跳到主要内容

STM32 DMA 存储器到外设

介绍

在嵌入式系统中,数据传输是一个常见的任务。STM32 微控制器提供了 DMA(Direct Memory Access,直接存储器访问)功能,允许数据在外设和存储器之间直接传输,而无需 CPU 的干预。这种方式可以显著提高系统的效率,尤其是在处理大量数据时。

本文将重点介绍 存储器到外设 的 DMA 传输模式。在这种模式下,数据从存储器(如 RAM)直接传输到外设(如 UART、SPI 或 ADC),从而减轻 CPU 的负担。

DMA 的基本概念

DMA 是一种硬件功能,允许外设和存储器之间直接进行数据传输。它通过一个独立的 DMA 控制器来管理数据传输,从而释放 CPU 的资源,使其可以执行其他任务。

在 STM32 中,DMA 控制器可以配置为多种传输模式,包括:

  • 存储器到存储器
  • 存储器到外设
  • 外设到存储器

本文将重点讨论 存储器到外设 的传输模式。

存储器到外设的 DMA 传输

在存储器到外设的 DMA 传输中,数据从存储器(通常是 RAM)传输到外设(如 UART、SPI 或 ADC)。这种传输模式通常用于将数据发送到外部设备,例如通过 UART 发送数据到串口终端。

配置步骤

  1. 启用 DMA 时钟:首先需要启用 DMA 控制器的时钟。
  2. 配置 DMA 通道:选择 DMA 通道,并配置源地址(存储器地址)、目标地址(外设地址)、传输方向、数据大小等参数。
  3. 配置外设:确保外设已正确配置,并启用 DMA 请求。
  4. 启动 DMA 传输:启动 DMA 传输,并等待传输完成。

代码示例

以下是一个简单的代码示例,展示了如何使用 DMA 将数据从存储器传输到 UART 外设。

c
#include "stm32f4xx.h"

#define BUFFER_SIZE 128

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

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

// 配置 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)tx_buffer;
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(DMA2_Stream7, &DMA_InitStruct);

// 启用 DMA 传输完成中断
DMA_ITConfig(DMA2_Stream7, DMA_IT_TC, ENABLE);

// 启用 DMA 流
DMA_Cmd(DMA2_Stream7, ENABLE);
}

void USART_Config(void) {
// 配置 USART1
USART_InitTypeDef USART_InitStruct;
USART_InitStruct.USART_BaudRate = 9600;
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);
}

int main(void) {
// 初始化系统时钟
SystemInit();

// 配置 DMA
DMA_Config();

// 配置 USART
USART_Config();

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

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

代码解释

  • DMA_Config 函数配置了 DMA 通道,将 tx_buffer 中的数据通过 DMA 传输到 USART1 的数据寄存器(USART1->DR)。
  • USART_Config 函数配置了 USART1,并启用了 DMA 请求。
  • main 函数中,首先初始化了系统时钟,然后配置了 DMA 和 USART,最后启动了 DMA 传输。

实际应用场景

存储器到外设的 DMA 传输在许多实际应用中非常有用。例如:

  • 串口通信:通过 UART 发送大量数据时,使用 DMA 可以显著提高效率。
  • SPI 通信:在 SPI 通信中,使用 DMA 可以快速传输数据到外部设备。
  • 音频输出:在音频应用中,使用 DMA 可以将音频数据从存储器传输到 DAC(数模转换器)。

总结

通过本文,我们了解了 STM32 中存储器到外设的 DMA 传输模式。这种模式可以显著提高数据传输的效率,尤其是在处理大量数据时。我们通过一个简单的代码示例展示了如何配置 DMA 和 USART,并启动数据传输。

提示

在实际项目中,建议结合中断机制来处理 DMA 传输完成事件,以便在传输完成后执行相应的操作。

附加资源与练习

  • 练习:尝试修改代码,使用 DMA 将数据从存储器传输到 SPI 外设。
  • 资源:参考 STM32 官方文档,了解更多关于 DMA 的配置和使用细节。

通过不断实践和探索,你将能够熟练掌握 STM32 的 DMA 功能,并在实际项目中灵活应用。