Adafruit GPS with a Pro Mini 3v3 8MHz

Posted on

The default 9600 baud rate is a little too fast for the 8MHz clock speed of the Pro Mini 3v3 when using a software serial connection. This can result in invalid data being received from the GPS.

Adafruit GPS with Pro Mini 3v3 8MHz

NMEA messages include a basic checksum to ensure the message was received correctly. In the example below the checksum for the message is 47 in hexidecimal, preceeded by a * (the last 3 characters).

$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47

If the message is corrupted, e.g. if some characters are missed due to the 8MHz clock speed, the checksum will not compute.

Unfortunately if the message checksum itself is corrupt and the * is lost the Adafruit GPS library blindly continues, resulting in invalid data being parsed and provided to the user (GitHub issue #67). This happened to me when I switched from an Arduino Uno to an Arduino Pro Mini in a project and started to get unusual data from the GPS.

The solution is to request a connection with the GPS at a lower baud rate. This can be done with a PMTK251 message as demonstrated below (based on Adafruit examples).

SoftwareSerial mySerial(3, 2);
Adafruit_GPS GPS(&mySerial);

void setup(void) {
    GPS.begin(9600);  // initial connection at 9600 baud
    GPS.sendCommand("$PMTK251,4800*14");  // request downgrade to 4800
    mySerial.end();  // close the connection
    delay(1000);  // wait...
    GPS.begin(4800);  // reconnect at 4800 baud
    // continue as normal...
    GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
    GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
    useInterrupt(true);
    mySerial.println(PMTK_Q_RELEASE);
}

As an aside, the checksum of an NMEA message can easily be computed in Python, which I used to calculate the checksum for this message. The checksum is computed for everything between $ and * in the message.

def nmea_checksum(message):
    checksum = 0
    for c in message:
        checksum ^= ord(c)
    return checksum

check_dec = nmea_checksum("PMTK251,4800") # returns 20
check_hex = hex(check_dec) # returns '0x14', e.g. '*14'

References