How do you read and parse  the GPS data - Page 1
Forum section: electronics / general

author: Dadu@
author_rank: Contributor
timestamp: February 06, 2023, 12:26:29 pm
content: I am trying to understand the program logic on how the microcontroller read and Parse the GPS data. I have looked through a lot of code but I do not fully understand logic.I know microcontroller receive character from GPS receiver via UART. I do not understand when interrupts are activated and what is done in the interrupt service routine. Does each character is read and stored in buffer in the interrupt service routine when the interrupt is activated

author: GromBeestje
author_rank: Frequent Contributor
timestamp: February 06, 2023, 06:49:00 pm
content: QuoteDepends on the microcontroller capabilities and implementation.In general, a GPS (GNSS) receiver sends characters over UART. As the receiver decides when it sends, and not the microcontroller, the microcontroller uses interrupts, to interrupts what is was doing, and receive what the GPS receiver sends. In this case, the ISR receives one byte from the UART and stores it somewhere in memory. Alternatively, it might do a DMA transfer. In this case, the UART peripheral in the microcontroller can receive the data from the GPS receiver and put it somewhere in memory.When the data is received, it has to be inspected. A GPS receiver sends NMEA sentences. These sentences are ASCII data, terminated with \r\n characters. The received data has to be chopped up in these sentences. This could be done inside the interrupt handler or in the main loop. Regardless, one has to keep track of where in the buffer the read and write pointer are.There are GPS receivers which communicate over other protocols such as I²C. In such case, the microcontroller is in charge of when communication happens.Once a whole sentence has been found, it can be parsed with an NMEA parser. For this purpose I recommendhttps://github.com/kosma/minmea

author: Dadu@
author_rank: Contributor
timestamp: February 08, 2023, 06:00:39 pm
content: Quote from: GromBeestje on February 06, 2023, 06:49:00 pm

author: GromBeestje
author_rank: Frequent Contributor
timestamp: February 08, 2023, 07:01:35 pm
content: Let's have a look. This is accessing the registers of the microcontroller directly.Using some code in a header file and linker script, making them appear as variables. Apart from that magic, I'll focus on the interrupt routine. This is called for every received character. This is a pretty limited parser which only looks for the GGA sentence. And in my opinion, it's rather awkward. Not a good reference to learn to understand.When the interrupt is called, one character is received. This is read from the register and put in a local variable.Code:received_char = U0RBR;If the received character is a '$', this is the character that indicated the beginning of an NMEA sentence.Code:if( received_char == '$' ){GGA_Index = 0;CommaCounter = 0;IsItGGAString = false;}Then have a look at the end. I will explain a bit out of order, but I need to explain this part first to understand what is going on.CGA is filled up from the end, and moved forwards.So initially, it contains "\0\0\0"The string the GNSS module transmits is "$GPGGA". The '$' was already eaten.So for each character we getCode:"\0\0G""\0GP""GPG""PGG""GGA"This looks rather awkward. Why would anyone write this? Okay, they're ignoring the "GP" part... I get that, but why do it like this. This is code running on an ARM processor. No need to save 2 bytes of memory. If this code were running on something with an amount of RAM measured in bytes, such as a 8051 based MCU. This code is to run on a fairly old ARM chip, but still that chip got 32 kB of RAM, so there is no need to do such awkward code.Code:else/* Store received character */{GGA = GGA;GGA = GGA;GGA = received_char;}Anyhow. After receiving this, we have "GGA" in GGA, then we look at where we were. If we have this "GGA" in GGA, a condition variable IsItGGAString is set, and GGA is nulled.Code:else if( ( GGA == 'G' ) && ( GGA == 'G' ) && ( GGA == 'A' ) )/* If GGA string received */{IsItGGAString = true;GGA = GGA = GGA = 0;}Now IsItGGAString is set, we enter this part of the code.This puts the data part of the string in GGA_String, and stored the location of the commas in GGA_Comma_PointersCode:else if( IsItGGAString == true )/* If $GPGGA string */{if ( received_char == ',' ){GGA_Comma_Pointers[CommaCounter++] = GGA_Index;/* Store locations of commas in the string in a buffer */}GGA_String[GGA_Index++] = received_char;/* Store the $GPGGA string in a buffer */}The rest of the parsing is done elsewhere in the code.

author: peter-h
author_rank: Super Contributor
timestamp: February 09, 2023, 10:15:47 am
content: In general, I parse NMEA by looking for the start character, then loading a max # of x bytes into a buffer size x, or until the end character is seen, whichever occurs first. Then check the checksum. Then extract the required data.Not all GPS units emit all possible NMEA strings; only some are common across them.