TinyGPS and hardware serial?

Hi,

Does anyone know how to use the TinyGPS library (version 12 currently) with hardware serial, instead of software serial?

This is the example sketch:

#include <SoftwareSerial.h>

#include <TinyGPS.h>

/* This sample code demonstrates the normal use of a TinyGPS object.
   It requires the use of SoftwareSerial, and assumes that you have a
   4800-baud serial GPS device hooked up on pins 3(rx) and 4(tx).
*/

TinyGPS gps;
SoftwareSerial ss(3, 4);

void setup()
{
  Serial.begin(115200);
  ss.begin(4800);
  
  Serial.print("Simple TinyGPS library v. "); Serial.println(TinyGPS::library_version());
  Serial.println("by Mikal Hart");
  Serial.println();
}

void loop()
{
  bool newData = false;
  unsigned long chars;
  unsigned short sentences, failed;

  // For one second we parse GPS data and report some key values
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (ss.available())
    {
      char c = ss.read();
      // Serial.write(c); // uncomment this line if you want to see the GPS data flowing
      if (gps.encode(c)) // Did a new valid sentence come in?
        newData = true;
    }
  }

  if (newData)
  {
    float flat, flon;
    unsigned long age;
    gps.f_get_position(&flat, &flon, &age);
    Serial.print("LAT=");
    Serial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
    Serial.print(" LON=");
    Serial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
    Serial.print(" SAT=");
    Serial.print(gps.satellites() == TinyGPS::GPS_INVALID_SATELLITES ? 0 : gps.satellites());
    Serial.print(" PREC=");
    Serial.print(gps.hdop() == TinyGPS::GPS_INVALID_HDOP ? 0 : gps.hdop());
  }
  
  gps.stats(&chars, &sentences, &failed);
  Serial.print(" CHARS=");
  Serial.print(chars);
  Serial.print(" SENTENCES=");
  Serial.print(sentences);
  Serial.print(" CSUM ERR=");
  Serial.println(failed);

But I need to use hardware serial on a MEGA 2560.

tia

Does anyone know how to use the TinyGPS library (version 12 currently) with hardware serial, instead of software serial?

TinyGPS doesn't care where you get the data.

    while (ss.available())
    {
      char c = ss.read();
      // Serial.write(c); // uncomment this line if you want to see the GPS data flowing
      if (gps.encode(c)) // Did a new valid sentence come in?
        newData = true;
    }

Change ss to Serial, to get data from the hardware serial port, instead.

Ok, that doesn't make much sense to me. As I understand it, one has to specify which Serial port to use on the MEGA 2560. In this case I have the "Adafriut Ultimate GPS Breakout V3" TX and TX pins connected to the MEGA's Serial2 (i.e. pins 16 & 17)

Changing the "ss" part in that sketch to "Serial2" didn't give any GPS data on the Serial Monitor.

This is what I get:

Simple TinyGPS library v. 12
by Mikal Hart

CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0

RudiAhlers:
Ok, that doesn't make much sense to me. As I understand it, one has to specify which Serial port to use on the MEGA 2560. In this case I have the "Adafriut Ultimate GPS Breakout V3" TX and TX pins connected to the MEGA's Serial2 (i.e. pins 16 & 17)

Changing the "ss" part in that sketch to "Serial2" didn't give any GPS data on the Serial Monitor.

This is what I get:

Simple TinyGPS library v. 12
by Mikal Hart

CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0
CHARS=0 SENTENCES=0 CSUM ERR=0

Since the last thread dealing with TinyGPS, I did some checking. If you look at the support site for TinyGPS (TinyGPS | Arduiniana) you should see this:

Feed the object serial NMEA data one character at a time using the encode() method. (TinyGPS does not handle retrieving serial data from a GPS unit.) When encode() returns “true”, a valid sentence has just changed the TinyGPS object’s internal state.

So, like PaulS stated, TinyGPS doesn't care where the data comes from, and doesn't communicate with any external device. Feed it one character at a time with .encode() and once it has a full sentence it will let you know and have parsed data available. (As long, of course, if it is a recognized sentence and the sentence structure is valid...)

So, just receive the data by what ever communication method is appropriate (hardware UART, SoftwareSerial, Wire, I2C, SPI, etc) and feed the data to TinyGPS.

Thanx, I understand what you're saying (and what PaulS said), but how do I configure the Arduino to get the data in on pins 16 & 17?

Looking at other GPS libraries, I see some use "Adafruit_GPS GPS(&Serial2);" to tell the Arduino where the GPS data comes from.

I'm using a SIM900 GSM shield on Serial1, and had to "hard code" the Serial1 interface in the GSM.cpp file. The developer has given some clear instructions on how to do that, but I can't figure out how to do something similar with TinyGPS.

I'm using a MEGA 2560, with a Adafruit Ultimate GPS breakout V3 on Serial2, and a IComsat GMS shield on Serial1

RudiAhlers:
Thanx, I understand what you're saying (and what PaulS said), but how do I configure the Arduino to get the data in on pins 16 & 17?

I'm not trying to be unkind, but I don't think you are understanding what PaulS and I are saying. I don't have a Mega, but aren't pins 16 & 17 Serial2? Access Serial2 just like any other serial device.

Looking at other GPS libraries, I see some use "Adafruit_GPS GPS(&Serial2);" to tell the Arduino where the GPS data comes from.

But the difference here is TinyGPS doesn't access any external ports. You have to do that yourself in your code. So you would do a Serial2.read() to a buffer variable (datatype char or larger) and then pass that variable to TinyGPS's method .encode(). Keep doing this until the .encode() method returns a true. You have to do the communication with the GPS device yourself in your sketch. I suppose you could skip the buffer variable entirely by putting the serial read inside the method, but then it would probably be best to use a flag variable for the return of the encode method.

Something like (untested code here, I have neither a Mega nor a GPS shield):

#include <TinyGPS.h>
TinyGPS gps;
boolean validGPS = false;

void setup()
{
  Serial2.begin(9600); // or what ever the GPS's baudrate is
}

void loop()
{
  if (Serial2.available())
  {
    validGPS = gps.encode(Serial2.read());
  }
  if (validGPS)
  {
    // TinyGPS has told us we have received a valid GPS fix. We can now query it for position/course/time/etc. information.
  }
}

Note, even with a good GPS fix, it will take several loops through loop() to fetch a full NMEA sentence. This is good because it allows the sketch to do OtherThingstm while it waits for GPS fix. An example of non-blocking code. :wink:

I'm using a SIM900 GSM shield on Serial1, and had to "hard code" the Serial1 interface in the GSM.cpp file. The developer has given some clear instructions on how to do that, but I can't figure out how to do something similar with TinyGPS.

I'm using a MEGA 2560, with a Adafruit Ultimate GPS breakout V3 on Serial2, and a IComsat GMS shield on Serial1

As long as the GPS unit on the Adafruit breakout sends standard $GPRMC and/or $GPGGA sentences, it should work with TinyGPS. (I expect that it does, but may need some configuration first. I really don't know it's default state.)

Don't forget to test where the GPS can actually get a fix. TinyGPS ignores NMEA sentences that don't indicate a fix. (i.e. even if the NMEA sentence is properly formed, if the GPS is reporting in those sentences that there is no GPS fix then TinyGPS will ignore that sentence. If it's important to your project, don't forget to keep an eye on fix_age.

You would have to clear the validGPS flag. Wouldn't this be easier?

void setup()
{
  Serial2.begin(9600); // or what ever the GPS's baudrate is
}

void loop()
  {
  if (Serial2.available())
    {
    if (gps.encode(Serial2.read()))
      {
      // TinyGPS has told us we have received a valid GPS fix. We can now query it for position/course/time/etc. information.
      }  // end of complete sentence parsed
    }    // end of serial data available
  }  // end of loop

Quite valid. It all depends on application and programming style.

If he only needs one fix it doesn't matter. If stale GPS data is an issue, he can capture the value of fix_age from any of the methods that support it and if the fix_age is older than he wants then he can clear the validGPS flag (or set a new staleGPS flag). If the GPS is continually maintaining a good fix then all his GPS positioning information will be updated every second automatically (as far as his sketch is concerned). All those details are really best decided with his application.

From the TinyGPS website:

To test whether the data returned is stale, examine the (optional) parameter “fix_age” which returns the number of milliseconds since the data was encoded.

The way I read the library code, each time you call encode() you get back true or false. If true, the last character you supplied resulted in a valid fix. Then next time through the loop it won't be valid (it only just started a new sentence) and thus it will be false again. So when you get true you get "new information" when you get back false it is "nothing ready yet".

There is another issue it can take up to 10 minutes depending on location, GPS doesn't work indoors as well as outside with a clear view of the sky. It can take as much as 10 minutes to update the ephemeris in the GPS receiver so seeing no data usually means not enough data yet for a position fix . I use GPS receivers for time standards in several of my projects along with the Time Library... The TimeGPS sketch doesn't work though. I had a friend re-write it so that it works
Mikal Harts TinyGPS12 has a sketch called test_with_gps_device.pde and I've attached it. I didn't make the changes for a Mega's serial ports however. It is really trivial. The sketch works well and was a big part of the re-written TimeGPS sketch. I know the sketch works, I've used it many times in learning about GPS receivers. I also added a windows program that will display GPS data from a GPS receiver connected to a computer via an USB to TTL serial adapter.
The U-Center software is available as a free download from the U-Blox website and it's data display is really interesting. Also to give you an idea of how well your device is working.

Doc

test_with_gps_device.txt (4.77 KB)

u-centerSetup-6.3.1.0.exe (3.4 MB)

Hey, thanx. I should have realized that. But, for one run through of loop there will be valid data.

Good point. I'll have to rethink.

Sembazuru:

[quote author=Nick Gammon link=topic=174454.msg1295695#msg1295695 date=1372392589]
The way I read the library code, each time you call encode() you get back true or false. If true, the last character you supplied resulted in a valid fix. Then next time through the loop it won't be valid (it only just started a new sentence) and thus it will be false again. So when you get true you get "new information" when you get back false it is "nothing ready yet".

Hey, thanx. I should have realized that. But, for one run through of loop there will be valid data.

Good point. I'll have to rethink.
[/quote]

Actually, thinking about it, after one epoch (may be several sentences, depending on the configuration of the GPS) is read in, there will most likely be some quiet time from the GPS until the next sentence is started. That quiet time from the GPS will result in quite a few iterations through loop() where the flag will continue to be true. (It doesn't try to send anything to .encode() unless there is something available on the serial port.)

It would be an interesting experiment to pretend like the Serial Monitor is a GPS and feed it valid sentences (I've got a megabytes of them lying around my HDD from GPS testing at work), seeing if the return from .encode() goes back to false on subsequent sentences after 1 good one. Unfortunately I'm in the middle of a move and both my UNOs are packed. I probably wouldn't be able to run this test until after the 4th (and maybe not until the week after depending on how long it takes to unpack).

I don't think so, although I haven't tested it.

The thing that triggers the "line complete" (eg. newline character) means that it resets its internal state to "start of new line". It doesn't require a new (additional) character to do that, just the final one from the old line.

Docedison:
There is another issue it can take up to 10 minutes depending on location, GPS doesn't work indoors as well as outside with a clear view of the sky. It can take as much as 10 minutes to update the ephemeris in the GPS receiver so seeing no data usually means not enough data yet for a position fix .

Such is the expected effect of working with GPS devices. Most modern GPSs will hold on to the ephemeris data until it expires, and continually refreshes it while in operation. So, once you get one good fix, reacquisition is relatively quick unless the GPS has been off for a while or has moved several miles while off. (I forget off the top of my head how long and/or how far the limits are while off. Could be different depending on the GPS device.) That said, I haven't looked at the datasheet for the AdaFruit Ultimate GPS to see how it handles reacquisition on bootup.

I use GPS receivers for time standards in several of my projects along with the Time Library... The TimeGPS sketch doesn't work though. I had a friend re-write it so that it works
Mikal Harts TinyGPS12 has a sketch called test_with_gps_device.pde and I've attached it. I didn't make the changes for a Mega's serial ports however. It is really trivial. The sketch works well and was a big part of the re-written TimeGPS sketch. I know the sketch works, I've used it many times in learning about GPS receivers. I also added a windows program that will display GPS data from a GPS receiver connected to a computer via an USB to TTL serial adapter.
The U-Center software is available as a free download from the U-Blox website and it's data display is really interesting. Also to give you an idea of how well your device is working.

Doc

Nifty, I'll have to check out that windows program at some point. I'll see how it compares to Ashtech Evaluate.

Sembazuru:

RudiAhlers:
Thanx, I understand what you're saying (and what PaulS said), but how do I configure the Arduino to get the data in on pins 16 & 17?

I'm not trying to be unkind, but I don't think you are understanding what PaulS and I are saying. I don't have a Mega, but aren't pins 16 & 17 Serial2? Access Serial2 just like any other serial device.

Looking at other GPS libraries, I see some use "Adafruit_GPS GPS(&Serial2);" to tell the Arduino where the GPS data comes from.

But the difference here is TinyGPS doesn't access any external ports. You have to do that yourself in your code. So you would do a Serial2.read() to a buffer variable (datatype char or larger) and then pass that variable to TinyGPS's method .encode(). Keep doing this until the .encode() method returns a true. You have to do the communication with the GPS device yourself in your sketch. I suppose you could skip the buffer variable entirely by putting the serial read inside the method, but then it would probably be best to use a flag variable for the return of the encode method.

Something like (untested code here, I have neither a Mega nor a GPS shield):

#include <TinyGPS.h>

TinyGPS gps;
boolean validGPS = false;

void setup()
{
  Serial2.begin(9600); // or what ever the GPS's baudrate is
}

void loop()
{
  if (Serial2.available())
  {
    validGPS = gps.encode(Serial2.read());
  }
  if (validGPS)
  {
    // TinyGPS has told us we have received a valid GPS fix. We can now query it for position/course/time/etc. information.
  }
}




Note, even with a good GPS fix, it will take several loops through loop() to fetch a full NMEA sentence. This is good because it allows the sketch to do OtherThings<sup>tm</sup> while it waits for GPS fix. An example of non-blocking code. ;)



> I'm using a SIM900 GSM shield on Serial1, and had to "hard code" the Serial1 interface in the GSM.cpp file. The developer has given some clear instructions on how to do that, but I can't figure out how to do something similar with TinyGPS. 
> 
> I'm using a MEGA 2560, with a Adafruit Ultimate GPS breakout V3 on Serial2, and a IComsat GMS shield on Serial1



As long as the GPS unit on the Adafruit breakout sends standard $GPRMC and/or $GPGGA sentences, it should work with TinyGPS. (I expect that it does, but may need some configuration first. I really don't know it's default state.)

Don't forget to test where the GPS can actually get a fix. TinyGPS ignores NMEA sentences that don't indicate a fix. (i.e. even if the NMEA sentence is properly formed, if the GPS is reporting in those sentences that there is no GPS fix then TinyGPS will ignore that sentence. If it's important to your project, don't forget to keep an eye on fix_age.

Thank you. I suspect there's a problem somewhere but don't yet know what / where. As a test, I connected the GPS (Adafruit Ultimate GPS Breakout - 66 channel w/10 Hz updates [PA1616S] : ID 746 : $29.95 : Adafruit Industries, Unique & fun DIY electronics and kits) to an Arduino NANO, on ports RX0 and TX0, and also 2 & 3 (D2 & D3?), and tried the sample code from the TinyGPS V12 zip file.
This didn't give me any output on the Serial Monitor either.

There's an "Active Antenna" (GPS Antenna - External Active Antenna - 3-5V 28dB 5 Meter SMA : ID 960 : $19.95 : Adafruit Industries, Unique & fun DIY electronics and kits) connected to it which is outside, and has been outside for a few days now. The backup battery is also in place.

The following sketch does give some output, but there's no output when trying the TinyGPS examples.

void setup(){}
void loop(){}

Here's the output from the Serial Monitor:

$GPRMC,082757.000,A,2615.xx40,S,02819.xx56,E,0.01,205.46,xx0613,,,A78
$GPRMC,082758.000,A,2615.xx40,S,02819.xx56,E,0.00,205.46,xx0613,,,A
76
$GPRMC,082759.000,A,2615.xx40,S,02819.xx56,E,0.02,205.46,xx0613,,,A75
$GPRMC,082800.000,A,2615.xx40,S,02819.xx56,E,0.01,205.46,xx0613,,,A
75
$GPRMC,082801.000,A,2615.xx40,S,02819.xx56,E,0.01,205.46,xx0613,,,A*74

P.S. I put the "xx" in for privacy reasons.

Docedison:
There is another issue it can take up to 10 minutes depending on location, GPS doesn't work indoors as well as outside with a clear view of the sky. It can take as much as 10 minutes to update the ephemeris in the GPS receiver so seeing no data usually means not enough data yet for a position fix . I use GPS receivers for time standards in several of my projects along with the Time Library... The TimeGPS sketch doesn't work though. I had a friend re-write it so that it works
Mikal Harts TinyGPS12 has a sketch called test_with_gps_device.pde and I've attached it. I didn't make the changes for a Mega's serial ports however. It is really trivial. The sketch works well and was a big part of the re-written TimeGPS sketch. I know the sketch works, I've used it many times in learning about GPS receivers. I also added a windows program that will display GPS data from a GPS receiver connected to a computer via an USB to TTL serial adapter.
The U-Center software is available as a free download from the U-Blox website and it's data display is really interesting. Also to give you an idea of how well your device is working.

Doc

I ran the attached sketch, modified to use Pins 10 & 11 (with Softserial) for about 40 minutes now and still don't get any GPS data on the Serial Monitor.
The "Fix" LED blinks very slowly, which means it has a fix (according to the documentation).

This is the output on the Serial Monitor:

**** **** ******* ******* **** ******* ******* **** ******* ****** ***** *** 0 0.00 *** 90138 0 3003
**** **** ******* ******* **** ******* ******* **** ******* ****** ***** *** 0 0.00 *** 90197 0 3091
**** **** ******* ******* **** ******* ******* **** ******* ****** ***** *** 0 0.00 *** 90255 0 3179
**** **** ******* ******* **** ******* ******* **** ******* ****** ***** *** 0 0.00 *** 90313 0 3255
**** **** ******* ******* **** ******* ******* **** ******* ****** ***** *** 0 0.00 *** 90372 0 3325
**** **** ******* ******* **** ******* ******* **** ******* ****** ***** *** 0 0.00 *** 90430 0 3401
**** **** ******* ******* **** ******* ******* **** ******* ****** ***** *** 0 0.00 *** 90489 0 3494

I ran the attached sketch, modified to use Pins 10 & 11 (with Softserial) for about 40 minutes now and still don't get any GPS data on the Serial Monitor.

Post a picture of how the GPS IS connected.

Stop using SoftwareSerial when you have 4 hardware serial ports on the Mega.

SoftwareSerial was also a cause for consternation in my project as well as it Will drop or mangle a character once in a while. When I switched to a Mega most problems went away. Is it possible that you have RX connected to RX and TX connected to...? That will also give you the results you report. GPS_RX must connect to Mega_TX and GPS_TX must connect to Mega_RX. Where Mega_RX is serial1,2,3 same for TX.
There is a serial0 but that is also the data connection to the usb converter and as such restricted to talking to the serial monitor or programming via the bootloader.
If you need it I can modify the two or three places where serial is mentioned in the sketch I did and enclosed it. It's untested both my Mega's are busy but the changes are just to assign serial data to a specific hardware port instead of an object.
One last thing, Verify both GPS connections and speed. The Ucenter thing comes with instructions, You can get them from the U-Blox webpage.

Doc

Mega_test_with_gps_device.ino (5.22 KB)

PaulS:

I ran the attached sketch, modified to use Pins 10 & 11 (with Softserial) for about 40 minutes now and still don't get any GPS data on the Serial Monitor.

Post a picture of how the GPS IS connected.

Stop using SoftwareSerial when you have 4 hardware serial ports on the Mega.

I'm trying to simplify things to make sure the GPS is working and responding properly. Right now I have the GPS connected to a NANO, with the GPS's RX going to D3 and TX going to D2, using the following sketch:

#include <SoftwareSerial.h>

#include <TinyGPS.h>

/* This sample code demonstrates the normal use of a TinyGPS object.
 It requires the use of SoftwareSerial, and assumes that you have a
 4800-baud serial GPS device hooked up on pins 3(rx) and 4(tx).
 */

TinyGPS gps;
SoftwareSerial nss(2, 3);

static void gpsdump(TinyGPS &gps);
static bool feedgps();
static void print_float(float val, float invalid, int len, int prec);
static void print_int(unsigned long val, unsigned long invalid, int len);
static void print_date(TinyGPS &gps);
static void print_str(const char *str, int len);

void setup()
{
  Serial.begin(115200);
  nss.begin(4800);

  Serial.print("Testing TinyGPS library v. "); 
  Serial.println(TinyGPS::library_version());
  Serial.println("by Mikal Hart");
  Serial.println();
  Serial.print("Sizeof(gpsobject) = "); 
  Serial.println(sizeof(TinyGPS));
  Serial.println();
  Serial.println("Sats HDOP Latitude Longitude Fix  Date       Time       Date Alt     Course Speed Card  Distance Course Card  Chars Sentences Checksum");
  Serial.println("          (deg)    (deg)     Age                        Age  (m)     --- from GPS ----  ---- to London  ----  RX    RX        Fail");
  Serial.println("--------------------------------------------------------------------------------------------------------------------------------------");
}

void loop()
{
  bool newdata = false;
  unsigned long start = millis();

  // Every second we print an update
  while (millis() - start < 1000)
  {
    if (feedgps())
      newdata = true;
  }

  gpsdump(gps);
}

static void gpsdump(TinyGPS &gps)
{
  float flat, flon;
  unsigned long age, date, time, chars = 0;
  unsigned short sentences = 0, failed = 0;
  static const float LONDON_LAT = 51.508131, LONDON_LON = -0.128002;

  print_int(gps.satellites(), TinyGPS::GPS_INVALID_SATELLITES, 5);
  print_int(gps.hdop(), TinyGPS::GPS_INVALID_HDOP, 5);
  gps.f_get_position(&flat, &flon, &age);
  print_float(flat, TinyGPS::GPS_INVALID_F_ANGLE, 9, 5);
  print_float(flon, TinyGPS::GPS_INVALID_F_ANGLE, 10, 5);
  print_int(age, TinyGPS::GPS_INVALID_AGE, 5);

  print_date(gps);

  print_float(gps.f_altitude(), TinyGPS::GPS_INVALID_F_ALTITUDE, 8, 2);
  print_float(gps.f_course(), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
  print_float(gps.f_speed_kmph(), TinyGPS::GPS_INVALID_F_SPEED, 6, 2);
  print_str(gps.f_course() == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(gps.f_course()), 6);
  print_int(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0UL : (unsigned long)TinyGPS::distance_between(flat, flon, LONDON_LAT, LONDON_LON) / 1000, 0xFFFFFFFF, 9);
  print_float(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : TinyGPS::course_to(flat, flon, 51.508131, -0.128002), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
  print_str(flat == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(TinyGPS::course_to(flat, flon, LONDON_LAT, LONDON_LON)), 6);

  gps.stats(&chars, &sentences, &failed);
  print_int(chars, 0xFFFFFFFF, 6);
  print_int(sentences, 0xFFFFFFFF, 10);
  print_int(failed, 0xFFFFFFFF, 9);
  Serial.println();
}

static void print_int(unsigned long val, unsigned long invalid, int len)
{
  char sz[32];
  if (val == invalid)
    strcpy(sz, "*******");
  else
    sprintf(sz, "%ld", val);
  sz[len] = 0;
  for (int i=strlen(sz); i<len; ++i)
    sz[i] = ' ';
  if (len > 0) 
    sz[len-1] = ' ';
  Serial.print(sz);
  feedgps();
}

static void print_float(float val, float invalid, int len, int prec)
{
  char sz[32];
  if (val == invalid)
  {
    strcpy(sz, "*******");
    sz[len] = 0;
    if (len > 0) 
      sz[len-1] = ' ';
    for (int i=7; i<len; ++i)
      sz[i] = ' ';
    Serial.print(sz);
  }
  else
  {
    Serial.print(val, prec);
    int vi = abs((int)val);
    int flen = prec + (val < 0.0 ? 2 : 1);
    flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
    for (int i=flen; i<len; ++i)
      Serial.print(" ");
  }
  feedgps();
}

static void print_date(TinyGPS &gps)
{
  int year;
  byte month, day, hour, minute, second, hundredths;
  unsigned long age;
  gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
  if (age == TinyGPS::GPS_INVALID_AGE)
    Serial.print("*******    *******    ");
  else
  {
    char sz[32];
    sprintf(sz, "%02d/%02d/%02d %02d:%02d:%02d   ",
    month, day, year, hour, minute, second);
    Serial.print(sz);
  }
  print_int(age, TinyGPS::GPS_INVALID_AGE, 5);
  feedgps();
}

static void print_str(const char *str, int len)
{
  int slen = strlen(str);
  for (int i=0; i<len; ++i)
    Serial.print(i<slen ? str[i] : ' ');
  feedgps();
}

static bool feedgps()
{
  while (nss.available())
  {
    if (gps.encode(nss.read()))
      return true;
  }
  return false;
}

The output is still the same:

**** **** ******* ******* **** ******* ******* **** ******* ****** ***** *** 0 0.00 *** 4374 0 715
**** **** ******* ******* **** ******* ******* **** ******* ****** ***** *** 0 0.00 *** 4455 0 728
**** **** ******* ******* **** ******* ******* **** ******* ****** ***** *** 0 0.00 *** 4536 0 741
**** **** ******* ******* **** ******* ******* **** ******* ****** ***** *** 0 0.00 *** 4617 0 753
**** **** ******* ******* **** ******* ******* **** ******* ****** ***** *** 0 0.00 *** 4698 0 767
**** **** ******* ******* **** ******* ******* **** ******* ****** ***** *** 0 0.00 *** 4779 0 781
**** **** ******* ******* **** ******* ******* **** ******* ****** ***** *** 0 0.00 *** 4860 0 795
**** **** ******* ******* **** ******* ******* **** ******* ****** ***** *** 0 0.00 *** 4941 0 810
**** **** ******* ******* **** ******* ******* **** ******* ****** ***** *** 0 0.00 *** 5022 0 825

Swapping the RX & TX pins around doesn't help either.

I'm trying to simplify things to make sure the GPS is working and responding properly. Right now I have the GPS connected to a NANO, with the GPS's RX going to D3 and TX going to D2, using the following sketch:

Possibly a dumb question, but you also connected ground, right?