Hi,
I'm using MCUXpresso with SDK V2.4.1 on a K22FN51212.
My design uses all uarts of the chip (the 3 uarts and the lp-uart) through FreeRTOS.
All uarts are intensively used (Tx and Rx).
I have other tasks running.
Globaly, everything works well. However, randomly, my system hangs and then reboots thanks to the watchog.
I spent many hours on this problem. I narrowed the problem down to uart Rx. Maybe more specifically to lp-uart Rx.
When my system doesn't receive datas on uarts, it never hangs (everything else is active in the system including uart Tx).
I beleive the problem is the lp-uart Rx ISR looping infinitely on some occasion (till reset).
I'm not 100% sure the problem is specific to lp-uart however I'm 99.99% sure it is an Rx (lp-)uart issue.
Anybody aware of such a bug ?
Best regards,
Nicolas
Hi Nicolas:
If you only enable lpuart, can you get the same result? Can this issue be reproduce with Frdmk22 board?
Regards
Daniel
Hi Daniel,
After days of bug hunting, I made some progress. The problem is not with RX but with TX.
Consider the following excerpt of code (TX section of UART IRQ handler in fsl_uart.c) :
void UART_TransferHandleIRQ(UART_Type *base, uart_handle_t *handle)
{
...
/* Send data register empty and the interrupt is enabled. */
if ((base->S1 & UART_S1_TDRE_MASK) && (base->C2 & UART_C2_TIE_MASK))
{
/* Get the bytes that available at this moment. */
#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
count = FSL_FEATURE_UART_FIFO_SIZEn(base) - base->TCFIFO;
#else
count = 1;
#endif
while ((count) && (handle->txDataSize))
{
#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
tempCount = MIN(handle->txDataSize, count);
#else
tempCount = 1;
#endif
/* Using non block API to write the data to the registers. */
UART_WriteNonBlocking(base, handle->txData, tempCount);
handle->txData += tempCount;
handle->txDataSize -= tempCount;
count -= tempCount;
/* If all the data are written to data register, TX finished. */
if (!handle->txDataSize)
{
handle->txState = kUART_TxIdle;
/* Disable TX register empty interrupt. */
base->C2 = (base->C2 & ~UART_C2_TIE_MASK);
/* Trigger callback. */
if (handle->callback)
{
handle->callback(base, handle, kStatus_UART_TxIdle, handle->userData);
}
}
}
}
}
I have discovered that sometimes, conditions at line 6 are fulfilled while the ones at line 15 are not.
This means that the TX IRQ has been triggered but is not cleared.
Once this has happened, the IRQ handler is fired indefinitely stalling the system (higher priority IRQs are still working).
My work around is to always clear the TX IRQ (lines 14 and 48) :
void UART_TransferHandleIRQ(UART_Type *base, uart_handle_t *handle)
{
....
/* Send data register empty and the interrupt is enabled. */
if ((base->S1 & UART_S1_TDRE_MASK) && (base->C2 & UART_C2_TIE_MASK))
{
/* Get the bytes that available at this moment. */
#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
count = FSL_FEATURE_UART_FIFO_SIZEn(base) - base->TCFIFO;
#else
count = 1;
#endif
if ((count) && (handle->txDataSize))
{
while ((count) && (handle->txDataSize))
{
#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
tempCount = MIN(handle->txDataSize, count);
#else
tempCount = 1;
#endif
/* Using non block API to write the data to the registers. */
UART_WriteNonBlocking(base, handle->txData, tempCount);
handle->txData += tempCount;
handle->txDataSize -= tempCount;
count -= tempCount;
/* If all the data are written to data register, TX finished. */
if (!handle->txDataSize)
{
handle->txState = kUART_TxIdle;
/* Disable TX register empty interrupt. */
base->C2 = (base->C2 & ~UART_C2_TIE_MASK);
/* Trigger callback. */
if (handle->callback)
{
handle->callback(base, handle, kStatus_UART_TxIdle, handle->userData);
}
}
}
}
else
{
base->C2 = (base->C2 & ~UART_C2_TIE_MASK);
}
}
}
There is the same problem for LPUART in fsl_lpuart.c.
Another fix in fsl_lpuart, line 1087 :
/* Clear IDLE flag.*/
base->STAT |= LPUART_STAT_IDLE_MASK;
The above code clears all STAT bits, making IRQ handler remaining code relying on STAT content not functional.
My fix is the following :
/* Clear IDLE flag.*/
//base->STAT |= LPUART_STAT_IDLE_MASK;
base->STAT = ((base->STAT & 0x3FE00000U) | LPUART_STAT_IDLE_MASK);
There is not the same problem with UART in fsl_uart.c
Regards,
Nicolas
Hi Nicolas
Thanks for sharing your solution. I will try to reproduce this issue on my end and report it to develop team.
Regards
Daniel