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 发送数据到串口终端。
配置步骤
- 启用 DMA 时钟:首先需要启用 DMA 控制器的时钟。
- 配置 DMA 通道:选择 DMA 通道,并配置源地址(存储器地址)、目标地址(外设地址)、传输方向、数据大小等参数。
- 配置外设:确保外设已正确配置,并启用 DMA 请求。
- 启动 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 功能,并在实际项目中灵活应用。