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

Dear Clive:

thanks for your quick response. based on your advice,

I will use timer1 with higher priority than uart, once system tasks level hang, in the timer1 interrupt routine, first check each uart status and then clear that uart and restart it on the task level . in this way, I could avoid system hang because uart interrupt routine hold all system.

thanks

brb once I do some tests.

roseanne

SysTick is probably easier because it likely already fired up and configured in a way to make HAL Ticks advance at the highest priority/preemption level. A "watchdog" here would be to load/check a count variable, and clear it, every 1ms and have a routine in the USART IRQ Handler(s) than increments the count. In case of an interrupt storm this counter would then peg full-scale in way that would be actionable within 1-2ms of onset.

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 help.

I do not quite understand your last paragraph, would you please give a small examples . I guess that you want me to try to count times inside UART IRQ?

if so, how could I know a special UART get reentered forever?

I look back the hal uart IRQHandler as above, once an interrupt happens, only when UART_RECEIVE_IT or UART_TRANSMIT_IT are skipped without execution, the related interrupt handler will be kept reentered. In my updates, once the interrupt get called, no matter whether there is error or not error,

I let one of UART_RECEIVE_IT or UART_TRANSMIT_IT get executed and clear interrupt .

this is what I could do.

but if something happen , they are not any errors listed in this uart IRQ handler, above two functions are never called, the uart interrupt routine will be reentered forever again.

IN MY understand, once the uart IRQ handler get called, one of rx or tx interrupt bit has to be cleared. It means that one of UART_RECEIVE_IT or UART_TRANSMIT_IT

have to be called . in this way, the reenter of the uart IRQ handler could be avoid . am I correct?

thanks

roseanne

So, you increment an entry count in the handler, and look for stupidly high counts in the SysTick Handler... Numbers in this context would be >10000 or >100000, I'd suppose, because the system has gone off the rails, and this is all it is doing. Suggest you review the count during the integration period to see how bad it gets, but you should be able to catch within 1-2ms, so you have some chance of recovering the system before other critical tasks fail.

At 9600 baud you'd expect no more than 2-4 (IN/OUT) invocations in 1ms. (9600 baud = 1000 chars/per second, or 1 every ms)

volatile unsigned int entrycount = 0;
 
void USART1_IRQHandler(void)
{
  entrycount++;
...
  HAL_UART_IRQHandler(&hUart1);
}
void SysTick_Handler(void) // Called at 1ms (1 KHz)
{
  HAL_IncTick();
 
  if (entrycount > 10000) // Detect interrupt storm saturating processor
  {
    // Something gravely wrong with USART
    //  Clear errors, status, or reinitialize, or whatever to recover situation
  }
 
  entrycount = 0; // zero count for next 1ms integration period
}

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:

I still could not get it how to do that inside UART IRQHander, since I have 3 uarts within one UART IRQhandler, every uart handler keep running with three uart interfaces, the interrupt handler kept calling , and switch between these interrupt and tasks happen a lot.

what I am doing is

in the while main loop

....

while(1)

{

start timer1<=============

switch(task)

{

case task1:

task1();

break;

case task2:

task2();

...

}

//switch

stop timer1<==================

}//while

...

//inside the timer1 handler,

// I set 2 second

// if it is over 2 second, above stop timer1 does not get execute

// the following interrupt happen

timer1_IRQHandle()

{

// check each uart status.

// if there is erro and also state is in busy

// this uart interrupt will be disable and cleanr

// and call:

UART_RECEIVE_IT // which will clear uart rv interrupt and call receive uar callback function

or

// the follow will disable interrupt and call interrupt callback

 UART_Transmit_IT(Uart1Handle)

 UART_EndTransmit_IT(Uart1Handle);

...

}

after above timer1 irq get executed, all stuck uart interrupt should be out and allow other task to continue running.

so whole system other tasks will continue running,maybe get a 1 or 2 second delay, but better than resetting whole system.

any comments for my solution?

also would like to understand your solution for detail.

thanks

roseanne

roseanne qiu
Associate II

continue: except above the code added inside main loop, the following are for timer1 interrupt, my question is whether my judgment for tx and rx are correct?

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

{

 if ( htim->Instance == TIM1 )

  {// this timer behavior as watchdog.

   gbTimerExpire |= TIMER1_INT;

   // check each uart and stop

   // reset uart interrupt

   //1. uart1 for sysbd

// for tx check?

   if ( Uart1Handle->gState == HAL_UART_STATE_ERROR ||

  Uart1Handle->gState == HAL_UART_STATE_BUSY_TX ||

  Uart1Handle->gState == HAL_UART_STATE_BUSY ||

  Uart1Handle->gState == HAL_UART_STATE_BUSY_TX_RX ||

  Uart1Handle->gState == HAL_UART_STATE_TIMEOUT )

{

 if ( Uart1Handle->ErrorCode != HAL_UART_ERROR_NONE )

  {

   // reset uart1

   UART_Transmit_IT(Uart1Handle);

   UART_EndTransmit_IT(Uart1Handle);

  }

}

// for rx check?

   else if ( Uart1Handle->RxState == HAL_UART_STATE_BUSY_RX ||

Uart1Handle->RxState == HAL_UART_STATE_BUSY_TX_RX )

{//rx

 if ( Uart1Handle->ErrorCode != HAL_UART_ERROR_NONE )

  {

   // reset uart1

   UART_Receive_IT(Uart1Handle);   

  }

  

}

   // 2. uart2 for display

    if ( Uart2Handle->gState == HAL_UART_STATE_ERROR ||

  Uart2Handle->gState == HAL_UART_STATE_BUSY_TX ||

  Uart2Handle->gState == HAL_UART_STATE_BUSY ||

  Uart2Handle->gState == HAL_UART_STATE_BUSY_TX_RX ||

  Uart2Handle->gState == HAL_UART_STATE_TIMEOUT )

{

 if ( Uart2Handle->ErrorCode != HAL_UART_ERROR_NONE )

  {

   // reset uart2

   UART_Transmit_IT(Uart2Handle);

   UART_EndTransmit_IT(Uart2Handle);

  }

}

   else if ( Uart2Handle->RxState == HAL_UART_STATE_BUSY_RX ||

Uart2Handle->RxState == HAL_UART_STATE_BUSY_TX_RX )

{//rx

 if ( Uart2Handle->ErrorCode != HAL_UART_ERROR_NONE )

  {

   // reset uart2

   UART_Receive_IT(Uart2Handle);

  

  }

  

}

   // 3. uart6 for console

    if ( Uart6Handle->gState == HAL_UART_STATE_ERROR ||

  Uart6Handle->gState == HAL_UART_STATE_BUSY_TX ||

  Uart6Handle->gState == HAL_UART_STATE_BUSY ||

  Uart6Handle->gState == HAL_UART_STATE_BUSY_TX_RX ||

  Uart6Handle->gState == HAL_UART_STATE_TIMEOUT )

{

 

 if ( Uart6Handle->ErrorCode != HAL_UART_ERROR_NONE )

  {

   // reset uart6

   UART_Transmit_IT(Uart6Handle);

   UART_EndTransmit_IT(Uart6Handle);

   sprintf(gbDbBuf, "uart6txerr:[0x%x]\r\n\0", Uart6Handle->ErrorCode);

   dbPrintf(gbDbbuf);

  }

}

   else if ( Uart6Handle->RxState == HAL_UART_STATE_BUSY_RX ||

Uart6Handle->RxState == HAL_UART_STATE_BUSY_TX_RX )

{//rx   

 if ( Uart6Handle->ErrorCode != HAL_UART_ERROR_NONE )

  {

   // reset uart6

   UART_Receive_IT(Uart6Handle);

   

  }

  

}

   

    

    

  }

....

roseanne qiu
Associate II

Dear Clive:

sorry, I did not see your code until I click "more" , yes, I understand you now.

my questions are:

  1. I have three uart, I have to check each one
  2. I have to clear them , not just find them.

3. I have to keep all other tasks running

4. whether my solution have any problems , do you have any comments.

in our systems , all the three uarts are very busy all the times, I have to find stuck one and clear it right way without influencing other tasks and uarts.

thanks

roseanne

roseanne qiu
Associate II

more : just saw stm32 hal : TIM1_BRK_TIM9_IRQn  with  TIM1 Break interrupt and TIM9 global interrupt

since Tim9 usage conflicts with our other usage, so I could not use TIM9,

but what does it mean TIM1 break interrupt?

thanks

roseanne

roseanne qiu
Associate II

Dear Clive:

i think I could not use tim1

I try to use your sysstick

but I have a question

how do you reset count ?

if no interrupt renter

once the interrupt uart get executed

the counts always keep up no matter whether it is normal enter or keep stuck there

I never use this

see normal case

uart interrupt get executed, counter increased

see not normal case

the uart interrupt keep stuck inside irq also , counter also get increase

how do you dinstinqushi normal interrupt and stuck interrupt ?

there must be reset count in normal interrupt

thx

The count clears every milli-second.

For multiple USART create multiple instances of the counter.

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