Code works on one Teensy but not on others

Status
Not open for further replies.

Snofoxx

Member
I am trying to write a code that will parse NMEA strings from a GPS module and pair the GPS data from those strings very precisely to the Teensy's internal time corresponding to the rising edge of the PPS signal. I'm trying to write my own code to do this, rather than using a library like TinyGPS++, because the library doesn't include a good way to tell if the PPS has arrived and the associated NMEA string has been fully processed, making it very difficult to try to match the NMEA string to the correct PPS time.

I wrote a code that does this, and it works fine on one Teensy I have, but not on others. As I was making this code, I built on it step by step using a Teensy to check that each added step worked correctly. The Teensy that I used to check each step is the one that the completed code works on, while any other Teensy I try to use does not work. Trying to upload the code to any other Teensy causes that Teensy to reboot several times in a row. Once the rebooting stops, nothing happens and no GPS data is logged. What could be causing the code to behave differently on different Teensys?

I'm not really sure where to start looking for the source of this problem. Is there something in my code that could be causing this? Is there something wrong with the Teensy's I'm using?

I am using the Teensy 3.6 with SparkFun's GPS logger shield. I wrote my code using the Arduino IDE version 1.8.5 and Teensyduino add on. My code is below. I'd appreciate any advice on what to do or where to look to begin troubleshooting and fixing this issue.

Code:
#include <SD.h>

#define gps Serial1
#define num_points 120 // Number of GPS data points to take before storing data to file

// Counts
int count_pps = 0;
int count_rmc = 0;
int count_gga = 0;
int count_match = 0;

// Timing Variables
unsigned long ppsms[200];
unsigned long bufms;
unsigned long rmcms[200];
unsigned long rmcms_pps[200];
unsigned long ggams[200];
unsigned long ggams_pps[200];

// NMEA Receiving Variables
String buf;
boolean complete = false;
String check_rmc;
String UTC;

// NMEA Parsing Variables
int j;
int comma[18];

// Time Pairing Variables
boolean rmc_match = false;
boolean gga_match = false;
int rmc_matched_indices[200];
int gga_matched_indices[200];

// RMC Variables: Time and Date
char utctime[11][200];
char utcdate[7][200];
char rmcstatus;

// GGA Variables: Location
char lat[10][200];
char ns[200];
char lon[11][200];
char ew[200];
char msl[8][200]; // Altitude
char nsats[3][200];
char fix;

// Accelerometer Variables
unsigned long ms[24000];
int16_t Ax[24000];
int16_t Ay[24000];
int16_t Az[24000];

// LED Variables
boolean light = false;

// SD Variables
char gpsFileName[13] = "gpsdata.csv";

void setup() {
  gps.begin(9600);
  SD.begin(BUILTIN_SDCARD);
  attachInterrupt(2, pps, RISING); // Attach interrupt to detect PPS signal
  pinMode(13, OUTPUT);
  gps.println( F("$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28") ); // Disables all NMEA sentences except RMC and GGA
  File gpsFile = SD.open(gpsFileName, FILE_WRITE);
  if (gpsFile) {
    gpsFile.print("Time");
    gpsFile.print(',');
    gpsFile.print("Date");
    gpsFile.print(',');
    gpsFile.print("Latitude");
    gpsFile.print(',');
    gpsFile.print("NS");
    gpsFile.print(',');
    gpsFile.print("Longitude");
    gpsFile.print(',');
    gpsFile.print("EW");
    gpsFile.print(',');
    gpsFile.print("Altitude (m)");
    gpsFile.print(',');
    gpsFile.print("Satellites");
    gpsFile.print(',');
    gpsFile.print("RMC");
    gpsFile.print(',');
    gpsFile.print("RMC PPS");
    gpsFile.print(',');
    gpsFile.print("GGA");
    gpsFile.print(',');
    gpsFile.println("GGA PPS");
    gpsFile.close();
  }
}

void loop() {
  if (gps.available()) { // If GPS data is available
    bufms = micros();
    buf = gps.readStringUntil(13);
    complete = true;
  }
  if (complete == true) {
    parseGPS();
  }
  if (count_rmc > num_points && count_gga > num_points) {
    pairTime();
    File gpsFile = SD.open(gpsFileName, FILE_WRITE);
    if (gpsFile) {
      for (int e1 = 0; e1 < count_match; e1++) {
        for (int e2 = 0; e2 < 10; e2++) {
          gpsFile.print(utctime[e2][rmc_matched_indices[e1]]);
        }
        gpsFile.print(',');
        for (int e2 = 0; e2 < 6; e2++) {
          gpsFile.print(utcdate[e2][rmc_matched_indices[e1]]);
        }
        gpsFile.print(',');
        for (int e2 = 0; e2 < 9; e2++) {
          gpsFile.print(lat[e2][gga_matched_indices[e1]]);
        }
        gpsFile.print(',');
        gpsFile.print(ns[gga_matched_indices[e1]]);
        gpsFile.print(',');
        for (int e2 = 0; e2 < 10; e2++) {
          gpsFile.print(lon[e2][gga_matched_indices[e1]]);
        }
        gpsFile.print(',');
        gpsFile.print(ew[gga_matched_indices[e1]]);
        gpsFile.print(',');
        for (int e2 = 0; e2 < 7; e2++) {
          gpsFile.print(msl[e2][gga_matched_indices[e1]]);
        }
        gpsFile.print(',');
        for (int e2 = 0; e2 < 2; e2++) {
          gpsFile.print(nsats[e2][gga_matched_indices[e1]]);
        }
        gpsFile.print(',');
        gpsFile.print(rmcms[rmc_matched_indices[e1]]);
        gpsFile.print(',');
        gpsFile.print(rmcms_pps[rmc_matched_indices[e1]]);
        gpsFile.print(',');
        gpsFile.print(ggams[gga_matched_indices[e1]]);
        gpsFile.print(',');
        gpsFile.println(ggams_pps[gga_matched_indices[e1]]);
      }
      gpsFile.close();
      count_pps = 0;
      count_rmc = 0;
      count_gga = 0;
      if (light == false) {
        digitalWrite(13, HIGH);
        light = true;
      }
      else {
        digitalWrite(13, LOW);
        light = false;
      }
    }
  }
}

void parseGPS() {
  if (buf.charAt(4) == 'R' && buf.charAt(5) == 'M' && buf.charAt(6) == 'C') {
    rmcms[count_rmc] = bufms;
    j = 0;
    for (int i = 0; i < buf.length(); i++) {
      if (buf.charAt(i) == ',') {
        comma[j] = i;
        j = j + 1;
      }
    }
    j = 0;
    for (int i = 0; i < buf.length(); i++) {
      if (i > comma[0] && i < comma[1]) {
        utctime[j][count_rmc] = buf.charAt(i);
        j = j + 1;
        if (i == comma[1] - 1) {
          j = 0;
        }
      }
      else if (i > comma[1] && i < comma[2]) {
        rmcstatus = buf.charAt(i);
      }
      else if (i > comma[8] && i < comma[9]) {
        utcdate[j][count_rmc] = buf.charAt(i);
        j = j + 1;
        if (i == comma[9] - 1) {
          j = 0;
        }
      }
    }
    if (rmcstatus == 'A') {
      UTC = "";
      for (int e = 0; e < 10; e++) {
        UTC = UTC + String(utctime[e][count_rmc]);
      }
      if (check_rmc != UTC) {
        count_rmc = count_rmc + 1;
        check_rmc = UTC;
      }
    }
  }
  if (buf.charAt(4) == 'G' && buf.charAt(5) == 'G' && buf.charAt(6) == 'A') {
    ggams[count_gga] = bufms;
    j = 0;
    for (int i = 0; i < buf.length(); i++) {
      if (buf.charAt(i) == ',') {
        comma[j] = i;
        j = j + 1;
      }
    }
    j = 0;
    for (int i = 0; i < buf.length(); i++) {
      if (i > comma[1] && i < comma[2]) {
        lat[j][count_gga] = buf.charAt(i);
        j = j + 1;
        if (i == comma[2] - 1) {
          j = 0;
        }
      }
      else if (i > comma[2] && i < comma[3]) {
        ns[count_gga] = buf.charAt(i);
      }
      else if (i > comma[3] && i < comma[4]) {
        lon[j][count_gga] = buf.charAt(i);
        j = j + 1;
        if (i == comma[4] - 1) {
          j = 0;
        }
      }
      else if (i > comma[4] && i < comma[5]) {
        ew[count_gga] = buf.charAt(i);
      }
      else if (i > comma[5] && i < comma[6]) {
        fix = buf.charAt(i);
      }
      else if (i > comma[6] && i < comma[7]) {
        nsats[j][count_gga] = buf.charAt(i);
        j = j + 1;
        if (i == comma[7] - 1) {
          j = 0;
        }
      }
      else if (i > comma[8] && i < comma[9]) {
        msl[j][count_gga] = buf.charAt(i);
        j = j + 1;
        if (i == comma[9] - 1) {
          j = 0;
        }
      }
    }
    if (fix == '1' || fix == '2') {
      count_gga = count_gga + 1;
    }
  }
  buf = ""; // Clear string so it can read next value.
  complete = false;
}

void pairTime() {
  // Pair RMC and GGA times to PPS times separately
  for (int e1 = 0; e1 < num_points; e1++) {
    for (int e2 = 0; e2 < count_pps; e2++) {
      if ((rmcms[e1] - ppsms[e2]) < 700000 && (rmcms[e1] - ppsms[e2]) > 0) {
        rmcms_pps[e1] = ppsms[e2];
        rmc_match = true;
      }
      if ((ggams[e1] - ppsms[e2]) < 700000 && (ggams[e1] - ppsms[e2]) > 0) {
        ggams_pps[e1] = ppsms[e2];
        gga_match = true;
      }
    }
    // If no matching PPS time available, set the pps time to equal an error value (99999)
    if (rmc_match == true) {
      rmc_match = false;
    }
    else {
      rmcms_pps[e1] = 99999;
    }
    if (gga_match == true) {
      gga_match = false;
    }
    else {
      ggams_pps[e1] = 99999;
    }
  }

  // Pair RMC and GGA times together
  count_match = 0;
  for (int e1 = 0; e1 < num_points; e1++) {
    for (int e2 = 0; e2 < num_points; e2++) {
      if (rmcms_pps[e1] == 99999) {
        // Ignore any data with an error value (no PPS matched)
      }
      else if (ggams_pps[e2] == 99999) {
        // Ignore any data with an error value (no PPS matched)
      }
      else if (rmcms_pps[e1] == ggams_pps[e2]) {
        rmc_matched_indices[count_match] = e1;
        gga_matched_indices[count_match] = e2;
        count_match = count_match + 1;
      }
    }
  }
}

void pps() {
  ppsms[count_pps] = micros();
  count_pps = count_pps + 1;
}
 
If your non-working units have their own gps and SD cards, try swapping those items with the ones in the working unit and that may point to something. It may be something like the units you debugged with have the file already on the SD card and the gps is already set up correctly.

Your code has compile warnings concerning signed vs unsigned variable types. I doubt that is causing your issue, it would still be good practice to clear up all the warnings if you can't figure out what is going on.

Your code uses a lot of arrays and nowhere in the code are checks to see if you are overwriting the bounds of the arrays. It seems that for the most part you are relying upon the variables to be detected as above 120 before any one of them could reach 200 and overflow the bounds of an array. Another thing I notice is that the pps() interrupt variable count_pps is not declared as volatile and also that its value can change while you are using it in the nested for loops of function pairTime(). I do not know if that could cause an issue, still something to think about.

Code:
// Accelerometer Variables
unsigned long ms[24000];
int16_t Ax[24000];
int16_t Ay[24000];
int16_t Az[24000];

This little section seems to be some unused variables and when I compile they are ignored and the compiler does not allocate space for them. You might want to check that is the case when you compile as my quick calculation shows they will use all of the ram available in a T3.6.
 
I wasn't sure exactly what you meant by declaring variables as volatile, but I changed how I was using the interrupt and added an overflow to make sure the array storing PPS times doesn't overflow, and this fixed my issue. I changed the interrupt to only store the incoming PPS time in a separate variable, then assign it to the next available place in the PPS time array inside the loop.

Thanks for the help!

The new interrupt:
Code:
void pps() {
  ppsms_temp = micros();
}

Added to the beginning of the loop:
Code:
if (ppsms_temp != ppsms[count_pps]) {
    count_pps = count_pps + 1;
    if (count_pps == 200) {
      count_pps = 0;
    }
    ppsms[count_pps] = ppsms_temp;
  }
 
Status
Not open for further replies.
Back
Top