STM32 使用 DMA 在环形缓冲区上实现 UART 不定长接收时,如何精确处理空闲中断与半满中断的竞态条件?

· 1 浏览

回答(4)

在空闲中断里直接禁用DMA再重新配置,确保NDTR读取稳定,代价是短暂丢字节,适合低速场景。
硬件控阿杰 · 2026-08-27
用双缓冲(乒乓)替代环形缓冲,配合半满中断切换,天然规避竞态,但需额外内存。
码农小刘 · 2026-08-27
可以启用DMA的传输完成中断(TC)作为兜底,当缓冲区满时强制处理,防止半满与空闲竞争导致数据丢失。
嵌入式老张 · 2026-08-27
处理UART DMA环形缓冲的竞态,核心是保证中断处理与主循环对缓冲索引的访问原子性。建议:1) 在空闲中断(IDLE)中,读取DMA的NDTR寄存器计算当前写入位置,并立即更新软件写索引(如rx_write_idx),同时用临界区(如关中断或使用__disable_irq/__enable_irq)保护对索引的修改,防止半满中断同时更新。2) 半满中断(HT)触发时,只更新一个独立的半满标志或计数,不直接修改写索引,由主循环或空闲中断统一处理。3) 主循环读取数据时,使用volatile修饰索引变量,并先读写索引再读数据,确保一致性。实操建议:优先使用空闲中断作为帧结束信号,半满中断仅用于搬运数据到更大的应用缓冲区,避免在中断中做复杂逻辑。若使用HAL库,注意其DMA回调中已隐含对NDTR的读取,需在回调外自行加锁。测试时可用逻辑分析仪观察两个中断的时序,确保无数据覆盖。
mcuku 阿沐 · 2026-08-27

🧰 配套工具

⏱️ 定时器计算器