Skip to main content
Super User
August 19, 2021
Solved

STM32H7 USART RX with FIFO - not working

  • August 19, 2021
  • 2 replies
  • 5760 views

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?

    This topic has been closed for replies.
    Best answer by Guenael Cadier

    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 ...

    2 replies

    Pavel A.Author
    Super User
    August 19, 2021

    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
    }

    Visitor II
    August 21, 2021

    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.

    Pavel A.Author
    Super User
    August 21, 2021

    > 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

    Pavel A.Author
    Super User
    August 21, 2021

    .