【问题现象】
本地使用S32K328 芯片时使用的UART中断的方式接收数据,偶发的串口无法接收。
【问题调查】
复现问题的时候本地attach 到板子上查UART 的寄存器发现控制寄存器的串口接收中断被关闭了。
知道了问题原因,我们就可以针对该问题进行调查确认,我们可以这对该寄存器下数据断点查看何发生了改写。
本地复现问题发现是触发了串口ERROR异常,从而关闭了串口接收中断
以下是uart 错误异常的处理代码,检测到错误事件后会清除对应的事件,并关闭接收处理同时调用event callback 函数通知应用层。
static void Lpuart_Uart_Ip_ErrIrqHandler(const uint8 Instance) { Lpuart_Uart_Ip_StateStructureType * UartState; const Lpuart_Uart_Ip_UserConfigType *UartUserCfg; LPUART_Type * Base; boolean IsError = FALSE; boolean IsReturn = FALSE; Base = Lpuart_Uart_Ip_apBases[Instance]; UartState = (Lpuart_Uart_Ip_StateStructureType *)Lpuart_Uart_Ip_apStateStructuresArray[Instance]; UartUserCfg = Lpuart_Uart_Ip_apUserConfig[Instance]; /* Handle receive overrun interrupt */ if (Lpuart_Uart_Ip_GetStatusFlag(Base, LPUART_UART_IP_RX_OVERRUN)) { if (!Lpuart_Uart_Ip_GetIntMode(Base, LPUART_UART_IP_INT_RX_OVERRUN)) { IsReturn = TRUE; } else { /* Update the status */ IsError = TRUE; UartState->ReceiveStatus = LPUART_UART_IP_STATUS_RX_OVERRUN; /* Clear the flag */ Lpuart_Uart_Ip_ClearStatusFlag(Base, LPUART_UART_IP_RX_OVERRUN); } } /* Handle framing error interrupt */ if (Lpuart_Uart_Ip_GetStatusFlag(Base, LPUART_UART_IP_FRAME_ERR) && (FALSE == IsReturn)) { if (!Lpuart_Uart_Ip_GetIntMode(Base, LPUART_UART_IP_INT_FRAME_ERR_FLAG)) { IsReturn = TRUE; } else { /* Update the status */ IsError = TRUE; UartState->ReceiveStatus = LPUART_UART_IP_STATUS_FRAMING_ERROR; /* Clear the flag */ Lpuart_Uart_Ip_ClearStatusFlag(Base, LPUART_UART_IP_FRAME_ERR); } } /* Handle parity error interrupt */ if (Lpuart_Uart_Ip_GetStatusFlag(Base, LPUART_UART_IP_PARITY_ERR) && (FALSE == IsReturn)) { if (!Lpuart_Uart_Ip_GetIntMode(Base, LPUART_UART_IP_INT_PARITY_ERR_FLAG)) { IsReturn = TRUE; } else { /* Update the status */ IsError = TRUE; UartState->ReceiveStatus = LPUART_UART_IP_STATUS_PARITY_ERROR; /* Clear the flag */ Lpuart_Uart_Ip_ClearStatusFlag(Base, LPUART_UART_IP_PARITY_ERR); } } /* Handle noise error interrupt */ if (Lpuart_Uart_Ip_GetStatusFlag(Base, LPUART_UART_IP_NOISE_DETECT) && (FALSE == IsReturn)) { if (!Lpuart_Uart_Ip_GetIntMode(Base, LPUART_UART_IP_INT_NOISE_ERR_FLAG)) { IsReturn = TRUE; } else { /* Update the internal status */ IsError = TRUE; UartState->ReceiveStatus = LPUART_UART_IP_STATUS_NOISE_ERROR; /* Clear the flag */ Lpuart_Uart_Ip_ClearStatusFlag(Base, LPUART_UART_IP_NOISE_DETECT); } } #if (LPUART_UART_IP_ENABLE_TIMEOUT_INTERRUPT == STD_ON) /* Handle the error interrupts if timeout error */ if (Lpuart_Uart_Ip_GetStatusFlag(Base, LPUART_UART_IP_TIMEOUT) && (FALSE == IsReturn)) { /* This checking also ensures that the feature is activated for the current instance * because the Interrupt can be enabled only in this case. */ if (Lpuart_Uart_Ip_GetIntMode(Base, LPUART_UART_IP_INT_TIMEOUT)) { /* Update the internal status */ IsError = TRUE; /* Update the status */ UartState->ReceiveStatus = LPUART_UART_IP_STATUS_RX_IDLE_STATE; /* Clear Timeout Interrupt Error flag */ Lpuart_Uart_Ip_ClearStatusFlag(Base, LPUART_UART_IP_TIMEOUT); } else { IsReturn = TRUE; } } #endif if (FALSE == IsReturn) { if (TRUE == IsError) { if (LPUART_UART_IP_USING_INTERRUPTS == UartUserCfg->TransferType) { /* Complete the transfer (disable rx logic) */ Lpuart_Uart_Ip_CompleteReceiveDataUsingInt(Instance); } #if (LPUART_UART_IP_HAS_DMA_ENABLED == STD_ON) else { /* Complete the transfer (stop DMA channel) */ (void)Dma_Ip_SetLogicChannelCommand(UartUserCfg->RxDMAChannel, DMA_IP_CH_CLEAR_HARDWARE_REQUEST); Lpuart_Uart_Ip_CompleteReceiveUsingDma(Instance); } #endif /* Invoke callback if there is one */ if (UartUserCfg->Callback != NULL_PTR) { #if (LPUART_UART_IP_ENABLE_TIMEOUT_INTERRUPT == STD_ON) if (LPUART_UART_IP_STATUS_RX_IDLE_STATE == UartState->ReceiveStatus) { UartUserCfg->Callback(Instance, LPUART_UART_IP_EVENT_IDLE_STATE, UartUserCfg->CallbackParam); } else #endif { UartUserCfg->Callback(Instance, LPUART_UART_IP_EVENT_ERROR, UartUserCfg->CallbackParam); } } } } }
知道了问题原因后我们就可以在针对该问题添加策略了,串口接收错误事件会通过callback 函数上报给用户,我们可以在里面检测错误事件并开启串口中断。
修改代码后串口异常关闭问题已经被解决。