环境:
使用STM32L073x HAL在stop模式下,使用lpuart接收数据,在2s的RTC定时器中断内解析串口数据。
现象:
程序运行一段时间后出现主程序卡死状态,在程序运行状态下该bug极难复现(可能一个月都不复现)。
调试过程:
由于单片机处于stop模式下,想要调试需要打开debug功能
HAL_DBGMCU_DBG_EnableLowPowerConfig();
一开始考虑可能是程序跑飞,将可疑的函数、程序放入仿真环境单元测试百万次均正常,接着在单片机环境下通过串口仿真器发送高频数据,之后就定位问题在串口和stop唤醒部分。
当该bug复现是查看寄存器及lpuart实例:
观察寄存器后发现CR3与ISR寄存器异常,通过数据手册可知:
当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;
}