cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F769NI: How to activate USART Receiver Timeout Interrupt (USART_RTOR.RTOF)?

Pascal Rosin
Associate II

I want the STM32F769NI to generate an interrupt when a pause after a received byte on USART6 was detected. I am using CubeMX and configured USART6 for Asynchronous mode with 9600 baud and to enable global USART6 interrupts and use the low level drivers for USART6. In the source files I enabled the RXNE interrupt with LL_USART_EnableIT_RXNE(USART6). So far this is working, on Interrupt I can read the correct byte from USART_RDR of USART6.

I want to get an Interrupt when a pause of 100 ms is detected after a byte was received. So I configured:

LL_USART_SetRxTimeout(USART6, 960);
LL_USART_ClearFlag_RTO(USART6);
LL_USART_EnableIT_RTO(USART6);

And tried to light a LED on the discovery board in the interrupt handler:

void USART6_IRQHandler(void)
{
  /* USER CODE BEGIN USART6_IRQn 0 */
 
  // Byte received:
  if (LL_USART_IsActiveFlag_RXNE(USART6))
  {
    serialHandleRXByte(LL_USART_ReceiveData8(USART6));
  }
 
  // RX inter-bxte timeout:
  else  if (LL_USART_IsActiveFlag_RTO(USART6))
  {
    LL_USART_ClearFlag_RTO(USART6);
 
    BSP_LED_On(LED1);
 
    serialHandleRXTimeout();
  }
  /* USER CODE END USART6_IRQn 0 */
  /* USER CODE BEGIN USART6_IRQn 1 */
 
  /* USER CODE END USART6_IRQn 1 */
}

The LED never lights up, I also tried to set breakpoints to check when the Interrupt handler is executed, but the interrupt is only executed when a byte is received, never after that and never with the RTO flag active.

Is there something I am missing to configure or is this feature only working in SmartCard mode? Can I use this smartcard mode for normal asynchronous bidirectional communication with 9600 baut?

1 ACCEPTED SOLUTION

Accepted Solutions

Thank you for your reply, the IDLE interrupt does not help because it is set after one byte idle time but to be compatible with some old devices here, I need an interrupt after 10 bytes of idle time.

I also noticed the strange note and thought maybe it is meant to be without the "only". But this did not help (the note seems also to be not valid with the "only" in it).

I simply missed the RTOEN bit in USART6.CR2 Register (Receiver Timout Enable). So for activating the Timeout, you need

    LL_USART_SetRxTimeout(USART6, 960);
    LL_USART_EnableRxTimeout(USART6); // <- I missed that
    LL_USART_ClearFlag_RTO(USART6);
    LL_USART_EnableIT_RTO(USART6);

The Manual states for the USART_ISR_RTOF flag, that an interrupt is generated if RTOIE in USART_CR1 is set. It does not mention RTOEN in USART_CR2. This should be updated in the Manual by ST!

Also the Note should be "The RTOF flag needs to be cleared once per received character". For some strange reason, the RTOF flag is set directly after reception of a character (together with the RXNE flag) without a timeout. You also don't need to set the USART_RTOR_RTO timeout value for every received byte. It is enough to set it once like in my initialization above. Also it seems to do no harm if I set the timeout value twice per received character :).

So my working ISR now looks like this:

void USART6_IRQHandler(void)
{
  /* USER CODE BEGIN USART6_IRQn 0 */
 
  // Byte received:
  if (LL_USART_IsActiveFlag_RXNE(USART6))
  {
    serialHandleRXByte(LL_USART_ReceiveData8(USART6));
 
    // USART_ISR_RTOF Flag is set at reception
    // and at timeout for some reason so you need
    // to reset it to not trigger this interrupt directly
    // after reception again:
    LL_USART_ClearFlag_RTO(USART6); 
  }
     
  // RX inter-bxte timeout:
  else  if (LL_USART_IsActiveFlag_RTO(USART6))
  {
    LL_USART_ClearFlag_RTO(USART6);
 
    BSP_LED_On(LED1);
     
    serialHandleRXTimeout();
  }
  /* USER CODE END USART6_IRQn 0 */
  /* USER CODE BEGIN USART6_IRQn 1 */
 
  /* USER CODE END USART6_IRQn 1 */
}

View solution in original post

3 REPLIES 3
Piranha
Chief II

In reference manual USART_RTOR field RTO has a strange note:

"Note: This value must only be programmed once per received character."

This ir confusing and ST should clarify it. However if we take word "only" out, then...

Additionally You can use simpler IDLE interrupt. It will trigger after line has been idle for a time of one frame.

https://github.com/MaJerle/STM32_USART_DMA_RX

Thank you for your reply, the IDLE interrupt does not help because it is set after one byte idle time but to be compatible with some old devices here, I need an interrupt after 10 bytes of idle time.

I also noticed the strange note and thought maybe it is meant to be without the "only". But this did not help (the note seems also to be not valid with the "only" in it).

I simply missed the RTOEN bit in USART6.CR2 Register (Receiver Timout Enable). So for activating the Timeout, you need

    LL_USART_SetRxTimeout(USART6, 960);
    LL_USART_EnableRxTimeout(USART6); // <- I missed that
    LL_USART_ClearFlag_RTO(USART6);
    LL_USART_EnableIT_RTO(USART6);

The Manual states for the USART_ISR_RTOF flag, that an interrupt is generated if RTOIE in USART_CR1 is set. It does not mention RTOEN in USART_CR2. This should be updated in the Manual by ST!

Also the Note should be "The RTOF flag needs to be cleared once per received character". For some strange reason, the RTOF flag is set directly after reception of a character (together with the RXNE flag) without a timeout. You also don't need to set the USART_RTOR_RTO timeout value for every received byte. It is enough to set it once like in my initialization above. Also it seems to do no harm if I set the timeout value twice per received character :).

So my working ISR now looks like this:

void USART6_IRQHandler(void)
{
  /* USER CODE BEGIN USART6_IRQn 0 */
 
  // Byte received:
  if (LL_USART_IsActiveFlag_RXNE(USART6))
  {
    serialHandleRXByte(LL_USART_ReceiveData8(USART6));
 
    // USART_ISR_RTOF Flag is set at reception
    // and at timeout for some reason so you need
    // to reset it to not trigger this interrupt directly
    // after reception again:
    LL_USART_ClearFlag_RTO(USART6); 
  }
     
  // RX inter-bxte timeout:
  else  if (LL_USART_IsActiveFlag_RTO(USART6))
  {
    LL_USART_ClearFlag_RTO(USART6);
 
    BSP_LED_On(LED1);
     
    serialHandleRXTimeout();
  }
  /* USER CODE END USART6_IRQn 0 */
  /* USER CODE BEGIN USART6_IRQn 1 */
 
  /* USER CODE END USART6_IRQn 1 */
}

Vitaly Lifanov
Associate

Hello!

You have enabled the interrupt, but forgot to enable the "overtimer". I mean the RTOEN bit in the CR2 register