2026-03-13 7:09 AM - last edited on 2026-04-03 8:30 AM by FBL
Split from: HAL_UARTEx_ReceiveToIdle_DMA return HAL_ERROR when stm32's partner restart.
That thread is solved; this is a new question.
I think I'm seeing a similar problem if I call `HAL_UARTEx_ReceiveToIdle_DMA()` when the UART receive line is actively receiving data (when the other end is transmitting). A good percentage of the time it returns HAL_ERROR.
I'm using STM32L4 HAL 1.13.6 (Cube 1.18.2).
The problem is that the UART generates an overrun error immediately when `UART_Start_Receive_DMA()` enables the overrun error. The overrun error overwrites `huart->ReceptionType = HAL_UART_RECEPTION_STANDARD` which causes `HAL_UARTEx_ReceiveToIdle_DMA()` to return HAL_ERROR as shown in the code snippet from `HAL_UARTEx_ReceiveToIdle_DMA()` below:
/* Set Reception type to reception till IDLE Event*/
huart->ReceptionType = HAL_UART_RECEPTION_TOIDLE;
huart->RxEventType = HAL_UART_RXEVENT_TC;
status = UART_Start_Receive_DMA(huart, pData, Size);
/* Check Rx process has been successfully started */
if (status == HAL_OK)
{
if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE) <<<< this check fails
{
__HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_IDLEF);
ATOMIC_SET_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
}
else
{
/* In case of errors already pending when reception is started,
Interrupts may have already been raised and lead to reception abortion.
(Overrun error for instance).
In such case Reception Type has been reset to HAL_UART_RECEPTION_STANDARD. */
status = HAL_ERROR; <<<< takes this path
}
I verified the problem with a tracepoint on husart3.ReceptionType. This is the stack trace:
Thread #1 [main] 1 [core: 0] (Suspended : Signal : SIGTRAP:Trace/breakpoint trap)
UART_EndRxTransfer() at stm32l4xx_hal_uart.c:3,810 0x801d6d8
HAL_UART_IRQHandler() at stm32l4xx_hal_uart.c:2,407 0x801c478
USART3_IRQHandler() at stm32l4xx_it.c:384 0x800d99a
<signal handler called>() at 0xfffffffd
UART_Start_Receive_DMA() at stm32l4xx_hal_uart.c:3,752 0x801d584
HAL_UARTEx_ReceiveToIdle_DMA() at stm32l4xx_hal_uart_ex.c:961 0x801dc2a
StartUsart3Reception() at main.c:2,603 0x800a218
commandTaskMain() at main.c:3,385 0x800abe8
pxPortInitialiseStack() at port.c:222 0x8024c90
This is where UART_Start_Receive_DMA() is interrupted (stm32l4xx_hal_uart.c:3,752):
3751 /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
3752 ATOMIC_SET_BIT(huart->Instance->CR3, USART_CR3_EIE);
And here is where we are in HAL_UART_IRQHandler():
2401 if ((HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)) ||
2402 ((errorcode & (HAL_UART_ERROR_RTO | HAL_UART_ERROR_ORE)) != 0U))
2403 {
2404 /* Blocking error : transfer is aborted
2405 Set the UART state ready to be able to start again the process,
2406 Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
2407 UART_EndRxTransfer(huart); <<<<<< We are here
A dirty hack workaround is to loop on the UART initialization until it succeeds:
bool success = false;
for (int i = 0;i < 5; i ++) {
MX_USART3_UART_Init();
if (HAL_OK == HAL_UARTEx_ReceiveToIdle_DMA(&huart3, Usart3RxDMABuffer, sizeof(Usart3RxDMABuffer))){
success = true;
break;
}
MX_USART3_UART_DeInit();
vTaskDelay(100);
}
This works for me - but I don't like it. I also considered de-initializing the UART receive GPIO prior to calling `HAL_UARTEx_ReceiveToIdle_DMA` and reinitializing immediately after - but that's not really any more palatable to me.
Either I'm doing something wrong with HAL, or there is a fundamental race condition in `HAL_UARTEx_ReceiveToIdle_DMA` if it is called while the UART receive line is seeing receive activity - which seems really fragile.
I would welcome any feedback - particularly if I'm doing something wrong that is creating this condition. Thanks in advance.
2026-03-13 8:28 AM
@sdtbb This thread has been solved. Create a new thread if you're having issues.