公司动态

多串口通信偶发锁死|STM32 ORE溢出故障完整排查方案

📅 2026/7/15 14:06:26
多串口通信偶发锁死|STM32 ORE溢出故障完整排查方案
一、发现问题用STMG070的4个串口中两个串口实时通信时偶发某个串口通信挂掉进入不了接收中断函数但是能进入接收回调函数另一个串口通信正常其他程序正常运行二、分析定位问题起初以为是多串口通信导致抢占资源频繁访问中断导致通信冲突于是在接收回调函数中各接收中断函数加入if, else if条件同一时间只能进入一个串口接收中断但是还是会偶发串口通信挂掉然后网上查资料看到HAL库的接收中断里面有加锁、解锁操作数据量大会导致串口锁死进入串口接收中断函数STM32Cube_FW_G0_V1.6.0版本里面没有加锁然后看到有说overrun导致过载溢出错误串口接收死掉仿真检测当串口通信挂掉时果然overrun被置位这里终于定位到了问题。三、解决问题overrun标志就是状态寄存器ISR寄存器的bit3:ORE如下图提示可以通过OVRDIS关闭ORE检测如下图三种解决方案推荐第3种1.在串口故障回调函数中检测ORE标志如果被置位则清除重新打开串口接收中断代码如下void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) { if(__HAL_UART_GET_FLAG(huart2, UART_FLAG_ORE) ! RESET) { __HAL_UART_CLEAR_OREFLAG(huart2); //__HAL_UART_ENABLE_IT(huart2,UART_IT_RXNE); HAL_UART_Receive_IT(huart2,(uint8_t*)rx, sizeof(rx)); su16Uart2OreCnt; if(su16Uart2OreCnt 60000) { su16Uart2OreCnt 0; } } if(__HAL_UART_GET_FLAG(huart3, UART_FLAG_ORE) ! RESET) { __HAL_UART_CLEAR_OREFLAG(huart3); //__HAL_UART_ENABLE_IT(huart2,UART_IT_RXNE); HAL_UART_Receive_IT(huart3,(uint8_t*)rx, sizeof(rx)); su16Uart3OreCnt; if(su16Uart3OreCnt 60000) { su16Uart3OreCnt 0; } } }通过检测进入串口故障回调函数中串口ORE置位清除的次数发现进入几次之后后边就进不来了不知什么原因2.STM32CubeMX串口配置中默认overrun默认使能关闭该使能但是有丢包的风险。该方法未尝试。3.定时500ms检测几个串口的ORE是否置位置位则清除ORE标志重新打开中断这个比较稳定靠谱一些即使串口接收回调函数异常也不影响清除ORE标志。代码如下//定时检测ORE //static uint16_t su16INVUart1OreCnt 0; //static uint16_t su16APPUart2OreCnt 0; //static uint16_t su16BMSUart3OreCnt 0; //static uint16_t su16MPPTUart4OreCnt 0; void PS_Modules_Uart_Clear_ORE(void) { static uint16_t su16OreCnt 0; // static uint16_t su16PrintfOreCnt 0; // su16PrintfOreCnt; // if(su16PrintfOreCnt 3000) // { // su16PrintfOreCnt 0; // printf(INV ORE cnt(USART1) %d\r\n,su16INVUart1OreCnt); // printf(APP ORE cnt(USART2) %d\r\n,su16APPUart2OreCnt); // printf(BMS ORE cnt(USART3) %d\r\n,su16BMSUart3OreCnt); // printf(MPPT ORE cnt(USART4) %d\r\n,su16MPPTUart4OreCnt); // } su16OreCnt; if(su16OreCnt 500) { su16OreCnt 0; if(__HAL_UART_GET_FLAG(huart1, UART_FLAG_ORE) ! RESET) { __HAL_UART_CLEAR_OREFLAG(huart1); HAL_UART_Receive_IT(huart1,(uint8_t*)rx, sizeof(rx)); // su16INVUart1OreCnt; } if(__HAL_UART_GET_FLAG(huart2, UART_FLAG_ORE) ! RESET) { __HAL_UART_CLEAR_OREFLAG(huart2); HAL_UART_Receive_IT(huart2,(uint8_t*)rx, sizeof(rx)); // su16APPUart2OreCnt; } if(__HAL_UART_GET_FLAG(huart3, UART_FLAG_ORE) ! RESET) { __HAL_UART_CLEAR_OREFLAG(huart3); HAL_UART_Receive_IT(huart3,(uint8_t*)rx, sizeof(rx)); // su16BMSUart3OreCnt; } if(__HAL_UART_GET_FLAG(huart4, UART_FLAG_ORE) ! RESET) { __HAL_UART_CLEAR_OREFLAG(huart4); HAL_UART_Receive_IT(huart4,(uint8_t*)rx, sizeof(rx)); // su16MPPTUart4OreCnt; } } }串口2和串口3通信压力测试2小时通信均正常。通过打印清除次数发现串口3清除了3次串口2清除了4次。四、为什么会出现overrun还是要看这个ORE位当RXFF 1时当移位寄存器中正在被接收到的数据转移到USART_RDR寄存器该位由硬件设置。当RXFF 1数据被转移到USART_RDR寄存器未完成时又来一个数据则发生过载溢出ORE置位。STM32F1中这样解释软件序列先读SR再读CR可将其清零。STM32G070也可通过串口中断标志位清除寄存器将ORE标志清除如下