<bug记录>STM32 HAL库lpuart低功耗串口通信错误/卡死

环境:
使用STM32L073x HAL在stop模式下,使用lpuart接收数据,在2s的RTC定时器中断内解析串口数据。

现象:
程序运行一段时间后出现主程序卡死状态,在程序运行状态下该bug极难复现(可能一个月都不复现)。

调试过程:
由于单片机处于stop模式下,想要调试需要打开debug功能

HAL_DBGMCU_DBG_EnableLowPowerConfig();
一开始考虑可能是程序跑飞,将可疑的函数、程序放入仿真环境单元测试百万次均正常,接着在单片机环境下通过串口仿真器发送高频数据,之后就定位问题在串口和stop唤醒部分。
当该bug复现是查看寄存器及lpuart实例:

<bug记录>STM32 HAL库lpuart低功耗串口通信错误/卡死_第1张图片

观察寄存器后发现CR3与ISR寄存器异常,通过数据手册可知:
<bug记录>STM32 HAL库lpuart低功耗串口通信错误/卡死_第2张图片当WUF=1时,如果WUFEIE=1,则产生唤醒中断。
接下来看串口中断的入口函数HAL_UART_IRQHandler

HAL_UART_IRQHandler函数分为三个部分
1 如果没有错误则执行回调函数RxISR()

  /* If no error occurs */
  errorflags = (isrflags & (uint32_t)(USART_ISR_PE | USART_ISR_FE | USART_ISR_ORE | USART_ISR_NE));
  if (errorflags == 0U)
  {
    /* UART in mode Receiver ---------------------------------------------------*/
    if (((isrflags & USART_ISR_RXNE) != 0U)
        && ((cr1its & USART_CR1_RXNEIE) != 0U))
    {
      if (huart->RxISR != NULL)
      {
        huart->RxISR(huart);
      }
      return;
    }
  }

2 如果有错误则清除错误标志位,之后或执行回调函数RxISR(),或执行错误处理函数

  /* If some errors occur */
  if ((errorflags != 0U)
      && (((cr3its & USART_CR3_EIE) != 0U)
          || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != 0U)))
  {
	......
    /* UART frame error interrupt occurred --------------------------------------*/
    if (((isrflags & USART_ISR_FE) != 0U) && ((cr3its & USART_CR3_EIE) != 0U))
    {
      __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_FEF);

      huart->ErrorCode |= HAL_UART_ERROR_FE;
    }

    /* Call UART Error Call back function if need be --------------------------*/
    if (huart->ErrorCode != HAL_UART_ERROR_NONE)
    {
		......
	}
    return;

  } /* End if some error occurs */

3 执行中断唤醒函数

  /* UART wakeup from Stop mode interrupt occurred ---------------------------*/
  if (((isrflags & USART_ISR_WUF) != 0U) && ((cr3its & USART_CR3_WUFIE) != 0U))
  {
    __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_WUF);

    /* UART Rx state is not reset as a reception process might be ongoing.
       If UART handle state fields need to be reset to READY, this could be done in Wakeup callback */

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
    /* Call registered Wakeup Callback */
    huart->WakeupCallback(huart);
#else
    /* Call legacy weak Wakeup Callback */
    HAL_UARTEx_WakeupCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
    return;
  }

你可能感兴趣的:(Bug,嵌入式,c语言,stm32,单片机)