cancel
Showing results for 
Search instead for 
Did you mean: 

How to correctly use HAL_UART_Receive_IT when sending&receiving data?

Tuoman
Senior II

I try to use UART to transmit and receive from the same port (transmit query to device, receive response). I receive 1 byte at time, because of unknown message length.

Problem is that I first needed to flush uart RX to clear interrupt status, otherwise interrupt will fire immidiately. Then when I flush it, I get overrun error, and need to clear that flag as well.

These problems indicate that I must use HAL UART incorrectly.

Currently I use HAL UART like this:

When sending:

//disable uart RX before transmitting
HAL_UART_AbortReceive(myUart);
 
//send data over usart
if (HAL_UART_Transmit_IT(myUart, data, len) != 0)
{
	//TODO: handle error
}
 
...
 
 void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle)
{
	if (UartHandle->Instance == huart7.Instance)
	{
             //I need to clear overrun flag
             __HAL_UART_CLEAR_OREFLAG(myUart);
               //I need to flush rx data, otherwise RX interrupt will fire immidiately
              __HAL_UART_SEND_REQ(myUart, UART_RXDATA_FLUSH_REQUEST);
 
           //enable receive after transmit
          if (HAL_UART_Receive_IT(myUart, &RxBuffer, 1) != 0)
          {
	      //TODO: handle error
           }
	}
}

When receiving:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
	if (UartHandle->Instance == huart7.Instance)
	{
               //store data
                 ...
              //I need to clear overrun flag
             __HAL_UART_CLEAR_OREFLAG(myUart);
               //I need to flush rx data, otherwise RX interrupt will fire immidiately
              __HAL_UART_SEND_REQ(myUart, UART_RXDATA_FLUSH_REQUEST);
 
               //reactivate uart interrupt for 1 byte
 		if (HAL_UART_Receive_IT(myUart, &RxBuffer, 1) != 0)
               {
	          //TODO: handle error
                }
         }
}

I have many questions how to use this HAL UART;

  1. Is it valid to re-activate UART interrupt by calling HAL_UART_Receive_IT in HAL_UART_RxCpltCallback, within interrupt context?
  2. Should I use HAL_UART_Receive_IT to reactivate interrupts for UART? Or some other function?
  3. Am I appropriately stopping UART receive with HAL_UART_AbortReceive?
  4. Is it necessary to clear any USART flags before reactivating HAL_UART_Receive_IT?

I cannot find any good examples of using HAL UART in such scenario (transmit&receive from same uart), and keep encountering problems if try to use this HAL myself.

TL;DR: How to use HAL UART in interrupt mode when sending & transmitting data?

4 REPLIES 4

UART HW can receive and transmit concurrently.

Now admittedly the whole HAL construct here is a overly convoluted. I chosen other approaches.

You might consider a buffering scheme that doesn't use a single variable to hold both in-bound and out-bound data.

I seem to recall the error flags being cleared by the function.

The HAL_UART_Receive_IT() can be called under interrupt/callback context, but you might want to be more aware if you have an existing pending request.

Might want to be specific about what "STM32" is being discussed.

The "interrupts immediately" seems a bit odd, the TXE fires as soon as the buffer is moved to the shift register, this can occur very quickly it the UART is otherwise idle.

The receiver interrupt would only typically occur if the RXNE indicates some content. Are you using a part with a FIFO, and failing to clear all the received data?

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

>UART HW can receive and transmit concurrently.

Ok. We use RS485 device in half-duplex operation, thus need to transmit first, then receive after a bit of delay.

>Now admittedly the whole HAL construct here is a overly convoluted. I chosen other approaches.

That might be necessary. In simple cases HAL UART works fine, but this 1. disable receive, 2. transmit, 3. receive, repeat needs more configuration.

I'm looking for appropriate example usage instead of trial&error myself.

>You might consider a buffering scheme that doesn't use a single variable to hold both in-bound and out-bound data.

This is not the case. I have separate RxBuffer and TxBuffer("data" variable in Transmit)

>Might want to be specific about what "STM32" is being discussed.

STM32H7B3II

>The "interrupts immediately" seems a bit odd, the TXE fires as soon as the buffer is moved to the shift register, this can occur very quickly it the UART is otherwise idle.

Sorry not being clear enough. Transmit interrupt seems to work as expected. HAL_UART_RxCpltCallback interrupt fires before anything has been received (not sure if it is immediately though).

>The receiver interrupt would only typically occur if the RXNE indicates some content.

Exactly, that is why I went with the flush. Uart handle has HAL_UART_ERROR_ORE Error Code, and presumably causes to fire the interrupt.

>Are you using a part with a FIFO, and failing to clear all the received data?

Not sure if I use a part with a FIFO. But yes, that is indeed the case. Just wondering how I should solve this appropriately, instead of guessing how to use the API.

Thank you!

Pavel A.
Evangelist III

> that is why I went with the flush. 

Be careful with the HAL implementation of flush, it can flush TX side as well and clobber TX data still in the FIFO.

> Not sure if I use a part with a FIFO. 

You do. H7 has the latest and greatest UART IP.

> Uart handle has HAL_UART_ERROR_ORE Error Code, and presumably causes to fire the interrupt.

Overflow (ORE) handling in the HAL library was broken, at least in some branches and versions. Better disable overflow detection.

-- pa

>Be careful with the HAL implementation of flush, it can flush TX side as well and clobber TX data still in the FIFO.

Hmm ok, even with the UART_RXDATA_FLUSH_REQUEST command? Would you suggest using READ_REG(huart->Instance->RDR) instead? I think it should flush the RX buffer as well.

>Overflow (ORE) handling in the HAL library was broken, at least in some branches and versions. Better disable overflow detection.

Hmm ok. Can disabling it lead to any problems?

Thanks!