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

    Super User
    August 1, 2018

    @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

    Super User
    August 2, 2018

    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

    Visitor II
    August 2, 2018

    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

    Graduate II
    August 2, 2018

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

    Technical Moderator
    August 3, 2018

    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

    Visitor II
    August 6, 2018

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

     }  

    }

    Visitor II
    August 6, 2018

    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;

     }

    }

    Visitor II
    August 6, 2018

    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

    Graduate II
    August 6, 2018

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

    Visitor II
    August 6, 2018

    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