USART overrun after receive timeout interrupt is enabled
USART1 is configured using code generated by CubeMX to run at 9600 8N1 in FIFO mode with Rx FIFO threshold set to 7/8 full. Receive is done via interrupts into an 80-byte buffer and callbacks are used to transfer data out of the 80-byte buffer. Everything seems to run as expected here.
Then I configure receive timeout and enable the interrupt. That's when I observe (using a GPIO toggle) the USART1 ISR running every 1.5 us or so even when no data is being received. When I break execution with a debugger, the overrun flag is set.
Why is it that when receive timeout is enabled, I get rx overruns?
I noted that the overruns start about 4 UART bytes after a call to HAL_UART_Receive_IT(). Without receive timeout interrupt enabled, the ISR runs every 7 UART bytes, which is expected for a 7/8 Rx FIFO threshold.
This is using stm32h7xx HAL v1.6.0.
Thanks! (code and scope trace are below)
#define RX_BUF_SZ 80
static unsigned char rx_buf[RX_BUF_SZ];
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 9600;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_7_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_EnableFifoMode(&huart1) != HAL_OK)
{
Error_Handler();
}
// USART overruns when the following code is commented out
//HAL_UART_ReceiverTimeout_Config(&huart1, 100);
//HAL_UART_EnableReceiverTimeout(&huart1);
HAL_UART_RegisterCallback(&huart1, HAL_UART_RX_COMPLETE_CB_ID, uart_rx_cb);
HAL_UART_RegisterCallback(&huart1, HAL_UART_ERROR_CB_ID, uart_rx_cb);
HAL_UART_Receive_IT(&huart1, rx_buf, RX_BUF_SZ);
}
static void uart_rx_cb(UART_HandleTypeDef *huart)
{
if (huart->ErrorCode & HAL_UART_ERROR_RTO)
{
HAL_GPIO_TogglePin(LED_RED_GPIO_Port, LED_RED_Pin);
}
else
{
HAL_GPIO_TogglePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin);
}
HAL_UART_Receive_IT(&huart1, rx_buf, RX_BUF_SZ);
}
void USART1_IRQHandler(void)
{
HAL_GPIO_TogglePin(LED_BLUE_GPIO_Port, LED_BLUE_Pin);
HAL_UART_IRQHandler(&huart1);
} 
