I'm using a RT685 with the FreeRTOS USART driver provided in the SDK. The driver seems to work most of the time. However I end up somehow getting into a weird state after an indeterminate period of time. It seems the base USART driver's IRQ Handler is called repeatedly over and over again. Digging into the reason it seems the tx level FIFO interrupt is firing. However there is no data to send.
Digging into the code I find:
/* Send data */
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;
}
}
When tx data runs out it clearly disabled that interrupt. Yet I find from a breakpoint that txDataSize is zero! So it's like it ran out of data without executing the code path that would disable tx lvl interrupts.
To confirm I added the following code:
if (!sendEnabled && (base->FIFOINTENSET & USART_FIFOINTENCLR_TXLVL_MASK) )
{
base->FIFOINTENCLR = USART_FIFOINTENCLR_TXLVL_MASK;
base->INTENSET = USART_INTENSET_TXIDLEEN_MASK;
}
This code does indeed fire. This seems impossible! Can anyone shed any light?
Thanks!
The issue does appear to be that when two writes to the FIFOINTENCLR register that are spaced closely in time, the second write may not work. I've confirmed via debugging that the register was written but did not clear. My solution is as follows:
In the USART_TransferHandleIRQ function replace:
base->FIFOINTENCLR = USART_FIFOINTENCLR_RXLVL_MASK | USART_FIFOINTENSET_RXERR_MASK;
with
while((base->FIFOINTENSET & USART_FIFOINTENCLR_TXLVL_MASK) || (base->FIFOINTENSET & USART_FIFOINTENCLR_TXLVL_MASK))
{
base->FIFOINTENCLR = USART_FIFOINTENCLR_RXLVL_MASK | USART_FIFOINTENSET_RXERR_MASK;
}
and replace
base->FIFOINTENCLR = USART_FIFOINTENCLR_TXLVL_MASK;
with
//This is necesary in case the previous loop iteration just wrote it or the receive logic just wrote it.
while(base->FIFOINTENSET & USART_FIFOINTENCLR_TXLVL_MASK)
{
base->FIFOINTENCLR = USART_FIFOINTENCLR_TXLVL_MASK;
}
Hopefully this helps anyone else encountering this issue.
This wasn't the source of the problem afterall. I just got really lucky and ran for many hours without getting stuck in the ISR. I think I know the real problem/solution, I'll report that if I am right.
Hello @jwprice100 ,
Did you find the root cause of this problem or are you still requiring support on this matter?
If you did find the root cause, we would appreciate it if you would please share it so that it may benefit other community members.
Regards,
Gustavo
Does anyone know if writing to the FIFOINTENCLR register twice, very close in time together, would cause the second write to not take? That appears to be what's happening.