cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 USART RX with FIFO - not working

Pavel A.
Evangelist III

Dear experts,

I'm trying to receive continuously from a USART with interrupts.

For some reason I don't want to use DMA (the Tilen Majerle's DMA example on github works well, though)

So I'm enabling RX FIFO and Receive timeout (RTO) for receiving less than FIFO threshold.

Then, loss of data occurs. Many sent bytes are not received in the ISR.

Without RX FIFO threshold interrupt + RTO; only with RXNE interrupt; RX works well as expected.

Does anybody have idea what is missing for RX FIFO threshold interrupt?

Below are two variants : with only RXNE interrupt (working) and with RXFTIE + RTO interrupts (failing).

Note that in both cases the FIFO mode is enabled, and any RX errors are ignored.

I've tried to reproduce the logic from the HAL UART driver, HAL_UART_Receive_IT.

Cannot use this function as is because need continuous RX (unlimited size) .

// INIT
void UART_init(UART_HandleTypeDef *pu, USART_TypeDef *U)
{
  pu->Instance        = U;
  pu->Init.BaudRate   = baud_rate;
  pu->Init.WordLength = UART_WORDLENGTH_8B;
  pu->Init.StopBits   = UART_STOPBITS_1;
  pu->Init.Parity     = UART_PARITY_NONE;
  pu->Init.HwFlowCtl  = UART_HWCONTROL_NONE;
  pu->Init.Mode       = UART_MODE_TX_RX;
  pu->Init.OverSampling = UART_OVERSAMPLING_8;
  pu->AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_RXOVERRUNDISABLE_INIT;
  pu->AdvancedInit.OverrunDisable = UART_ADVFEATURE_OVERRUN_DISABLE;
 
  if (HAL_UART_Init(pu) != HAL_OK)
          Error_Handler();
 
  HAL_UARTEx_SetTxFifoThreshold(pu, UART_TXFIFO_THRESHOLD_3_4);
  HAL_UARTEx_SetRxFifoThreshold(pu, UART_RXFIFO_THRESHOLD_1_2);
  if (HAL_UARTEx_EnableFifoMode(pu) != HAL_OK)
  {
    Error_Handler();
  }
 
  SET_BIT(U->CR1, USART_CR1_RXNEIE);
 
  HAL_NVIC_SetPriority(USART_X_IRQn, USART_X_IRQ_PRIO_UART, 0); 
  HAL_NVIC_EnableIRQ(USART_X_IRQn);
}
 
// ISR
void  USART1_IRQHandler()
{
    USART_TypeDef *Instance  = USART1;
    uint32_t isrflags   = READ_REG(Instance->ISR);
 
    while ((isrflags & USART_ISR_RXNE_RXFNE) != 0U)
    {
      uint32_t udata = READ_REG(Instance->RDR);
 
      usart_rx_handler(udata); // consume data
 
      isrflags = READ_REG(Instance->ISR);
    }
}

FIFO variant - failing:

// INIT
void UART_init(UART_HandleTypeDef *pu, USART_TypeDef *U)
{
  pu->Instance        = U;
  pu->Init.BaudRate   = baud_rate;
  pu->Init.WordLength = UART_WORDLENGTH_8B;
  pu->Init.StopBits   = UART_STOPBITS_1;
  pu->Init.Parity     = UART_PARITY_NONE;
  pu->Init.HwFlowCtl  = UART_HWCONTROL_NONE;
  pu->Init.Mode       = UART_MODE_TX_RX;
  pu->Init.OverSampling = UART_OVERSAMPLING_8;
  pu->AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_RXOVERRUNDISABLE_INIT;
  pu->AdvancedInit.OverrunDisable = UART_ADVFEATURE_OVERRUN_DISABLE;
 
   if (HAL_UART_Init(pu) != HAL_OK)
          Error_Handler();
 
  HAL_UARTEx_SetTxFifoThreshold(pu, UART_TXFIFO_THRESHOLD_3_4);
  HAL_UARTEx_SetRxFifoThreshold(pu, UART_RXFIFO_THRESHOLD_1_2);
  if (HAL_UARTEx_EnableFifoMode(pu) != HAL_OK)
  {
    Error_Handler();
  }
  
  HAL_UART_ReceiverTimeout_Config(pu, 4 *10); // RTO, in bit times ~ 4 bytes
  HAL_UART_EnableReceiverTimeout(pu);
 
  SET_BIT(U->CR3, USART_CR3_RXFTIE);
  SET_BIT(U->CR1, USART_CR1_RTOIE);
 
  // Clear pending things:
  U->ICR = UART_CLEAR_RTOF;
 
  HAL_NVIC_SetPriority(USART_X_IRQn, USART_X_IRQ_PRIO_UART, 0); 
  HAL_NVIC_EnableIRQ(USART_X_IRQn);
}
 
// ISR
void USART1_IRQHandler()
{
    USART_TypeDef *Instance  = USART1;
    uint32_t isrflags   = READ_REG(Instance->ISR);
 
     if (isrflags & USART_ISR_RTOF) {
      Instance->ICR = UART_CLEAR_RTOF;
    }
    // no way to clear RXFT ineterrupt?
 
    while ((isrflags & USART_ISR_RXNE_RXFNE) != 0U)
    {
      uint32_t udata = READ_REG(Instance->RDR);
 
      usart_rx_handler(udata); // consume data
 
      isrflags = READ_REG(Instance->ISR);
    }
}

 *** ADDED ***

Debugging shows that the RXFT interrupt is never activated. Only RTOF interrupt is activated.

If I don't enable RTOIE, no interrupts occur.

What is missing to get interrupts from RXFT?

1 ACCEPTED SOLUTION

Accepted Solutions

Dear @Pavel A.​ 

An additional check : could you try to remove the Overrun feature disabling (keeping Overrun function as usual) for a check. I'm afraid this could be interacting with the FIFO mode: See following excerpt from Reference Manual about OVERDIS bit :

 0693W00000Dq5QyQAJ.pngWhat might happen is that OVERDIS is set, only a RXNE interrupt could be triggered but as FIFO is enabled, only RXFTIE is enabled ...

View solution in original post

7 REPLIES 7
Pavel A.
Evangelist III

Debugging shows that the RXFT interrupt is never activated.

Below is a simplified example to demonstrate the problem with RXFIFO threshold interrupt

If the code is as below - the interrupt handler is never entered.

If I comment out HAL_UARTEx_EnableFifoMode (lines 23-26) the interrupt handler is entered and data is received.

What is wrong with enabling the FIFO?

STM32H753 (Nucleo H753), Cube library H7 v 1.9.0

UART_HandleTypeDef  husart1;
 
// INIT
void UART_init()
{
  UART_HandleTypeDef *pu = &husart1;
  USART_TypeDef *U = USART1;
  pu->Instance        = U;
  pu->Init.BaudRate   = baud_rate;
  pu->Init.WordLength = UART_WORDLENGTH_8B;
  pu->Init.StopBits   = UART_STOPBITS_1;
  pu->Init.Parity     = UART_PARITY_NONE;
  pu->Init.HwFlowCtl  = UART_HWCONTROL_NONE;
  pu->Init.Mode       = UART_MODE_TX_RX;
  pu->AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_RXOVERRUNDISABLE_INIT;
  pu->AdvancedInit.OverrunDisable = UART_ADVFEATURE_OVERRUN_DISABLE;
 
   if (HAL_UART_Init(pu) != HAL_OK)
          Error_Handler();
 
  HAL_UARTEx_SetTxFifoThreshold(pu, UART_TXFIFO_THRESHOLD_3_4);
  HAL_UARTEx_SetRxFifoThreshold(pu, UART_RXFIFO_THRESHOLD_1_2);
  if (HAL_UARTEx_EnableFifoMode(pu) != HAL_OK)
  {
    Error_Handler();
  }
  
  HAL_NVIC_SetPriority(USART1_IRQn, 4, 0); 
  HAL_NVIC_EnableIRQ(USART1_IRQn);
 
 {
  static uint8_t rxbuf[50];
  HAL_UART_Receive_IT(pu, rxbuf, 40);
  }
}
 
// ISR
void USART1_IRQHandler()
{
    HAL_UART_IRQHandler(&husart1); // <<< Set breakpoint here
}

Pavel A.
Evangelist III

.

Since you're already using HAL, should you be using USART1_IRQHandler directly?

HAL has it's own weak references (HAL_UART_RxCpltCallback for receive completion into rxbuf, when using HAL_UART_Receive_IT) which you're probably supposed to use.

> when using HAL_UART_Receive_IT) which you're probably supposed to use.

No, thank you. Heaven forbid.

My handler is only ~10 code lines, compare to the dreadful HAL implementation...

(In my last example what USARTx_IRQHandler does is not important. The point of this example is only to get into the interrupt handler. Further handling is not interesting)

-- pa

Dear @Pavel A.​ 

1) Could you try to add

  pu.FifoMode = UART_FIFOMODE_ENABLE;

prior calling HAL_UART_Init(pu) ?

2) if you still encounter the issue, how many data are you sending to your H7 board ?

In case 1 (Fifo disabled), an interrupt RXNE is expected to be raised on 1st received character.

In case 2 (Fifo enabled, threshol 1/2), an interrupt RXFT is expected to be raised on when 8 cars have been received.

Regards

Guenael

Dear @Pavel A.​ 

An additional check : could you try to remove the Overrun feature disabling (keeping Overrun function as usual) for a check. I'm afraid this could be interacting with the FIFO mode: See following excerpt from Reference Manual about OVERDIS bit :

 0693W00000Dq5QyQAJ.pngWhat might happen is that OVERDIS is set, only a RXNE interrupt could be triggered but as FIFO is enabled, only RXFTIE is enabled ...

Dear Guenael,

This was it! Without overrun disable the FIFO threshold interrupt works fine.

I've developed a habit to always disable overrun detection because it somehow interfered with polling HAL RX function.

Will re-test this with the latest H7 HAL library.

Thank you a lot!

-- Pavel

p.s.

Setting pu.FifoMode = UART_FIFOMODE_ENABLE before HAL_UART_Init is not needed.

HAL_UARTEx_EnableFifoMode() call will set it.