cancel
Showing results for 
Search instead for 
Did you mean: 

How to change default UART Idle line Inactivity time

KAgga.1
Associate III

Hello There,

I'm utilizing IDLE event functionality of UART and use HAL_UARTEx_ReceiveToIdle_IT() for it.
The issue that I'm facing is that some times this API falsely detects an IDLE event upon reception (May be a Transmitter issue). So, to overcome that, I'm looking to increase IDLE inactivity time.

Kindly help on how to configure this.

Regards,
Keshav Aggarwal

13 REPLIES 13
Karl Yamashita
Lead III

The idle time is hardware dependant. You can't change it in FW. Check to see why the transmitting device is not sending the bytes in a continuous stream. 

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.
Pavel A.
Evangelist III

On STM32H7 UARTs have the Receiver timeout feature (RTO). This is what you want to use instead of idle detection. The RTO length can be specified.

Hello Karl, Thanks for replying.
Actually, the transmitting device isn't configurable.
I'm using STM32H7A3VIT6. The documentation says it is programmable.


stm32h7xx_hal_uart_ex.c

[..] This subsection also provides a set of additional functions providing enhanced reception
services to user. (For example, these functions allow application to handle use cases
where number of data to be received is unknown).

(#) Compared to standard reception services which only consider number of received
data elements as reception completion criteria, these functions also consider additional events
as triggers for updating reception status to caller :
(+) Detection of inactivity period (RX line has not been active for a given period).
(++) RX inactivity detected by IDLE event, i.e. RX line has been in idle state (normally high state)
for 1 frame time, after last received byte.
(++) RX inactivity detected by RTO, i.e. line has been in idle state
for a programmable time, after last received byte.
(+) Detection that a specific character has been received.

Hello Pavel,
Thanks for replying. I think RTO and Idle Inactivity time are different things.
By the way, how the Default RTO value could be changed?
Let me also tell you my use case-
Firstly, I'm using UART module in half-duplex receive only mode and STM32 UART would be receiving the data asynchronously every few seconds. The data length is unknown, So I'm using HAL_UARTEx_ReceiveToIdle_IT() .
The problem I'm facing is that I'm receiving data in chunks via multiple interrupts for a single stream of data being sent by the transmitter.
It means STM32 UART is unnecessarily detecting IDLE events and hence raising multiple interrupts for single stream of data.

Well you specifically said "IDLE"  which i know isn't programmable and "and HAL_UARTEx_ReceiveToIdle_IT()"   which uses HAL_UART_RECEPTION_TOIDLE type. I never used RTO as I've always used IDLE, so I totally forgot the RTO HAL driver exists .

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.
KAgga.1
Associate III

Hello @Tesla DeLorean @TDK
Could you help on this?

Pavel A.
Evangelist III

 I think RTO and Idle Inactivity time are different things.

Yes, different. And when users ask for idle detection for receive, they usually want RTO. Inactivity detection usually is needed for TX.

> how the Default RTO value could be changed

In stm32h7xx_ll_usart.h :

LL_USART_SetRxTimeout() -  the timeout is specified in bit times,  after the last received byte
LL_USART_EnableRxTimeout()  - enable the RTO operation. There is no default RTO value.

 

__STATIC_INLINE 
void LL_USART_EnableRxTimeout(USART_TypeDef *USARTx)
{
  SET_BIT(USARTx->CR2, USART_CR2_RTOEN);
}

__STATIC_INLINE 
void LL_USART_SetRxTimeout(USART_TypeDef *USARTx, uint32_t Timeout)
{
  MODIFY_REG(USARTx->RTOR, USART_RTOR_RTO, Timeout);
}

__STATIC_INLINE 
void LL_USART_EnableIT_RTO(USART_TypeDef *USARTx)
{
  ATOMIC_SET_BIT(USARTx->CR1, USART_CR1_RTOIE);
}

 

Karl Yamashita
Lead III

So after playing with RTO, it calls an error callback. 

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)

So let's say you set  HAL_UART_Receive_IT or HAL_UARTEx_ReceiveToIdle_IT

to receive 13 bytes, but you only get 5 bytes, then the error callback is called. It doesn't indicate how many bytes have been received. If it's binary then how do you determine if the last byte that may be 0x00 or 0xFF is really data or initialized value? If it's ASCII then you can determine the string length if the buffer was initialized prior to receiving. Using IDLE is better as the callback indicates how many bytes were received.

 

And just to be sure, you do know that HAL_UARTEx_RxEventCallback is called at half callback as well?

 

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.
Pavel A.
Evangelist III

Hi @Karl Yamashita 

In any HAL_UART callback, you can get the number of already received bytes in huart-> RxXferCount (or TxXferCount for TX). IMHO the current HAL libraries do not fully support RTO (maybe the latest products which I have not used, do...).  For example here the "RX types" are defined: HAL_UART_RECEPTION_TOIDLE and HAL_UART_RECEPTION_TORTO. But the latter does not appear anywhere in the source.  Advantage of custom code for UARTs over the HAL library is that you do just what is needed and don't have to struggle with limitations of someone else's code.