SlashDevin / NeoGPS

NMEA and ublox GPS parser for Arduino, configurable to use as few as 10 bytes of RAM
GNU General Public License v3.0
707 stars 195 forks source link

ESP32 HardwareSerial: Cannot receive any GPS data: Seems that gpsPort is flushed with gps.available() #110

Open AlexZibin opened 5 years ago

AlexZibin commented 5 years ago

All your library examples work fine on Arduino Nano; thank you for your great job!

But when I upload the sample code to ESP32 Dev Module, gps.available( gpsPort ) always returns false - simply saying, the code didn't work as expected. The same ESP32 hardware works fine with examples - so I tried to find the reason in NMEAGPS.cpp, put some debugprints there, but didn't catch the bug.

Here is the sample code:

#define GPSport_h
#include <NMEAGPS.h>
NMEAGPS gps;
gps_fix fix;

#define DEBUG_PORT  Serial
#define gpsPort     Serial2
#define RXD2        16
#define TXD2        17

void setup() {
    Serial.begin(115200);
    while (!Serial) {
        ;
    }

    gpsPort.begin(9600, SERIAL_8N1, RXD2, TXD2);
}

void loop() { 

#define THIS_WORKS_FINE
#ifdef  THIS_WORKS_FINE    
    while (gpsPort.available()) {
        DEBUG_PORT.print(char(gpsPort.read())); // This branch prints out all GPS data as expected
    }
#else        
    if (gps.available( gpsPort )) {
        DEBUG_PORT.println ("This branch never happens :(");
        fix = gps.read();

    } else {
        DEBUG_PORT.println ("We always get here: gps.available( gpsPort ) == false");
        while (gpsPort.available()) {
            DEBUG_PORT.print(char(gpsPort.read()));
            DEBUG_PORT.println ("This branch ALSO never happens :("); // Seems that gpsPort if flushed with gps.available()
            DEBUG_PORT.print(' ');
        }
        DEBUG_PORT.println ();
        delay(500);
    }
    if (fix.valid.location ) {
    }
#endif    
}

Please help to find the solution :)

Vorms commented 5 years ago

Hello, I am interested to use your library with ESP32. Can you tell me if you find a workarround ? Best regards Thierry

AlexZibin commented 5 years ago

Currently using another library; awaiting help from the community ))

Vorms commented 5 years ago

I use the gpstiny library... And you ?

AlexZibin commented 5 years ago

I tried ada, it works. But NeoGPS seems to be the most smart one - just need some bugfixes for ESP32.

mattogodoy commented 5 years ago

Also interested in making it work with ESP32!

AlexZibin commented 5 years ago

Also still interested in it. Still hope the developer will answer us.

mattogodoy commented 5 years ago

Invoking @SlashDevin Any ideas of why is this happening?

AlexZibin commented 5 years ago

Need to dig deep into library source files.

cyberman54 commented 5 years ago

@AlexZibin @Vorms I cannot confirm this in general for ESP32. I'm using hardware Serial on a ESP32 board and it works with NeoGPS:

#define GPSport_h
#define DEBUG_PORT Serial

NMEAGPS gps;
gps_fix fix;

HardwareSerial GPS_Serial(1); // use UART #1
#define gpsPort GPS_Serial(1)
#define GPS_PORT_NAME "GPS_Serial 1"

GPS_Serial.begin(9600, SERIAL_8N1, GPIO_NUM_12, GPIO_NUM_15);

while (gps.available(GPS_Serial))
        fix = gps.read();
AlexZibin commented 5 years ago

@cyberman54 I tested your example on my board (just fixed typo in your line 8), but nothing changed. I will try on different ESP32 board and report results later.

cyberman54 commented 5 years ago

@AlexZibin Where is the typo? i c&p'ed this from the running example, here it works.

AlexZibin commented 5 years ago

@cyberman54 #define gpsPort GPS_Serial(1) didn't compile; so I changed it to #define gpsPort GPS_Serial

AlexZibin commented 5 years ago

Just tried this code on bare ESP32-WROOM-32 chip with the same (bad) results.

timothy3001 commented 5 years ago

Any news on this?

AlexZibin commented 5 years ago

No news at all. I keep using another lib for ESP32.

rob4226 commented 5 years ago

I have the same issue on my ESP32 with HardwareSerial ports and the provided example programs!! FYI I am familiar with using this library successfully on Arduino's. I found when I unplug the GPS modules VCC power line and then plug it right back in the gps.available() & fix.read() finally returns one or two results then goes back to not returning anything after that. The same code works ok on an Arudino Nano but with the ESP32 I can't get the the code below to return any data either. I tried using all three of the UART ports but none work like it should (aside from my trick of unpluging and repluging in the power of the GPS module which returns one or two GPS results). I know the GPS is transmitting every second on the TX line because I can see LED attached to the RX pin on my ESP32 dev port and also the GPS outputs valid GPS sentence data when tested with a simple program on the same ESP32 board. Any ideas on why this doesn't work?? Thanks.

while (gps.available())
        fix = gps.read();
rob4226 commented 5 years ago

Ok, I figured it out! Hopefully, this will help someone...Some GPS's like the Neo 6M series and also the one I am using right now that says "16E TTL from DIYmalls.com" on the label are u-blox based GPS's and use a different command prefix to configure them. Ublox NEO-6 and similar chips use "$PUBX" and other MTK chips use "$PMTK" commands. It seems like most of the examples use "$PMTK" commands but I know there is a ublox folder also but seems complicated for casual users.

Anyway the real problem of why the gps.available(gpsPort) doesn't ever return true in some situations is that by default, GPS chips like the NEO-6M, 16E TTL and other GPS modules output RMC, VTG, GGA, GSA, GSV, GLL messages once a second (these are standard NMEA messages)...and for whatever reason, it screws up the gps.available(gpsPort) function. I'm not sure why but when all 6 default NMEA sentences are output by this GPS module the gps.available(gpsPort) function never returns true, so the while loop it controls never gets executed. (most likely due to some NeoGPS library configuration options I guess). This is why when I unplugged my GPS module and quickly put it right back in, the gps.available(gpsPort) would return true once and only once because it would catch the GPS midway though outputting the entire set of 6 default NMEA sentences.

The easiest way I found to fix this is at setup(), send commands to shut off all the default NMEA sentences except the one(s) you need. The below code shuts all default off except the RMC sentence which is like the minimum amount of useful GPS information. One I discovered to used "$PUBX" as the command prefix and to shut off some of the default output of the GPS module, the NeoGPS library's gps.available(gpsPort) and the while loop it controls finally worked fine! Here is a small sketch that is a good starting point if you run into this situation and are using an ESP32 or any board using a HardwareSerial UART interface connecting the GPS module to the board...

/**
 * Rob 5/16/2019
 * Github: Rob4226
 * 
 * Basic code using U-blox based GPS module via UART 
 * using HardwareSerial and NeoGPS Arudino library to 
 * parse various NMEA sentences with ESP32 or other boards.
 * 
 * */

#include <Arduino.h>
#include <NMEAGPS.h>

//-------------------------------------------------------------------------
// Check that the config files are set up properly
#if !defined(NMEAGPS_PARSE_RMC) & \
    !defined(NMEAGPS_PARSE_GGA) & \
    !defined(NMEAGPS_PARSE_GLL)
#error You must uncomment at least one of NMEAGPS_PARSE_RMC, NMEAGPS_PARSE_GGA or NMEAGPS_PARSE_GLL in NMEAGPS_cfg.h!
#endif

#if !defined(GPS_FIX_LOCATION)
#error You must uncomment GPS_FIX_LOCATION in GPSfix_cfg.h!
#endif

#define gpsPort Serial2 //ESP32 pins 16RX, 17TX  UART02
#define GPS_PORT_NAME "ESP32_Serial2"
#define DEBUG_PORT Serial
#define BAUD_GPS 9600
#define BAUD_USB_SERIAL 115200
#define fixLEDPin 19

using namespace NeoGPS;
NMEAGPS gps;

void setup()
{
  Serial.begin(BAUD_USB_SERIAL);
  gpsPort.begin(BAUD_GPS);

  pinMode(fixLEDPin, OUTPUT);

  // Wait for USB Serial
  while (!Serial)
  {
    yield();
  }

  // By default, "16E TTL" and other U-blox GPS modules output RMC, VTG, CGA, GSA, GSV, GLL messages once a second (these are standard NMEA messages)
  // Configure the GPS to only output what is needed, like just RMC as is shown below by disabling all other default sentences.

  //gpsPort.println(F("$PUBX,40,RMC,0,0,0,0*47")); //RMC ON (Comented out to leave RMC on...uncomment this line to disable RMC)
  //delay(100);
  gpsPort.println(F("$PUBX,40,VTG,0,0,0,0*5E")); //VTG OFF
  delay(100);
  gpsPort.println(F("$PUBX,40,GGA,0,0,0,0*5A")); //GGA OFF
  delay(100);
  gpsPort.println(F("$PUBX,40,GSA,0,0,0,0*4E")); //GSA OFF
  delay(100);
  gpsPort.println(F("$PUBX,40,GSV,0,0,0,0*59")); //GSV OFF
  delay(100);
  gpsPort.println(F("$PUBX,40,GLL,0,0,0,0*5C")); //GLL OFF
  delay(100);
}

void loop()
{
  while (gps.available(gpsPort)) // basically true every second if 1Hz from GPS, only true when the GPS returns a sentence
  {
    gps_fix fix = gps.read(); // save the latest

    // Set the "fix" LED to on or off
    bool gpsWasFixed = fix.valid.status && (fix.status >= gps_fix::STATUS_STD);
    digitalWrite(fixLEDPin, gpsWasFixed);

    // When we have a valid location, print the latitude and longitude to the USB Serial terminal
    if (fix.valid.location)
    {
      DEBUG_PORT.println("The fix's location is valid!");
      DEBUG_PORT.print("     Latitude: ");
      DEBUG_PORT.println(fix.latitudeL());
      DEBUG_PORT.print("     Longitude: ");
      DEBUG_PORT.println(fix.longitudeL());
    }
  } // gps.available while loop

} // loop()
AlexZibin commented 5 years ago

Wow that's great! Thank you!

bamapookie commented 5 years ago

Did you set the last message type? I read somewhere in the code that it starts the quiet period and does the "hard work" once it knows it has received the last message. If you have all the messages on, see which one comes last and set the last message type to that one. See if that helps.

roblatour commented 4 years ago

The above workaround is not working for me using an esp32 devkit v1 board.

However, more or less the exact same code, with some changes for the rx and tx pin numbers, does work on an esp32-s2-saola-1 board.

I've tried two esp32 devkit v1 boards, with the same non-functioning results. Have quadruple checked the wiring, and have tried powering the GPS unit and the esp32 devkit v1 board separately.

Using the Arduino IDE - have tried current stable release and most current daily release.

I've been battling this for a couple of days, any other suggestions for a workaround - or ideally a fix would be helpful.

cbpdk commented 3 years ago

I have tried to connect a GPS module to an esp32 (Nodecmu esp32) using HW Serial2. This connection only worked from a cold boot, but hang up after a warm(sw) boot. Using SoftwareSerial for a second serial poert, the connection always worked.

Searching for a solution, I came across one solution in the Arduino forum.

There is an explanation included: https://forum.arduino.cc/index.php?topic=605550.0 see message #9

Here are snippets from my implementation adopted from the example code: `

include

...

define SERIAL2_RXGpio 16 //receive gpio UART2

define SERIAL2_TXGpio 17 //transmit gpio UART2

define gpsPort Serial2

define GPS_PORT_NAME "Serial2"

define DEBUG_PORT Serial

static const uint32_t GPSBaud = 9600;

...

void setup() {

//Serial2 not working correctly after .end() or warm boot gpio_matrix_out(SERIAL2_TXGpio, SIG_GPIO_OUT_IDX, false, false); pinMode(SERIAL2_TXGpio, OUTPUT); digitalWrite(SERIAL2_TXGpio, HIGH); delay(300); digitalWrite(SERIAL2_TXGpio, LOW); delay(25); digitalWrite(SERIAL2_TXGpio, HIGH); delay(25);

Serial.begin(115200); gpsPort.begin(GPSBaud);

... `

tmargot commented 2 years ago

Hopefully this may help someone, I appear to got my ESP32 Dev Kit v1 board working after hours of trying. This worked with the NMEA.INO file so far.

In GPSPort.h: I deleted everything and put:

#ifndef GPSport_h
#define GPSport_h

//           #define gpsPort Serial
             #define GPS_PORT_NAME "HardwareSerial"
             #define DEBUG_PORT Serial

#endif

In .INO file: At the top included my includes and defined my required HardwareSerial variables. In setup changed the gpsPort,begin to include the defined HardwareSerial variables.

#include <HardwareSerial.h>
#include <GPSport.h>
#define GPS_SERIAL_NUM 1
#define GPS_RX_PIN 17
#define GPS_TX_PIN 16
HardwareSerial gpsPort(GPS_SERIAL_NUM);

void setup()
{
//normal code removed for clarity - changed gpsPort.begin( 9600) to below
gpsPort.begin( 9600, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
}
R1DEN commented 1 year ago

I'm gonna provide some more input to this one. I had a project since 2019 which is working perfectly fine on my old laptop with the old version of toolchain-xtensa and framework-arduinoespressif32. The platform version in PlatformIO is 1.11.1 On my new laptop with the 5.4.0 or 6.3.2 platform version - it doesn't work. So the bug is NOT in the library itself, as it worked perfectly fine in the days it was created and maintained. Unfortunately @SlashDevin's last commit in GitHub was in 2018 so we can only guess where he's now...

I would bet there's something changed in the logic how the HW serial port is being read in the newer framework which doesn't work well with @SlashDevin's original implementation.

P.S. by the way you cannot download the necessary 2.10004.191002 version of framework-arduinoespressif32. But I have it on my laptop. In case anyone needs it I will upload it to Github