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-TM4C123GXL: Reading GPS data by UART4 and sending to PC by UART0

Part Number: EK-TM4C123GXL
Other Parts Discussed in Thread: MAX3232

Tool/software: Code Composer Studio

Hey people

I am trying to connect my U-blox Neo6M GPS sensor to EK-TM4C123GXL launchpad. My connections are below;

GPS Tx -> TM4C PC4

TM4C Debug USB -> PC

I am trying to read GPS data afrom Uart 4 (PC4-PC5) and without even touching it, directly passing to PC via UART0 and usb cable. To be safe, I based my source code on uart_echo example. And kinda tried to do everything that is done for UART0 for UART4 too(copied function calls with parameters changed to UART4 related ones).

My source code is below

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "driverlib/debug.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"

#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif

void
UARTIntHandler(void)
{
    uint32_t ui32Status0;
    uint32_t ui32Status1;

    ui32Status0 = ROM_UARTIntStatus(UART0_BASE, true);
    ROM_UARTIntClear(UART0_BASE, ui32Status0);

    ui32Status1 = ROM_UARTIntStatus(UART4_BASE, true);
    ROM_UARTIntClear(UART4_BASE, ui32Status1);

    while(ROM_UARTCharsAvail(UART4_BASE))
    {
        ROM_UARTCharPutNonBlocking(UART0_BASE,ROM_UARTCharGetNonBlocking(UART4_BASE));
    }
}

void UARTSend(const uint8_t *pui8Buffer, uint32_t ui32Count)
{
    while(ui32Count--)
    {
        ROM_UARTCharPutNonBlocking(UART0_BASE, *pui8Buffer++);
    }
}

int
main(void)
{
    ROM_FPUEnable();
    ROM_FPULazyStackingEnable();

    ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_16MHZ);

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART4);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);

    ROM_IntMasterEnable();

    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    GPIOPinConfigure(GPIO_PC4_U4RX);
    GPIOPinConfigure(GPIO_PC5_U4TX);
    ROM_GPIOPinTypeUART(GPIO_PORTC_BASE, GPIO_PIN_4 | GPIO_PIN_5);

    ROM_UARTConfigSetExpClk(UART0_BASE, ROM_SysCtlClockGet(), 115200,
                            (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                             UART_CONFIG_PAR_NONE));
    ROM_UARTConfigSetExpClk(UART4_BASE, ROM_SysCtlClockGet(), 9600,
                            (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                             UART_CONFIG_PAR_NONE));


    ROM_IntEnable(INT_UART0);
    ROM_UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT);

    ROM_IntEnable(INT_UART4);
    ROM_UARTIntEnable(UART4_BASE, UART_INT_RX | UART_INT_RT);

    UARTSend((uint8_t *)"\033[2JEnter text: ", 16);

    while(1)
    {
    }
}

When I debug the code, and after a while pausing, it stops at FaultISR function's infinite loop.

I might be doing some fundamental mistake as all UARTs might not be exactly same, maybe I do need another circuitry like MAX3232. Can you help me about this problem?
Note: I can test uart_echo example binary on my TM4C so at least UART0 works properly.

 Data sheet for GPS is :   www.u-blox.com/.../NEO-6_DataSheet_(GPS.G6-HW-09005).pdf

  • A FaultISR usually means that an interrupt condition has happened, but there is NO ISR associated to it.

    There is a separate file inside your project, which we refer to as "The Startup" file. It is there one tells the compiler which function is to be called when a certain peripheral triggers an interrupt. Apparently, when your UART4 receives a byte, there is no defined function to be called, and the code execution goes to the default ISR.

    MAS3232 is related to shifting the UART levels from TTL to RS232. Your NEO module already sends the signal in the level expected by the TM4C, so it is OK to connect them directly. And from the MCU to the PC (the PC is the guy who needs RS232 level), I understand you are using the USB "virtual" serial port emulated by the launchpad, correct? In that case, again there is no conversion needed.

    Now, I see you configure interrupts for two uarts (0 and 4), but your description says you only want UBlox => MCU forwarded to PC, correct? In that case, you shall not configure interrupts for bytes arriving at port 0.

    Bruno
  • Hello,

    To add to Bruno's excellent advice and going along with his point of there being two UART's configured, it looks like there is no call to enable the UART0 peripheral:

        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART4);
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);

    I see the above calls, but none for SYSCTL_PERIPH_UART0. You should definitely include that if you are using UART0 for something beyond your GPS, or remove all lines concerning UART0 if it ins't really being put to use.

    FYI the startup file Bruno is referring to is the startup_ccs.c file.

    Also for FaultISR issues, if the above advice doesn't resolve it, I'd also recommend reading: http://www.ti.com/lit/an/spma043/spma043.pdf

  • May I too acknowledge the value of Bruno's finding - yet the dominant issue DOES Appear to be the absence of,  "UART0's  being enabled."

    Yet - might other elements of user's code demand review?     Specifically:   (see Highlights)

    void

    UARTIntHandler(void)

    {

       uint32_t ui32Status0;

       uint32_t ui32Status1;

       ui32Status0 = ROM_UARTIntStatus(UART0_BASE, true);

       ROM_UARTIntClear(UART0_BASE, ui32Status0);

       ui32Status1 = ROM_UARTIntStatus(UART4_BASE, true);

       ROM_UARTIntClear(UART4_BASE, ui32Status1);

       while(ROM_UARTCharsAvail(UART4_BASE))

       {

           ROM_UARTCharPutNonBlocking(UART0_BASE,ROM_UARTCharGetNonBlocking(UART4_BASE));

       }

    }

    Are those TWO  "ROM_UARTIntClear()s" - both implemented (and both always executed) w/in a single UART Interrupt - yet  generated by  ONLY ONE  UART  - likely to, "Cause a Fault?"     (alternatively worded - may an "unneeded"  ROM_UARTIntClear()  be issued - without causing harm?      Past MCU's  "errored"  when such was detected.)

    Your insider info is sure to prove helpful as regards such detail.     Poster's (apparent) use of a single interrupt - in service of two UARTs - registers (also) as unusual - I'm reluctant to "bless that as a general method" - for  "Just the weakness"  (potentially)  herein identified..."

    Thanks your time & attention...

  • Grettings cb1,

    I suspect that his usage of one ISR for two peripherals was actually a copy/paste misinterpretation of how interrupts work... Two sources, single interrupt routine, A LOT OF care required, not only "some"!

    One thing I do NOT usually do here is try to find Waldo in OP's code: I just get the general doubt and try to ask relevant questions, or when time permits, try to create a more generic "basic how-to" guide.

    So "general warning" - when Bruno replies, he probably did NOT dig into each line of your code... That's YOUR JOB, poster... :)

    Particularly, I noted OP's description that he gets the FaultISR "after a while". This is dangerous description which might suggests things worked fine "before a while"... Fellow freshmen, when debugging early stage code, turn off all optimizations, and run code step-by-step until the fault! That will at least show you how far you got with NO fault!

    Cheers

    Bruno
  • Hello Bruno,

    Others here too - may (often) attempt to provide, "General Solution Methods" - even on occasion - ranging beyond the "MCU Alone" limitation - so often "on display here" - and true too @ most any MCU-centric forum.

    As to "some" - "some" (may) suggest "little" (as you hint) but in fact - proves broader - and is often used "legally" - due to its (deliberate) lack of specificity...    Note too - that in my "Tag's context" - the use of "A LOT of care" would NOT have, "served as well..."

  • Bruno Saraiva said:
    I understand you are using the USB "virtual" serial port emulated by the launchpad, correct?
    Correct.
    Bruno Saraiva said:
    Apparently, when your UART4 receives a byte, there is no defined function to be called, and the code execution goes to the default ISR.
    There is a callback method in posted source code where i check characters in uart4. I thought that function was general callback for all uart channels. I am on mobile, cant check anything but i believe i have to define another function for uart4 interrupt in startup file. 
    Bruno Saraiva said:
    In that case, you shall not configure interrupts for bytes arriving at port 0.
    True. In my hasty attempt I did not have enough time to customize the source code. I will take a more detailed look and craete leaner version of this one.
  • Yes, my post and source code is inconsistent. I am focusing more on reading GPS data from UART4 part(that part of source code have breakpoints for that purpose). I will take all suggestions posted here and will try with leaner and more consistent code.
  • As my attempt to read GPS TM4C's UART quickly, so was my post on the forum. I will try to provide better source code and better debug results as soon as possible.
  • Thanks to everyone for valuable suggestion. Now I can read GPS data to TM4C and send it to PC from TM4C. I rearranged source code and removed unnecessary parts(imho).

    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "driverlib/debug.h"
    #include "driverlib/fpu.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "stdio.h"
    
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
    }
    #endif
    
    // Handler function of interrupts on UART4
    // Configuration is done in startup_ccs.c file
    // Vector table definition in startup_ccs.c as
    /*...*/
    /* UART4IntHandler,                        // UART4 Rx and Tx */
    /*...*/
    void
    UART4IntHandler(void)
    {
        // Clear interrupts on UART4
        uint32_t ui32Status;
        ui32Status = ROM_UARTIntStatus(UART4_BASE, true);
        ROM_UARTIntClear(UART4_BASE, ui32Status);
    
        // Turn on the led at the start of reading
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
        while(ROM_UARTCharsAvail(UART4_BASE))
        {
            // Write GPS data(that is read from UART4) to UART0
            ROM_UARTCharPutNonBlocking(UART0_BASE, ROM_UARTCharGetNonBlocking(UART4_BASE));
        }
    
        //Turn off the led at the end of reading
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
    }
    
    int
    main(void)
    {
        // Enable lazy stacking for interrupt handlers.
        ROM_FPUEnable();
        ROM_FPULazyStackingEnable();
    
        // Set the clocking to run directly from the crystal.
        ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
                           SYSCTL_XTAL_16MHZ);
    
        // Enable the peripherals used:
        // Port C Pins will be used as UART4
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART4);
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
        // Port F will be used for on-board led
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
        // Port A pins will be used as UART0(Virtual serial connection-debug)
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
        // Enable processor interrupts.
        ROM_IntMasterEnable();
    
        // Set PC4 as UART4 RX
        GPIOPinConfigure(GPIO_PC4_U4RX);
        ROM_GPIOPinTypeUART(GPIO_PORTC_BASE, GPIO_PIN_4);
    
        // Set GPIO A1 as UART0 Tx(Transmit)
        GPIOPinConfigure(GPIO_PA1_U0TX);
        ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_1);
    
        // Configure the UART0 for 115,200, 8-N-1 operation.
        // This is the serial connection between TM4C and PC
        ROM_UARTConfigSetExpClk(UART0_BASE, ROM_SysCtlClockGet(), 115200,
                                (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                                 UART_CONFIG_PAR_NONE));
    
        // Configure the UART0 for 115,200, 8-N-1 operation.
        // This is the serial connection between TM4C and PC
        ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);
    
        // Configure the UART for 9600, 8-N-1 operation. GPS module provides data in 9600 bps
        // This is the connection between GPS Module(U-blox NEO6M)
        ROM_UARTConfigSetExpClk(UART4_BASE, ROM_SysCtlClockGet(), 9600,
                                (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                                 UART_CONFIG_PAR_NONE));
    
        // Enable the UART4 interrupt. Other interrupts are not needed since
        // we do not expect anything from PC, it is used for displaying GPS data
        ROM_IntEnable(INT_UART4);
        ROM_UARTIntEnable(UART4_BASE, UART_INT_RX | UART_INT_RT);
    
        while(1)
        {
        }
    }
    

    I also changed default Interrupt handler of UART4 to UART4Handler function in startup_ccs . But I will not include that file just for one line change. After making GPS ground and Vcc  connection, connection GPS Tx pin to TM4C123GXL PC4 pin. Then connect TM4C to PC through debug port(UART0). Load the software and watch the values in Putty or similar software.

  • Always good to note, "Poster Success" - and especially your detailed code listing - sure to prove helpful to many.

    All helpers "missed" the necessity to, "insure that a common Gnd exists" between external device (GPS here) and your MCU.
    Long term - depending upon the current requirement of that GPS - you may benefit from a higher output power source...

    Even longer term - you may consider, "Use of a serial-driven, small/portable Display" - freeing you from any, "PC tether."     (more standard "parallel Lcd" may also be used - yet requires more MCU pins & altered program code...)

  • Bruno Saraiva said:
    Fellow freshmen, when debugging early stage code, turn off all optimizations, and run code step-by-step until the fault!

    No, I would advise against this route. It will hide faults that you really need to see and track down. And by doing so it will falsely lead you to belive you have found compiler bugs.

    Robert

  • Robert,

    I disagree on this one.

    Debugging is a tool that servers all level of developers and tasks. When you use the step-by-step debugger, optimizations most of the time change the execution sequence and "hide your logical line".

    Let's say for example that a "fresh" programmer has to transpose 8 bytes. You want to convert an array of 8 uint8_t that contains

    00001111
    00001111
    00111111
    11111111
    11111111
    00111111
    00001111
    00001111

    To an array in which each byte contains the nth bit of the original variables:

    00011000
    00011000
    00111100
    00111100
    11111111
    11111111
    11111111
    11111111

    One is likely to use a function with two nested loops. On my early days, this used to be the typical exercise that would so much benefit from debugging. It was fun and useful to see step by step values of the variables, and so on.

    If you compile this kind of stuff optimized, the "natural expected flow" gets totally gone. It becomes impossible to make proper use of the debugger. Hence, if the programmer messed up a little something (maybe started in index 1 instead of 0, or limited the counter to 8 instead of 7, those typical C traps), he won't understand at all what is going on.

    If I ever find a piece of code that serves as a proof of concept, I'll remember to come back here. But this is no "competition" nor a trial, just an exchange of experiences. And I stick to my suggestion: it is very useful to turn off optimizations, and test small functions with the debugger. Once happy with the result, maybe it is a good practice to run the code again to the desired optimization, and check for unexpected errors - which will then need to be addressed with some "further experience".

    This particularly applies to the level of OP, who is still not that comfortable to immediately understand different UARTs in one program.

    Regards

    Bruno

  • Hello again user-bignumber,

    A couple more comments on your task and post:

    - The UBlox GNSS modules are able to export both NMEA messages as well as a priority binary message. While the second is "more complicated", or rather less popular, it is more efficient: the information you are likely to need can be packaged all in one message, it uses less bytes on the transmission, and it requires less parsing. It is interesting if you use your module on that mode instead.

    - Either way, I'm pretty sure your next goal is to interpret the values received. You will construct (or try to find on the web) a NMEA parser. My hint is that you develop it "fully independent of your main application". Aim for an external function, to which you only pass a pointer with the address of the first byte of the received GNSS message, and a pointer to the internal structure in which you want your vales stored. Do not fall in the trap of mixing your GNSS library into your main application.

    - Regarding the post itself, let me point that the green button that means "This solved my question" should be actually clicked on the message which solved your question. You kind of pointed elsewhere on this case.

    Regards

    Bruno
  • Bruno Saraiva said:
    But this is no "competition" not a trial

    So - the fact that,  "Judge,  Jury,  Trial Lawyers,  Uncomfortable Bench Seating" all "are present" ... means nothing!      Did not Brazil's school system teach:  "If it walks, looks, and quacks like a duck - then it IS a duck!"    Or TRIAL - as in this case...

    You are aware that,  "only certain "optimizations" - cause the condition you present - are you not?     Discard of ALL optimization benefits may prove, "Hard to justify!"

    We WERE WARNED -  "Judge Robert" is a "Hanging Judge!"     (best to stay on his good side...)

  • Hey Bruno, this account is created many years ago and I do not know why my name is user-bigNumber :) .
    My answers to your comments;
    - Yes, I actually need far less data than my GPS module sends by default. I will check the data sheet or any other resource to configure device to send as little as possible data. Right now, as all can see, I am directly passing huge chunk of data without interpreting, to another serial port. This in fact is costly as transmission cost is takes up a high percentage or resource usage.
    - After doing first step, I will also try to write a standalone, small NMEA parser library as most of the open source parsers are written for ALL possible C applications. But since I will reduce sensor data to my desired one, a handmade library would prove useful.