在嵌入式开发中,STM32系列MCU凭借其强大的性能和灵活的外设资源备受开发者青睐。本文将以STM32F446为例,介绍如何使用DMA(直接存储器访问)提升数据传输效率,并通过一个案例展示DMA的基本配置和使用方法。
为什么选择STM32F446?STM32F446属于ST的高性能MCU系列,主频高达180 MHz,配备丰富的外设资源。它特别适合高吞吐量的应用场景,例如音频处理、实时控制和数据采集等。
DMA的优势DMA可以直接在外设和内存之间传输数据,无需CPU介入,从而减轻CPU负担。典型应用包括:
- 串口数据发送和接收
- ADC采样结果的搬运
- 图像或音频数据处理
开发环境准备- 硬件:STM32F446开发板
- 软件:STM32CubeIDE
- 外设:USART2用于串口通信
应用场景我们将实现一个通过USART2发送字符串数据的功能,使用DMA传输代替传统的中断或轮询方式,以提升效率。
实现代码以下是完整的代码实现:
#include "main.h"
#include "string.h"
UART_HandleTypeDef huart2; // USART2句柄
DMA_HandleTypeDef hdma_usart2_tx; // DMA句柄
// 要发送的数据
char txData[] = "Hello, DMA! This is STM32F446.\r\n";
// 初始化GPIO
void MX_GPIO_Init(void) {
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3; // USART2 TX/RX
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
// 初始化USART2
void MX_USART2_UART_Init(void) {
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart2);
}
// 初始化DMA
void MX_DMA_Init(void) {
__HAL_RCC_DMA1_CLK_ENABLE();
hdma_usart2_tx.Instance = DMA1_Stream6; // 使用DMA1的Stream6
hdma_usart2_tx.Init.Channel = DMA_CHANNEL_4;
hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart2_tx.Init.Mode = DMA_NORMAL;
hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_usart2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_usart2_tx);
__HAL_LINKDMA(&huart2, hdmatx, hdma_usart2_tx); // 连接DMA到USART2
}
// 主函数
int main(void) {
HAL_Init(); // 初始化HAL库
SystemClock_Config(); // 配置系统时钟
MX_GPIO_Init(); // 初始化GPIO
MX_USART2_UART_Init(); // 初始化USART2
MX_DMA_Init(); // 初始化DMA
while (1) {
// 使用DMA发送数据
HAL_UART_Transmit_DMA(&huart2, (uint8_t *)txData, strlen(txData));
HAL_Delay(1000); // 延时1秒
}
}
// 时钟配置
void SystemClock_Config(void) {
// 此处略去详细时钟配置代码,可使用STM32CubeMX生成
}
核心逻辑分析- DMA初始化
使用HAL_DMA_Init完成DMA的通道和方向配置,并通过__HAL_LINKDMA将DMA句柄与USART2的TX绑定。
- DMA数据发送
使用HAL_UART_Transmit_DMA启动数据传输,DMA会自动将数据从内存搬运到USART的发送寄存器,整个过程无需CPU干预。
- 主循环
每隔1秒调用一次发送函数,通过串口不断输出字符串。
测试与优化将代码烧录到STM32F446开发板,打开串口调试助手,可以看到每秒输出"Hello, DMA! This is STM32F446."的字符串。
优化方向:
- 提升速率:通过调整波特率增加传输速度。
- 多通道并行传输:利用STM32的多DMA通道,实现更多外设的并行数据传输。
总结通过本文的案例,我们展示了如何在STM32F446中使用DMA实现高效数据传输。与传统的中断或轮询方式相比,DMA极大地减轻了CPU的负担,特别适用于需要高性能的场景。
|