STM32H5 HAL UART: pending ORE lost when FIFO RxISR handles a parity error
- 1 reply
- 15 views
Hello,
I found an issue in the STM32H5 HAL UART driver: during interrupt-based reception with FIFO enabled, a pending overrun error can be cleared from huart->ErrorCode inside the FIFO RxISR. Consequently, HAL_UART_IRQHandler() does not abort the reception as intended.
I used AI to create a standalone CubeMX-generated project and reproduced the problem, without modifying the HAL driver. The test project is in the attachment.
Environment
- Board: NUCLEO-H533RE, STM32H533RET6
- Firmware package: STM32Cube FW_H5 V1.7.0
- HAL_GetHalVersion(): 0x01070000
- HCLK and peripheral clocks: 32 MHz
- Receiver: USART1, PB15, 9600 baud, 8 data bits with even parity, 1 stop bit
- HAL configuration: UART_WORDLENGTH_9B with UART_PARITY_EVEN
- FIFO enabled, RX FIFO threshold = ½
- NbRxDataToProcess = 4
- Interrupt-based reception, no DMA
- Receiver timeout disabled
- Sender: USART3, PB10, same frame format
- Connection: PB10 → PB15
Steps to reproduce
- Disable only the USART1 NVIC interrupt, leaving UART reception and SysTick running.
- Call HAL_UART_Receive_IT(&huart1, rx_buffer, 32).
- Send 16 characters from USART3:
- First character: correct even parity.
- Second character: incorrect parity, generated by temporarily configuring the sender for odd parity.
- Remaining characters: correct even parity.
- Wait for transmission completion and allow the final frame to finish reception.
- Re-enable the USART1 NVIC interrupt.
The delayed IRQ handling allows the receive buffer to overflow. The first buffered character is valid, while the second buffered character has a parity error.
The error callback only records the error code and handle state. It does not clear ErrorCode, abort reception, restart reception, or print anything.
Relevant code path
In HAL_UART_IRQHandler(), ORE is cleared in hardware and recorded in the handle:
__HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF);
huart->ErrorCode |= HAL_UART_ERROR_ORE;The handler then calls huart->RxISR(huart) before taking the error-code snapshot used for the blocking-error decision:
huart->RxISR(huart);
errorcode = huart->ErrorCode;
if ((HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)) ||
((errorcode & (HAL_UART_ERROR_RTO | HAL_UART_ERROR_ORE)) != 0U))
{
UART_EndRxTransfer(huart);
/* ... */
}Inside UART_RxISR_8BIT_FIFOEN(), after reading the first character, the parity error associated with the next buffered character becomes visible. The RxISR adds PE to ErrorCode, calls the error callback, and then clears the entire field:
huart->ErrorCode |= HAL_UART_ERROR_PE;
/* Error callback is called here. */
HAL_UART_ErrorCallback(huart);
huart->ErrorCode = HAL_UART_ERROR_NONE;At this point, ErrorCode contained ORE | PE, so this assignment also removes the pending ORE.
When control returns to HAL_UART_IRQHandler(), errorcode becomes zero. With DMA disabled, the blocking-error branch is skipped.
Observed hardware results
The following events occurred within the same USART1 IRQ:
ENTER:
ISR=0DC010F8 CR1=20001505 CR3=14000001
ErrorCode=00 RxState=22 RxXferCount=32 RxISR!=NULL
First ERROR callback:
ISR=0CC010F0 CR1=20001505 CR3=14000001
ErrorCode=09 RxState=22 RxXferCount=31 RxISR!=NULL
Second ERROR callback:
ISR=08C010D0 CR1=20001505 CR3=14000001
ErrorCode=00 RxState=22 RxXferCount=23 RxISR!=NULL
EXIT:
ISR=08C010D0 CR1=20001505 CR3=14000001
ErrorCode=00 RxState=22 RxXferCount=23 RxISR!=NULL
Here:
- At IRQ entry, ORE is set and PE is clear.
- The first error callback receives 0x09 = ORE | PE.
- The second error callback receives 0x00.
- Reception remains HAL_UART_STATE_BUSY_RX.
- RxISR remains non-NULL.
- PEIE, EIE and RXFTIE remain enabled.
Nine characters were copied into the receive buffer:
41 42 43 44 45 46 47 48 49
Two control tests also passed:
- Normal reception: all 32 characters received correctly, one receive-complete callback, no errors.
- ORE without PE: one error callback with ErrorCode=0x08; reception correctly terminated with RxState=READY, RxISR=NULL, and receive interrupts disabled.
Expected behavior
An ORE already detected by the outer IRQ handler should remain effective for the blocking-error decision, even if the FIFO RxISR subsequently handles PE/FE/NE.
In this case, reception should be terminated according to the driver's documented ORE handling. The later callback with ErrorCode=HAL_UART_ERROR_NONE also appears unintended.
Could you please confirm whether this is a known issue and advise on the recommended fix?
A fix appears to require preserving pending blocking errors across the RxISR call, while also retaining any errors detected during FIFO processing.
Thank you.
