Sparkfun GNSS Library being Blocking

Hello everyone, I’m using the SAM M8Q breakout paired with a Teensy 3.2 and an MS5607 barometric pressure sensor. What I want to do is log the data from both the SAM M8Q and the MS5607.

I’ve based the SAM M8Q’s code on the get PVT callback example but it seems like getting the GNSS data is lagging the whole code by a few hundred milliseconds causing the MS5607 to go haywire.

Does anyone know how to make the Sparkfun library non-blocking so I don’t lag my code.

Thanks

Hi @moonman,

We’ve used the library to log GNSS data at 25-30Hz with no difficulty. The “automatic” message processing and callbacks make it very efficient.

Could it be your serial prints which are slowing your code down? If you are printing a lot of information, that could cause ‘blocking’.

Best wishes,

Paul

Hi Paul, that was something I thought about too, so as I mentioned before I edited the Callbacks PVT example to print only the altitude from my barometer and only the latitude from the GNSS.

But I’m noticing the same issues, any other ideas?

Thanks.

Hi @moonman,

Can you post your code somewhere and send me a link? Or attach a zip file here? I will take a quick look IF I get some spare time.

Maybe you can narrow it down by checking millis() at the start and end of critical sections of your code and printing the difference?

Are you calling checkUblox and checkCalbacks often? If you only call them occasionally, they will have a lot of data to process before they return.

Best wishes,

Paul

Hey Paul, here’s the code:-

#include <Wire.h> //Needed for I2C to GPS
#include "MS56XX.h"
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //http://librarymanager/All#SparkFun_u-blox_GNSS
SFE_UBLOX_GNSS myGNSS;
MS56XX MSXX(MS56XX_ADDR_LOW, MS5607);

// Callback: printPVTdata will be called when new NAV PVT data arrives
// See u-blox_structs.h for the full definition of UBX_NAV_PVT_data_t
//         _____  You can use any name you like for the callback. Use the same name when you call setAutoPVTcallback
//        /                  _____  This _must_ be UBX_NAV_PVT_data_t
//        |                 /               _____ You can use any name you like for the struct
//        |                 |              /
//        |                 |              |
void printPVTdata(UBX_NAV_PVT_data_t *ubxDataStruct)
{

    long latitude = ubxDataStruct->lat; // Print the latitude

}

void setup()
{
  Serial.begin(9600);
  while (!Serial); //Wait for user to open terminal
  Serial.println("SparkFun u-blox Example");

  Wire.begin();
  MSXX.begin();

  //myGNSS.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial

  if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
  {
    Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing."));
    while (1);
  }

  myGNSS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
  myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR

  myGNSS.setNavigationFrequency(4); //Produce four solutions per second

  myGNSS.setAutoPVTcallbackPtr(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata
  MSXX.configBaro(BARO_PRESS_D1_OSR_4096, BARO_TEMP_D2_OSR_4096);
}

uint32_t millis2;
void loop()
{
  MSXX.doBaro(true);
  myGNSS.checkUblox(); // Check for the arrival of new data and process it.
  myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.

  if (millis() - millis2 >= 20){
   millis2 = millis();
    Serial.println(MSXX.altitude);
  }
}

And the data is from the sensors is the same as the image from the first post. It looks like the big spikes only happen when GNSS data is read

Thanks for the help!

Hi @PaulZC, did you get some space time to take a look at my code?

Sorry - I missed the notification about your post. I’ll try and take a look tomorrow.

Best wishes,

Paul

Hi,

You are trying to read the MS56XX as fast as possible - each time you go around the loop. With OSR set to 4096, the conversion will take between 7ms and 9ms. So, if I understand your data correctly, when the GNSS produces a solution, every 0.25 seconds, the change in the MS56XX read interval produces a change in the measured pressure… Humm. I have not seen that before.

Trying to read the MS56XX as fast as possible is not a sensible thing to do. I would recommend only reading every 20ms and see if it makes a difference. Please try moving the “MSXX.doBaro(true);” inside your “if (millis() - millis2 >= 20)” loop. Does that make a difference?

Also, 9600 baud is very slow. Each “Serial.println(MSXX.altitude)” will take several ms to complete. I recommend changing that to 115200.

Good luck with your project!

Paul

Hi Paul, seems like that fixed most of it. But looks like there are still a couple altitude jumps that looks like they’re caused by the GNSS being read. The second picture is the raw data from the sensor without gnss being read, the first one is with the GNSS being read, but the data is still usable. Any idea what could be causing this? Again thank you so much for the help!

I think we already know the answer? That the MS5607 is sensitive to the read interval? If you keep the read interval constant, the pressure reading is stable. The small delay introduced by the GNSS read changes the interval and hence the pressure.

The PVT message (Position Velocity Time) is 100 bytes long. With 100kHz I2C, that will take approximately 10ms to read. The I2C read itself is ‘blocking’ - there is no way to avoid that.

Some things that might help:

You could synchronize your code carefully, so the that the GNSS read happens between two pressure samples.

You could use Serial (UART) for the GNSS connection, instead of I2C. The hardware serial receive buffer will help - multiple bytes can be received automatically in the background. The SAM-M8Q defaults to 9600 baud. The PVT message will take just over 100ms to be received. So you can still use the 4Hz navigation rate. The following example will help, but I would recommend continuing to use the callback:

https://github.com/sparkfun/SparkFun_u- … iaUart.ino

Ah. I guess you are using this library?

https://github.com/OrlandoR4/MS56XX

Looking at the library example, the doBaro method returns a Bool (Boolean). It “RETURNS TRUE IF NEW DATA IS CALCULATED”

https://github.com/OrlandoR4/MS56XX/blo … ic.cpp#L23

In your code, you do not check the return value… Maybe you should only use the pressure if doBaro returns true?

Also, I think there are some weaknesses in the way that library has been written.

One weakness is that prev_time and dt are declared as int:

https://github.com/OrlandoR4/MS56XX/blo … 56XX.h#L31

but millis() returns unsigned long. Not int. If this causes the sensor to be read when the data is not ready, erroneous data will be used in the temperature and pressure calculation.

Another possible weakness is that requestFromBaro does not check how many bytes are returned by requestFrom:

https://github.com/OrlandoR4/MS56XX/blo … XX.cpp#L16

If an I2C error happens, because the sensor conversion is not complete, doBaro will attempt to read the data regardless, even though there may be no data available:

https://github.com/OrlandoR4/MS56XX/blo … pp#L84-L86

I would recommend trying another library - or make improvements to this one.

I hope this helps!

Paul