已解决 STM32F4/G4通过DMA+空闲中断(IDLE)接收不定长串口数据,偶发丢失最后一字节怎么解决?

j
jmskapy 提问于 2026-09-13 00:03
554 浏览 2 回答
使用STM32CubeMX配置串口DMA接收不定长数据,开启了UART的IDLE空闲中断。波特率115200bps,在通信比较频繁时,偶尔会发现一包数据的最后一个字节丢失或者DMA计数值(NDTR)没有及时刷新。
测试环境:STM32F407VET6,FreeRTOS系统,串口接收缓冲区256字节。
请问这种偶发数据丢失通常是什么机制导致的?有可靠的标准接收代码逻辑吗?

回答 2

最佳回答
t
tickettm20191649 2026-09-14 07:39
3
这是经典的DMA与空闲中断时序竞争问题!
根本原因在于:串口空闲中断(IDLE)是在接收线上出现1个字节时间的空闲高电平时触发的,而此时DMA控制器可能正在把最后一个字节从DR寄存器搬移到SRAM内存中,或者DMA传输刚刚完成还没有完全同步到内核。
标准可靠的解决方法:
1. 在空闲中断服务函数中,先读取SR和DR寄存器清除IDLE标志位;
2. 关键一步:立刻调用 `__HAL_DMA_DISABLE(hdma_usart_rx);` 临时关闭DMA通道;
3. 此时读取 `__HAL_DMA_GET_COUNTER(hdma_usart_rx)` 计算本次接收长度;
4. 复制有效数据后,重新设置NDTR计数器并重新开启DMA通道。
我们在几万台工业网关上按这个逻辑运行,连续跑几个月从未再出现过掉字节问题。
高
高速信号老郑 2026-09-15 02:00
27
补充一点:如果你开启了FreeRTOS,串口中断优先级一定要设置在 `configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY` 之下(数值大于它),否则在中断里调用 `xQueueSendFromISR` 或者通知信号量时,会触发内核断言导致死机。
写下你的回答
问题信息
状态 已解决
浏览554
回答2
发布2026-09-13
相关标签
快捷操作