Go Down

Topic: adafruit GPS logger giving some weird readings? (Read 414 times) previous topic - next topic

mysteriousmonkey29

Yes, the delays are definitely solving the problem. I see the weird messages without them and no weird messages with them. They don't have to be one second by the way; I played around with them and concluded that they just needs to be some kind of manual delay (I'm using 100 ms now) around the print statements that were giving the garbled characters. Maybe the Arduino was trying to communicate too fast for the serial communication or computer or whatever to parse correctly?

jboyton


mysteriousmonkey29

Code: [Select]
// 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.

#include <SPI.h>
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
#include <SD.h>
#include <avr/sleep.h>

SoftwareSerial mySerial(8, 7);
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  true
/* set to true to only log to SD when GPS has a fix, for debugging, keep it false */
#define LOG_FIXONLY true

// 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

// Set the pins used
#define chipSelect 10
#define ledPin 13

File logfile;

// read a Hex value and return the decimal equivalent
uint8_t parseHex(char c)
{
  if (c < '0')
    return 0;
  if (c <= '9')
    return c - '0';
  if (c < 'A')
    return 0;
  if (c <= 'F')
    return (c - 'A')+10;
}

// blink out an error code
void error(uint8_t errno)
{
  while(1)
  {
    uint8_t i;
    for (i=0; i<errno; i++)
    {
      digitalWrite(ledPin, HIGH);
      delay(100);
      digitalWrite(ledPin, LOW);
      delay(100);
    }
    for (i=errno; i<10; i++)
    {
      delay(200);
    }
  }
}

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("\r\nUltimate GPSlogger Shield");
  pinMode(ledPin, OUTPUT);

  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect))
  {
    Serial.println("Card init. failed!");
    error(2);
  }
  char filename[15];
  strcpy(filename, "GPSLOG00.TXT");
  for (uint8_t i = 0; i < 100; i++)
  {
    filename[6] = '0' + i/10;
    filename[7] = '0' + i%10;
    // create if does not exist, do not open existing, write, sync after write
    if (! SD.exists(filename))
    {
      break;
    }
  }

  logfile = SD.open(filename, FILE_WRITE);
  if( ! logfile )
  {
    Serial.print("Couldnt create ");
    Serial.println(filename);
    error(3);
  }
  Serial.print("Writing to ");
  Serial.println(filename);

  // connect to the GPS at the desired rate
  GPS.begin(9600);

  delay(100);

  // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  delay(100);
  // uncomment this line to turn on only the "minimum recommended" data
  //GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
  // For logging data, we don't suggest using anything but either RMC only or RMC+GGA
  // to keep the log files at a reasonable size
  // Set the update rate
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // 100 millihertz (once every 10 seconds), 1Hz or 5Hz update rate

  delay(100);
  // Turn off updates on antenna status, if the firmware permits it
  GPS.sendCommand(PGCMD_NOANTENNA);

  // 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);

  delay(100);
  Serial.println("Ready!");
}


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

void loop()
{
  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 trying to print out data
   
    // Don't call lastNMEA more than once between parse calls!  Calling lastNMEA
    // will clear the received flag and can cause very subtle race conditions if
    // new data comes in before parse is called again.
    char *stringptr = GPS.lastNMEA();
   
    if (!GPS.parse(stringptr))   // 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

    delay(100);

    // Sentence parsed!
    Serial.println("OK");
    if (LOG_FIXONLY && !GPS.fix)
    {
      Serial.println("No Fix");
      return;
    }

    // Rad. lets log it!
    Serial.println("Log");

    uint8_t stringsize = strlen(stringptr);
    if (stringsize != logfile.write((uint8_t *)stringptr, stringsize))    //write the string to the SD file
        error(4);
    if (strstr(stringptr, "RMC") || strstr(stringptr, "GGA"))   logfile.flush();
      Serial.println();
  }
}

jboyton

#18
Jul 30, 2015, 09:23 pm Last Edit: Jul 30, 2015, 09:24 pm by jboyton
Your sketch works for me, with or without those delays.

The only delay that's likely to be having any effect is the one in loop(). By pausing for 100ms after receiving a sentence you allow the next sentence to arrive without anything else going on: no serial output to your computer and no writes to the SD card. I think that still points to something funny with your hardware.

You could try to isolate it by: (1) removing the delays and the Serial.print statements in loop() and see if the data on the SD card looks okay; and then (2) remove the delays and the logfile.write() and logfile.flush() calls and see if what is printed on the screen looks okay.

mysteriousmonkey29

Well I may have hardware problems, but these displays are definitely at least compensating for them. You mentioned that the one in the loop is the one that's likely to be having an effect, but if I remove any of the other ones I get garbled characters at the beginning.

I tried what you suggested, and removing all the serial.print statements removed the weird characters while removing the write and flush commands did not. Not sure what that tells us though

jboyton

So the two serials are somehow interacting.

When you just take out the delays and use the original sketch, is the data written to the SD card also garbled or just what appears on the screen?

mysteriousmonkey29

With no delays, and garbled characters in the serial output, the GPS data large to the SD card is fine. I tested it by going outside so it could actually get a lock, and it logged my data successfully and accurately with no garbled characters.

jboyton

#22
Jul 31, 2015, 02:27 am Last Edit: Jul 31, 2015, 02:41 am by jboyton
GPS --> pin8 --> Arduino (software serial)

and

Arduino (UART) --> pin 1 --> computer

They both work independently, but when they are simultaneous only one (the GPS->Arduino) works. That's a little weird and puts some doubt on my hardware theory.

One possible place to look -- assuming it is hardware -- is around the slide switch. Pins 8 and 1 are selected by that switch. Maybe the switch has an issue or there is some other anomaly.

A good puzzle, for sure!


edit:

You could try this as a way to isolate the two serial paths:

Pull the GPS shield off of the Uno and connect it with jumper wires:

VCC -- VCC
GND -- GND
D8 -- D8

Then run the original sketch (no delays).

mysteriousmonkey29

I tried connecting it with jumper wires the way you suggested, and alternatively, with pin 1 on the Arduino connected to pin 8 on the adafruit, then ran the original program, and got "card init failed." Not sure what I'm doing wrong, because I don't get this problem when I stack them on top of each other

jboyton

#24
Jul 31, 2015, 09:57 pm Last Edit: Jul 31, 2015, 09:58 pm by jboyton
You didn't do anything wrong. Rather, my attempt to help you wasn't very well thought out. The SD card requires more jumpers between the boards: Pins 10, 11, 12 and 13.
So:

orignal (no delay) sketch
vcc - vcc, gnd - gnd, p8 - p8, p10 - p10, p11 - p11, p12 - p12, p13-p13 and the slide switch in soft serial mode.

The idea behind this test is to try and figure out where the UART signal is getting corrupted. When you stack the boards the output of the UART (pin 1) is also connected to the shield. When the boards are separated and jumpered, the signal on pin 1 doesn't touch the shield. So if the characters on the monitor look good then it's evidence that the problem is with the shield.

If you had another Uno that would also be a pretty convincing way to test it.

This is kind of like chess by mail.

mysteriousmonkey29

Okay, no card initiation error, but I still got the weird symbols. Maybe this has something to do with the interrupt built into the sketch? I don't really understand it but I have it set to false and it seems to have something to do with the rate of communication.

Also, on a side note, does this mean that when I have boards stacked on top of each other the GPS shield is using pins 8 through 13? I thought it was only using pins 7, 8, and 10, but it changes my eventual circuit design if it uses this many pins.

And yes, it kind of is! Thanks for being so helpful.

jboyton

#26
Aug 01, 2015, 12:45 am Last Edit: Aug 01, 2015, 12:48 am by jboyton
That interrupt routine concept isn't really the greatest idea in the context of that sketch, or for that matter in most typical Arduino sketches. But that doesn't change the fact that it works on my Uno and GPS shield and not yours. There's still something different about our hardware that (in my mind) requires an explanation.

Pin 10 is the SD card chip select. Pins 11-13 are the SPI bus. You can use those three for other SPI devices. Depending on what you're doing you might be able to use them for other non-SPI purposes, but probably not.

As for the serial corruption problem, I'm stumped. It doesn't make sense to me. If it were mine I'd swap in a different Uno and see if that made a difference. I'd try anything to isolate it. A different USB cable. I would even consider unbolting the other GPS shield I have in a finished project and trying it just to see if it made a difference.

I have run out ideas.

mysteriousmonkey29

Okay, I'll see if I can get my hands on another Arduino, but either way, thanks.

One last question though: what is an SPI bus? For my final project, the other things on the plugging into the Arduino are several switches and an LCD screen + backpack (to make it use less pins). So am I correct in assuming that I definitely couldn't plug the switches in to 11-13, but that I could plug the LCD backpack in if I was using SPI communication?

jboyton

The SPI interface uses 3 wires + a chip select for each device. There's a clock (SCK), an ouput from the perspective of the master device called MOSI (master out slave in) and an input called MISO (master in slave out). It can be quite complicated if you have multiple masters but in a typical application there is one master (your Arduino) and some number of slave devices. They all share the SCK, MISO and MOSI. You can have as many devices as you want sharing those lines. But each device has a chip select which gets activated (usually pulled low) before talking to it so the limit of devices ends up being how many pins you have for those chip selects.

You could google and read about SPI for hours. It might be a good way to help go to sleep if you're having trouble dropping off one night.

I usually point people to Nick Gammon's pages about Arduino stuff because he has a knack for getting to the heart of the matter. This is his page on SPI: http://gammon.com.au/spi


Go Up