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

For the F4 series you should be able to clear the condition by reading the DR.

On newer series STM32 the mechanism is a bit different.

https://community.st.com/s/question/0D50X00009ZEOZ3SAP/nucleo-f767zi-system-freeze-upon-uart-ore-interrupt

Perhaps you need to address the underlying cause of the underrunning, and if/how you flags that for your own code. The IRQ Handler will keep re-entering when there are causes pending, make sure your fully service the USART. Do not use a Debug View of the USART registers, it is invasive.

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

Dear Clive:

thanks for your quick response. I am doing tests now. with above solution , it seems work( when overrun happens one time, it continue running, but I need long time to test and confirm). but

new problem shows up.

as I said I use three uarts:1,2,6

once uart 1 has overrun, I immediately press a key from console port which is uart6, the whole system hangs again.

first: I do not know whether above patch really solve the problem, as I said I need running the system more time and get more overrunts to see whether the system hang.

second: if the original patch solves uart overrun problem, why :when uart1 has overrun, and uart6 has input, whole the system hang,

both of them have different interrupt handlers.

a little confused. I will report more after I run the system with above patch work.

keep in page

thanks

roseanne

Pavel A.
Evangelist III

Pardon me for jumping in. The F4 HAL interrupt handler clears ORE always, by reading all status regs

https://github.com/pavel-a/stm32f4_libs/blob/c4560650ddaea6ee33de171027d801a31109565a/STM32Cube_FW_F4/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c#L1525

and it checks ORE later in line 1565, and in line 1582.

The explicit macro for F4 to clear ORE works by reading both SR and DR:

https://github.com/pavel-a/stm32f4_libs/blob/c4560650ddaea6ee33de171027d801a31109565a/STM32Cube_FW_F4/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_uart.h#L450

So, if the ST HAL library does the right thing, just use it? Otherwise use the LL library.

If you use code from 3rd party (which is for a different chip, F2, by the way), please ask the 3rd party to help with it?

Regards,

-- pa

The HAL UART stuff is a total hack, I'm not going to spend the man-hours to wade through it. I've got multiple USART working on a lot of my systems, and I'm really not having issues, or data loss with them.

I can tell you that the IRQ handlers will continue to re-enter, and not allow for any foreground code execution to occur, if any interrupts remain pending.

You'll need to do your own debugging to understand why things hang or how they interact, or the meta-stability the HAL introduces. Don't look at the USART registers in the debuggers peripheral view, this will be invasive. Also avoid break-points and single-stepping, this will run orders of magnitude slower than the expected performance/responsiveness of a real-time system. Instrument your code, use SWV, and understand the dynamics and interplay.

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

> The F4 HAL interrupt handler clears ORE always, by reading all status regs

RM0090 for the ORE bit says:

 It is cleared by a software sequence (an read to the

USART_SR register followed by a read to the USART_DR register).

i.e. it's not enough to read the status registers to clear ORE.

roseanne qiu
Associate II

Dear Sir/madam:

I come back . after overnight test, my patch does not work.

once rx overrun happen, it locked again.

here is hal source code for handler, I still try to understand the link method.

/**
 * @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))
 {
#if 1
  uint8_t sysRxChar; // clear the regular interrupt 
  sysRxChar = (uint8_t) huart->Instance->DR;<======this is work around, not sure whether it is correct, but it does not work
#endif
 
  __HAL_UART_CLEAR_OREFLAG(huart);   
  huart->ErrorCode |= HAL_UART_ERROR_ORE;
 }
 
 tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE);
 tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE);
 
 /* UART in mode Receiver ---------------------------------------------------*/
 if((tmp1 != RESET) && (tmp2 != RESET))
 { 
  UART_Receive_IT(huart); <=======this part will call normal uart rx interrupt
 }
 
 tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_TXE);
 tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TXE);
 
 /* UART in mode Transmitter ------------------------------------------------*/
 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);
 
 /* 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); <===========this part calls error uart interrupt.
 }  
}

 I look at the normal call for interrupt function: 

/**
 * @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); <=========normal uart rx interrupt callback.
 
  return HAL_OK;
 }
 return HAL_OK;
 }
 else
 {
 return HAL_BUSY;
 }
}

waclawek.jan mentioned that

RM0090 for the ORE bit says:

 It is cleared by a software sequence (an read to the

USART_SR register followed by a read to the USART_DR register).

I am not quietly understand? would you please give me more details?

thanks

rosean

Pavel A.
Evangelist III

@Community member​  Yes. I stand corrected. In the IRQhandler they read DR later after checking RXNE (line 1574).

So there's the correct sequence.

-- pa

>>the whole system hangs again.

You'll need to debug it a little more precisely.

Hangs where, doing what, waiting on what, what expectations?

Does setting these ErrorCode values have any downstream ramifications? Does anything check or react to them?

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

already debug , hang come from the uart interrupt reented forever. Now I used new work around based on another thread

work around patch work is:

...

 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 defined(RQIU_DEBUG2) <=== add this park

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

    (huart->ErrorCode&HAL_UART_ERROR_ORE) )

  {

     UART_Receive_IT(huart);

  }

 else 

#endif

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

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

 { 

  UART_Receive_IT(huart);

 }

  ...

the reason I add this is:

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

Found a bug where P1/photon can seem like it's frozen due to the HAL_USART_Handler constantly going off when the ORE flag is set in USART_SR and the RXNE bit is not set.

ORE = Overrun error flag in the USART Status Reg

RXNE = Rx buffer not empty flag

RXNEIE = ISR enable on RXNE flag set

Currently HAL_USART Handler doesn't handle the case where RXNEIE=1, RXNE=0, ORE=1 and the USART ISR goes off constantly.

The UART ISR will go off if ORE is set and RXNEIE is enabled. Overrun errors are handled just fine most of the time since the RXNE bit is set on most occurrences and the ISR currently will read the USART DR if RXNE is set. The ORE bit is cleared by a read to USART_SR followed by a read to the USART_DR. However, it's possible the ORE can be set as the RXNE is cleared.

...

I am running now to see whether the problem is solved.

it takes long time to get this situation.

thanks

roseanne