STM32 使用 DMA 双缓冲接收不定长串口数据时,如何避免缓冲切换瞬间丢字节?

· 3 浏览

回答(4)

注意DMA的传输完成中断优先级要高于串口中断,且关闭DMA后需等待总线空闲(如延时几个时钟周期)再重新配置,否则可能丢失最后几个字节。
硬件工程师阿强 · 2026-08-27
建议使用空闲中断+DMA循环模式,不切换缓冲,而是用环形缓冲区(如双缓冲拼成环形),通过CNDTR差值计算有效数据,彻底避免切换瞬间。
码农小刘 · 2026-08-27
可以在DMA中断中直接操作寄存器,避免HAL库的延迟。切换时先读CNDTR,再写M0AR/M1AR,并用软件触发一次DMA请求,确保无缝衔接。
嵌入式老张 · 2026-08-27
核心思路是让DMA始终有缓冲可写,避免在切换瞬间因缓冲满而丢弃数据。推荐使用DMA双缓冲模式(DBM)配合空闲中断(IDLE)或超时判断。具体实操:1)配置DMA为循环模式+双缓冲,使能传输完成中断(TC)和半传输中断(HT),在HT/TC中切换用户处理缓冲,但注意DMA硬件自动切换,软件仅需记录当前有效缓冲。2)关键点:在IDLE中断中,先读取DMA的CNDTR寄存器获取剩余字节数,再计算已接收长度,并立即暂停DMA(DMA_Cmd(DMAx, DISABLE)),处理完数据后重新使能,并确保切换时先清空DMA标志位(如DMA_IT_FLAG_TC/HT)。3)避免丢字节的实操技巧:将DMA缓冲设为2的幂次大小(如256字节),并启用FIFO(若支持),可缓冲硬件层面的突发数据;同时,在IDLE中断中,若CNDTR显示缓冲已满但未触发TC,需手动处理剩余数据。4)若使用HAL库,注意在HAL_UARTEx_ReceiveToIdle_DMA中,回调函数里调用HAL_UARTEx_ReceiveToIdle_DMA重新启动接收,但需先调用HAL_UART_DMAStop暂停,防止竞态。最后,测试时用逻辑分析仪或串口助手发送连续数据流,验证切换瞬间无丢包。
mcuku 阿沐 · 2026-08-27

🧰 配套工具

🔗 波特率计算器