user19806: I've programmed my Arduino Ethernet to receive data from a Skytraq Venus GPS receiver and separate it using TinyGPS, then store it on an SD card. With the SD card inserted, everything else except the time is totally wrong. Once I remove the SD card and reset, the longitude and latitude are still wrong but everything else is correct. I've tried supplying more power, replacing the receiver, antenna, the arduino itself, even switched the serial ports I use but I can't seem to find a solution.
Here's a link for the TinyGPS library and a link for the NewSoftSerial library. And for the schematics, I haven't drawn any yet but I'm using the Arduino Ethernet's SD port as my SD shield. My Skytraq GPS receiver's RX pin is connected to pin 2 on the arduino ethernet and the TX pin is connected to pin 3 on the ethernet. (Ethernet TX/RX has been set to pin 3 and 2 respectively.)
I'm using the Sparkfun Venus GPS with SMA connector from sparkfun.com. I would post the link but it says I need at least 10 reputation to post more than two links. Serial signals at 3.3V and GPS module is a 3.3V module. I use the same sketch with and without the SD Card. SD.begin is called just once and Serial.begin is also called once.
Here's my code:
#include <SoftwareSerial.h> //NewSoftwareSerial Library
#include <TinyGPS.h>        //TinyGPS Library
#include <SPI.h>            //This Library is used by the SD library.
                            //Must be defined before SD library to prevent errors.
#include <SD.h>             //SD Card Library

//NB: To avoid SD Card Errors, use an SD Card whose size is at most 2GB
//and use FAT16 format. Arduino has problems with FAT32 and cards>2GB.

#define RXPIN 2
#define TXPIN 3

const int chipSelect = 4; //This selects the SD card port for read/write

#define GPSBAUD 9600

File logs; //Used to write to SD card later

TinyGPS gps;

//Initialize the Software Serial to recognize
//our UART pins (Read(RX) and Write(TX))
SoftwareSerial read_gps(RXPIN, TXPIN); 

void getdata(TinyGPS &gps);


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);  //Start the serial port
  read_gps.begin(GPSBAUD);  //Start reading from the gps
  
  pinMode(chipSelect, OUTPUT); //Make pin 4 an output pin
  pinMode(10, OUTPUT);  //Pin 10 must always be set to output to avoid errors
  digitalWrite(10, HIGH); //Pin 10 must always be high to prevent errors.
  
  Serial.println("");
  Serial.println("Awaiting Lock");
  Serial.println("");
  
  //Initialize the SD Card
  SD.begin();
  Serial.println("Initializing SD Card. Please Wait.");
  if(!SD.begin(4)){//If card not available or card not recognized
    Serial.println("Failed.");
    return;
  }
  Serial.println("Card Initialized");

}


//the loop function is used to read the data from the gps,
//check for valid data and then separate the data based on our specs.
void loop() {
  // put your main code here, to run repeatedly:
  while(read_gps.available()){//as data is received from the gps
    int c = read_gps.read();
    if(gps.encode(c)){//check if new valid data available
      getgps(gps); //read the valid gps data and process
    }
  }
  
  
  
}

void getgps(TinyGPS &gps)
{
  float latitude, longitude;
  
  gps.f_get_position(&latitude, &longitude); //Feature of tinygps.
                                             //Gets the latitude and longitude
  
  Serial.print("Latitude: "); Serial.print(latitude);
  Serial.print("\nLongitude: "); Serial.print(longitude);
  
  int yr;
  byte mnth, dy, hr, minu, sec, hundredths;
  gps.crack_datetime(&yr, &mnth, &dy, &hr, &minu, &sec, &hundredths); //Gets the date and time and separates them
                                                                      //into individual components.
  
  Serial.print("\nDate: "); Serial.print(mnth, DEC); Serial.print("/");
  Serial.print(dy, DEC); Serial.print("/"); Serial.print(yr);
  Serial.print("   \nTime: "); Serial.print(hr, DEC); Serial.print(":");
  Serial.print(minu, DEC); Serial.print(":"); Serial.print(sec, DEC);
  Serial.print("."); Serial.println(hundredths, DEC);
  
  
  
  Serial.print("Altitude(metres): "); Serial.println(gps.f_altitude());
  
  Serial.print("Speed(kmph): "); Serial.println(gps.f_speed_kmph());
  Serial.println();
  
  logs = SD.open("datalogs.csv", FILE_WRITE);  //open the datalog file on the sd card. If it doesn't exist on the card, create it.
  
  if(logs){//Start writing data to SD Card
    Serial.print("Writing to datalogs...");
    logs.println("\nLatitude: "); logs.print(latitude);
    logs.print("\nLongitude: "); logs.print(longitude);
    logs.print("\nDate: "); logs.print(mnth, DEC); logs.print("/");
    logs.print(dy, DEC); logs.print("/"); logs.print(yr);
    logs.print("   \nTime: "); logs.print(hr, DEC); logs.print(":");
    logs.print(minu, DEC); logs.print(":"); logs.print(sec, DEC);
    logs.print("."); logs.println(hundredths, DEC);
    logs.print("Altitude(metres): "); logs.println(gps.f_altitude());
  
    logs.print("Speed(kmph): "); logs.println(gps.f_speed_kmph());
    logs.print("\n");
    logs.println();
    
    logs.close(); //close the file
    Serial.println("done.");
    Serial.println("\n");
  }
  else{
    Serial.println("Error opening file.");
  }
    
    
  
  unsigned long chars;
  unsigned short sentences, failed_checksum;
  gps.stats(&chars, &sentences, &failed_checksum);
}


user14737: You're trying to do too much (SD and Serial print operations) at the wrong time (GPS character receiving).
Most GPS devices will send several "sentences" per second, in a batch.  TinyGPS.encode returns true after each sentence, so your code will try to write multiple sentences per second to the SD card.  But it takes so long to open/write/close the SD card (and print to Serial) that the input buffer fills up and overflows.  Here's a detailed description of what is happening.
You must wait until the GPS "quiet time" begins.  Even then, you could have trouble, depending on how much data you need to save and print.
It may be possible to make it work with TinyGPS, but I eventually gave up in frustration and wrote the NeoGPS library to help address these problems.  It can be configured to save just the data you need (via the configuration files), and it can be used to detect when the quiet time begins (see NMEAorder.ino and NMEAfused.ino).  It uses much less RAM and takes much less time to parse the GPS characters.  This will be important if you try to add the Ethernet libraries to the sketch.
If you still have trouble getting all the information written during the quiet time, you can use a companion library (e.g., NeoSWSerial) to handle the GPS characters during the RX interrupt.
Regardless, I would suggest replacing SoftwareSerial with NeoSWSerial.  It, too, is much more efficient than the CPU-killer SoftwareSerial.  It won't fix the main problem, but it will pay off later.

19806: <p>I've programmed my Arduino Ethernet to receive data from a Skytraq Venus GPS receiver and separate it using TinyGPS, then store it on an SD card. With the SD card inserted, everything else except the time is totally wrong. Once I remove the SD card and reset, the longitude and latitude are still wrong but everything else is correct. I've tried supplying more power, replacing the receiver, antenna, the arduino itself, even switched the serial ports I use but I can't seem to find a solution.</p>

<p>Here's a <a href="https://github.com/mikalhart/TinyGPS" rel="nofollow">link</a> for the TinyGPS library and a <a href="http://arduiniana.org/libraries/newsoftserial/" rel="nofollow">link</a> for the NewSoftSerial library. And for the schematics, I haven't drawn any yet but I'm using the Arduino Ethernet's SD port as my SD shield. My Skytraq GPS receiver's RX pin is connected to pin 2 on the arduino ethernet and the TX pin is connected to pin 3 on the ethernet. (Ethernet TX/RX has been set to pin 3 and 2 respectively.)</p>

<p>I'm using the Sparkfun Venus GPS with SMA connector from sparkfun.com. I would post the link but it says I need at least 10 reputation to post more than two links. Serial signals at 3.3V and GPS module is a 3.3V module. I use the same sketch with and without the SD Card. SD.begin is called just once and Serial.begin is also called once.</p>

<p>Here's my code:</p>

<pre><code>#include &lt;SoftwareSerial.h&gt; //NewSoftwareSerial Library
#include &lt;TinyGPS.h&gt;        //TinyGPS Library
#include &lt;SPI.h&gt;            //This Library is used by the SD library.
                            //Must be defined before SD library to prevent errors.
#include &lt;SD.h&gt;             //SD Card Library

//NB: To avoid SD Card Errors, use an SD Card whose size is at most 2GB
//and use FAT16 format. Arduino has problems with FAT32 and cards&gt;2GB.

#define RXPIN 2
#define TXPIN 3

const int chipSelect = 4; //This selects the SD card port for read/write

#define GPSBAUD 9600

File logs; //Used to write to SD card later

TinyGPS gps;

//Initialize the Software Serial to recognize
//our UART pins (Read(RX) and Write(TX))
SoftwareSerial read_gps(RXPIN, TXPIN); 

void getdata(TinyGPS &amp;gps);


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);  //Start the serial port
  read_gps.begin(GPSBAUD);  //Start reading from the gps
  
  pinMode(chipSelect, OUTPUT); //Make pin 4 an output pin
  pinMode(10, OUTPUT);  //Pin 10 must always be set to output to avoid errors
  digitalWrite(10, HIGH); //Pin 10 must always be high to prevent errors.
  
  Serial.println("");
  Serial.println("Awaiting Lock");
  Serial.println("");
  
  //Initialize the SD Card
  SD.begin();
  Serial.println("Initializing SD Card. Please Wait.");
  if(!SD.begin(4)){//If card not available or card not recognized
    Serial.println("Failed.");
    return;
  }
  Serial.println("Card Initialized");

}


//the loop function is used to read the data from the gps,
//check for valid data and then separate the data based on our specs.
void loop() {
  // put your main code here, to run repeatedly:
  while(read_gps.available()){//as data is received from the gps
    int c = read_gps.read();
    if(gps.encode(c)){//check if new valid data available
      getgps(gps); //read the valid gps data and process
    }
  }
  
  
  
}

void getgps(TinyGPS &amp;gps)
{
  float latitude, longitude;
  
  gps.f_get_position(&amp;latitude, &amp;longitude); //Feature of tinygps.
                                             //Gets the latitude and longitude
  
  Serial.print("Latitude: "); Serial.print(latitude);
  Serial.print("\nLongitude: "); Serial.print(longitude);
  
  int yr;
  byte mnth, dy, hr, minu, sec, hundredths;
  gps.crack_datetime(&amp;yr, &amp;mnth, &amp;dy, &amp;hr, &amp;minu, &amp;sec, &amp;hundredths); //Gets the date and time and separates them
                                                                      //into individual components.
  
  Serial.print("\nDate: "); Serial.print(mnth, DEC); Serial.print("/");
  Serial.print(dy, DEC); Serial.print("/"); Serial.print(yr);
  Serial.print("   \nTime: "); Serial.print(hr, DEC); Serial.print(":");
  Serial.print(minu, DEC); Serial.print(":"); Serial.print(sec, DEC);
  Serial.print("."); Serial.println(hundredths, DEC);
  
  
  
  Serial.print("Altitude(metres): "); Serial.println(gps.f_altitude());
  
  Serial.print("Speed(kmph): "); Serial.println(gps.f_speed_kmph());
  Serial.println();
  
  logs = SD.open("datalogs.csv", FILE_WRITE);  //open the datalog file on the sd card. If it doesn't exist on the card, create it.
  
  if(logs){//Start writing data to SD Card
    Serial.print("Writing to datalogs...");
    logs.println("\nLatitude: "); logs.print(latitude);
    logs.print("\nLongitude: "); logs.print(longitude);
    logs.print("\nDate: "); logs.print(mnth, DEC); logs.print("/");
    logs.print(dy, DEC); logs.print("/"); logs.print(yr);
    logs.print("   \nTime: "); logs.print(hr, DEC); logs.print(":");
    logs.print(minu, DEC); logs.print(":"); logs.print(sec, DEC);
    logs.print("."); logs.println(hundredths, DEC);
    logs.print("Altitude(metres): "); logs.println(gps.f_altitude());
  
    logs.print("Speed(kmph): "); logs.println(gps.f_speed_kmph());
    logs.print("\n");
    logs.println();
    
    logs.close(); //close the file
    Serial.println("done.");
    Serial.println("\n");
  }
  else{
    Serial.println("Error opening file.");
  }
    
    
  
  unsigned long chars;
  unsigned short sentences, failed_checksum;
  gps.stats(&amp;chars, &amp;sentences, &amp;failed_checksum);
}
</code></pre>
 14737: <p>You're trying to do too much (SD and Serial print operations) at the wrong time (GPS character receiving).</p>

<p>Most GPS devices will send several "sentences" per second, in a batch.  <code>TinyGPS.encode</code> returns <code>true</code> after <em>each</em> sentence, so your code will try to write multiple sentences per second to the SD card.  But it takes so long to open/write/close the SD card (and print to <code>Serial</code>) that the input buffer fills up and overflows.  <a href="https://github.com/SlashDevin/NeoGPS/blob/master/doc/Troubleshooting.md#quiet-time-interval" rel="nofollow">Here's</a> a detailed description of what is happening.</p>

<p>You must wait until the GPS "quiet time" begins.  Even then, you could have trouble, depending on how much data you need to save and print.</p>

<p>It may be possible to make it work with TinyGPS, but I eventually gave up in frustration and wrote the <a href="https://github.com/SlashDevin/NeoGPS" rel="nofollow">NeoGPS</a> library to help address these problems.  It can be configured to save just the data you need (via the <a href="https://github.com/SlashDevin/NeoGPS/blob/master/doc/Configurations.md" rel="nofollow">configuration files</a>), and it can be used to detect when the quiet time begins (see NMEAorder.ino and NMEAfused.ino).  It <a href="https://github.com/SlashDevin/NeoGPS/blob/master/doc/RAM.md" rel="nofollow">uses much less RAM</a> and <a href="https://github.com/SlashDevin/NeoGPS/blob/master/doc/Performance.md" rel="nofollow">takes much less time</a> to parse the GPS characters.  This will be important if you try to add the Ethernet libraries to the sketch.</p>

<p>If you still have trouble getting all the information written during the quiet time, you can use a companion library (e.g., <a href="https://github.com/SlashDevin/NeoSWSerial" rel="nofollow">NeoSWSerial</a>) to handle the GPS characters <em>during</em> the RX interrupt.</p>

<p>Regardless, I would suggest replacing <code>SoftwareSerial</code> with <code>NeoSWSerial</code>.  It, too, is much more efficient than the CPU-killer <code>SoftwareSerial</code>.  It won't fix the main problem, but it will pay off later.</p>
