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.

EK-TM4C1294XL: Trouble receiving and comparing strings

Part Number: EK-TM4C1294XL

Hi, so I have to use multiple UART ports for my project - one of which I will wait for a key word and respond with a corresponding string. I am having two main problems:

My receive function only will receive only 6 characters without messing up - I can work around this and make all keywords only 6 characters max but I think there is a bigger underlying issue which I need to watch out for. I am kind of stuck and I am not sure where my errors are any advice, help or pointing in some direction would be very appreciated

void EnableUART0(void)
{
    //
    // Enable GPIO and UART 0
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    //
    // Configure UART Pins for UART MODE
    //
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);


    UARTClockSourceSet(UART0_BASE, UART_CLOCK_SYSTEM);
    UARTConfigSetExpClk(UART0_BASE, g_ui32SysClock, 115200, UART_CONFIG_WLEN_8 | UART_CONFIG_PAR_NONE | UART_CONFIG_STOP_ONE);

    IntRegister(INT_UART0, UART0Get);
    IntEnable(INT_UART0);
    UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT);

}

void UART0print(const char* text)
{
    const char* p;

    // Iterate over each character of `text`,
    // until we reach the NUL terminator
    for (p = text; *p != '\0'; p++)
    {

        // Pass each character to some function
        UARTCharPut(UART0_BASE, *p);
    }
}

void UART0Get(void)
{
    int i = 0;
//    if (UARTCharsAvail(UART0_BASE) == true)
    while(UARTCharsAvail(UART0_BASE))
    {
        Incoming1[i] = UARTCharGetNonBlocking(UART0_BASE);
        ++i;
//        int i;
//        for(i=0;i<21;i++) // maybe change 21 to something more realistic in the future >>>
//        {
//            Incoming1[i] = UARTCharGetNonBlocking(UART0_BASE);
//        }
    }

}

The issue I am referring to is with regards to the UART0Get function - which will only work for 6 characters max without an issue, slightly beyond 6 characters for example 7, it will eliminate the first character and print out the last 6 for example if I send "1234567" it will only store "234567". If I send something much larger than 6 then it acts very randomly, I do not understand what is happening.

In my main function I am trying to get it to recognize that I send the word "Temp" and it should reply back with an arbitrary string value I am using for now during testing:

int
main(void)
{
    g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                                 SYSCTL_OSC_MAIN |
                                                 SYSCTL_USE_PLL |
                                                 SYSCTL_CFG_VCO_480), 120000000);

    FPUEnable();
    //FPURoundingModeSet(FPU_ROUND_POS_INF);

    IntMasterEnable(); // Enable the processor to respond to interrupts.



    //configureUARTTesting();
    EnableUART0();

    while(1)
    {
        UART0print(Incoming1);
        if (strcmp(Incoming1,"Temp") == 0)
        {
            UART0print(TempValue);
//            UART0print(Incoming1);
        }
//        UART0print(Test);
//        UART0print(Line);
//        UART0print(Incoming1);
//        UART0print(Line);
//        UART0print(Inductance);
//        UART0print(Line);
//        UART0print(Frequency);
//        UART0print(Line);
    }
}

TempValue is just a string variable I had saved earlier and looks like this

char TempValue[] = "50 Deg";

Incoming1 is just a char array meant to store the incoming chars sent in over UART and is defined as follows

char Incoming1[15];

In the beginning I had tried to keep Incoming1 an array without a set number of spaces but that caused even more problems, which seemed to go away when I typed a value into Incoming1 such as 15 in this case.

  • Hello Hisham,

    I don't see anything glaringly wrong at first glance as you are able to at least receive some data.

    Few thoughts for debugging.

    1) Can you track if you re-enter the UART0Get function possibly causing the data to be overwritten?

    2) Have you tried lowering the UART speed so you don't receive data as rapidly and give the code more time to process?

    3) You may want to remove the extra line of code by including the increment as part of the buffer store function like this:

    Incoming1[i++] = UARTCharGetNonBlocking(UART0_BASE);

    4) When debugging, can you pause the code right after you get out of UART0Get and see what the contents in the buffer are at that point? (Not sure if this is how you've been determining what was stored). Also when looking at the buffer, you can see which indexes have data you expect, especially if you initialize it to 0.

    Also regarding the comment about leaving the buffer undefined space wise at first, yes that makes sense it would cause issues. You will want to reserve space for your buffer in pretty much any case.

  • Hey Ralph,
    I will attempt to answer your questions - I am new to this and my methods may be dumb so please correct me if I am wrong or misunderstood.

    1) Can you track if you re-enter the UART0Get function possibly causing the data to be overwritten?

    The UART0Get function is called by a UART interrupt every time something is transmitted over UART it should replace the Incoming1 with the new text and overwrite it, this is done because the device I am communicating with should query the desired value for example "temp" should be replied to with TempValue, which stores the value, if it sends me "Induc" I should reply with the inductance value etc.

    2) Have you tried lowering the UART speed so you don't receive data as rapidly and give the code more time to process?

    I have tried using 9600 buadrate instead of 115200 but the same issue still prevails - which makes me believe that speed may not be the issue, but I can try again since I have made a couple changes since then.

    3) You may want to remove the extra line of code by including the increment as part of the buffer store function like this:
    Incoming1[i++] = UARTCharGetNonBlocking(UART0_BASE);

    I haven't tried doing this, I think you suggested this to save a line of code, I do not think that it will/meant to solve my issue but I will give it a try now anyway (I maybe mistaken)

    4) When debugging, can you pause the code right after you get out of UART0Get and see what the contents in the buffer are at that point? (Not sure if this is how you've been determining what was stored). Also when looking at the buffer, you can see which indexes have data you expect, especially if you initialize it to 0.

    I am unsure how to do this, maybe you could provide more of an explanation. I have been using something like putty to check, so if you look at my main function I print out the Incoming1 variable right before the if statement. So I send in "Temp" using Putty and it gets printed back to me before the comparison. However, it just constantly prints out "Temp", therefore the if statement never goes through. This has been my debugging method so far, maybe there is a more telling method you could explain. For some reason I am unable to get CCS to show me the value of the Incoming1 variable.

    Also do you have any idea why it acts so weird if my incoming text is greater than 6 characters?
  • Hello Hisham,

    My comment on 3) was along the lines of optimization in case speed is an issue plus it is just a better practice for C coding in general.

    Thanks for the further details, the naming of UART0Get made me miss that it was an ISR.

    By pausing, what I mean is using a breakpoint so you can pause the code during debugging and see the buffer yourself. Using Putty right not may not give us a full picture. If something is off in terms of indexing, then you would be missing that, plus Putty may include additional terminating characters. By pausing the code after sending a string over Putty while the software is still in Debug mode on CCS, you can add your buffer as a variable to the Watch Expressions list and then browse it's contents. This way you can see what data exactly you are receiving, or not receiving.

    Looking at your while loop and that you note it always prints out Temp, I wonder if you should put a delay between prints to allow time to receive a new packet? How fast is the "Temp" message being sent out? Could it be holding the UART bus busy the whole time?
  • Hey Ralph, so I am trying to see the value of the buffer but I cant figure out where to find it. It is not in my variable location. I included a picture so you may see what I am seeing. I also played around with the buffer value and by the amount times I had to allow the breakpoint to resume there appears to be at least 2 terminating characters. I am not sure what they are. I did notice that once it goes through "Temp" is printed with a new line so I think there may be /n and something else but I am unsure what it could be.

    Could you please tell me how I can observe what is going into my buffer?

    I know I am not using Putty, I only said putty because it is more popular than what I am using but I think they are the same. That "Temp" that appears in Serial Communicator is the one I typed in to initiate the interrupt.

  • Hello Hisham,

    That is not what I had meant, I mean using the Expressions view in CCS to view the variable straight out of memory which leverages the debugging capability of CCS and JTAG. You can search for "Expressions View" in CCS help for more details about it.

    It can be brought up by going to the "View" menu and selecting Expressions, and then you can add your buffer to it either by typing the name in, or by right clicking it and selecting "Add Watch Expression..."

    If you want to type the name in, you can see a simple demo here (ignore the breakpoint part): www.youtube.com/watch

    For setting a breakpoint given how your program is setup, you may need to place a flag in your ISR to indicate when you received data, and then you can break on the flag being set within your main code so when you send a message over UART you can immediate break to see what the data is in your buffer after reception.
  • Ok Ralph I got it thank you for the help there was a remaining '\x0d', it only works when I create a variable to compare to such as char var[] = "Temp\x0d".
    Thank you again.
    I do have one more question do you know why I am having a character limit on the amount of characters I can save? If I send it a string over 6 characters it does not save them properly in my Incoming1 variable, any suggestions would be appreciated.
  • Hello Hisham,

    What behavior do you witness when sending a string over 6 characters? Do you not receive other characters? Do the first ones get overwritten? Something else?
  • The first ones get overwritten.
  • Hi Hisham,

    That makes me suspect that perhaps the ISR exits and then re-enters. An easy way to test this would be to set a GPIO to toggle on each ISR entry, and then you can monitor the GPIO after sending a packet of 6 bytes vs larger and see if you get one toggle or multiple. If multiple, then that would indicate that the UART data isn't coming in quick enough to remain within the ISR and that the issue is resetting the counter inside the ISR.

    I suppose the other way to test that would be to make the index variable a volatile global variable and then handle resetting the index inside of the application code, though the application would need to be setup to know how many bytes it should have received so it wouldn't be a flexible fix, but it would help quickly debug if that's the issue.

    If we confirm that is the case, then discussions about how to handle that can be had.
  • Ok Ill try out testing it and let you know what I find.
    Thank you!
  • You were right, the interrupt was being exited too quickly and being recalled, I added a delay within the for loop and my issue is fixed, I was wondering if you had any ideas on how else I could solve this other than the delay?
  • Hello Hisham,

    Not sure a delay is a good method to use, especially within an interrupt.

    One method would be for part of the message to include how many bytes would be sent. For example if you think you won't need more than 255 bytes, then set your buffer to be maxed at 255 bytes, and then send the first byte of your packet as a 'header' which is the byte count for the rest of the packet. So if you send 50 bytes, then send 0x32 (50 in Hex) as the first byte. In your code, track if you are receiving an initial byte or not with a flag. If you get an initial byte, store that as your max index counter (global variable), and have your index counter also be a global (make sure they are both volatile). Then whenever you receive bytes, check your index vs the max index, if it's less, add to the buffer and increment. If it is equal you can finish the last transaction and ignore further bytes and optionally set a second flag to indicate to your application code that you have fully received a byte. Then in your application you can reset the max index and the 'initial byte' flag when you are ready to receive more data.

    A far simpler method would be along what I initially described as a second debug idea which would be to use just make the index a global variable and handle resetting it within the application, but then it puts a burden on the application to understand when the variable needs to be reset, which is why I suggest having a header byte on your received packet as that way your application can know every time what it should be expecting. The simpler method is probably only viable if you either think your max size will be low, like 10 or 15 bytes and you are confident with just handling that in the application alone, or if you have a fixed size transfer every time.

    I am sure there are other methods I am not thinking of as while I have a lot of software experience, I haven't done much detailed architecture for software systems, but hopefully this gives you some ideas to work from.