I believe I identified the root cause of this matter. It's a fairly significant bug in the UART driver but it would only manifest if transmitting and receiving at the same time. I suspect most applications are not doing this which is why it may have remained hidden.
To understand the issue, the interrupt handler for the fsl_uart code has a snippet as follows:
if (sendEnabled && ((base->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK) != 0U))
{
base->FIFOWR = *handle->txData;
handle->txDataSize--;
handle->txData++;
sendEnabled = handle->txDataSize != 0U;
if (!sendEnabled)
{
base->FIFOINTENCLR = USART_FIFOINTENCLR_TXLVL_MASK;
base->INTENSET = USART_INTENSET_TXIDLEEN_MASK;
}
}
The important thing to note is that it disables the tx interrupt sources in the interrupt handler itself.
In the USART_TransferSendNonBlocking function there are two lines:
uint32_t interruptMask = USART_GetEnabledInterrupts(base);
USART_DisableInterrupts(base, interruptMask);
Followed later by:
USART_EnableInterrupts(base, interruptMask | (uint32_t)kUSART_TxLevelInterruptEnable);
If the interrupt happens to fire in between those first tw0o lines, and happened to clear the Tx interrupts in that call, the tx interrupts would then be re-enabled.
As one of those tx interrupt sources are the Tx FIFO level threshold the interrupt fires immediately. There's no code path to disable the tx interrupts in this case (they are only cleared if there was something to send and then all the bytes were drained), so the interrupt exists and fires again immediately. This hangs the processor.
Hopefully that all made sense, let me know if there are any questions about it. It's a very nasty bug so it should definitely get fixed.