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.

CCS/EK-TM4C129EXL: UART data loss

Part Number: EK-TM4C129EXL
Other Parts Discussed in Thread: TM4C129ENCPDT

Tool/software: Code Composer Studio

Hi,

I am using EK-TM4C129EXL evaluation kit with CCS 7.0

I need to transmit a paragraph (char array) from my PC to controller and vice versa. For that, I have planned to use UART communication.

To start with UART communication, I checked the uart_echo example. The code inside UART interrupt handler goes like this : 

while(ROM_UARTCharsAvail(UART0_BASE))

{
//
// Read the next character from the UART and write it back to the UART.
//
ROM_UARTCharPutNonBlocking(UART0_BASE,ROM_UARTCharGetNonBlocking(UART0_BASE));

/* commented 

//
// Blink the LED to show a character transfer is occuring.
//
GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, GPIO_PIN_0);

//
// Delay for 1 millisecond. Each SysCtlDelay is about 3 clocks.
//
SysCtlDelay(g_ui32SysClock / (1000 * 3));

//
// Turn off the LED
//
GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, 0);

*/
}

At first, when I send a paragraph, only 16 to 18 characters are echoed back and printed on the console screen.

Then I removed the LED blinking logic, which blinks on reception of every char by commenting it. Now the whole paragraph gets echoed and printed irrespective of the size of the paragraph. Works perfectly.

The problem is if I try to store the incoming characters in a char array once again only 16 - 18 gets stored and very unreliable. I use the following code inside the while loop to store the incoming data in a buffer.

buf[i++] = ROM_UARTCharGetNonBlocking(UART0_BASE);

I need to collect the data and process it in the main function. 

Some suggest going for the Buffered operation. I even tried that with UARTgets() function. I cannot achieve it.

A programming example for buffered UART operation or examples with UARTgets() function would be a great help. Or can I achieve it without going for the Buffered operation?

Note: The paragraph will be sent from my PC completely in one stretch. 

Thank You for your time.

  • The "UARTCharGetNonBlocking" function always return immediately even if there are no characters in the buffer. You can use "UARTCharGet" instead if it is OK to sit and wait in that function for characters to be received. Otherwise you can check for the function UARTCharGetNonBlocking returning -1. That means the receive buffer was empty. Another method is to call UARTCharsAvail() and only call UARTCharGetNonBlocking() when UARTCharsAvail() returns "true".
  • Thanks Bob.

    The example program uses UARTCharsAvail() function as while loop condition to get the incoming bunch of characters and prints them as they come. Printing the characters works perfectly as shown in this below image.

    But in the same condition if I try to store those chars in a buffer only 16 gets stored.

    I'll try with the UARTCharGet() function.

    Between, In the TM4C129ENCPDT datasheet it is mentioned that the UART receive FIFO is only 16 x 12bit  deep. So receiving a bunch of characters(paragraph) in a single UART interrupt occurrence will definitely need a buffered operation of UART i.e using the UARTgets function and maintaining an internal buffer.

    Unfortunately, there are no examples for Buffered UART operation in CCS or example using the UARTgets function. Any examples in UART buffered operation?

    Thank You for your time.

  • I have created and attached a project that uses the UART Standard IO routines in buffered mode. I actually ran into an issue. The UARTWrite function was not terminating on a NULL character as it should. Therefore this project includes a modified version of "uartstdio.c". I will log that bug for fixing in the next release. Use "File" -> "Import" and import this project from the attached .zip file.

    /cfs-file/__key/communityserver-discussions-components-files/908/EK_2D00_Buffered_5F00_uart_5F00_echo.zip

  • Thanks Bob.

    I'll try the code.

    Between, as per your code, the UARTgets function resides inside an infinite while loop. I have tried something similar to this.

    I have a requirement like, there'll be an infinite while loop in the main function.

    Only when a UART receive interrupt occurs, the control has to go to the UART interrupt subroutine and

    the incoming stream of characters has to be stored in a buffer.

    Further, Inside the UART interrupt function, I enqueue the buffer data in a char array queue and return back to the infinite while loop in main.

    In the infinite while loop, I check for data in the char array queue. If the data is present in the queue, I dequeue the data and process it. Else the control will be revolving continuously in the infinite while loop.

    When I used the UARTgets function inside the UART interrupt subroutine, I faced UART data loss and unreliable data reception.

    Any alternate method for my requirement?

    Once again, Thank you for your time.

  • Using UART Standard IO in buffered mode, the interrupt function UARTStdioIntHandler() takes care of receiving characters and putting them into a circular buffer. This is a different buffer than the one I created "UARTBuffer" in my example. The size of this "internal" static circular buffer is defined by "UART_RX_BUFFER_SIZE" in the file "uartstdio.h".

    Now in your main() loop, you want to grab data from the internal circular buffer and process it. The question is how do you determine when you have a complete set of data for processing. If the incoming strings are NULL or RETURN delimited, they will be stored as NULL terminated strings in the circular buffer. A call to the function UARTPeek(0) can determine if a null terminated string has been completely received or not. If yes, the function returns the number of characters in that string. If not, the function returns -1. You can then use UARTgets() to grab the string from the circular buffer.

    If instead you want to process the incoming data after a set number of characters have been received, use the function UARTRxBytesAvail() to find the number of bytes already received. When that value is the number of bytes you want, grab them with UARTgets() unless the array of characters has embedded NULL characters. Then use a loop and UARTgetc().

    Set the size of the internal circular buffer based on available RAM, the size of strings you receive and how many characters can be received before you can come back and process the next string.
  • Thank you for your quick reply Bob.

    First to answer your question,

    how do you determine when you have a complete set of data for processing?

    I'll be getting data in through UART at an irregular interval of says 1 second or 2 sec or .5 sec etc.

    I'll get a string line in the format of   ">abcdefghijklmnopqrstuvwxyz<". The length of the string is not constant. It varies each time.

    I have looked at the  UARTStdioIntHandler() . As you said, It has a circular buffer g_pcUARTRxBuffer. The data at each reception through UART are getting appended to that buffer not replaced.

    Shall I clear the buffer every time after getting the data and queueing them in a separate char queue array?

    Does clearing the circular buffer affects somewhere?

    Secondly, your idea of using UARTPeek followed by UARTgets seems to work perfectly for my requirement.

    I have read about those before. But because of the lack of example programs using those function, I skipped those.

    I don't know where to use those two functions( in the main function or in UART interrupt function) and how to structure those correctly for reliable data reception.

    Since my incomming stream of data starts with '>' and ends with '<',  shalI use following logic.

    main()

    {

    while(1)

    {

    if( UARTPeek('<') != -1)

    { UARTgets(buf, UARTPeek('<'));    }  // I plan to use the length from the return value of UARTPeek('<')

    }

    }

    Or

    Should the UARTPeek('<') needs to be used inside the UART stdio Interrupt handler?

    Thank you, Bob.

  • That sounds like a good plan. You do not need to reset the circular buffer. The UARTgets() function moves the "tail" pointer forward making that portion on the circular buffer available again. The only concern is that you are able to process the strings as fast as they come in so that the "head" pointer never over-runs the "tail" pointer. Having the buffer twice as large as the longest possible string should work. Currently the interrupt handler simply discards incoming characters if the circular buffer is full. You can modify the function UARTStdioIntHandler() by adding an "else" statement to the existing "if(!RX_BUFFER_FULL)" to set some global volatile flag to let you now an overrun error has occurred.
  • Use UARTPeek('<') in the main loop, not in the interrupt handler.
  • Thanks Bob.

    I tried using UARTpeek inside the main function, It is working fine. However, the idea is like polling method. It keeps on checking for data through UART and if data is present, it checks for the termination character given in the UARTpeek function. Like shown below:

    main()

    {

    while(1)
    {
    if( UARTPeek('<') != -1)
     {
     UARTgets_new(buf,(UARTPeek('<')+1));
     memset(buf,0,sizeof(buf));
     }
    }

    }

    So I tried using UARTpeek function inside UART Stdio interrupt handler, immediatley after getting the data and storing it in the circular buffer. In the UART Stdio interrupt handler, there'll be a while loop as shown below. At the end of while loop, I included the UARTpeek followed by UARTgets function.

     while(MAP_UARTCharsAvail(g_ui32Base))

    {....

    }

    if( UARTPeek('<') != -1)
     {
     UARTgets_new(buf,(UARTPeek('<')+1));
     memset(buf,0,sizeof(buf));
     }

    But this methods gave me once again UART data loss and very unreliable. Can't find out why?

    Secondly,

    the UART peek function finds out the length by calculating the first occurrence of the termination char and UARTgets function reads data using that length.

    for eg: if my incoming stream of data is ">abcdef<", the UARTets function stores the data as ">abcdef".

    but what if, my incoming string has more than one termination chars. like ">abcdef<efghij<klmnop<"

    In that case, I am getting two sets of data like ">abcdef" the first time I go into uart peek and efghij< the second time I go into uart peek.

    but the iteration stops after two times. Irrespective of the size of the string, only two iterations happen and remaining are discarded.

    Can you explain this strange behavior?

    Thank you for your time.

  • If I may - relevant comments follow:

    • Vendor's 'Bob' has gone WAY 'Above & Beyond'  -  the 'Vendor Assistance Norm!'      It is much hoped that our poster recognizes & appreciates such - and (often) voices thanks.
    • Poster's (latest) operational tweak:
      • it is 'normal' for the 'Termination Character' to prove 'unique' - so that its 'singular arrival'  - halts the process!    (i.e. terminates!)
      • when such uniqueness 'cannot be guaranteed' - it is then 'typical' to  require a, 'Back to back Arrival' of such 'termination character' - to effect the 'termination.'
      • this is achieved via 'Alerting'  (yet not logging or printing) that 'first terminating char's arrival'
      • and then either 'writing/printing' that char - provided it is not  'immediately repeated'
      • or effecting 'Termination' - when that terminating char. is  received consecutively

    Should it not be noted that Bob has (thus far) 'obliged poster's (clearly) Non-MCU issues!'       Vendor's 'Bob' is one of a very limited - and highly valued - forum  RESOURCE!    

    Basic Code procedure is OUTSIDE the 'MCU-Centric' nature of this forum - and is 'Not in the forum's best interest!'     Consider the impact here - should 'many/most' forum participants - present an 'ONGOING SEQUENCE of (rather)  BASIC Programming Questions.'     Would (any) time (then) remain - to address the (PROPER) MCU-Based Issues?

    There ARE (other) Forums (and/or learning resources) which FOCUS upon such code guidance and general 'problem solving' - those should receive (serious) poster 'consideration.'

  • Thank you for your guidance.

    I strongly apologize for the inconvenience caused.

    As you told, Bob has already provided me the code example for my doubts. It was far more helpful to achieve my requirement. 

    Just thought of closing this thread with this last question.

    I got your point completely and won't repeat this in future.

    Thank you, Once again...

  • My friend - No one here (least of all me) seeks your apology!     Yet - was it not proper - and beneficial to the forum - to 'Sound an ALERT!'

    You are clearly 'anxious to learn' - AND making very good progress - and the odds of your submitting 'One LAST Question' (trust my TEN PLUS years here) prove EXCEEDINGLY SMALL!

    My firm's investors always stress that it proves, "Inefficient & Improper' to 'Identify a Weakness' - yet then FAIL to 'Provide a Superior Alternative!'     And - in accord w/their guidance (rule, actually) I believe that I have 'well complied.'

    In your excitement - you 'Made no mention' of the programming assistance I provided - in the attempt to 'Resolve' - that (famed) Last Question.     Might you provide (some) feedback?

    Good luck w/your 'Accelerated Learning' - and "Launching your hook' - into a (more properly stocked) stream...