Skip to main content
Visitor II
July 31, 2018
Question

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

  • July 31, 2018
  • 42 replies
  • 10574 views

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

    This topic has been closed for replies.

    42 replies

    Graduate II
    August 6, 2018

    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.

    Visitor II
    August 6, 2018

    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

    Graduate II
    August 6, 2018

    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
    }

    Visitor II
    August 6, 2018

    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

    Visitor II
    August 6, 2018

    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);

       

      }

      

    }

       

        

        

      }

    ....

    Visitor II
    August 6, 2018

    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

    Visitor II
    August 6, 2018

    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

    Visitor II
    August 6, 2018

    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

    Graduate II
    August 7, 2018

    The count clears every milli-second.

    For multiple USART create multiple instances of the counter.

    Visitor II
    August 7, 2018

    Dear Clive:

    this is a good idea for interrupt problem. I also have adc interrupt, I may also use this way to avoid adc interrupt has the same problems.

    I am wondering that I also use timer interrupt, if timer interrupt also has the simillar problem, that will be terrible . and chip will be just useless.

    thanks for the hint and help.

    roseanne