cancel
Showing results for 
Search instead for 
Did you mean: 

using HAL_UART_Transmit with safety

MMath.10
Associate II

Hi,

I'm using the USART function HAL_UART_Transmit for debugging.

Most of the time everything works well.

But sometimes the HAL_UART_ErrorCallback is called... And all my program freeze.

Could you help me with these 2 options (first is best for me) :

how can i get back to a functionnal state after a HAL_UART_ErrorCallback call ?

how can i check if UART is ready to send data before using HAL_UART_Transmit ?

Regards

17 REPLIES 17

Thx Bob,

I use sw4stm32 with Eclipse and I easily find what I'm looking for if I know what I'm looking for. ^^

At first I read this and i'm not really happy with this part ,

        /* Non Blocking error : transfer could go on. 
           Error is notified to user through user error callback */
        HAL_UART_ErrorCallback(huart);
        huart->ErrorCode = HAL_UART_ERROR_NONE;

some error is not blocking and my error callback look like this, waiting the wadchdog reset the stm32...

void Error_Handler(void)
{
  PRINTF("Error_Handler %d\n\r",advanten_error_code);
  while (1)
  {
    ;
  }
}

Adding some error code find the error exactly here :

        /* Non Blocking error : transfer could go on. 
           Error is notified to user through user error callback */
    	  huart->ErrorCode = 0x40;
        HAL_UART_ErrorCallback(huart);
        huart->ErrorCode = HAL_UART_ERROR_NONE;
      }

So i had a non blocking error.

I had this part in the handler

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
  /* Initialization Error */
  if (huart->ErrorCode == 0x40)
  {
    PRINTF("HAL_UART_ErrorCallback not blocking\n\r");
  }
  else
  {
    advanten_error_code = huart->ErrorCode;
    Error_Handler();
  }
}

Thanks

HI @Bob S​ 

This morning's tests show that the non-blocking error is not really corrected.

The UARTs do not work well after this error ... Some characters remain blocked in the Rx buffer ...

Could you explain to me how to reset the USART functionally after this error?

EDIT : do you think this error could come because my debug USART is in blocking mode and the STM32 go in RX overun? => NO, I disable my debug USART and the overrun still appears.

EDIT 2 10h24 :

the error come from here, the errorcode is 0 so the HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR) is the error.

      if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) ||
          (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))
      {  

Bob S
Principal

Almost, but not quite. That "if" statement you show is indeed the "if" that is causing your error callback to be called. However, if you really are getting the "non blocking" callback, that "if" statement is evaluating to FALSE (i.e. the code goes to the "else" clause"). At least that is what happens in the 32L4xx HAL code. So this means that ORE is "reset" (no overrun error) AND that DMA is DIS-abled (that is a big clue here).

So go back to my initial debug suggestions. In you callback, what does the "huart" point to? Which of your UART structures? I don't know that you ever answered that question. Read the control and status registers for that uart. What do you see? Looking at those register values, can you look at the HAL_UART_IRQHandler() code and verify how it got to calling the error callback? Post the values here if you can't see what is going on.

Hmmmm.... actually, since you cannot run the debugger on this hardware and single-step through the HAL_UART_IRQHandler(), you will need to modify the code. HAL_UART_IRQHandler() reads the UART's ISR, CR1 and CR3 registers, and then clears some of the error/interrupt flags as it processes things (via __HAL_UIART_CLEAR_FLAG). You will need to change this to store a copy of the ISR register in some global variable where your error callback function can read it, so you can see the un-modified version. At a quick glance, it don't THINK it alters the contents of CR1 or CR3, so you should be able to read those directly from the USART peripheral. Though if you save the ISR to a global variable, you may as well save the CR1 and CR3 values as well.

"if you really are getting the "non blocking" callback, that "if" statement is evaluating to FALSE "

=> yes

So this means that ORE is "reset" (no overrun error) AND that DMA is DIS-abled (that is a big clue here)

=> OK, DMA disabled is odd, maybe the error come from the receive function?

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
   if (HAL_UART_ERROR_NONE == huart->ErrorCode) {
     CMD_GetChar(&charRx);
   }
   HAL_UART_Receive_IT(huart, &charRx,1);
}

The huart is defined here,

used in DMA mode for TX and IT mode for RX

void vcom_Init(  void (*TxCb)(void) )
{
 
  /*Record Tx complete for DMA*/
  TxCpltCallback=TxCb;
  /*## Configure the UART peripheral ######################################*/
  /* Put the USART peripheral in the Asynchronous mode (UART Mode) */
  /* UART1 configured as follow:
      - Word Length = 8 Bits
      - Stop Bit = One Stop bit
      - Parity = ODD parity
      - BaudRate = 921600 baud
      - Hardware flow control disabled (RTS and CTS signals) */
  huart2.Instance        = USART2;
  huart2.Init.BaudRate   = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits   = UART_STOPBITS_1;
  huart2.Init.Parity     = UART_PARITY_NONE;
  huart2.Init.HwFlowCtl  = UART_HWCONTROL_NONE;
  huart2.Init.Mode       = UART_MODE_TX_RX;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
 
  if(HAL_UART_Init(&huart2) != HAL_OK)
  {
    /* Initialization Error */
    advanten_error_code = 1;
    Error_Handler();
  }
 
}

HAL_UART_IRQHandler() called the error callback where i show you :

/* Call UART Error Call back function if need be --------------------------*/
    if(huart->ErrorCode != HAL_UART_ERROR_NONE)
    {
      /* UART in mode Receiver ---------------------------------------------------*/
      if(((isrflags & USART_ISR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
      {
        UART_Receive_IT(huart);
      }
 
      /* If Overrun error occurs, or if any error occurs in DMA mode reception,
         consider error as blocking */
      if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) ||
          (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))
      {  
        /* Blocking error : transfer is aborted
           Set the UART state ready to be able to start again the process,
           Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
        UART_EndRxTransfer(huart);
 
        /* Disable the UART DMA Rx request if enabled */
        if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
        {
          CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
 
          /* Abort the UART DMA Rx channel */
          if(huart->hdmarx != NULL)
          {
            /* Set the UART DMA Abort callback : 
               will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */
            huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;
 
            /* Abort DMA RX */
            if(HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
            {
              /* Call Directly huart->hdmarx->XferAbortCallback function in case of error */
              huart->hdmarx->XferAbortCallback(huart->hdmarx);
            }
          }
          else
          {
            /* Call user error callback */
            HAL_UART_ErrorCallback(huart);
          }
        }
        else
        {
          /* Call user error callback */
          HAL_UART_ErrorCallback(huart);
        }
      }
      else
      {
        /* Non Blocking error : transfer could go on. 
           Error is notified to user through user error callback */
    	huart->ErrorCode = 0x40;
        HAL_UART_ErrorCallback(huart);
        huart->ErrorCode = HAL_UART_ERROR_NONE;
      }
    }
    return;
 
  } /* End if some error occurs */

Here the ISR CR1 and CR3 value in the error callback

ISR = 6010D0

CR1 = 012D

CR3 = 0001

Good news,I managed to fix the problem of the character blocking in the RX buffer.

Make some other test but it works with a wooden cane

EDIT: ISR seems to say there is no error. ORE NF and FE are set to 0

I don't understand why my error code in the callback is 0 before i change it to 0x40.

The first test (lign 2) is verify ErrorCode is != 0...

    /* Call UART Error Call back function if need be --------------------------*/
    if(huart->ErrorCode != HAL_UART_ERROR_NONE)
    {
      /* UART in mode Receiver ---------------------------------------------------*/
      if(((isrflags & USART_ISR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
      {
        UART_Receive_IT(huart);
      }
 
      /* If Overrun error occurs, or if any error occurs in DMA mode reception,
         consider error as blocking */
      if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) ||
          (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))
      {  
        /* Blocking error : transfer is aborted
           Set the UART state ready to be able to start again the process,
           Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
        UART_EndRxTransfer(huart);
 
        /* Disable the UART DMA Rx request if enabled */
        if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
        {
          CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
 
          /* Abort the UART DMA Rx channel */
          if(huart->hdmarx != NULL)
          {
            /* Set the UART DMA Abort callback : 
               will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */
            huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;
 
            /* Abort DMA RX */
            if(HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
            {
              /* Call Directly huart->hdmarx->XferAbortCallback function in case of error */
              huart->hdmarx->XferAbortCallback(huart->hdmarx);
            }
          }
          else
          {
            /* Call user error callback */
            HAL_UART_ErrorCallback(huart);
          }
        }
        else
        {
          /* Call user error callback */
          HAL_UART_ErrorCallback(huart);
        }
      }
      else
      {
        /* Non Blocking error : transfer could go on. 
           Error is notified to user through user error callback */
    	huart->ErrorCode |= 0x40;
        HAL_UART_ErrorCallback(huart);
        huart->ErrorCode = HAL_UART_ERROR_NONE;
      }
    }
    return;

Bob S
Principal

(1) The ISR value that you posted, did you get that by reading the ISR register in your callback function, or did you alter the HAL_UART_ISRHandler() to save its values somewhere? My guess is you read the huart->instance->ISR in your error callback function, but I may be wrong.

(2) This is basic debugging - Follow/Simulate (in your head or on paper) the HAL_UART_ISRHandler() code from the beginning of the function, presuming that the interrupt is caused by receiving a character (which your previous posts point to) along with some kind of error except overrun. Look at what happens in each function called from HAL_UART_ISRHandler() before it calls the error callback. Hint - do any of them modify huart->ErrorCode?

1- yes in the callback

value in the handler :

Error = 0008

Isr = 6110F8

Cr1 = 012D

CR3 = 0001

My Rx handler is not fast enough if i understand well? a character stay in the rx buffer before i read it?

  

MMath.10
Associate II

Hi @Bob S​ 

i found the source of the problem, i use these function when i receive char on uart.

LORA_Init( &LoRaMainCallbacks, &LoRaParamInit);
          LORA_Join();

problem solved by doing one thing at a time

regards