This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C1294NCPDT: UART RX Missing Data at Higher Baud Rate

Part Number: TM4C1294NCPDT


I need to periodically receive a string of RS-232 data about 45 bytes long at 115200 baud but I'm missing some of the bytes later in the string.

If the string I'm receiving is "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", I'll always get the first 16 characters, which makes sense since the UART FIFO is 16 bytes, but I'll miss many of the later bytes, for example, I might only get a few characters from  mid-to-later part of the alphabet.

I'm going to lengths to make sure I'm calling UARTGetChar as fast as possible without letting interrupts occur when doing so - please see my code below - but I still miss data.  If I slow it down to 9600 I seem to not miss any data, but this is too slow for my needs.

I'm wondering if the only way to do this at 115200 without losing data is to use DMA with UART?

I've configured UART as follows:

SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

// Configure the GPIO Pin Mux for RX
GPIOPinConfigure(GPIO_PA0_U0RX);
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0);

// Configure the GPIO Pin Mux for TX
GPIOPinConfigure(GPIO_PA1_U0TX);
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_1);

// Enable the UART module
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_UART0));

// Configure the given serial IO port for the given baud rate and, 8-N-1 operation.
UARTConfigSetExpClk(UART0_BASE, sysClockFreq, 115200, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));

UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX1_8, UART_FIFO_RX1_8);

// Enable the RX UART interrupt.
IntEnable(INT_UART0);
UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT);        

And the interrupt handler:

   
void SerialCommIntHandler(enum SERIAL_COMM_NUM serialCommNum)
{
     // Get the interrupt status
    uint32_t status = UARTIntStatus(UART0_BASE, true);

    // Clear the asserted interrupts
    UARTIntClear(UART0_BASE, status);

    IntMasterDisable();
            
    // Loop while there are characters in the receive FIFO
    while(UARTCharsAvail(UART0_BASE))
    {
        LogInfo("%c", UARTCharGetNonBlocking(UART0_BASE));
    }
        
    IntMasterEnable();
}

  • Hi,

      I have a couple of suggestions for you to try. 

     - First check if you are getting OE flag (UART Overrun error) in  UARTDR register. If there is a overrun error then it confirms that FIFO is overwritten with new data before the processor is able to process the unread data.

     - I'm not sure how much time you are spending in ISR due to LogInfo. Normally we recommend processing the data outside the ISR. You can set a flag when you enter the ISR. Read the RXFIFO in your main() if the flag is set. After finish reading RXFIFO you can clear the flag again. The reason is that while you are processing the data using LogInfo() there may be more chars come in. You set the FIFO level to 1/8 which means 2 chars. The next two chars is supposed to generate RXFIFO interrupt but you are still in the ISR. The new interrupt may be just lost. 

      - As explained above, LogInfo should be done outside. I don't know how you implement LogInfo. It looks like it is reformatting the data (e.g. usprintf) and can take many cycles. It is similar to UARTPrintf() that we normally try to avoid calling inside any ISR. ISR is supposed to exit in a quick manner. 

      - Try increase FIFO level interrupt from 1/8 to higher like 1/2 so that more data is received before you generate interrupt. See if this help the case.

  • Thank you for the helpful reply .  To reply to the points in your previous message:

    • Yes, I've confirmed I'm getting an over-run error.  Please see the scrreenshot below.
    • Agree having the LogInfo() in the interrupt was not good.  I've replaced it with a simple buffer that the characters are copied to, you'll see this in the image below.
    • I've increased the FIFO interrupt to 1/2 like you suggested by using UART_FIFO_RX4_8 and the problem persists.

    After more investigation, I believe what is happening is the SysTick interrupt is blocking or interrupting the UART RX interrupt.  The SysTick interrupt is taking a lot of time.  This is unfortunately necessary since there is a lot of essential I2C communication that occurs in the SysTick once every 10 milliseconds.

    I believe since the SysTick has higher priority, it is either blocking or interrupting the UART RX interrupt.

    I think if I use DMA with the UART this should resolve the problem.  The DMA will happen behind the scenes between the UART controller and the DMA controller, populating a buffer, and then I can deal with this buffer after the SysTick interrupt.  Do you agree?

  • Hi Terence,

      Yes, uDMA should resolve the issue. There is an udma_demo example that transfers between SRAM and UART using ping-pong mode. I don't know about your application regarding using SysTick interrupt. You can consider disable NVIC interrupts when you are inside UART interrupt so it does not get preempted by SysTick interrupt. But if your SysTick interrupt is critical then this option may not be viable. 

  • Thank you .  Yes, I've considered disabling interrupts while inside the UART interrupt handler but I think there will still be a problem with buffer overflow when receiving data if the SysTick interrupt is currently triggered and the UART RX interrupt has been received but is being blocked for an extended period of time due to the SysTick interrupt.  Do you disagree?

  • but I think there will still be a problem with buffer overflow when receiving data if the SysTick interrupt is currently triggered and the UART RX interrupt has been received but is being blocked for an extended period of time due to the SysTick interrupt.  Do you disagree?

    I agree if SysTick is spending a lot time in the ISR it will block UART interrupt from being serviced since SysTick has higher priority. You could change the priority of UART vs SysTick but that may create implications on SysTick side. Using uDMA should alleviate the issue.  

  • Okay, I'll give it a try.  Thank you  .

  • - Thanks for your help with this.  I've implemented DMA and it appears to be working well.