Hi all,
I've got an interesting bug here I'm hoping I can get help with. I've built a GPS datalogger using the Arduino Mega, the Arduino Ethernet Shield, and a standard GPS module. The TinyGPS, SDFat, and SDFatUtil libraries do most of the work. The Mega pareses NMEA sentences from the GPS and logs the data onto the SD Card at a preset interval (roughly once every 5 seconds). Everything was working great so I took the unit out on a road test. The first trip worked fine, but on the second attempt the program froze up. Upon closer inspection via serial debugging the program is unable to log data onto the card and halts. This is the error code:
error: write data failed
SD errorCode: 0X6
I've tried other microSD cards with the same result. Being that this code is basically a mash-up of the included analogger example with a TinyGPS example, I loaded the analogger code onto the Arduino. It worked without problem. This makes me think it's a software issue, but then why would it have originally worked and then suddenly quit? The entire code is printed below. There are a few adjustments I still plan to make, but it was fully functional. It hangs at the "if (timer==300)" condition near the bottom. The GPS input data is fine so there's no issue with that. I'm really stumped on this one so any help would be greatly appreciated.
Thanks!
-Jeff
// GPS datalogger by Rocket_Man_Jeff
// 2012
#include "TinyGPS.h"
#include "SoftwareSerial.h"
#include <SdFat.h>
#include <SdFatUtil.h> // define FreeRam()
#define CHIP_SELECT SS_PIN // SD chip select pin
#define ECHO_TO_SERIAL 1 // echo data to serial port if nonzero
TinyGPS gps;
// NMEA Data to pin 19
int RedPin = 5;
int GrnPin = 6;
int BluPin = 7;
int timer = 0;
// file system object
SdFat sd;
// text file for logging
ofstream logfile;
// Serial print stream
ArduinoOutStream cout(Serial);
// buffer to format data - makes it eaiser to echo to Serial
char buf[80];
// store error strings in flash to save RAM
#define error(s) sd.errorHalt_P(PSTR(s))
//**********************************************************
void setup() {
Serial.begin(115200); // Serial Output
Serial1.begin(4800); // To read NMEA from GPS
// pstr stores strings in flash to save RAM
cout << endl << pstr("FreeRam: ") << FreeRam() << endl;
if (!sd.init(SPI_HALF_SPEED, CHIP_SELECT)) sd.initErrorHalt();
// create a new file in root, the current working directory
char name[] = "LOGGER00.CSV";
for (uint8_t i = 0; i < 100; i++) {
name[6] = i/10 + '0';
name[7] = i%10 + '0';
if (sd.exists(name)) continue;
logfile.open(name);
break;
}
if (!logfile.is_open()) error("file.open");
cout << pstr("Logging to: ") << name << endl;
// format header in buffer
obufstream bout(buf, sizeof(buf));
bout << pstr("Time,Latitude,Longitude,Altitude,Speed,Heading,Direction,SatNum");
logfile << buf << endl;
#if ECHO_TO_SERIAL
cout << buf << endl;
#endif // ECHO_TO_SERIAL
}
//**********************************************************
void loop() {
uint32_t m;
pinMode(RedPin, OUTPUT);
pinMode(GrnPin, OUTPUT);
pinMode(BluPin, OUTPUT);
while (Serial1.available()) {
int c = Serial1.read();
gps.encode(c);
//Serial.println("oh no, I'm never gonna exit this while loop");
}
long latitude, longitude;
unsigned long fix_age;
// gps.get_position(&latitude, &longitude, NULL);
gps.get_position(&latitude, &longitude, &fix_age);
//Serial.print("Fix Age: "); Serial.println(fix_age);
Serial.print("Latitude: "); Serial.println(latitude);
Serial.print("Longitude: "); Serial.println(longitude);
int year;
byte month, day, hour, minute, second, hundredths;
gps.crack_datetime(&year,&month,&day,&hour,&minute,&second,&hundredths);
// Print data and time
Serial.print("Date: "); Serial.print(month, DEC); Serial.print("/");
Serial.print(day, DEC); Serial.print("/"); Serial.print(year);
Serial.print(" Time: "); Serial.print(hour, DEC); Serial.print(":");
Serial.print(minute, DEC); Serial.print(":"); Serial.print(second, DEC);
Serial.print("."); Serial.println(hundredths, DEC);
int hour_int=hour;
int minute_int=minute;
int second_int=second;
Serial.print("Altitude (meters): "); Serial.println(gps.f_altitude());
Serial.print("Course (degrees): "); Serial.println(gps.f_course());
Serial.print("Course (cardinal): "); Serial.println(TinyGPS::cardinal(gps.f_course()));
Serial.print("Speed(knots): "); Serial.println(gps.f_speed_knots());
Serial.print("Satellites: "); Serial.println(gps.satellites());
Serial.println();
unsigned long chars;
unsigned short sentences, failed_checksum;
gps.stats(&chars, &sentences, &failed_checksum);
Serial.print("Failed Checksums: ");Serial.print(failed_checksum);
Serial.println(); Serial.println();
// Check status of fix and light LEDs accordingly
if (fix_age == TinyGPS::GPS_INVALID_AGE) {
Serial.println("No fix detected");
digitalWrite(BluPin, HIGH);
digitalWrite(RedPin, LOW);
digitalWrite(GrnPin, LOW);
}
else if (fix_age > 5000) {
Serial.println("Warning: possible stale data!");
digitalWrite(BluPin, LOW);
digitalWrite(RedPin, HIGH);
digitalWrite(GrnPin, LOW);
}
else {
Serial.println("Data is current.");
digitalWrite(BluPin, LOW);
digitalWrite(RedPin, LOW);
digitalWrite(GrnPin, HIGH);
timer++; // Rough timer to increment data logging rate
if (timer==300) {
digitalWrite(BluPin, HIGH); // Light all LEDs when data logs
digitalWrite(RedPin, HIGH);
digitalWrite(GrnPin, HIGH);
// use buffer stream to format line
obufstream bout(buf, sizeof(buf));
long lat_num=(latitude/100000); // Splits lat/lon from GPS
long lat_dec=(latitude%100000); // into xx.xxxxx
long lon_num=(latitude/100000);
long lon_dec=(latitude%100000);
// long lat_num=(latitude/100000);
// long lat_dec=(lat_num*100000);
// lat_dec=(latitude-lat_dec);
// if (lat_dec<0) {
// lat_dec=-lat_dec;
// }
//
// long lon_num=(longitude/100000);
// long lon_dec=(lon_num*100000);
// lon_dec=(longitude-lon_dec);
// if (lon_dec<0) {
// lon_dec=-lon_dec;
// }
bout << hour_int;
bout << ':' << minute_int;
bout << ':' << second_int;
bout << ',' << lat_num;
bout << '.' << lat_dec;
bout << ',' << lon_num;
bout << '.' << lon_dec;
bout << ',' << (gps.f_altitude());
bout << ',' << (gps.f_speed_knots());
bout << ',' << (gps.f_course());
bout << ',' << (TinyGPS::cardinal(gps.f_course()));
bout << ',' << (gps.satellites());
bout << endl;
// log data and flush to SD
logfile << buf << flush;
// check for error
if (!logfile) error("write data failed");
#if ECHO_TO_SERIAL
cout << buf;
#endif // ECHO_TO_SERIAL
delay (1);
timer=0;
} // closes if timer == 300 statement
} // closes else statement
Serial.println();
} // closes void loop
[code/]