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.
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;
}