cancel
Showing results for 
Search instead for 
Did you mean: 

Unexpected IDLE Interrupt with Full Buffer Size Before Any UART Data Received on STM32L433 (HAL_UARTEx_ReceiveToIdle_DMA)

Abhimanyu
Associate II

Hello ST Community,

I’d like to report an issue  observed with HAL_UARTEx_ReceiveToIdle_DMA() on STM32L433RCT6P using STM32CubeIDE v1.17.0 and the latest STM32CubeMX code generator (L4 series).

Setup:

  • Board: NUCLEO-L433RC-P

  • IDE: STM32CubeIDE 1.17.0

  • HAL version: STM32CubeL4 latest

  • UART: USART2

  • DMA Mode: Circular

  • Baudrate: 115200

  • Buffer size: 128 or 256

  • Code: Generated with CubeMX

What we do:

  1. Call MX_USART2_UART_Init()

  2. Immediately call HAL_UARTEx_ReceiveToIdle_DMA() without delay

  3. Do not send any UART data to the board

  4. Wait...

What we expect:

  • The callback HAL_UARTEx_RxEventCallback() should not trigger until at least one byte has been received, followed by line idle.

What actually happens:

  • Immediately after startup, without any incoming UART data:

    • The callback fires once

    • Size == RX_BUFFER_SIZE (e.g., 128 or 256)

Additional Observations:

  • The issue doesn't occur at very low system clock frequencies

    • On STM32L4 series: it triggers when running on HSI (16 MHz)

    • When using MSI @ 4 MHz, the issue does not occur

    • On STM32U5 series (e.g., STM32U595), the threshold frequency differs but the pattern is the same

Why this matters:

As part of building high-quality embedded platforms, we aim to avoid:

  • Arbitrary HAL_Delay() or for(__NOP()) hacks

  • Fragile time-based fixes that behave differently across platforms or temperature/voltage conditions

We need a deterministic solution to prevent this false RX interrupt on startup.

Reproduction Snippet: (A simple example code snippet)

#define RX_BUFFER_SIZE 128
uint8_t aRXBufferUser[RX_BUFFER_SIZE];

int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_USART2_UART_Init();

HAL_UARTEx_ReceiveToIdle_DMA(&huart2, aRXBufferUser, RX_BUFFER_SIZE);

while (1) {}
}


void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
//echo back the received size
 uint8_t low = Size & 0xFF;
 while (!(__HAL_UART_GET_FLAG(huart, UART_FLAG_TXE))) {}
 huart->Instance->TDR = low;
}

 

My Questions to ST:

  1. Why does HAL_UARTEx_RxEventCallback() trigger immediately with Size == buffer_size, even though no data was received?

  2. Is there a documented correct sequence or flag to wait for before calling HAL_UARTEx_ReceiveToIdle_DMA()?
  3. What is the correct way to prevent this spurious interrupt from happening without using arbitrary HAL_Delay()?

Attached Video Evidence:

I’ve attached a short video demonstrating the issue:

When using MSI @ 4 MHz, no interrupt is triggered → expected behavior

When switching to HSI @ 16 MHz, the interrupt fires immediately after HAL_UARTEx_ReceiveToIdle_DMA()→ even though no data is received

The video shows a breakpoint inside HAL_UARTEx_RxEventCallback() and proves the size equals the buffer length, with no bytes transferred by DMA.

1 REPLY 1
Khaled_DHIF
ST Employee

Hello @Abhimanyu

When the DMA is configured in circular mode, the callback associated with HAL_UARTEx_ReceiveToIdle_DMA() is executed during three events:

  1. HT Event: Occurs when half of the reception buffer is filled.
  2. TC Event: Occurs when the buffer is full.
  3. IDLE Event: Occurs after the reception phase.

At higher frequencies, the callback may trigger prematurely because the IDLE flag is set as soon as the UART is enabled, and its reset process may be skipped due to high frequency. If this flag isn't reset before the DMA starts, it can lead to premature callback execution.

To mitigate this, you can introduce a delay after MX_USART2_UART_Init() to allow the IDLE flag to reset in the USART ICR before transmission begins. However, this approach lacks robustness. Alternatively, ensure the flag is reset before invoking HAL_UARTEx_ReceiveToIdle_DMA(&huart2, aRXBufferUser, RX_BUFFER_SIZE) by using the following code:

while (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE) != SET);
__HAL_UART_CLEAR_FLAG(&huart2, UART_CLEAR_IDLEF);

Kind regards, 

Please mark my answer as best by clicking on the “Accept as solution" button if it fully answered your question. This will help other users find this solution faster.​