打印
[STM32F4]

STM32F446基于DMA的高效数据传输实践

[复制链接]
614|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Wordsworth|  楼主 | 2024-11-22 07:57 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在嵌入式开发中,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的负担,特别适用于需要高性能的场景。

使用特权

评论回复
沙发
公羊子丹| | 2024-11-22 07:57 | 只看该作者
原来DMA用起来这么简单,配置逻辑也很清晰,学习了!

使用特权

评论回复
板凳
周半梅| | 2024-11-22 07:58 | 只看该作者
STM32F446确实好用,这个例子正好用在我的项目里!

使用特权

评论回复
地板
帛灿灿| | 2024-11-22 07:58 | 只看该作者
有没有可能再增加一个DMA接收的例子?

使用特权

评论回复
5
童雨竹| | 2024-11-22 07:58 | 只看该作者
感觉DMA好神奇,之前一直用中断,看来得换个思路了。

使用特权

评论回复
6
万图| | 2024-11-22 07:58 | 只看该作者
这个波特率115200太低了,高速场景下能跑多快?

使用特权

评论回复
7
Bblythe| | 2024-11-22 07:58 | 只看该作者
代码注释很详细,特别适合像我这种小白!

使用特权

评论回复
8
Pulitzer| | 2024-11-22 07:59 | 只看该作者
有没有建议的调试方法,怎么知道DMA是不是工作正常?

使用特权

评论回复
9
Clyde011| | 2024-11-22 07:59 | 只看该作者
STM32系列真强大,用起来简直停不下来!

使用特权

评论回复
10
Uriah| | 2024-11-22 07:59 | 只看该作者
DMA的FIFO模式能不能用到这个例子里,有什么好处?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

34

主题

3716

帖子

1

粉丝