[Solved] Adafruit Ultimate GPS Logger with Mega 2560

Hi,

I'm a total noob with Arduino. I've just bought my first (an Arduino Uno R3) few days ago.

I've bought a GPS shield too from Adafruit (Adafruit Ultimate GPS Logger Shield - Includes GPS Module : ID 1272 : $29.95 : Adafruit Industries, Unique & fun DIY electronics and kits). I've mounted on my Uno and Adafruit GPS examples (parsing & shield_sdlog) were working flawlessly.
But for my project, I've discovered that Uno memory was insufficient. So I've bought a Mega 2560 too in spite of announced incompatibility with the shield.

Indeed, I've found lots of blog posts (ex: http://www.instructables.com/id/Personal-Black-Box-Arduino-Mega-Ultimate-GPS-Shiel/) et forum thread which explain how to make it work with Mega.

I've followed this instructions :

  • Connect GPS shield pin 8/TX to Mega pin 15/RX3
  • Connect GPS shield pin 7/RX to Mega pin 14/TX3
  • Replace in parsing example "SoftwareSerial mySerial(8,7);" by "HardwareSerial mySerial = Serial3;" (I've made the same test with Serial1 (RX1/TX1) and Serial2 (RX2/TX2))

Sadly, serial monitor show only "Adafruit GPS library basic test!" and nothing more. I've added additional traces to debug

// Test code for Adafruit GPS modules using MTK3329/MTK3339 driver
//
// This code shows how to listen to the GPS module in an interrupt
// which allows the program to have more 'freedom' - just parse
// when a new NMEA sentence is available! Then access data when
// desired.
//
// Tested and works great with the Adafruit Ultimate GPS module
// using MTK33x9 chipset
//    ------> http://www.adafruit.com/products/746
// Pick one up today at the Adafruit electronics shop 
// and help support open source hardware & software! -ada

#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>

// If you're using a GPS module:
// Connect the GPS Power pin to 5V
// Connect the GPS Ground pin to ground
// If using software serial (sketch example default):
//   Connect the GPS TX (transmit) pin to Digital 3
//   Connect the GPS RX (receive) pin to Digital 2
// If using hardware serial (e.g. Arduino Mega):
//   Connect the GPS TX (transmit) pin to Arduino RX1, RX2 or RX3
//   Connect the GPS RX (receive) pin to matching TX1, TX2 or TX3

// If you're using the Adafruit GPS shield, change 
// SoftwareSerial mySerial(3, 2); -> SoftwareSerial mySerial(8, 7);
// and make sure the switch is set to SoftSerial

// If using software serial, keep this line enabled
// (you can change the pin numbers to match your wiring):
//SoftwareSerial mySerial(8,7);

// If using hardware serial (e.g. Arduino Mega), comment out the
// above SoftwareSerial line, and enable this line instead
// (you can change the Serial number to match your wiring):

HardwareSerial mySerial = Serial3;


Adafruit_GPS GPS(&mySerial);


// Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console
// Set to 'true' if you want to debug and listen to the raw GPS sentences. 
#define GPSECHO  false

// this keeps track of whether we're using the interrupt
// off by default!
boolean usingInterrupt = false;
void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy

void setup()  
{
    
  // connect at 115200 so we can read the GPS fast enough and echo without dropping chars
  // also spit it out
  Serial.begin(115200);
  Serial.println("Adafruit GPS library basic test!");
  Serial.println("A");
  // 9600 NMEA is the default baud rate for Adafruit MTK GPS's- some use 4800
  GPS.begin(9600);
  Serial.println("B");
  // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  // uncomment this line to turn on only the "minimum recommended" data
  //GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
  // For parsing data, we don't suggest using anything but either RMC only or RMC+GGA since
  // the parser doesn't care about other sentences at this time
  Serial.println("C");
  // Set the update rate
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // 1 Hz update rate
  // For the parsing code to work nicely and have time to sort thru the data, and
  // print it out we don't suggest using anything higher than 1 Hz
Serial.println("D");
  // Request updates on antenna status, comment out to keep quiet
  GPS.sendCommand(PGCMD_ANTENNA);
Serial.println("E");
  // the nice thing about this code is you can have a timer0 interrupt go off
  // every 1 millisecond, and read data from the GPS for you. that makes the
  // loop code a heck of a lot easier!
  useInterrupt(true);
Serial.println("F");
  delay(1000);
  // Ask for firmware version
  mySerial.println(PMTK_Q_RELEASE);
}


// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
  char c = GPS.read();
  // if you want to debug, this is a good time to do it!
#ifdef UDR0
  if (GPSECHO)
    if (c) UDR0 = c;  
    // writing direct to UDR0 is much much faster than Serial.print 
    // but only one character can be written at a time. 
#endif
}

void useInterrupt(boolean v) {
  if (v) {
    // Timer0 is already used for millis() - we'll just interrupt somewhere
    // in the middle and call the "Compare A" function above
    OCR0A = 0xAF;
    TIMSK0 |= _BV(OCIE0A);
    usingInterrupt = true;
  } else {
    // do not call the interrupt function COMPA anymore
    TIMSK0 &= ~_BV(OCIE0A);
    usingInterrupt = false;
  }
}

uint32_t timer = millis();
void loop()                     // run over and over again
{
  
  // in case you are not using the interrupt above, you'll
  // need to 'hand query' the GPS, not suggested :(
  if (! usingInterrupt) {
    // read data from the GPS in the 'main loop'
    char c = GPS.read();
    // if you want to debug, this is a good time to do it!
    if (GPSECHO)
      if (c) Serial.print(c);
  }
  
  // if a sentence is received, we can check the checksum, parse it...
  if (GPS.newNMEAreceived()) {
    // a tricky thing here is if we print the NMEA sentence, or data
    // we end up not listening and catching other sentences! 
    // so be very wary if using OUTPUT_ALLDATA and trytng to print out data
    //Serial.println(GPS.lastNMEA());   // this also sets the newNMEAreceived() flag to false
  
    if (!GPS.parse(GPS.lastNMEA()))   // this also sets the newNMEAreceived() flag to false
      return;  // we can fail to parse a sentence in which case we should just wait for another
  }

  // if millis() or timer wraps around, we'll just reset it
  if (timer > millis())  timer = millis();

  // approximately every 2 seconds or so, print out the current stats
  if (millis() - timer > 2000) { 
    timer = millis(); // reset the timer
    
    Serial.print("\nTime: ");
    Serial.print(GPS.hour, DEC); Serial.print(':');
    Serial.print(GPS.minute, DEC); Serial.print(':');
    Serial.print(GPS.seconds, DEC); Serial.print('.');
    Serial.println(GPS.milliseconds);
    Serial.print("Date: ");
    Serial.print(GPS.day, DEC); Serial.print('/');
    Serial.print(GPS.month, DEC); Serial.print("/20");
    Serial.println(GPS.year, DEC);
    Serial.print("Fix: "); Serial.print((int)GPS.fix);
    Serial.print(" quality: "); Serial.println((int)GPS.fixquality); 
    if (GPS.fix) {
      Serial.print("Location: ");
      Serial.print(GPS.latitude, 4); Serial.print(GPS.lat);
      Serial.print(", "); 
      Serial.print(GPS.longitude, 4); Serial.println(GPS.lon);
      Serial.print("Location (in degrees, works with Google Maps): ");
      Serial.print(GPS.latitudeDegrees, 4);
      Serial.print(", "); 
      Serial.println(GPS.longitudeDegrees, 4);
      
      Serial.print("Speed (knots): "); Serial.println(GPS.speed);
      Serial.print("Angle: "); Serial.println(GPS.angle);
      Serial.print("Altitude: "); Serial.println(GPS.altitude);
      Serial.print("Satellites: "); Serial.println((int)GPS.satellites);
    }
  }
}

Here is what is displayed :

Adafruit GPS library basic test!
A
B
C

Problem seems to come from serial connection with GPS but I can't manage to find what is wrong :-
Of course, if I mount back the shield on my Uno, it works again.

I presume that the shield doesn't fit on the MEAG at all, so have you also connected the power and ground between the MEGA and the shield?

If so, try this very basic sketch. Whatever it receives from Serial3 (GPS) is sent to the Serial monitor. This should print out NMEA sentences.

// Very basic sketch to monitor GPS data from Serial3 
void setup(void)
{
  Serial3.begin(9600);
  Serial.begin(115200);
}

void loop(void)
{
  // while there's data from the GPS, send it to the computer
  while(Serial3.available() > 0) {
    Serial.write(Serial3.read());
  }
  // while there's data from the computer, send it to the GPS
  while(Serial.available() > 0) {
    Serial3.write(Serial.read());
  }  
}

Pete

Hi,

thank you for your answer !

Shield seems to fit with Mega except for software serial (which is corrected with link between shield and Mega Serial3).

Your sketch is working, I see NMEA sentences in my serial Monitor.

$GPGGA,195252.397,,,,,0,00,,,M,,M,,*7D
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,195252.397,V,,,,,0.00,0.00,281217,,,N*47
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,195253.397,,,,,0,00,,,M,,M,,*7C
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,195253.397,V,,,,,0.00,0.00,281217,,,N*46
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,195254.397,,,,,0,00,,,M,,M,,*7B
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,195254.397,V,,,,,0.00,0.00,281217,,,N*41
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,195255.397,,,,,0,00,,,M,,M,,*7A
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,195255.397,V,,,,,0.00,0.00,281217,,,N*40
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,195256.397,,,,,0,00,,,M,,M,,*79
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPGSV,1,1,00*79
$GPRMC,195256.397,V,,,,,0.00,0.00,281217,,,N*43
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,195257.397,,,,,0,00,,,M,,M,,*78
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,195257.397,V,,,,,0.00,0.00,281217,,,N*42
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32

That's a good start. The connections are obviously OK.
I really don't like that Adafruit GPS code. It is unnecessarily complex and despite what they say it does not allow "the program to have more 'freedom'". I have taken the interrupt stuff out of that code and temporarily removed the initialization code in setup() (inside #ifdef EVERYTHING). Let's see if this does anything - it compiles but I can't test it right now.

// Test code for Adafruit GPS modules using MTK3329/MTK3339 driver
//
// Tested and works great with the Adafruit Ultimate GPS module
// using MTK33x9 chipset
//    ------> http://www.adafruit.com/products/746
// Pick one up today at the Adafruit electronics shop
// and help support open source hardware & software! -ada

#include <Adafruit_GPS.h>


// If you're using a GPS module:
// Connect the GPS Power pin to 5V
// Connect the GPS Ground pin to ground
// If using software serial (sketch example default):
//   Connect the GPS TX (transmit) pin to Digital 3
//   Connect the GPS RX (receive) pin to Digital 2
// If using hardware serial (e.g. Arduino Mega):
//   Connect the GPS TX (transmit) pin to Arduino RX1, RX2 or RX3
//   Connect the GPS RX (receive) pin to matching TX1, TX2 or TX3

// If you're using the Adafruit GPS shield, change
// SoftwareSerial mySerial(3, 2); -> SoftwareSerial mySerial(8, 7);
// and make sure the switch is set to SoftSerial

// If using software serial, keep this line enabled
// (you can change the pin numbers to match your wiring):
//SoftwareSerial mySerial(8,7);

// If using hardware serial (e.g. Arduino Mega), comment out the
// above SoftwareSerial line, and enable this line instead
// (you can change the Serial number to match your wiring):

HardwareSerial mySerial = Serial3;

Adafruit_GPS GPS(&mySerial);

void setup(void) 
{
   
  // connect at 115200 so we can read the GPS fast enough and echo without dropping chars
  // also spit it out
  Serial.begin(115200);
  Serial.println("Adafruit GPS library basic test!");

//#define EVERYTHING
#ifdef EVERYTHING
  Serial.println("A");
  // 9600 NMEA is the default baud rate for Adafruit MTK GPS's- some use 4800
  GPS.begin(9600);
  Serial.println("B");
  // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  // uncomment this line to turn on only the "minimum recommended" data
  //GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
  // For parsing data, we don't suggest using anything but either RMC only or RMC+GGA since
  // the parser doesn't care about other sentences at this time
  Serial.println("C");
  // Set the update rate
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // 1 Hz update rate
  // For the parsing code to work nicely and have time to sort thru the data, and
  // print it out we don't suggest using anything higher than 1 Hz
Serial.println("D");
  // Request updates on antenna status, comment out to keep quiet
  GPS.sendCommand(PGCMD_ANTENNA);
Serial.println("E");

  delay(1000);
  // Ask for firmware version
  mySerial.println(PMTK_Q_RELEASE);
#endif
}

uint32_t timer = millis();
void loop(void)
{
  // Read a character
  char c = GPS.read();
  // If there's nothing there, give up
  if(c == 0)return;
  // If you want to monitor the GPS output uncomment this
//  Serial.print(c);
  // Otherwise check whether a sentence has been received
  if (GPS.newNMEAreceived()) {
    // a tricky thing here is if we print the NMEA sentence, or data
    // we end up not listening and catching other sentences!
    // so be very wary if using OUTPUT_ALLDATA and trytng to print out data
    //Serial.println(GPS.lastNMEA());   // this also sets the newNMEAreceived() flag to false
 
    if (!GPS.parse(GPS.lastNMEA()))   // this also sets the newNMEAreceived() flag to false
      return;  // we can fail to parse a sentence in which case we should just wait for another
  }

  // if millis() or timer wraps around, we'll just reset it
  if (timer > millis())  timer = millis();

  // approximately every 2 seconds or so, print out the current stats
  if (millis() - timer > 2000) {
    timer = millis(); // reset the timer
   
    Serial.print("\nTime: ");
    Serial.print(GPS.hour, DEC); Serial.print(':');
    Serial.print(GPS.minute, DEC); Serial.print(':');
    Serial.print(GPS.seconds, DEC); Serial.print('.');
    Serial.println(GPS.milliseconds);
    Serial.print("Date: ");
    Serial.print(GPS.day, DEC); Serial.print('/');
    Serial.print(GPS.month, DEC); Serial.print("/20");
    Serial.println(GPS.year, DEC);
    Serial.print("Fix: "); Serial.print((int)GPS.fix);
    Serial.print(" quality: "); Serial.println((int)GPS.fixquality);
    if (GPS.fix) {
      Serial.print("Location: ");
      Serial.print(GPS.latitude, 4); Serial.print(GPS.lat);
      Serial.print(", ");
      Serial.print(GPS.longitude, 4); Serial.println(GPS.lon);
      Serial.print("Location (in degrees, works with Google Maps): ");
      Serial.print(GPS.latitudeDegrees, 4);
      Serial.print(", ");
      Serial.println(GPS.longitudeDegrees, 4);
     
      Serial.print("Speed (knots): "); Serial.println(GPS.speed);
      Serial.print("Angle: "); Serial.println(GPS.angle);
      Serial.print("Altitude: "); Serial.println(GPS.altitude);
      Serial.print("Satellites: "); Serial.println((int)GPS.satellites);
    }
  }
}

Pete

Nope, nothing more on serial monitor :
It's crazy ...

Loop never start (or never show Serial.println()) if I don't comment these lines :

GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); 
GPS.sendCommand(PGCMD_ANTENNA);

If they are commented, loop is starting but inside Adafruit library there is a test if(!gpsHwSerial->available()) which is always true. It seems that there is nothing which is written through Serial3

In my loop function is this code:

  // If you want to monitor the GPS output uncomment this
//  Serial.print(c);

Uncomment Serial.print(c); and let's see if it prints anything.

Pete

It does nothing more. It's because c always equals 0 and the loop always return. But it seems normal if GPS.begin() is commented, isn't it ?

I've found this thread which seems to relate similar problems but the explanations are beyond my understanding.

Arghhhhhh. Yup. Silly me. Instead of this:

#ifdef EVERYTHING
  Serial.println("A");
  // 9600 NMEA is the default baud rate for Adafruit MTK GPS's- some use 4800
  GPS.begin(9600);
  Serial.println("B");

Try this:

  Serial.println("A");
  // 9600 NMEA is the default baud rate for Adafruit MTK GPS's- some use 4800
  GPS.begin(9600);
#ifdef EVERYTHING
  Serial.println("B");

Pete

I've tried and as always, nothing more :-\

Try changing this:

HardwareSerial mySerial = Serial3;


Adafruit_GPS GPS(&mySerial);

to this:

Adafruit_GPS GPS(&Serial3);

Pete

Hahaha ! I've just discovered too that gpsHwSerial in Adafruit GPS Library was different from &Serial3. If I replace it by &Serial3, everything was working normally. But your solution is better !

Do you have any idea why it works for others but not for me ? Why Serial3 address is changed when set in HardwareSerial ?

thank you very much for your help :slight_smile:

I'm not sure what is going on there. I am really not familiar with C++. This particular situation is something to do with object instantiation which looks like a black art to me :slight_smile:

NOTE that with the change in msg #10 this code will cause a compiler error:

  // Ask for firmware version
  mySerial.println(PMTK_Q_RELEASE);

because mySerial isn't declared any more.

Pete

thank you for everything !

PROBLEM BELOW WAS CAUSED BY BROKEN RX WIRE!
Hello, I use an Adafruit Ultimate board and an Arduino Mega 2560 board and connected RX to TX3 and TX to RX3 and the GRND and 3.3V. On the Adafruit Ultimate board the red LED flashes about 1/2 sec every sec. I uploaded the simple Serial3 read code you mentioned above but I see nothing. Nothing is available on the serial3 or 2 or 1 (loop is executed; I see it by putting Serial.print("."); in it).
My code is

 // Very basic sketch to monitor GPS data from Serial3 
void setup(void)
{
  Serial1.begin(9600);  Serial2.begin(9600);Serial3.begin(9600);
  Serial.begin(115200);
}

void loop(void)
{
    //  Serial.write(";");
  // while there's data from the GPS, send it to the computer
  while(Serial3.available() > 0) {
    Serial.write(Serial3.read());
    //Serial.write(".");
  }
    while(Serial2.available() > 0) {
    Serial.write(Serial2.read());
    //Serial.write(".");
  }
    while(Serial1.available() > 0) {
    Serial.write(Serial1.read());
    //Serial.write(".");
  }
  // while there's data from the computer, send it to the GPS
  while(Serial.available() > 0) {
    Serial3.write(Serial.read());
  }  
}

and it didn't worked on either Serial port . (I presume I do not have to be outside to see NMEA strings send from the board.)