cancel
Showing results for 
Search instead for 
Did you mean: 

LPUART1 interrupt stuck in HAL_UART_IRQHandler on STM32MP2 (RS485 + ReceiveToIdle)

rutiklunagariya6
Associate

 

Hi everyone,

I am working on an STM32MP2 platform and facing a persistent issue with LPUART1 in interrupt mode.


Setup

  • MCU: STM32MP2
  • UART used: LPUART1 (RS485 communication via MAX485)
  • Debug UART: UART5 (polling mode, printf works fine)
  • Using:
    • HAL_UARTEx_ReceiveToIdle_IT() for RX
    • HAL_UART_Transmit() for TX
  • Baudrate: 115200

Problem

When using interrupt mode, the system gets stuck in:

 

HAL_UART_IRQHandler()
The interrupt keeps triggering continuously and the system appears stuck (infinite IRQ loop).

Observations

  • Polling mode (HAL_UART_Receive) works perfectly
  • Sensor communication works fine in polling
  • Issue only happens in interrupt mode

What I already checked

 NVIC enabled correctly:

HAL_NVIC_SetPriority(LPUART1_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(LPUART1_IRQn);
 IRQ handler is correct:
void LPUART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&hlpuart1);
}
No wrong handle (huart1) is used anywhere

FIFO configuration added:

HAL_UARTEx_SetTxFifoThreshold(&hlpuart1, UART_TXFIFO_THRESHOLD_1_8);
HAL_UARTEx_SetRxFifoThreshold(&hlpuart1, UART_RXFIFO_THRESHOLD_1_8);
HAL_UARTEx_DisableFifoMode(&hlpuart1); 
1 REPLY 1
ZAKARIA_C1
ST Employee

Hello @rutiklunagariya6 ,

1. Overrun Error (ORE) Lockup 

If the OverRun Error flag sets but the receive data register is empty (RXNE = 0), 
HAL_UART_IRQHandler() does not clear ORE and exits immediately.
Since ORE remains set, the interrupt fires again instantly, creating an infinite loop.

Fix: In your LPUART1_IRQHandler, clear error flags before calling HAL_UART_IRQHandler():

void LPUART1_IRQHandler(void)
{
uint32_t isrflags = READ_REG(hlpuart1.Instance->ISR);
/* Clear overrun error if set but no data pending */
if ((isrflags & USART_ISR_ORE) && !(isrflags & USART_ISR_RXNE))
{
__HAL_UART_CLEAR_OREFLAG(&hlpuart1); // Clears ORE via USART_ICR_ORECF
}
HAL_UART_IRQHandler(&hlpuart1);
}

Also verify your HAL_UART_ErrorCallback() is implemented. If an overrun or framing error occurs and you have no error callback, HAL may leave the peripheral in a stuck state.

2. STM32MP2 LPUART1 Clock Source

LPUART1 on STM32MP2 does not use the same clock tree as standard UARTs. If the peripheral clock is misconfigured or too slow for 115200 baud, timing violations can cause spurious flags.

Fix: In HAL_UART_MspInit(), explicitly configure the LPUART1 kernel clock:

RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
PeriphClkInit.XBAR_Channel RCC_PERIPHCLK_LPUART1;
PeriphClkInit.XBAR_ClkSrc = RCC_LPUART1CLKSRC_HSI;
PeriphClkInit.Div = 0x01;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { while(1); }

Verify the actual LPUART1 kernel clock frequency in your clock config. An incorrect baud rate divider can cause framing errors that trigger continuous interrupts.


3. RS485 DE/RE Direction Timing

With MAX485, if the DE/RE pin is left HIGH after transmission, the transceiver stays in transmit mode and cannot receive. More subtly, if you toggle DE/RE immediately after HAL_UART_Transmit(), the last byte may not have fully shifted out, causing bus contention or an echo that triggers RX interrupts.

4. FIFO Configuration on STM32MP2

You mentioned disabling FIFO mode, but on STM32MP2 the UART peripheral has a 16-byte FIFO that behaves differently from non-FIFO UARTs. If FIFO threshold interrupts are not handled correctly, they can cause repeated triggering.

Fix: Since you're using HAL_UARTEx_ReceiveToIdle_IT(), you should fully disable FIFO or configure it consistently. Your current approach is valid, but verify:

/* Explicitly disable FIFO before starting reception */
HAL_UARTEx_DisableFifoMode(&hlpuart1);
/* Then start the IT-based reception */
HAL_UARTEx_ReceiveToIdle_IT(&hlpuart1, RxBuf, RX_BUF_SIZE);

If you ever enable FIFO, you must use HAL_UARTEx_SetRxFifoThreshold() and handle the RXFF (RX FIFO Full) interrupt, or HAL may miss data and trigger error paths.

5. Missing Callback Re-arming

HAL_UARTEx_ReceiveToIdle_IT() disables the RX interrupt after each idle event or when the buffer fills. You must re-arm it in the callback, or the next incoming byte may cause an unexpected interrupt state

  1. Check the ISR register: In the debugger, read LPUART1->ISR when stuck. If ORE or FE (Framing Error) is set, that confirms the root cause.

  2. Check hlpuart1.gState and RxState: If RxState is stuck in HAL_UART_STATE_BUSY_RX but no reception is active, the HAL state machine is desynchronized.

  3. Verify LPUART1 clock: Check RCC->LPUART1CKSELR or use HAL_RCCEx_GetPeriphCLKFreq() to confirm the kernel clock.

  4. Scope the A/B lines: Verify the MAX485 is actually releasing the bus (DE/RE goes LOW) and that your sensor's response is clean.

Best Regards,
Zakaria