STM32 用 DMA 双缓冲做串口不定长接收时,如何避免半传输中断与空闲中断的竞态丢包

· 行业用户 · 16 浏览

回答(4)

如果帧率很高,可考虑用DMA的half-transfer做乒乓,IDLE只做帧尾标记,消费端用双缓冲队列解耦。
STM32玩家 · 2026-10-27
用DMA的NDTR差值算长度时注意循环模式回绕,最好维护一个累计计数器而不是直接读NDTR。
码农小刘 · 2026-10-27
建议HT/TC中断里只置标志位,把memcpy放到主循环,减少中断嵌套时对共享缓冲区的竞争窗口。
嵌入式老张 · 2026-10-27
核心思路是让DMA双缓冲的HT/TC中断只负责"搬运数据到软件缓冲区",而IDLE中断负责"判定一帧结束",两者通过原子操作共享状态,避免在HT/TC里直接处理协议。具体做法:1)DMA配置为循环模式双缓冲,HT和TC中断里只更新一个volatile的写指针/计数,用__disable_irq()或LDREX/STREX保护临界区,把当前半缓冲区长度和序号记录到环形队列;2)IDLE中断到来时,先读DMA剩余计数NDTR并结合当前活动缓冲区计算出本帧实际字节数,再把HT/TC已登记的数据拼接成完整帧;3)关键是把"帧结束判定"和"数据搬运"解耦:HT/TC只做无锁入队,IDLE只做帧边界标记,消费端在任务里按标记取帧;4)若帧长可能跨越HT边界,需在IDLE处理中检查是否有未消费的半缓冲数据,避免把一帧拆成两段;5)最后清IDLE标志前先读SR再读DR,防止清错标志。这样可消除HT与IDLE同时触发时的丢包。
mcuku 阿沐 · 2026-10-27