Other Parts Discussed in Thread: MSPM0-SDK,
Tool/software:
TI Team,
Our customer has first observed noise on the MSPM0G UART that lead to an observation of the IDDX STAT reading 0x00 observing that the code occasionally will vector to the UART IRQ handler with the event condition register empty (IIDX STAT reading 0x00). Seeing this roughly every several thousand characters. We wonder what condition might cause this?
Additional debug conversations has lead to this input directly from the customer:
"
I have collected some more information. First, I'd like to share some details about how we are handling received data, as it might be peculiar.
We are running this data bus at 10MBaud and using DMA to collect the received data in a buffer. We do not know how long each line on the data bus will be, so we are running DMA one byte at a time, and have the UART FIFO enabled:
Transfer size is configured at runtime to be the size of the receive buffer, so that we can let DMA handle data until our end of line characters are received. We send/receive two EOL characters at the end of every line.
Baud rate is also set at runtime.
To detect EOL, I am using the UART RXINT to trigger searching the buffer for the first EOL. It would certainly be better to perform this search after the DMA completes, but I did not see a good way to get an interrupt after the DMA is done with each individual character yet keep the DMA active in case the interrupt is handled late. This isn't a problem though, as with two EOLs, we can just search for the first, and missing/discarding the second EOL isn't a problem.
Upon further investigation, I noticed the UART interrupt handler only observes IIDX of 0 after a line is received. This happens every couple of lines and is after we have identified that first EOL.
I noticed the reference manual details two ways for RXINT to be cleared. The first, by reading IIDX as our interrupt handler does:
But this can also clear the interrupt, which the DMA will be doing often:
However, there is some timing I can't yet explain. I'd expect the DMA to often complete before our interrupt handler is called, causing the interrupt handler to see IIDX set to 0 most of the time, if not always. But I only observe IIDX set to zero in the interrupt handler at the end of a received line, and only at the end of every couple received lines.
When I modify the sender to wait roughly 2ms between sending each byte, IIDX is never observed as 0, even if a delay is added between the interrupt handler call and checking IIDX. Perhaps it is somehow related to interaction between the DMA and the FIFIO, when the FIFO contains more than one byte?
Here's a code snippet of the interrupt handler: (apologies for the formatting!)
void UART0_IRQHandler(void)
{
SCIIntManager(isrSciStructHandlePtrs[SCI_UART_0]);
}
void UART1_IRQHandler(void)
{
SCIIntManager(isrSciStructHandlePtrs[SCI_UART_1]);
}
void UART3_IRQHandler(void)
{
SCIIntManager(isrSciStructHandlePtrs[SCI_UART_3]);
}
void SCIIntManager(sciStruct *handle)
{
DL_GPIO_setPins(GPIO_TEST_POINTS_PORT, GPIO_TEST_POINTS_Rosc_PIN); // hooked up to logic analyzer so timing can be observed
//delay_cycles(300); // uncommenting this in does not cause IIDX to be observed as 0 after every byte, even when bytes are sent 2ms apart.
/* Assume the handle is valid if its register field pointer is mapped */
if (handle != NULL && handle->uartReferences->registers != NULL)
{
/* Read the UART interrupt event condition, which is assigned as the active UART interrupt
with the highest priority. Reading will cause it to clear. */
switch (handle->uartReferences->registers->CPU_INT.IIDX & UART_CPU_INT_IIDX_STAT_MASK)
{
case 0:
delay_cycles(10); // just so a breakpoint may be placed here.
break;
case UART_CPU_INT_IIDX_STAT_BEFG: // Break Error
SCIBreakInt(handle);
break;
case UART_CPU_INT_IIDX_STAT_RXIFG:// Received byte
SCIUartRxInt(handle);
break;
case UART_CPU_INT_IIDX_STAT_EOT: // end of transmission
SCIUartEndTransmitDMA(handle);
break;
case UART_CPU_INT_IIDX_STAT_OEFG: // overrun error
case UART_CPU_INT_IIDX_STAT_FEFG: // framing error
default: // just in case something else was configured...
SCIErrorInt(handle);
break;
}
}
DL_GPIO_clearPins(GPIO_TEST_POINTS_PORT, GPIO_TEST_POINTS_Rosc_PIN);
}
SCIUartRxInt is what searches the receive buffer for the first EOL. Upon finding that EOL, it will disable DMA before indicating to other code the receive buffer is ready to be processed.
Let me know if this brings about any further questions!
'
Your feedback welcomed.
TY,
Chris