Tutorial: Freedom Board with Adafruit Ultimate GPS Data Logger Shield
Join the DZone community and get the full member experience.
Join For Freemany times i start with a project and tutorial, only to get interrupted for emergency tasks and assignments. for a long time i wanted to add gps (global positioning system) functionality to one of my projects. while i started a few months ago on this, it took me until this week-end to finish at least the first part: a sd card data logger with gps :-): i calculate global positioning and time information, can use it in google maps and store it on a sd card:
adafruit ultimate gps module and shield
this tutorial is about using the adafruit ultimate gps data logger shield with eclipse and processor expert. i’m using the freescale frdm-kl25z board, but in general any board or hardware can be used, as long i have 5v, gnd and rx on the microcontroller.
adafruit offers several gps offerings:
- gps only module ( http://www.adafruit.com/products/746 )
- data logger shield ( http://www.adafruit.com/products/1272 ) which includes micro sd card slot and prototyping area
- wearable gps module ( http://www.adafruit.com/products/1059 )
- the gps receive module alone ( http://www.adafruit.com/products/790 )
i ordered the data logger shield version because of the sd card socket integrated :-). both options come with a backup battery which keeps time/data in the gps module. the module comes with an internal patch antenna which worked very well for me, even in-house. i recommend the external antenna for better tracking performance.
:idea: if you order the external antenna ( http://www.adafruit.com/products/960 ), do not forget to order the sma-to-ufl cable ( http://www.adafruit.com/products/851 ).
i highly recommend to read trough the adafruit tutorial: https://learn.adafruit.com/adafruit-ultimate-gps-logger-shield
hardware setup
the shield comes with headers and backup battery:
board details
the board has a 3.3v level shifter as both the sd card and the gps module are 3.3v. the board is powered by 5v, and generates the 3.3v with a rt9193 dc-dc converter.
there is a ‘direct serial switch’ for the tx/rx lines of the gps module to digital i/o d0/d1 of the arduino shield. that way the signals can be routed directly to the k20 opensda chip and sent to the host pc (as a direct serial connection to the host pc). i have not used that option, but used the signals directly with the microcontroller.
headers
instead using the included headers, i decided to use ‘stacking headers’ so i can easily probe the signals, and stack the shields. ‘stackable headers’ are provided by many sources, e.g. pololu #1035 .
:idea: if using the shield in an environment with vibrations, consider using ‘precision socket’ headers, as these stackable headers are wire-wrap headers and might cause contact problems.
i recommend to use another shield to align the headers before starting soldering:
r5 10k ohm pull-up to 5v
although the shield works with 3.3v systems, there is a 10k pull-up resistor (r5) which pulls-up the sd card chip select line to +5v (before the 3.3v level shifter to the sd card). see board schematics here .
because i want to control that line with my 3.3v arm core, i decided to remove r5:
mini-signal header
there is another mini-header which has all the important signals:
- 3v generated from the on board dc-dc converter
- cd (sd card detect)
- ccs : sd chip select
- pps : gps pulse-per-second
- tx : serial from the gps module to the microcontroller
- rx : serial from the microcontroller to the gps module
i have added a header there too:
then insert the backup battery with the ‘+’ side up.
minimal connections for gps mode
to receive the gps information, only three wires are needed: 5v, gnd and gps tx. it is easily possible to connect the shield ‘off-the-stack’ to a frdm board like this:
that setup is ideal to get the pin assignments sorted out. make sure the switch is on the ‘soft serial’ position:
for a new board, i recommend to prototype the connections in a first step:
after that, i have wired the connections on the back like this:
for the frdm-kl25z i have following connections to the microcontroller:
- sd miso: ptd3
- sd mosi: ptd2
- sd clk: ptd1
- sd cs: ptd0
- sd cd: ptd5
- gps rx: pte0
- gps tx: pte1
-
gps pps:
ptc8ptd4
this completes the hardware setup. next step is to write the software :-).
eclipse project with processor expert
a complete project created with eclipse (see “ constructing a classroom ide with eclipse for arm “) and processor expert is available on github here . i do not go into the details of project creation. instead i show the most important settings. the project includes already the settings for the sd card. see “ tutorial: data logger with the frdm-k64f board ” how this works.
gps pps signal: extint (external interrupt)
once the gps receiver has a lock, it produces a ‘pps’ pulse-per-second every second for 100 ms:
i use an extint (external interrupt) processor expert component to trigger on the raising edge: that way i can either just count the pulses, or synchronize my internal clocks with it.
gps rx/tx: asynchroserial
i use the asynchroserial component to interface with the rx/tx lines of the gps receiver. as the receiver is constantly sending data with 9600 baud by default, it is configured for that speed:
parsing the nmea messages
the gps is constantly sending nmea messages. to see them, you can use the command
nmea print msg on
for more details about nmea sentences and what data they contain, check out this site
the most interesting message is the $gprmc ( rmc , recommended minimum data) message:
the message has the items separated by commas, and is terminated by \r\n:
$gprmc,105056.000,a,4700.2752,n,00835.1145,e,0.33,106.84,310514,,,a*6d
means:
- $gprmc : start of rmc message
- 105056.000 : time (hh:mm:ss,ms) at gmt (greenwich mean time) location. your time zone offset needs to be added. i’m in gmt+1, so i need to add one hour.
- a (active, have a lock), or v (void, no lock)
- 4700.2751, n : latitude 47 degrees, 00.2751 decimal minutes north
- 00835.1145,e : longitude 8 degrees, 35.1145 decimal minutes east
- 0.33 : speed over ground in knots
- 106.84 : track angle in degrees
- 310514 : date (dd.mm.yy)
- ,, :the next two fields are always empty?
- a : seems to be the repeat of the active or void flag?
- *6d : checksum, everything between the ‘$’ and ‘*’
i have implemented a first version of the parser. see https://github.com/erichstyger/mcuoneclipse/blob/master/examples/eclipse/frdm-kl25z/frdm-kl25z_adafruit_gps/sources/nmea.c .
the parser is in a freertos task: it indicates nmea messages with leds, retrieves the message characters and stores them in a global buffer:
static porttask_function(nmeatask, pvparameters) { gps_tcomdata ch; (void)pvparameters; /* parameter not used */ gps_clearrxbuf(); /* clear gps rx buffer, as it already could contain some data */ for(;;) { /* indicate we are receiving data from gps with green and red led */ if (gps_getcharsinrxbuf()==0) { ledr_neg(); ledg_off(); /* blink red led if no gps data */ } else { ledr_off(); ledg_neg(); /* blink green led if we have gps data */ } while(gps_getcharsinrxbuf()!=0) { /* do we have data? */ if (gps_recvchar(&ch)==err_ok) { /* yes, and no problem to get it */ readchar(ch); /* read character and store in buffer */ if (nmea_printmsg) { /* print messages to console? */ cls1_sendchar(ch); /* yes, print it */ } /* if */ } /* if */ } /* while */ frtos1_vtaskdelay(200/porttick_rate_ms); /* give back some time */ } }
once a valid message end (and start) is detected, it parses the message:
static void readchar(uint8_t ch) { static uint8_t prevch = '\0'; /* needed to detect \r\n as end of a message */ if (nmea_parsemsg) { /* enabled to parse messages? */ if (ch=='with the shell i can check the status:
location with google maps
the application already makes the correct coordinate transformation so i can copy-paste the position information into google maps:
summary
with this gps module i have a data logger with position information. i already have a special application in mind, let’s see how soon i can have it implemented :-). so i will constantly extend the project and sources on github for it.
happy gpsing :-)
) { /* check start of a message */ nmea_msgidx = 0; /* reset index */ prevch = '\0'; /* reset previous char */ } if (nmea_msgidx<sizeof(nmea_msg)-1) { /* check for buffer overflow */ nmea_msg[nmea_msgidx++] = ch; /* store character */ } else { /* message too long! */ err((uint8_t*)"buffer overflow!"); nmea_msgidx = 0; prevch = '\0'; } if (nmea_msgidx>sizeof("$gpxxx,") && (ch=='\n' && prevch=='\r')) { /* valid end of message */ nmea_msg[nmea_msgidx] = '\0'; /* terminate */ /* reached end of a message */ if (util1_strncmp((char*)nmea_msg, (char*)"$gp", sizeof("$gp")-1)==0) { /* valid start of a message? */ if (verifychecksum(nmea_msg)==err_ok) { /* check first the checksum */ parsemsg(); /* checksum ok, parse message and store data */ } else { err((uint8_t*)"checksum failure!"); } } else { err((uint8_t*)"message does not start with \"$gp\"?"); } } } prevch = ch; }
with the shell i can check the status:
location with google maps
the application already makes the correct coordinate transformation so i can copy-paste the position information into google maps:
summary
with this gps module i have a data logger with position information. i already have a special application in mind, let’s see how soon i can have it implemented :-). so i will constantly extend the project and sources on github for it.
happy gpsing :-)
Published at DZone with permission of Erich Styger, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments