Making a SD card GPS logger with Arduino and MTK3329 GPS module

Finally I got the MTK3329 GPS module connected with Arduino. The module works in 1Hz mode by default. I referred to Adafruit’s test sketch to switch the module to 10Hz mode and the update speed rocks!

The next day, I placed the Arduino and GPS module on my bike and ride to record some data.


I converted the recorded NMEA data into KML with a utility called NMEA2KML and loaded it into Google Earth to inspect and found that though the module provides 10Hz update speed, the actual data is not 10Hz all the time. There are more positions recorded comparing to using 1Hz module anyway but not that much.


My goal is to make a SD card GPS logger. So I put a SD shield in the middle of Arduino board and the LCD shield. Using the SD library provided bu Arduino 1.0, it’s so easy to manipulate files on a SD card. Later I switched to SD breakout board as I found it has better compatiblity with different types of SD cards (including SDHC).


After setting up the logger in my car and took it for a ride, I got more logged data.


The logged data in high speed seems more precise.


Finally I connected a 3-axis accelerometer to Arduino’s port A1-A3 and display the acceleration value on the LCD. They are not yet recorded and I’m going to translate them into NMEA sentences so as to multiplex with GPS NMEA stream.


More attempts are being made. Stay tuned!


The sketch of my GPS logger:

* SD card GPS logger
* Distributed under GPL v2.0
* Copyright (c) 2012 Stanley Huang All rights reserved.
#include <SD.h>
#include <TinyGPS.h>
#include <LCD4884.h>

#define PMTK_SET_NMEA_UPDATE_1HZ "$PMTK220,1000*1F"
#define PMTK_SET_NMEA_UPDATE_5HZ "$PMTK220,200*2C"
#define PMTK_SET_NMEA_UPDATE_10HZ "$PMTK220,100*2F"

#define SD_CHIP_SELECT 10

File sdfile;
TinyGPS gps;

static char filename[13];
static bool fileOpened = false;

bool openSDFile()
    // open log file
    for (unsigned int index = 0; index < 65535; index++) {
        char filename[16];
        sprintf(filename, "GPS%05d.TXT", index);
        lcd.LCD_write_string(0, 2, filename, MENU_NORMAL);
        if (!SD.exists(filename)) {
            sdfile =, FILE_WRITE);
            if (sdfile) {
                lcd.LCD_write_string(0, 3, "OK", MENU_NORMAL);
                return true;
            lcd.LCD_write_string(0, 3, "Can't open", MENU_NORMAL);
    return false;

void setup()
    // Setup timer2 -- Prescaler/256
    TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
    TCCR2B &= ~(1<<WGM22);
    TCCR2B = (1<<CS22)|(1<<CS21);

    ASSR |=(0<<AS2);

    // Use normal mode
    TCCR2A =0;
    //Timer2 Overflow Interrupt Enable
    TIMSK2 |= (0<<OCIE2A);
    TCNT2=0x6;  // counting starts from 6;
    TIMSK2 = (1<<TOIE2);


    lcd.LCD_write_string(0, 0, " WAITING GPS  ", MENU_HIGHLIGHT);


    // Set the update rate
    // 1 Hz update rate
    // 5 Hz update rate
    // 10 Hz update rate

    // initialize the digital pin as an output.
    // Pin 13 has an LED connected on most Arduino boards:

    // enable SD card
    if (SD.begin(SD_CHIP_SELECT)) {
        fileOpened = openSDFile();

void loop()
    static int byteCount = 0;
    static unsigned long lastTime = 0;
    static unsigned int recDataKB = 0;

    if (!Serial.available()) return;

    char c =;
    // dump NMEA to file on SD card
    if (fileOpened) {
        if (++byteCount >= 1024) {
            // flush to file every 1KB
            byteCount = 0;

    // push NMEA characters to TinyGPS
    if (!gps.encode(c)) {
        // parsed data not ready

    if (!fileOpened) {
        fileOpened = openSDFile();
        if (!fileOpened) {
            lcd.LCD_write_string(0, 0, "SD CARD ERROR", MENU_HIGHLIGHT);

    // update screen every 250ms
    if (millis() - lastTime > 250) {
        char buf[16];
        unsigned long fix_age;
        unsigned long speed;
        unsigned long date, time;
        long lat, lon;

        gps.get_datetime(&date, &time, &fix_age);
        sprintf(buf, "%06ld %08ld", date, time);
        lcd.LCD_write_string(0, 0, buf, MENU_HIGHLIGHT);

        gps.get_position(&lat, &lon, &fix_age);
        sprintf(buf, "LAT:%d.%05ld",
            (int)(lat / 100000), lat % 100000);
        lcd.LCD_write_string(0, 1, buf, MENU_NORMAL);
        sprintf(buf, "LON:%d.%05ld",
            (int)(lon / 100000), lon % 100000);
        lcd.LCD_write_string(0, 2, buf, MENU_NORMAL);
        sprintf(buf, "ALT:%d SAT:%d",
            (int)(gps.altitude() / 100), gps.satellites());
        lcd.LCD_write_string(0, 3, buf, MENU_NORMAL);

        sprintf(buf, "%5dKB", recDataKB);
        lcd.LCD_write_string(7*6, 4, buf, MENU_NORMAL);

        speed = gps.speed();
        if (speed > 1000) speed = 0;
        // 1knot = 1.852km
        sprintf(buf, "%d km/h  ", (int)(speed * 1852 / 100000));
        lcd.LCD_write_string(0, 4, buf, MENU_NORMAL);

        // read accelerometer and display X/Y/Z acceleration
        int x,y,z;
        x = analogRead(1);
        y = analogRead(2);
        z = analogRead(3);
        sprintf(buf, "X%03d Y%03d Z%03d", x, y, z);
        lcd.LCD_write_string(0, 5, buf, MENU_NORMAL);

        lastTime = millis();

// Timer2 interrupt routine -
// 1/(160000000/256/(256-6)) = 4ms interval
ISR(TIMER2_OVF_vect) {
  TCNT2  = 6;

Useful Links:


Comments are closed.