cancel
Showing results for 
Search instead for 
Did you mean: 

when uart over run happens by using stm32 hal lib, the system hang

roseanne qiu
Associate II

Dear Sir/Madam:

I use three uart of stm32f4 : uart1, uart2 and uart6

I have some problems . when uart1 has overrun error,

all system get stuck there. I read some websites about this.

they mention that in the hal lib, clear ORE does not work, they said, only reading uart data register , this bit will clear. I do that, still do not work:

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)

{

...

 tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_ORE);

 tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);

 /* UART Over-Run interrupt occurred ----------------------------------------*/

 if((tmp1 != RESET) && (tmp2 != RESET))

 {

#if 1// I add this , but it does not work, system still hang/stuck when ore happens,

// any clue?

  uint8_t sysRxChar; // clear the regular interrupt

  sysRxChar = (uint8_t) huart->Instance->DR;

#endif

  // if does not really clear big

  __HAL_UART_CLEAR_OREFLAG(huart);

   

  huart->ErrorCode |= HAL_UART_ERROR_ORE;

 }

...

}

reference link is:

https://github.com/particle-iot/firmware/pull/796/commits/677b4b114b9b6503dcd10ddb83d128c9a65d6640

https://github.com/particle-iot/firmware/issues/776

thanks

roseanne

42 REPLIES 42
roseanne qiu
Associate II

no matter whether clear ORE , when this happen, we have to disable regular UART interrupt inside the function UART_Receive_IT ,

if not disabling it, uart interrupt routine will keep called .... . this come from by reading UART_Receive_IT.

of course, the test is still under going until no hang for long time when ORE happens.

any advice ?

thanks

roseanne

@Pavel A.​ DR is read in line 1574 only if (huart->ErrorCode != HAL_UART_ERROR_NONE) in line 1571. And that for the case of overrun is set to nonzero only if EIE is set, see line 1565. But the issue here is that - as the fine manual clearly explains in the USART interrupts subchapter - interrupt is fired by ORE not only when EIE is set...

JW

Pavel A.
Evangelist III

Well then what can be advise to the OP? 1. Talk to maintainers of particle-iot/firmware (and note that you use a different chip: F4, not F2)

2. Do not use their HAL for UART, roll your own, and do not enable ORE interrupt as it looks poblematic

@Community member​  - maybe you've found a bug in the ST library, hope ST can review this point.

--pa

roseanne qiu
Associate II

Dear Sir/Madam:

fyi: I believe that I fix the problem. the problem is : clearing ORE does not disable interrupt.

but to other errors, clearing them causes interrupt bit clear(disable interrupt).

the added part I made works .

thanks for all of your help and advices

roseanne

@Community member​ if nothing clears the ErrorCode down stream you're going to run into situations after you flag an overrun once it will jam up in subsequent failure.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Amel NASRI
ST Employee

Hello,

This issue is acknowledged and reported internally. We will take care to manage properly the overrun error in the UART driver.

Thanks all for the help you bring to improve our solutions.

-Amel

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

roseanne qiu
Associate II

more : I am not sure whether it is just overrun error or other errors or stm32 hal api. after running for half week, system hang again without overrun error. after the hang happens, even timer interrupt can not get executed. I am not sure whether hal uart interrupt routine hold the system(timers and uart interrupts have same priority, we have three uarts and two of them communication with external in normal case)

I look back at hal IRQHander, and add more : if there are any erros, not just overrun, I stop the interrupt. , I am not sure whether it could avoid uart interrupt reenter. here are what I have done, please advice. (I am running now)

/**

 * @brief This function handles UART interrupt request.

 * @param huart: pointer to a UART_HandleTypeDef structure that contains

 *        the configuration information for the specified UART module.

 * @retval None

 */

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)

{

 uint32_t tmp1 = 0U, tmp2 = 0U;

  

 tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_PE);

 tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_PE);  

 /* UART parity error interrupt occurred ------------------------------------*/

 if((tmp1 != RESET) && (tmp2 != RESET))

 { 

  __HAL_UART_CLEAR_PEFLAG(huart);

   

  huart->ErrorCode |= HAL_UART_ERROR_PE;

 }

  

 tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_FE);

 tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);

 /* UART frame error interrupt occurred -------------------------------------*/

 if((tmp1 != RESET) && (tmp2 != RESET))

 { 

  __HAL_UART_CLEAR_FEFLAG(huart);

   

  huart->ErrorCode |= HAL_UART_ERROR_FE;

 }

  

 tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_NE);

 tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);

 /* UART noise error interrupt occurred -------------------------------------*/

 if((tmp1 != RESET) && (tmp2 != RESET))

 { 

  __HAL_UART_CLEAR_NEFLAG(huart);

   

  huart->ErrorCode |= HAL_UART_ERROR_NE;

 }

  

 tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_ORE);

 tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);

 /* UART Over-Run interrupt occurred ----------------------------------------*/

 if((tmp1 != RESET) && (tmp2 != RESET))

 {

  __HAL_UART_CLEAR_OREFLAG(huart);   

  huart->ErrorCode |= HAL_UART_ERROR_ORE; // does not clear interrupt bit which

                      // cause interrupt reentered and hold the system

 }

 /*================= Rx mode */

 tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE);// rx buffer status

 tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE);// for interrupt check

#if 1 // RQIU_DEBUGG add more to to avoid hang and need long time to test

 if ( tmp2 != RESET && huart->ErrorCode != HAL_UART_ERROR_NONE )

  {// no matter what status, if there is error, just call

   // Receive_IT to disable interrupt,

   // since above clear for any codes could not garrantee clearing interrupt bit

   UART_Receive_IT(huart); <=============any error happens, disable interrupt

  }

 else

#endif

 if ( (tmp1 == RESET) && (tmp2 != RESET ) &&

    (huart->ErrorCode&HAL_UART_ERROR_ORE) )

  {

   UART_Receive_IT(huart); // this fix some problem with interrupt reentry

               // but still has some hang.

  }

 else 

 /* UART in mode Receiver ---------------------------------------------------*/

 if((tmp1 != RESET) && (tmp2 != RESET)) // RX NOT EMPTY, RX 

 { 

  UART_Receive_IT(huart);

 }

 /* transfer =================*/

  

 tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_TXE);

 tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TXE);

 /* UART in mode Transmitter ------------------------------------------------*/

#if 1 // RQIU_DEBUG if there is any error, just clean up interrupt

 // to avoid interrupt routine reenter forever

 if ( tmp2 != RESET && (huart->ErrorCode != HAL_UART_ERROR_NONE ) )

  {

   UART_Transmit_IT(huart); <=============any error happens, disable interrupt

  }

  else

#endif

 if((tmp1 != RESET) && (tmp2 != RESET))

 {

  UART_Transmit_IT(huart);

 }

  

 tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_TC);

 tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TC);

#if 1 // if there is any error for transfer, just clean up interrupt

 // to avoid interrupt routine reenter forever

 if ( tmp2 != RESET && (huart->ErrorCode != HAL_UART_ERROR_NONE ) )

  UART_Transmit_IT(huart);<=============any error happens, disable interrupt

 else

#endif

 /* UART in mode Transmitter end --------------------------------------------*/

 if((tmp1 != RESET) && (tmp2 != RESET))

 {

  UART_EndTransmit_IT(huart);

 }

 if(huart->ErrorCode != HAL_UART_ERROR_NONE)

 {

  /* Set the UART state ready to be able to start again the process */

  huart->gState = HAL_UART_STATE_READY;

  huart->RxState = HAL_UART_STATE_READY;

   

  HAL_UART_ErrorCallback(huart);

 }  

}

roseanne qiu
Associate II

continue: when calling the following functions by _IRQHandler, uart interrupt get clear

<===========this function will disable interrupt

/**

 * @brief Receives an amount of data in non blocking mode 

 * @param huart: pointer to a UART_HandleTypeDef structure that contains

 *        the configuration information for the specified UART module.

 * @retval HAL status

 */

static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)

{

 uint16_t* tmp;

 /* Check that a Rx process is ongoing */

 if(huart->RxState == HAL_UART_STATE_BUSY_RX) 

 {

  if(huart->Init.WordLength == UART_WORDLENGTH_9B)

  {

   tmp = (uint16_t*) huart->pRxBuffPtr;

   if(huart->Init.Parity == UART_PARITY_NONE)

   {

    *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FFU);

    huart->pRxBuffPtr += 2U;

   }

   else

   {

    *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FFU);

    huart->pRxBuffPtr += 1U;

   }

  }

  else

  {

   if(huart->Init.Parity == UART_PARITY_NONE)

   {

    *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FFU);

   }

   else

   {

    *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007FU);

   }

  }

   

  if(--huart->RxXferCount == 0U)

  {

    

   __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);

   /* Disable the UART Parity Error Interrupt */

   __HAL_UART_DISABLE_IT(huart, UART_IT_PE);

   /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */

   __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);

   /* Rx process is completed, restore huart->RxState to Ready */

   huart->RxState = HAL_UART_STATE_READY;

   HAL_UART_RxCpltCallback(huart);

   return HAL_OK;

  }

   

  return HAL_OK;

 }

 else

 {

  return HAL_BUSY;

 }

}

<===========this function will disable interrupt

 * @brief Sends an amount of data in non blocking mode.

 * @param huart: Pointer to a UART_HandleTypeDef structure that contains

 *        the configuration information for the specified UART module.

 * @retval HAL status

 */

static HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart)

{

 uint16_t* tmp;

  

 /* Check that a Tx process is ongoing */

 if(huart->gState == HAL_UART_STATE_BUSY_TX)

 {

  if(huart->Init.WordLength == UART_WORDLENGTH_9B)

  {

   tmp = (uint16_t*) huart->pTxBuffPtr;

   huart->Instance->DR = (uint16_t)(*tmp & (uint16_t)0x01FFU);

   if(huart->Init.Parity == UART_PARITY_NONE)

   {

    huart->pTxBuffPtr += 2U;

   }

   else

   {

    huart->pTxBuffPtr += 1U;

   }

  } 

  else

  {

   huart->Instance->DR = (uint8_t)(*huart->pTxBuffPtr++ & (uint8_t)0x00FFU);

  }

  if(--huart->TxXferCount == 0U)

  {

   /* Disable the UART Transmit Complete Interrupt */

   __HAL_UART_DISABLE_IT(huart, UART_IT_TXE);

   /* Enable the UART Transmit Complete Interrupt */   

   __HAL_UART_ENABLE_IT(huart, UART_IT_TC);

  }

  return HAL_OK;

 }

 else

 {

  return HAL_BUSY;

 }

}

roseanne qiu
Associate II

continue: I am a little panic for the uart interrupts. I am thinking even I take the actions I know,

if there is still hang from interrupts, I am thinking to restart this uarts

from task level, I could not restart the uart, I am thinking by using watchdog.

but since some data are very sensitive and need previous history, I do not want to reset whole system.

so I with if I could use watchdog which trigger higher priority interrupt

and this watchdog interrupt routine only reset uart communication and reset some of tasks to make other data sensitive tasks keep running.

can I do this?

as I know once the watchdog happens, it will reset whole system, but I really do not want to reset whole system which will make some tasks lose

their history.

any advice and suggestion?

thanks

roseanne

>>any advice and suggestion?

Read the Reference Manual and refactor the code so it is simpler, cleaner and less convoluted. Root cause what's actually going on in your system and remediate that.

Why couldn't you use a higher priority interrupt on a TIM, or frankly via the existing SysTick, to provide time-out or recovery of the USART? Or count entry into USART IRQ Handler, and if you see 100,000 hits, or whatever, in a milli-second you'd know something was awry.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..