打印
[STM32H7]

STM32 UART + DMA + 空闲中断使用中的帧错误(FE)问题及解决方案

[复制链接]
30|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
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 | USART_CR3_RXFTIE));

  /* In case of reception waiting for IDLE event, disable also the IDLE IE interrupt source */
  if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
  {
    ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
  }

  /* At end of Rx process, restore huart->RxState to Ready */
  huart->RxState = HAL_UART_STATE_READY;
  huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;

  /* Reset RxIsr function pointer */
  huart->RxISR = NULL;
}



可以看到确实是这个函数清掉了中断使能标志位,由于这个是库函数,我们不好直接对其改动,这样整个代码的可移植性会降低,所以需要换一种方式

EIE 被清除:

在 HAL 的 UART_EndRxTransfer 函数中,错误中断使能位(EIE)被清除,这是设计上的默认行为,但会导致后续错误无法触发 HAL_UART_ErrorCallback函数
DMA 与空闲中断的联动:

DMA 停止时,HAL 会清除相关中断使能位(包括 IDLEIE),而空闲中断的触发依赖于 IDLEIE,导致无法检测数据接收完成。
解决方案
为解决上述问题,采用以下方法:

1. 修改中断处理函数
在 UART 中断处理函数中(例如 UART4_IRQHandler),针对帧错误(FE)的特殊处理:

检测 FE 标志位。
停止当前的 DMA。
手动恢复错误中断使能位(EIE)。
代码如下:

void UART4_IRQHandler(void)
{
    /* USER CODE BEGIN UART4_IRQn 0 */
    if (__HAL_UART_GET_FLAG(&huart4, UART_FLAG_FE) != RESET)
    {
        // 停止 DMA 接收
        HAL_UART_DMAStop(&huart4);
        // 恢复错误中断使能
        ATOMIC_SET_BIT(UART4->CR3, USART_CR3_EIE);
    }
    /* USER CODE END UART4_IRQn 0 */

    HAL_UART_IRQHandler(&huart4);

    /* USER CODE BEGIN UART4_IRQn 1 */
    /* USER CODE END UART4_IRQn 1 */
}





2. 修改错误回调函数
在 HAL 库的错误回调函数 HAL_UART_ErrorCallback 中:

针对 FE 标志,清除帧错误标志位。
重置接收状态
重新启用空闲中断(IDLEIE),以确保后续接收正常工作。
使用 HAL_UARTEx_ReceiveToIdle_DMA 重新启动 DMA 接收。
代码如下:

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == UART4)
    {
        if (huart->ErrorCode & HAL_UART_ERROR_FE)
        {
            // 清除帧错误标志
            __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_FEF);
            // 重置接收状态
                huart->RxState = HAL_UART_STATE_READY;
            // 重新启用空闲中断
            __HAL_UART_ENABLE_IT(huart, UART_IT_IDLE);
        }

        // 重新启动 DMA 接收
        HAL_UARTEx_ReceiveToIdle_DMA(&huart4, rxdata3, sizeof(rxdata3));
    }
}



3. 防止错误标志干扰
在系统初始化时,提前清除 UART 的所有错误标志,确保上电过程中不会因干扰触发错误中断:

__HAL_UART_CLEAR_FLAG(&huart4, UART_CLEAR_FEF | UART_CLEAR_OREF | UART_CLEAR_NEF);


完整解决流程
检测和恢复中断配置:
在中断处理函数中手动恢复 EIE 和其他相关标志位。
错误回调中清理状态:
在 HAL_UART_ErrorCallback 中清除错误标志,并重新启用 DMA 和空闲中断。
初始化时预处理:
上电后立即清除所有挂起的错误标志,避免误触发中断。
优化建议
为了提升代码复用性,可以将错误恢复处理提取成独立函数:

void HandleUARTFrameError(UART_HandleTypeDef *huart)
{
    // 停止 DMA
    HAL_UART_DMAStop(huart);
    // 清除错误标志
    __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_FEF);
    // 恢复错误中断使能
    ATOMIC_SET_BIT(huart->Instance->CR3, USART_CR3_EIE);
    // 恢复空闲中断
}


然后在 UART4_IRQHandler 中调用:

if (__HAL_UART_GET_FLAG(&huart4, UART_FLAG_FE) != RESET)
{
    HandleUARTFrameError(&huart4);
}


效果验证
通过上述修改,可以确保:

帧错误发生后,错误回调函数(HAL_UART_ErrorCallback)能够正常触发。
在错误恢复后,DMA 和空闲中断功能继续正常工作,后续数据传输不受影响。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/Jonshen/article/details/144032215

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

66

主题

4106

帖子

5

粉丝