STM32 使用DMA+双缓冲接收不定长串口数据时,如何避免缓存覆盖与丢帧?

· 2 浏览

回答(4)

补充:若使用RTOS,可将DMA中断通过信号量通知任务,任务内处理数据,但需注意中断优先级低于系统节拍,避免死锁。另外,可考虑使用环形缓冲区替代双缓冲,但双缓冲在CPU负载均衡上更优。
FreeRTOS爱好者 · 2026-08-27
补充:双缓冲的缓冲区大小应大于最大帧长,否则需分帧处理。可增加超时机制(如定时器)判断帧结束,防止IDLE未触发时数据滞留。
串口调试侠 · 2026-08-27
补充:在IDLE中断中,务必先读取USART_ISR的IDLE位并清除,再读取NDTR,否则可能漏帧。同时,建议将数据处理放在主循环或任务中,中断内仅做标志置位和指针更新,避免长时间阻塞。
嵌入式老周 · 2026-08-27
核心方案是采用“双缓冲乒乓切换+空闲中断+DMA半传输/传输完成中断”的组合。具体做法:配置两个等长缓冲区(如BUF1/BUF2),DMA循环模式接收,使能DMA半传输中断(HT)和传输完成中断(TC),以及串口空闲中断(IDLE)。当HT触发时,CPU处理BUF1前半段数据;TC触发时处理BUF2后半段;IDLE触发时,先读取DMA剩余计数(NDTR)确定当前有效数据长度,再处理剩余部分,并重置DMA。关键点:1)在中断中必须立即读取并保存数据,避免被下一次DMA写入覆盖;2)使用volatile修饰缓冲区,防止编译器优化;3)处理数据时禁止DMA写入对应缓冲区,可通过关闭DMA或切换缓冲区实现;4)若数据帧长度超过缓冲区,需设计帧头/帧尾或长度字段,配合状态机解析。实操建议:优先使用HAL库的HAL_UARTEx_ReceiveToIdle_DMA,其内部已集成空闲中断和DMA管理,但需注意在回调中及时拷贝数据。若追求极致性能,可手写寄存器版本,减少中断延迟。
mcuku 阿沐 · 2026-08-27

🧰 配套工具

🔗 波特率计算器