这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » STM32H533串口DMA发送失败调试

共2条 1/1 1 跳转至

STM32H533串口DMA发送失败调试

助工
2026-06-30 15:33:11     打赏

问题现象:

使用 STM32H533 的 UART2 + GPDMA1 进行 DMA 发送测试,期望通过 DMA 将字符串 STM32H533CODE TEST MODE(33字节)完整发送到串口,实际却只能发送第一个字符 S,后续字符丢失。

image.png

调试过程

第一阶段:怀疑代码还原

最初怀疑是代码被 IDE/CubeMX 还原,但检查后发现 USER CODE 区域的自定义代码确实存在。发现 tx_buffer 只初始化了前 9 字节,剩余 24 字节为未初始化内存。

第二阶段:DMA 完成回调不触发

添加 HAL_UART_TxCpltCallback 回调函数用于 DMA 完成通知,但在主循环中 while (dma_tx_complete == 0) 死等,回调从未被调用。

第三阶段:DMA 配置错误 — 根本原因

检查 HAL_UART_MspInit 中的 DMA 初始化代码,发现 TX 通道配置:

handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_FIXED;  // 错误配置

DMA_SINC_FIXED 表示源地址固定,DMA 控制器始终从同一个内存地址读取数据,导致 UART 始终发送缓冲区第一个字节 S。

修复方案

将 SrcInc 从 DMA_SINC_FIXED 改为 DMA_SINC_INCREMENTED:

handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_INCREMENTED;  // 源地址递增

image.png

修改后 DMA 控制器会依次读取缓冲区的每个字节,完整发送 33 个字符。

关键参数说明

image.png

(一)循环配置(Circular configuration)

  • Circular Mode(循环模式):当前为 Disable(关闭)

    • 如果开启,DMA 传输完设定的数据量后会自动从头开始(常用于音频/ADC 连续采样);关闭则传输一次即停止,需手动重新触发。

(二)请求配置(Request Configuration)

  • Request(请求源):当前为 USART2_TX

    • 指定触发该 DMA 通道的外设请求信号(这里是 USART2 的发送请求)。

  • DMA Handle in IP Structure(IP结构中的DMA句柄):当前为 hdmatx

    • 软件代码中用于管理该 DMA 传输的句柄变量名。

  • Block HW request protocol(块硬件请求协议):当前为 Single/Burst Level

    • 硬件握手协议类型,决定外设请求 DMA 的方式(单次传输还是突发传输块)。

(三)通道配置(Channel configuration)

  • Priority(优先级):当前为 Low(低)

    • 当多个 DMA 通道同时请求时,决定谁先被响应(可设为 Very High/High/Medium/Low)。

  • Transaction Mode(传输模式):当前为 Normal(正常模式)

    • 对应循环模式的开关,正常模式即非循环,传完指定数量就停止。

  • Direction(方向):当前为 Memory To Peripheral(内存到外设)

    • 数据流动方向(源是内存,目标是 USART 外设)。

(四)源数据设置(Source Data Setting)—— 这里是关键

  • Source Address Increment Aft(源地址递增)Enabled(已启用) 

  • Data Width(数据宽度)Byte(字节,即 8-bit)

    • 每次传输的数据大小(可选 Byte/Half-word/Word)。增量步长等于此宽度。

  • Burst Length(突发长度)64

    • 一次 DMA 请求连续传输的个数(此处为 64 个字节/次)。

  • Allocated Port for Transfer(分配传输端口)Port 0

    • 在支持多端口的总线矩阵中,指定源端走哪个总线端口(用于优化带宽)。

(五)目标数据设置(Destination Data Setting)

  • Destination Address Increment(目标地址递增)Enabled(已启用)

    • 目标地址是否自增(如果目标是内存数组,通常开启;如果目标是外设数据寄存器,通常关闭)。

  • Data Width / Burst Length / Allocated Port:与源端含义相同,分别作用于目标端。

(六)数据处理(Data Handling)

  • Data Handling Configuration(数据处理配置):当前为 Disable(关闭)

    • 通常指 FIFO(先进先出)模式、数据打包/解包或半字/字节对齐转换功能。关闭即直通传输。

(七)触发(Trigger)

  • Trigger Configuration(触发配置):当前为 Disable(关闭)

    • 额外引入的软件或硬件触发器(如定时器触发 DMA),关闭则仅靠外设请求(USART)触发。

(八)传输事件配置(Transfer Event Configuration)

  • Transfer Event Generation(传输事件生成):当前为 The TC (and the HT) event is generated...(传输完成 TC 和半传输 HT 事件生成)。

    • 表示当传输完成(TC)或传输到一半(HT)时,会生成中断或事件信号,方便 CPU 做后续处理(如关闭 DMA 或切换缓冲区)。

其他相关修改

缓冲区声明

#define TX_SIZE  (33)
uint8_t tx_buffer[TX_SIZE] = "STM32H533CODE TEST MODE    ";

注意:C 语言字符串字面量若长度不足定义长度,剩余字节为未初始化内存,会导致垃圾数据。

DMA 完成回调

volatile uint8_t dma_tx_complete = 0;

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart == &huart2)
    {
        dma_tx_complete = 1;
    }
}

主循环

while (1)
{
    HAL_UART_Transmit_DMA(&huart2, (uint8_t *)tx_buffer, TX_SIZE);
    while (dma_tx_complete == 0) { }  // 等待 DMA 完成
    dma_tx_complete = 0;
    HAL_Delay(2000);
}

总结

DMA 只发送第一个字符最常见的原因是 SrcInc 配置为 DMA_SINC_FIXED。发送前务必确认:

  1. SrcInc = DMA_SINC_INCREMENTED(内存发送源)

  2. DestInc = DMA_DINC_FIXED(UART 数据寄存器不需要递增)

  3. 缓冲区大小与传输长度匹配

  4. 缓冲区内容已正确初始化





关键词: STM32H533     串口     调试    

院士
2026-06-30 16:03:43     打赏
2楼

谢谢分享,学习了


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]