STM32 UART + DMA + IDLE中断使用中的帧错误(FE)问题及解决方案
在我调试STM32H7串口空闲中断DMA接受时遇到了一个bug,这个现象发生在系统刚上电时,有个串口由于帧错误FE挂起了中断,之后在HAL_UART_IRQHandler这个全局中断处理函数结束后,所有的中断使能标志位都被清除了,经过反复调试发现以下问题:
- 上电初始化后,串口的 帧错误标志(FE) 会被意外触发,导致系统进入中断。
- 在中断处理中,由于 EIE(错误中断使能位) 被清除,导致帧错误的处理没有进入预期的
HAL_UART_ErrorCallback
函数。 - 当 DMA 被停止时,空闲中断功能(
IDLEIE
)也被清除,后续数据接收无法正常触发空闲中断。
这是一个隐藏较深的问题,目前尚无直接的参考案例。
问题分析
通过对 HAL 库源码和中断流程的分析,发现问题的根源如下:
-
帧错误(FE)触发中断:
-
帧错误通常发生在上电阶段,可能是由于串口初始化前的干扰或接收了无效数据。
-
帧错误会触发中断,但由于 HAL 中的错误处理逻辑,
UART_EndRxTransfer
会清除EIE
和IDLEIE
,导致后续的错误无法触发中断。HAL_UART_IRQHandler中的UART_EndRxTransfer函数导致所有中断使能标志位被清除
进入这个函数的原因是因为我是用DMA来传输数据,如果这时候发生了任何错误,都会进入这个函数,看看这个函数原型
/** * @brief End ongoing Rx transfer on UART peripheral (following error detection or Reception completion). * @param huart UART handle. * @retval None */ static void UART_EndRxTransfer(UART_HandleTypeDef *huart) { /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */ ATOMIC_CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE_RXFNEIE | USART_CR1_PEIE)); ATOMIC_CLEAR_BIT(huart->Instance->CR3, (USART_CR3_EIE
-