Arduino MEGA behaving differently to Diecimila

I just got my new Arduino Mega to take advantage of the extra capabilities. I have upgraded to Arduino IDE 0015 and the IDE is set up correctly for the MEGA board.

I am building a GPS/compass unit using the GPS shield from Adafruit, a HMC6352 digital compass module and a 4x20 LCD with the LCD117 interface board from moderndevice.com

My code is working great on the Diecimila - compass works great, GPS is fine and the LCD displayss the correct output.

BUT - if I upload the sketch to the MEGA (upload is fine) and then try the MEGA (using the exact same pins on the GPS shield) then it doesn't work!!!

With the MEGA my sketch runs the "void setup()" function and then seems to die - it doesn't appear to enter the "void loop()".

Am I doing something wrong? Is this a known problem?

Here's my sketch - still a work in progress - if it'll help:

#include <SoftwareSerial.h>
#include <NewSoftSerial.h>
#include <Stdio.h>
#include <Wire.h>

// LCD variables
#define LcdRxPin 13  // LcdRxPin is immaterial - not used - just make this an unused Arduino pin number
#define LcdTxPin 3
SoftwareSerial LcdSerial =  SoftwareSerial(LcdRxPin, LcdTxPin);
// end LCD variables

// GPS variables
NewSoftSerial GpsSerial =  NewSoftSerial(0, 1);
#define GpsPwrPin 2
#define GPSRATE 4800
// GPS parser for 406a
#define BUFFSIZ 90 // plenty big
char buffer[BUFFSIZ];
char *parseptr;
char buffidx;
uint8_t hour, minute, second, year, month, date;
uint32_t latitude, longitude;
uint8_t groundspeed, trackangle;
char latdir, longdir;
char status;
// end GPS variables

// compass variables
int compassAddress = 0x42 >> 1;
int compassHeading;
 
int compassSWpin=4;
int compassWpin=5;
int compassNWpin=6;
int compassNpin=7;
int compassNEpin=8;
int compassEpin=9;
int compassSEpin=10;
int compassSpin=11;
// end compass variables

// initialise LCD
void initLcd(){
  pinMode(LcdTxPin, OUTPUT);
  LcdSerial.begin(9600);    // 9600 baud is chip comm speed
  LcdSerial.print("?G420");
  delay(100);                 // pause to allow LCD EEPROM to program
  LcdSerial.print("?Bff");  // set backlight to 40 hex
  delay(100);              // pause to allow LCD EEPROM to program
  LcdSerial.print("?s6");   // set tabs to six spaces
  delay(1000);              // pause to allow LCD EEPROM to program
/*  LcdSerial.print("?D0040E150404000000"); // N arrow
  delay(200);
  LcdSerial.print("?D10F03050910000000"); // NE arrow
  delay(200);
  LcdSerial.print("?D20004021F02040000"); // E arrow
  delay(200);
  LcdSerial.print("?D3000000100905030F"); // SE arrow
  delay(200);
  LcdSerial.print("?D40000000404150E04"); // S arrow
  delay(200);
  LcdSerial.print("?D5000000011214181E"); // SW arrow
  delay(200);
  LcdSerial.print("?D60004081F08040000"); // W arrow
  delay(200);
  LcdSerial.print("?D71E18141201000000"); // NW arrow
  delay(200);
*/
  LcdSerial.print("?c0");                            // turn cursor off
  delay(200);  
  LcdSerial.print("?f");                   // clear the LCD
  delay(1000);
  LcdSerial.print("?x00?y0");
  delay(100);
  LcdSerial.print("    LCD Ready...");
  delay(500);
}

// initialise GPS
void initGps(){
  if (GpsPwrPin) {
    pinMode(GpsPwrPin, OUTPUT);
  }
  pinMode(13, OUTPUT);
  GpsSerial.begin(GPSRATE);
   
  digitalWrite(GpsPwrPin, LOW);         // pull low to turn on!

  LcdSerial.print("?x00?y1");
  delay(100);
  LcdSerial.print("    GPS Ready...");
  delay(500);
}

void initCompass(){
  // this for debugging the data
  //Serial.begin(9600);
  // set up
  CLKPR = (1<<CLKPCE);
  CLKPR = 0;
  // initialize the HMC6352
  Wire.begin(); // join i2c bus (compassAddress optional for master)
  
  //
  pinMode(compassSWpin, OUTPUT);
  pinMode(compassWpin, OUTPUT);
  pinMode(compassNWpin, OUTPUT);
  pinMode(compassNpin, OUTPUT);
  pinMode(compassNEpin, OUTPUT);
  pinMode(compassEpin, OUTPUT);
  pinMode(compassSEpin, OUTPUT);
  pinMode(compassSpin, OUTPUT);
  LcdSerial.print("?x00?y2");
  delay(100);
  LcdSerial.print("  Compass Ready...");
  delay(500);
}

// setup
void setup(){
  initLcd();
  delay(1000);
  initGps();
  delay(1000);
  initCompass();
  delay(2000);
}

// main
void loop() 
{ 
  uint32_t tmp;
  
  readline();
  
  // check if $GPRMC (global positioning fixed data)
  if (strncmp(buffer, "$GPRMC",6) == 0) {
    
    // hhmmss time data
    parseptr = buffer+7;
    tmp = parsedecimal(parseptr); 
    hour = tmp / 10000;
    minute = (tmp / 100) % 100;
    second = tmp % 100;
    
    parseptr = strchr(parseptr, ',') + 1;
    status = parseptr[0];
    parseptr += 2;
    
    // grab latitude & long data
    // latitude
    latitude = parsedecimal(parseptr);
    if (latitude != 0) {
      latitude *= 10000;
      parseptr = strchr(parseptr, '.')+1;
      latitude += parsedecimal(parseptr);
    }
    parseptr = strchr(parseptr, ',') + 1;
    // read latitude N/S data
    if (parseptr[0] != ',') {
      latdir = parseptr[0];
    }
    
    // longitude
    parseptr = strchr(parseptr, ',')+1;
    longitude = parsedecimal(parseptr);
    if (longitude != 0) {
      longitude *= 10000;
      parseptr = strchr(parseptr, '.')+1;
      longitude += parsedecimal(parseptr);
    }
    parseptr = strchr(parseptr, ',')+1;
    // read longitude E/W data
    if (parseptr[0] != ',') {
      longdir = parseptr[0];
    }
    

    // groundspeed
    parseptr = strchr(parseptr, ',')+1;
    groundspeed = parsedecimal(parseptr);

    // track angle
    parseptr = strchr(parseptr, ',')+1;
    trackangle = parsedecimal(parseptr);


    // date
    parseptr = strchr(parseptr, ',')+1;
    tmp = parsedecimal(parseptr); 
    date = tmp / 10000;
    month = (tmp / 100) % 100;
    year = tmp % 100;
    
    LcdSerial.print("?f");
    LcdSerial.print("?x00?y0");
    char datetime[17];
    sprintf(datetime,"%02d/%02d/%02d %02d:%02d:%02d",date,month,year,hour,minute,second);
    LcdSerial.print(datetime);
    
    LcdSerial.print("?x00?y1");
    //char latitude[13];
    //sprintf(latitude,"%s %02do%02d'%2d.$2d\"",latdir,
    LcdSerial.print(latdir);
    LcdSerial.print(' ');
    LcdSerial.print(latitude/1000000, DEC);
    LcdSerial.print("o");
    LcdSerial.print((latitude/10000)%100, DEC);
    LcdSerial.print('\'');
    LcdSerial.print((latitude%10000)*6/1000, DEC);
    LcdSerial.print('.');
    LcdSerial.print(((latitude%10000)*6/10)%100, DEC);
    LcdSerial.print('"');
   
    LcdSerial.print("?x00?y2");
    LcdSerial.print(longdir);
    LcdSerial.print(' ');
    LcdSerial.print(longitude/1000000, DEC);
    LcdSerial.print("o");
    LcdSerial.print((longitude/10000)%100, DEC);
    LcdSerial.print('\'');
    LcdSerial.print((longitude%10000)*6/1000, DEC);
    LcdSerial.print('.');
    LcdSerial.print(((longitude%10000)*6/10)%100, DEC);
    LcdSerial.print('"');
    
    Wire.beginTransmission(compassAddress);
    Wire.send('A');
    Wire.endTransmission();
    delay(10);
    Wire.requestFrom(compassAddress, 2);
 
    if(2 <= Wire.available())    // if two bytes were received 
    { 
      compassHeading = Wire.receive();  // receive high byte (overwrites previous compassHeading) 
      compassHeading = compassHeading << 8;    // shift high byte to be high 8 bits 
      compassHeading += Wire.receive(); // receive low byte as lower 8 bits 
      compassHeading /= 10; 
      lightNorth(compassHeading);
      //Serial.println(compassHeading);   // print the compassHeading 
    } 
  }
}


uint32_t parsedecimal(char *str) {
  uint32_t d = 0;
  
  while (str[0] != 0) {
   if ((str[0] > '9') || (str[0] < '0'))
     return d;
   d *= 10;
   d += str[0] - '0';
   str++;
  }
  return d;
}

void readline(void) {
  char c;
  
  buffidx = 0; // start at begninning
  while (1) {
      c=GpsSerial.read();
      if (c == -1)
        continue;
      //Serial.print(c);
      if (c == '\n')
        continue;
      if ((buffidx == BUFFSIZ-1) || (c == '\r')) {
        buffer[buffidx] = 0;
        return;
      }
      buffer[buffidx++]= c;
  }
}

void lightNorth(int compassHeading){
  digitalWrite(compassSWpin, LOW);
  digitalWrite(compassWpin, LOW);
  digitalWrite(compassNWpin, LOW);
  digitalWrite(compassNpin, LOW);
  digitalWrite(compassNEpin, LOW);
  digitalWrite(compassEpin, LOW);
  digitalWrite(compassSEpin, LOW);
  digitalWrite(compassSpin, LOW);
  if ((compassHeading>=338 && compassHeading<=360) || (compassHeading>=0 && compassHeading<23))
    digitalWrite(compassNpin, HIGH);
  else if (compassHeading>=23 && compassHeading<68)
    digitalWrite(compassNEpin, HIGH);
  else if (compassHeading>=68 && compassHeading<113)
    digitalWrite(compassEpin, HIGH);
  else if (compassHeading>=113 && compassHeading<158)
    digitalWrite(compassSEpin, HIGH);
  else if (compassHeading>=158 && compassHeading<203)
    digitalWrite(compassSpin, HIGH);
  else if (compassHeading>=203 && compassHeading<248)
    digitalWrite(compassSWpin, HIGH);
  else if (compassHeading>=248 && compassHeading<293)
    digitalWrite(compassWpin, HIGH);
  else if (compassHeading>=293 && compassHeading<338)
    digitalWrite(compassNWpin, HIGH);
}

The I2C pins are in a different location on the Mega. On a standard Arduino they're on Analog 4 & 5, on the Mega they're on digital 20 & 21. If you change your connections to the HMC6352 you'll probably be good.

Another possible problem: Why are you using pins 0 & 1 for your NewSoftSerial connection? Those are the hardware serial pins. I can imagine all kinds of bad interactions trying to use these pins for a non-hardware based serial.

Thanks for the pointers on the pins - the compass module works fine on the MEGA pins 20 and 21.

And the 0 and 1 pins I forgot to change to 3 and 4 after I finished testing the GPS shield with the Arduino onboard FTDI connection ::slight_smile:

But the project still doesn't work properly - I think the NewSoftSerial library is not compatible with the Arduino Mega yet - the author had to release a new version when the Atmega 328 chips started appearing in Arduinos. I'm sure an update for MEGA support will be coming soon.

Thanks for the help.

The MEGA has 4 hardware serial ports, why not use one of those instead of the NewSoftSerial port?

why not use one of those instead of the NewSoftSerial port?

Basically... because I'm a newb :-[. And I've largely been relying on pasting together bits of other people's code so far.

But again, thanks for the pointer!

I always avoided the hardware serial port on the Diecimila because it's also connected to the FTDI. I didn't realize that the additional UARTS on the MEGA are separate from the FTDI chip.

I wonder if I can use one for the LCD interface too, and eliminate both the SoftSerial libraries from my sketch?

Lots to experiment with later...if only I didn't have to work now.

I wonder if I can use one for the LCD interface too, and eliminate both the SoftSerial libraries from my sketch?

That should work - give it a try.

Serial1 (the second UART) is on pins 18 & 19 (TX,RX)
Serial2 is on pins 16 & 17 (TX,RX)
Serial3 is on pins 14 & 15 (TX,RX)