NeoGPS - RATE and BAUD commands not working

I’ve got the code working w/o the commands on a Neo-6m and Neo-7n. Serial monitor shows the data, 1Hz and 10Hz respectively. When I enable the BAUD command, I get no serial data. When I enable the RATE command, the frequency doesn’t change. I tried 2 different formats for the commands. Chip is a Pro Mini connected via FTDI cable.

I suspect this relates to using AltSoftSerial. I’d like to keep using pins 8 & 9 because I plan on using a bluetooth device to relay serial data. I’m not sure how I can have AltSoftSerial send the serial data to the BT module via pins 8 & 9 while communicating with the GPS via Rx/Tx pins. This sort of code is still a bit mysterious to me.

Am I correct that I’d change “AltSoftSerial gpsPort” to something like “AltSoftSerial serialforbluetooth” & send serial data via “serialforbluetooth.print( fix.satellites );”?

#include <NMEAGPS.h>
#include <AltSoftSerial.h>

AltSoftSerial gpsPort; // GPS TX to pin 8, GPS RX to pin 9
NMEAGPS gps;

void setup()
{
  Serial.begin(9600);
  gpsPort.begin(9600);
//  while (!Serial)
//    ;

//  gps.send_P( &gpsPort, F("PMTK251,38400") );  // set baud rate
  gpsPort.println("$PMTK251,38400*22");         // a different method I saw on the forums
  gpsPort.flush();                              // wait for the command to go out
  delay( 100 );                                  // wait for the GPS device to change speeds
  gpsPort.end();                                // empty the input buffer, too
  gpsPort.begin( 38400 );                      // use the new baud rate
  gps.send_P( &gpsPort, F("PMTK220,200") );     // set 5Hz update rate
//  gpsPort.println("$PMTK220,500*2B");              // a different method I saw on the forums
 
  Serial.println( F("GPS Start") );  // F macro saves RAM
}

void loop()
{
  if (gps.available( gpsPort ))
  {
    //Get the latest info from the gps object which it derived from the data sent by the GPS unit
    gps_fix fix = gps.read();

    Serial.print( F("Satellite Count:") );
    if (fix.valid.satellites)
      Serial.print( fix.satellites );
    Serial.print( F("\nLatitude:") );
    if (fix.valid.location)
      Serial.print( fix.latitude(), 6 );
    Serial.print( F("\nLongitude:") );
    if (fix.valid.location)
      Serial.print( fix.longitude(), 6 );
    Serial.print( F("\nSpeed MPH:") );
    if (fix.valid.speed)
      Serial.print( fix.speed_mph() );
//    Serial.print( F("\nAltitude Meters:") );
//    if (fix.valid.altitude)
//      Serial.print( fix.altitude());
    Serial.print( F("\nHeading:") );
    if (fix.valid.heading)
      Serial.print( fix.heading() );
    Serial.print( F("\nMinutes:") );
    if (fix.valid.time){
      Serial.print(fix.dateTime.minutes);
    Serial.print( F("\nSeconds:") );
      Serial.print(fix.dateTime.seconds);
    }


    Serial.println();
  }
}

FYI the whole reason I’m doing this is because I’d prefer 5 or 10Hz for the 6m, but it’s not saving the settings from u-center for long periods. Also thanks for any ideas & help.

There is a windows based software to configure and save as default the configuration - have you tried that? then your arduino does not need to mess around with trying to set up the device every time, just connect at the right baud rate

Yes I have, but the 6m doesn't hold settings for more than 2 seconds lol. I read that it can take up to 96 hours to fully charge the backup supercap, but only takes ~2 weeks to discharge them. I'm considering either a coin cell or i2c eeprom, but hoping I can do it with software.

what hardware do you have?

Many modules do have embedded EEPROM to save configs usually
gps.png

The $PMTK commands are for the MTK chip, not the ublox NEO chip.

All ublox NEO configuration commands start with $PUBX (NMEA text commands). There are additional configuration options you can set with UBX binary commands. See the example program ubloxRate.ino for the exact character sequences and code samples. Of course, feel free to ask more specific questions!

I always recommend setting the configuration during setup, because that lets anyone else use your program without having to use u-center in the exact same way you used it for your hardware. And if the GPS module ever loses battery backup power, the sketch will still work. You can send a command the makes it “permanent”, but you should still send these commands during setup, as if it were a brand-new, unconfigured GPS module.

The ubloxRate example allows you to enter commands from the Serial Monitor window. See the comment block at the top of the INO file for the list. For example, sending “r5” will set the NEO update rate to 5Hz.

Regarding the serial ports for BT and GPS: Is it possible you could use Serial for the GPS and AltSoftSerial for the BT? That would be most reliable, but you would have to disconnect the GPS TX from the Arduino RX pin 0 to upload new sketches over USB (full description here). The Arduino TX pin 1 can remain connected to the GPS RX pin.

Arduino pin 0 ← GPS TX (Serial, disconnect to upload new sketch)
Arduino pin 1 → GPS RX (Serial,level shift required)
Arduino pin 8 ← BT TX (AltSoftSerial)
Arduino pin 9 → BT RX (AltSoftSerial)

You could still print debug messages to Serial, and they would show up on the Serial Monitor window. As long as your debug messages don’t start with a ‘$’, the GPS would ignore them. You would also see the configuration commands on the Serial Monitor window.

I should also ask if you are performing the 5V to 3.3V level shifting for the RX and TX connections (read this). Sometimes the GPS TX to Arduino RX works, but you can damage the GPS device if you connect the GPS RX to the Arduino TX with just a wire.

Am I correct that I’d change “AltSoftSerial gpsPort” to something like “AltSoftSerial serialforbluetooth” & send serial data via “serialforbluetooth.print( fix.satellites );”?

I assume that you are connecting two listeners (GPS & BT) to the same Arduino transmit pin 9. You cannot connect two transmitters to the same Arduino receive pin 8. If that’s what you’re asking, I would suggest something like this:

AltSoftSerial gpsAndBT; // pins 8 (RX) and 9 (TX)
#define gpsPort gpsAndBT    // just an alias for the one AltSoftSerial
#define btPort gpsAndBT    // another alias for the same variable

void setup()
{
  gpsPort.begin( 9600 );

  gps.send_P( &gpsPort, F("$PUBX, baud rate command") ); // also goes to BT port.  Is that OK?
  gps.flush();
  delay( 200 );
  gpsPort.begin( 38400 ); // BT must run at this rate, too.

  btPort.println( F("AT BT config commands?") );
}

void loop()
{
  if (gps.available( gpsPort )) { // reads from AltSoftSerial RX pin
    fix = gps.read();
    if (fix.valid.satellites)
      btPort.println( fix.satellites );
  }
}

As noted above, the BT would forward the GPS configuration commands, too. If you are writing the app that listens to the BT, you could watch for the $PUBX header and ignore the rest of the line.

Cheers,
/dev

hiprofile67: Yes I have, but the 6m doesn't hold settings for more than 2 seconds lol. I read that it can take up to 96 hours to fully charge the backup supercap, but only takes ~2 weeks to discharge them. I'm considering either a coin cell or i2c eeprom, but hoping I can do it with software.

You could possibly modify your GPS module to add a backup battery or I2C EEPROM - or maybe not.

So much easier to use a GPS module that has proper (working) backup built in.

And as as others have said, it makes a lot of sense if your program sets up the GPS as if new, rather than requireing setup with an external program.

-dev: Cheers, /dev

It's good to know it was just the wrong commands for this device, but I'm not quite sure what the the full working commands are. Your example ino is be coded to work with serial monitor inputs, not setup commands. I'm not sure how to go from ""PMTK251,38400" or "PMTK220,500" to "$PUBX, ?". Is it as simple as "$PUBX,r5" for 5hz and "$PUBX,3" for 38400 baud?

As far as the serial pins, I have no issues using Serial (pins D1/D0) for GPS and AltSoftSerial for BT (pins 8/9) besides me not really knowing how to change the code to do so. All arduino code I know is self-taught from various simple projects, and this is the first using the serial monitor and software serial. The BT is just for serial monitor data viewed via android, Max observed MPH and maybe 1-2 more lines of data.

Regading level shift, I'm using a voltage divider on the arduino but not with the FTDI. When I use a voltage divider with the FTDI cable it will not connect to u-center. Both ublox still function fine, both sending/receiving data with u-center and arduino. Either I'm lucky or I have a 3v3 FTDI, I never pulled the cable apart.

Also since you're here, thanks for the NeoGPS library & your thoroughness with the github page.

J-M-L: Many modules do have embedded EEPROM to save configs usually

The 6m has a chip marked "432rk, st k427", the 7n has a chip marked "ATH317, 32DM, 0P7771C" (indicating 24c32 eeprom). I have tried saving config as BRR, EEPROM, etc but the 6m doesn't hold it for more than a few seconds after losing power. The 7n accepts changes when connected via serial (ftdi), but reverts back to the settings I previously input via USB (usb micro port onboard) after losing power. The RX light on the FTDI changes frequency when I send RATE changes via FDTI serial.

Edit: one thing I noticed is the Neo-6 datasheets indicates all 6-series have USB_DP/USB_DM pins, so I think it could be possible to add full usb 2.0 connectivity to my 6m.

I really appreciate the responses, this forum is always so friendly - even with n00bs like me lol.

hiprofile67: I'm not quite sure what the the full working commands are.

Did you look at the source? You send those commands with this:

    gps.send_P( &gpsPort, (const __FlashStringHelper *) baud38400 );

This appear later in the sketch, when a "3" is received from the Serial Monitor window.

not really knowing how to change the code

    AltSoftSerial btPort; // pins 8 (RX) and 9 (TX)
    #define gpsPort Serial    // just an alias for Serial

Regarding level shift, I'm using a voltage divider on the arduino but not with the FTDI.

Good, the divider goes from the Arduino transmit pin to the GPS RX pin. You do not use a divider for the GPS TX pin to the Arduino receive pin. It may work with a direct connection, but if you are not receiving data reliably, it should look like this, or use a level-shifting module.

Unfortunately I saw that but didn’t really understand it. I’ve never been good at passing variables and jumping around code. I presume the following is the correct lines to send in Void Setup for baud?

"gps.send_P( &gpsPort, (const __FlashStringHelper *) "PUBX,41,1,3,3,38400,0" );"

The rate change is really getting me stuck. If it’s best to perform it in Setup, why make the example a stand-alone sketch running it outside of Setup?

In any case it’s looking to me like Rate must be done after Setup, at least with the code offered. I have absolutely no idea how to incorporate it into Setup w/o errors. This is what I have for variables & Setup, and it compiles fine:

#include <NMEAGPS.h>
#include <AltSoftSerial.h>

AltSoftSerial gpsPort; // GPS TX to pin 8, GPS RX to pin 9
NMEAGPS gps;
const unsigned char ubxRate5Hz[] PROGMEM =
{ 0x06,0x08,0x06,0x00,200,0x00,0x01,0x00,0x01,0x00 };
int runoncevar = 0;

void setup()
{
  Serial.begin(9600);
  gpsPort.begin(9600);
  gps.send_P( &gpsPort, (const __FlashStringHelper *) "PUBX,41,1,3,3,38400,0" );
  gpsPort.flush();                              // wait for the command to go out
  delay( 100 );                                  // wait for the GPS device to change speeds
  gpsPort.end();                                // empty the input buffer, too
  gpsPort.begin( 38400 );                      // use the new baud rate
  Serial.println( F("GPS Start") );  // F macro saves RAM
}

void loop()
{
  if (runoncevar = 0)
  {
   runoncevar++;
   sendUBX( ubxRate5Hz, sizeof(ubxRate5Hz) );    
  }
  if (gps.available( gpsPort ))
  {
    //Get the latest info from the gps object which it derived from the data sent by the GPS unit
    gps_fix fix = gps.read();

    Serial.print( F("Satellite Count:") );
    if (fix.valid.satellites)
      Serial.print( fix.satellites );
    Serial.print( F("\nLatitude:") );
    if (fix.valid.location)
      Serial.print( fix.latitude(), 6 );
    Serial.print( F("\nLongitude:") );
    if (fix.valid.location)
      Serial.print( fix.longitude(), 6 );
    Serial.print( F("\nSpeed MPH:") );
    if (fix.valid.speed)
      Serial.print( fix.speed_mph() );
//    Serial.print( F("\nAltitude Meters:") );
//    if (fix.valid.altitude)
//      Serial.print( fix.altitude());
    Serial.print( F("\nHeading:") );
    if (fix.valid.heading)
      Serial.print( fix.heading() );
    Serial.print( F("\nMinutes:") );
    if (fix.valid.time){
      Serial.print(fix.dateTime.minutes);
    Serial.print( F("\nSeconds:") );
      Serial.print(fix.dateTime.seconds);
    }
    Serial.println();
  }
}

void sendUBX( const unsigned char *progmemBytes, size_t len )
{
  gpsPort.write( 0xB5 ); // SYNC1
  gpsPort.write( 0x62 ); // SYNC2

  uint8_t a = 0, b = 0;
  while (len-- > 0) {
    uint8_t c = pgm_read_byte( progmemBytes++ );
    a += c;
    b += a;
    gpsPort.write( c );
  }

  gpsPort.write( a ); // CHECKSUM A
  gpsPort.write( b ); // CHECKSUM B

}

This is the first time I’ve ever used code with unsigned char variables and certainly the first sending them to another device, so I reeeeeeally don’t understand how to recode it for Setup. Running the void sendUBX code w/in Setup gives me “error: increment of read-only location”.

I presume the following is the correct lines to send in Void Setup for baud?

No. Was there something wrong with the code I provided?

    gps.send_P( &gpsPort, (const __FlashStringHelper *) baud38400 );

Copy the baud38400 variable declaration too:

    const char baud38400 [] PROGMEM = "PUBX,41,1,3,3,38400,0";

If it's best to perform it in Setup, why make the example a stand-alone sketch running it outside of Setup?

The example lets you try different settings. With echo on (send the 'e' command), you can see what the GPS device does in response. NeoGPS will try to parse whatever comes back, depending on the update rate and which sentences are enabled.

Once you know the settings that you want, copy those commands into your sketch and send them during setup.

it's looking to me like Rate must be done after setup

Nope.

void setup()
{
  Serial.begin(9600);
  gpsPort.begin(9600);
  gps.send_P( &gpsPort, (const __FlashStringHelper *) baud38400 );
  gpsPort.flush();                              // wait for the command to go out
  delay( 100 );                                  // wait for the GPS device to change speeds
  gpsPort.end();                                // empty the input buffer, too
  gpsPort.begin( 38400 );                      // use the new baud rate

  sendUBX( ubxRate5Hz, sizeof(ubxRate5Hz) );

  Serial.println( F("GPS Start") );  // F macro saves RAM
}

void loop()
{
  if (gps.available( gpsPort ))
  {
     ...

Sometimes (I can't figure out when), it helps to disable all the sentences before changing the baud rate or update rate:

void setup()
{
  Serial.begin(9600);
  Serial.println( F("GPS Start") );  // F macro saves RAM

  configGPS();
}

void loop()
{
  if (gps.available( gpsPort ))
  {
     ...
  }

} // loop

const uint32_t COMMAND_DELAY = 250;

void configGPS()
{
  gpsPort.begin(9600); // assume it's not configured

  // Disable all the sentences
  gps.send_P( &gpsPort, (const __FlashStringHelper *) disableRMC );
  delay( COMMAND_DELAY );
  gps.send_P( &gpsPort, (const __FlashStringHelper *) disableGLL );
  delay( COMMAND_DELAY );
  gps.send_P( &gpsPort, (const __FlashStringHelper *) disableGSV );
  delay( COMMAND_DELAY );
  gps.send_P( &gpsPort, (const __FlashStringHelper *) disableGSA );
  delay( COMMAND_DELAY );
  gps.send_P( &gpsPort, (const __FlashStringHelper *) disableGGA );
  delay( COMMAND_DELAY );
  gps.send_P( &gpsPort, (const __FlashStringHelper *) disableVTG );
  delay( COMMAND_DELAY );
  gps.send_P( &gpsPort, (const __FlashStringHelper *) disableZDA );

  // Wait a little for it to stop sending those sentences, then change the baud rate
  delay( 500 );
  gps.send_P( &gpsPort, (const __FlashStringHelper *) baud38400 );
  gpsPort.flush();
  gpsPort.end();
  delay( 500 );
  gpsPort.begin( 38400 );

  //  Now that the baud rate is faster, set the update rate
  sendUBX( ubxRate5Hz, sizeof(ubxRate5Hz) );
  delay( 200 );

  //  Then re-enable the sentences that provide the pieces you want.
  gps.send_P( &gpsPort, (const __FlashStringHelper *) enableRMC );
  delay( COMMAND_DELAY );
  gps.send_P( &gpsPort, (const __FlashStringHelper *) enableGGA );
  delay( COMMAND_DELAY );

} // changeBaud

This is just a bunch of snippets from ubloxRate.ino.

Running the void sendUBX code w/in Setup gives me "error: increment of read-only location".

That doesn't make any sense. Post the entire sketch that causes this error, and post all the error messages in a separate code block. You might have been missing a closing curly brace: '}'.

-dev:
No. Was there something wrong with the code I provided?

    gps.send_P( &gpsPort, (const __FlashStringHelper *) baud38400 );

Copy the baud38400 variable declaration too:

    const char baud38400 [] PROGMEM = "PUBX,41,1,3,3,38400,0";

The problem was I didn’t realize the first line you gave me also needed the 2nd line added to create the variable. I thought “baud38400” was the actual command, not a variable.

Regarding the rate change w/in Setup, nobody ever told me I could call functions in setup. Putting the void sendUBX code into Setup didn’t work well. Whoops.

I just tested the revised code and it works GREAT! At 5Hz and 10Hz the 6m reports centiseconds of 00/20/40/60/80, at 1Hz it shows 00 and refreshes the serial monitor only once per sec as expected.

Here’s what I’m sticking with, hopefully it helps provide other people with a shortcut along with the “NeoGPS for Dummies” provided above. :stuck_out_tongue: Thanks again -dev, you’re a great guy with great code. This will save me a lot of time dinking around with eeprom, batteries, and connecting the GPS separately.

#include <NMEAGPS.h>
#include <AltSoftSerial.h>

AltSoftSerial gpsPort; // GPS TX to pin 8, GPS RX to pin 9
NMEAGPS gps;
const unsigned char ubxRate1Hz[] PROGMEM = 
{ 0x06,0x08,0x06,0x00,0xE8,0x03,0x01,0x00,0x01,0x00 };
const unsigned char ubxRate5Hz[] PROGMEM =
{ 0x06,0x08,0x06,0x00,200,0x00,0x01,0x00,0x01,0x00 };
const unsigned char ubxRate10Hz[] PROGMEM =
{ 0x06,0x08,0x06,0x00,100,0x00,0x01,0x00,0x01,0x00 };
const char baud38400 [] PROGMEM = "PUBX,41,1,3,3,38400,0";
int runoncevar = 0;
//size_t len;
//uint8_t a = 0, b = 0;

void setup()
{
  Serial.begin(9600);
  gpsPort.begin(9600);
  gps.send_P( &gpsPort, (const __FlashStringHelper *) baud38400 );
  gpsPort.flush();                              // wait for the command to go out
  delay( 100 );                                  // wait for the GPS device to change speeds
  gpsPort.end();                                // empty the input buffer, too
  gpsPort.begin( 38400 );                      // use the new baud rate

  sendUBX( ubxRate5Hz, sizeof(ubxRate5Hz) );   // change both "ubxRate5Hz" to "ubxRate1Hz" or ubxRate10Hz" for different rates
 
  Serial.println( F("GPS Start") );  // F macro saves RAM
}

void loop()
{
//  if (runoncevar = 0)
//  {
//   runoncevar++;
//   sendUBX( ubxRate5Hz, sizeof(ubxRate5Hz) );    
//  }
  if (gps.available( gpsPort ))
  {
    //Get the latest info from the gps object which it derived from the data sent by the GPS unit
    gps_fix fix = gps.read();

    Serial.print( F("Satellite Count:") );
    if (fix.valid.satellites)
      Serial.print( fix.satellites );
    Serial.print( F("\nLatitude:") );
    if (fix.valid.location)
      Serial.print( fix.latitude(), 6 );
    Serial.print( F("\nLongitude:") );
    if (fix.valid.location)
      Serial.print( fix.longitude(), 6 );
    Serial.print( F("\nSpeed MPH:") );
    if (fix.valid.speed)
      Serial.print( fix.speed_mph() );
//    Serial.print( F("\nAltitude Meters:") );
//    if (fix.valid.altitude)
//      Serial.print( fix.altitude());
    Serial.print( F("\nHeading:") );
    if (fix.valid.heading)
      Serial.print( fix.heading() );
    if (fix.valid.time){
    Serial.print( F("\nMinutes:") );
      Serial.print(fix.dateTime.minutes);
    Serial.print( F("\nSeconds:") );
      Serial.print(fix.dateTime.seconds);
    Serial.print( F("\nCentiSeconds:") );      
      Serial.print( fix.dateTime_cs );
    }
    Serial.println();
  }
}

void sendUBX( const unsigned char *progmemBytes, size_t len )
{
  gpsPort.write( 0xB5 ); // SYNC1
  gpsPort.write( 0x62 ); // SYNC2

  uint8_t a = 0, b = 0;
  while (len-- > 0) {
    uint8_t c = pgm_read_byte( progmemBytes++ );
    a += c;
    b += a;
    gpsPort.write( c );
  }

  gpsPort.write( a ); // CHECKSUM A
  gpsPort.write( b ); // CHECKSUM B

}

Quick follow-up, I wired the parts together and it seems to be working well. I'll be adding a microSD reader for datalogging in addition to the BT for certain stats. I'm also going to include MCP9700A temp sensors for the r/c boat's motor and ESC at a later date. I'll be putting it all in a water-tight 3d printed box.

http://i.imgur.com/MSw9iOd.jpg http://i.imgur.com/ikG9yDF.png