Race condition in UART_RxISR_8BIT (HAL)
The error occurred while reading a UART interface (heavy load @ 115200 baud) byte by byte (with HAL_UART_Receive_IT(&huart1, &com_uartRxSignBuffer, 1) ).
MCU: STM32F302VB ST firmware version : STM32Cube_FW_F3_V1.11.2
Before the RXNE interrupt is disabled when 1 byte is received, the interrupt can be re-triggered by another received byte.
If this happens when huart->RxXferCount is already counted down to 0, huart->RxXferCount is counted down again.
An underflow occurs, obviously the RXNE interrupt is not disabled, and the following 65535 bytes are written to com_uartRxSignBuffer[0 ... 65535].
Almost certainly this will overwrite a pointer. By accessing it, an invalid memory address is accessed, resulting in a hard fault.
The code (I have commented the places where this underflow occurs) that triggered this error (stm32f3xx_hal_uart.c line 3800):
/* Check that a Rx process is ongoing */
if (huart->RxState == HAL_UART_STATE_BUSY_RX)
{
uhdata = (uint16_t) READ_REG(huart->Instance->RDR); //<< RXNE flag is reset -> IRQ can be triggered again
*huart->pRxBuffPtr = (uint8_t)(uhdata & (uint8_t)uhMask);
huart->pRxBuffPtr++;
huart->RxXferCount--; // << first IRQ: count to 0; second IRQ: count to 0xFFFF;
//<< second IRQ is triggert ( RXNE-interrupt is not yet disabled)
if (huart->RxXferCount == 0U) //<< due to the secont IRQ RxXferCount is not 0 -> RXNE-interrupt gets not disabled
{
/* Disable the UART Parity Error Interrupt and RXNE interrupts */
CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE)); //<< RXNE-interrupt would be disabled here, no more Interrupts would arriveMy workaround: before counting down check for huart->RxXferCount is zero already:
/* Check that a Rx process is ongoing */
if (huart->RxState == HAL_UART_STATE_BUSY_RX)
{
uhdata = (uint16_t) READ_REG(huart->Instance->RDR);
*huart->pRxBuffPtr = (uint8_t)(uhdata & (uint8_t)uhMask);
if (huart->RxXferCount >0){
huart->pRxBuffPtr++;
huart->RxXferCount--;
}
if (huart->RxXferCount == 0U)
{
/* Disable the UART Parity Error Interrupt and RXNE interrupts */
CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));The big Problem with this, is that this is not a usercode section, therefore it gets overwritten by CubeMX on regeneration.
Is there a solution, with little overhead which gets not overwritten by CubeMX?
Best regards,
Johannes Strobel
