diff --git a/examples/Example16_Nanosecond_MaxOutput/Example16_Nanosecond_MaxOutput.ino b/examples/Example16_Nanosecond_MaxOutput/Example16_Nanosecond_MaxOutput.ino new file mode 100644 index 0000000..9ec5eaa --- /dev/null +++ b/examples/Example16_Nanosecond_MaxOutput/Example16_Nanosecond_MaxOutput.ino @@ -0,0 +1,105 @@ +/* + Getting time and date using Ublox commands + By: davidallenmann + SparkFun Electronics + Date: April 16th, 2019 + License: MIT. See license file for more information but you can + basically do whatever you want with this code. + + This example shows how to query a Ublox module for the current time and date. We also + turn off the NMEA output on the I2C port. This decreases the amount of I2C traffic + dramatically. + + Leave NMEA parsing behind. Now you can simply ask the module for the datums you want! + + Feel like supporting open source hardware? + Buy a board from SparkFun! + ZED-F9P RTK2: https://www.sparkfun.com/products/15136 + NEO-M8P RTK: https://www.sparkfun.com/products/15005 + SAM-M8Q: https://www.sparkfun.com/products/15106 + + Hardware Connections: + Plug a Qwiic cable into the GPS and a BlackBoard + If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425) + Open the serial monitor at 115200 baud to see the output +*/ + +#include //Needed for I2C to GPS + +#include "SparkFun_Ublox_Arduino_Library.h" //http://librarymanager/All#SparkFun_Ublox_GPS +SFE_UBLOX_GPS myGPS; + +long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to Ublox module. + +void setup() +{ + Serial.begin(500000); //Increase serial speed to maximize + while (!Serial) + ; //Wait for user to open terminal + Serial.println("SparkFun Ublox Example"); + + Wire.begin(); + Wire.setClock(400000); + + if (myGPS.begin() == false) //Connect to the Ublox module using Wire port + { + Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing.")); + while (1) + ; + } + + myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) + myGPS.saveConfiguration(); //Save the current settings to flash and BBR + + //myGPS.enableDebugging(); //Enable debug messages over Serial (default) + + myGPS.setNavigationFrequency(10); //Set output to 10 times a second + byte rate = myGPS.getNavigationFrequency(); //Get the update rate of this module + Serial.print("Current update rate:"); + Serial.println(rate); + +} + +void loop() +{ + //Query module only every second. Doing it more often will just cause I2C traffic. + //The module only responds when a new position is available + if (millis() - lastTime > 10) + { + lastTime = millis(); //Update the timer + + long latitude = myGPS.getLatitude(); + Serial.print(F("Lat: ")); + Serial.print(latitude); + + long longitude = myGPS.getLongitude(); + Serial.print(F(" Long: ")); + Serial.print(longitude); + Serial.print(F(" (degrees * 10^-7)")); + + long altitude = myGPS.getAltitude(); + Serial.print(F(" Alt: ")); + Serial.print(altitude); + Serial.print(F(" (mm)")); + + byte SIV = myGPS.getSIV(); + Serial.print(F(" SIV: ")); + Serial.print(SIV); + + Serial.print(myGPS.getYear()); + Serial.print("-"); + Serial.print(myGPS.getMonth()); + Serial.print("-"); + Serial.print(myGPS.getDay()); + Serial.print(" "); + Serial.print(myGPS.getHour()); + Serial.print(":"); + Serial.print(myGPS.getMinute()); + Serial.print(":"); + Serial.print(myGPS.getSecond()); + Serial.print("."); + Serial.print(myGPS.getNanosecond()); + + Serial.println(); + } +} diff --git a/examples/Example16_PartialSecond_MaxOutput/Example16_PartialSecond_MaxOutput.ino b/examples/Example16_PartialSecond_MaxOutput/Example16_PartialSecond_MaxOutput.ino new file mode 100644 index 0000000..49a2031 --- /dev/null +++ b/examples/Example16_PartialSecond_MaxOutput/Example16_PartialSecond_MaxOutput.ino @@ -0,0 +1,114 @@ +/* + Getting time and date using Ublox commands + By: Nathan Seidle + SparkFun Electronics + Date: April 16th, 2019 + License: MIT. See license file for more information but you can + basically do whatever you want with this code. + + This example shows how to use the Millisecond and Nanosecond output as well as increase the + I2C speed (100 to 400kHz), and serial output (115200 to 500kbps). + + Leave NMEA parsing behind. Now you can simply ask the module for the datums you want! + + Feel like supporting open source hardware? + Buy a board from SparkFun! + ZED-F9P RTK2: https://www.sparkfun.com/products/15136 + NEO-M8P RTK: https://www.sparkfun.com/products/15005 + SAM-M8Q: https://www.sparkfun.com/products/15106 + + Hardware Connections: + Plug a Qwiic cable into the GPS and a BlackBoard + If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425) + Open the serial monitor at 115200 baud to see the output +*/ + +#include //Needed for I2C to GPS + +#include "SparkFun_Ublox_Arduino_Library.h" //http://librarymanager/All#SparkFun_Ublox_GPS +SFE_UBLOX_GPS myGPS; + +long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to Ublox module. + +void setup() +{ + Serial.begin(500000); //Increase serial speed to maximize + while (!Serial) + ; //Wait for user to open terminal + Serial.println("SparkFun Ublox Example"); + + Wire.begin(); + Wire.setClock(400000); + + if (myGPS.begin() == false) //Connect to the Ublox module using Wire port + { + Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing.")); + while (1) + ; + } + + myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) + + //myGPS.enableDebugging(); //Enable debug messages over Serial (default) + + myGPS.setNavigationFrequency(10); //Set output to 10 times a second + byte rate = myGPS.getNavigationFrequency(); //Get the update rate of this module + Serial.print("Current update rate:"); + Serial.println(rate); + + myGPS.saveConfiguration(); //Save the current settings to flash and BBR + + pinMode(2, OUTPUT); //For debug capture + digitalWrite(2, HIGH); +} + +void loop() +{ + //Query module very often to get max update rate + if (millis() - lastTime > 10) + { + lastTime = millis(); //Update the timer + + long latitude = myGPS.getLatitude(); + Serial.print(F("Lat: ")); + Serial.print(latitude); + + long longitude = myGPS.getLongitude(); + Serial.print(F(" Long: ")); + Serial.print(longitude); + Serial.print(F(" (degrees * 10^-7)")); + + long altitude = myGPS.getAltitude(); + Serial.print(F(" Alt: ")); + Serial.print(altitude); + Serial.print(F(" (mm)")); + + byte SIV = myGPS.getSIV(); + Serial.print(F(" SIV: ")); + Serial.print(SIV); + + Serial.print(" "); + Serial.print(myGPS.getYear()); + Serial.print("-"); + Serial.print(myGPS.getMonth()); + Serial.print("-"); + Serial.print(myGPS.getDay()); + Serial.print(" "); + Serial.print(myGPS.getHour()); + Serial.print(":"); + Serial.print(myGPS.getMinute()); + Serial.print(":"); + Serial.print(myGPS.getSecond()); + Serial.print("."); + //Pretty print leading zeros + int mseconds = myGPS.getMillisecond(); + if(mseconds < 100) Serial.print("0"); + if(mseconds < 10) Serial.print("0"); + Serial.print(mseconds); + + Serial.print(" nanoSeconds: "); + Serial.print(myGPS.getNanosecond()); + + Serial.println(); + } +} diff --git a/keywords.txt b/keywords.txt index debd6ed..5c7b301 100644 --- a/keywords.txt +++ b/keywords.txt @@ -95,6 +95,8 @@ getDay KEYWORD2 getHour KEYWORD2 getMinute KEYWORD2 getSecond KEYWORD2 +getMillisecond KEYWORD2 +getNanosecond KEYWORD2 getHPPOSLLH KEYWORD2 getTimeOfWeek KEYWORD2 diff --git a/src/SparkFun_Ublox_Arduino_Library.cpp b/src/SparkFun_Ublox_Arduino_Library.cpp index c7f36c9..4f7495e 100644 --- a/src/SparkFun_Ublox_Arduino_Library.cpp +++ b/src/SparkFun_Ublox_Arduino_Library.cpp @@ -244,7 +244,7 @@ boolean SFE_UBLOX_GPS::checkUbloxI2C() while (bytesAvailable) { _i2cPort->beginTransmission(_gpsI2Caddress); - _i2cPort->write(0xFF); //0xFF is the register to read general NMEA data from + _i2cPort->write(0xFF); //0xFF is the register to read data from if (_i2cPort->endTransmission(false) != 0) //Send a restart command. Do not release bus. return (false); //Sensor did not ACK @@ -253,12 +253,28 @@ boolean SFE_UBLOX_GPS::checkUbloxI2C() if (bytesToRead > I2C_BUFFER_LENGTH) bytesToRead = I2C_BUFFER_LENGTH; + TRY_AGAIN: + _i2cPort->requestFrom((uint8_t)_gpsI2Caddress, (uint8_t)bytesToRead); if (_i2cPort->available()) { for (uint16_t x = 0; x < bytesToRead; x++) { - process(_i2cPort->read()); //Grab the actual character and process it + uint8_t incoming = _i2cPort->read(); //Grab the actual character + + //Check to see if the first read is 0x7F. If it is, the module is not ready + //to respond. Stop, wait, and try again + if (x == 0) + { + if (incoming == 0x7F) + { + debugPrintln("Module not ready with data"); + delay(5); //In logic analyzation, the module starting responding after 1.48ms + goto TRY_AGAIN; + } + } + + process(incoming); //Process this valid character } } else @@ -479,7 +495,9 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX) { if (_printDebug == true) { - _debugSerial->print("Received: "); + _debugSerial->print("Size: "); + _debugSerial->print(incomingUBX->len); + _debugSerial->print(" Received: "); printPacket(incomingUBX); } incomingUBX->valid = true; @@ -487,7 +505,30 @@ void SFE_UBLOX_GPS::processUBX(uint8_t incoming, ubxPacket *incomingUBX) } else { - debugPrintln("Checksum failed. Response too big?"); + if (_printDebug == true) + { + debugPrintln("Checksum failed. Response too big?"); + + digitalWrite(2, LOW); + delay(10); + digitalWrite(2, HIGH); + + _debugSerial->print("Received: "); + printPacket(incomingUBX); + + _debugSerial->print("Size: "); + _debugSerial->print(incomingUBX->len); + _debugSerial->print(" checksumA: "); + _debugSerial->print(incomingUBX->checksumA); + _debugSerial->print(" checksumB: "); + _debugSerial->print(incomingUBX->checksumB); + + _debugSerial->print(" rollingChecksumA: "); + _debugSerial->print(rollingChecksumA); + _debugSerial->print(" rollingChecksumB: "); + _debugSerial->print(rollingChecksumB); + _debugSerial->println(); + } } } else //Load this byte into the payload array @@ -529,12 +570,14 @@ void SFE_UBLOX_GPS::processUBXpacket(ubxPacket *msg) //Parse various byte fields into global vars constexpr int startingSpot = 0; //fixed value used in processUBX + gpsMillisecond = extractLong(0) % 1000; //Get last three digits of iTOW gpsYear = extractInt(4); gpsMonth = extractByte(6); gpsDay = extractByte(7); gpsHour = extractByte(8); gpsMinute = extractByte(9); gpsSecond = extractByte(10); + gpsNanosecond = extractLong(16); //Includes milliseconds fixType = extractByte(20 - startingSpot); carrierSolution = extractByte(21 - startingSpot) >> 6; //Get 6th&7th bits of this byte @@ -554,6 +597,7 @@ void SFE_UBLOX_GPS::processUBXpacket(ubxPacket *msg) moduleQueried.gpsHour = true; moduleQueried.gpsMinute = true; moduleQueried.gpsSecond = true; + moduleQueried.gpsNanosecond = true; moduleQueried.all = true; moduleQueried.longitude = true; @@ -1307,7 +1351,7 @@ uint8_t SFE_UBLOX_GPS::getMonth(uint16_t maxWait) return (gpsMonth); } -//Get the current year +//Get the current day uint8_t SFE_UBLOX_GPS::getDay(uint16_t maxWait) { if (moduleQueried.gpsDay == false) @@ -1316,7 +1360,7 @@ uint8_t SFE_UBLOX_GPS::getDay(uint16_t maxWait) return (gpsDay); } -//Get the current year +//Get the current hour uint8_t SFE_UBLOX_GPS::getHour(uint16_t maxWait) { if (moduleQueried.gpsHour == false) @@ -1325,7 +1369,7 @@ uint8_t SFE_UBLOX_GPS::getHour(uint16_t maxWait) return (gpsHour); } -//Get the current year +//Get the current minute uint8_t SFE_UBLOX_GPS::getMinute(uint16_t maxWait) { if (moduleQueried.gpsMinute == false) @@ -1334,7 +1378,7 @@ uint8_t SFE_UBLOX_GPS::getMinute(uint16_t maxWait) return (gpsMinute); } -//Get the current year +//Get the current second uint8_t SFE_UBLOX_GPS::getSecond(uint16_t maxWait) { if (moduleQueried.gpsSecond == false) @@ -1343,6 +1387,24 @@ uint8_t SFE_UBLOX_GPS::getSecond(uint16_t maxWait) return (gpsSecond); } +//Get the current millisecond +uint16_t SFE_UBLOX_GPS::getMillisecond(uint16_t maxWait) +{ + if (moduleQueried.gpsiTOW == false) + getPVT(); + moduleQueried.gpsiTOW = false; //Since we are about to give this to user, mark this data as stale + return (gpsMillisecond); +} + +//Get the current nanoseconds - includes milliseconds +int32_t SFE_UBLOX_GPS::getNanosecond(uint16_t maxWait) +{ + if (moduleQueried.gpsNanosecond == false) + getPVT(); + moduleQueried.gpsNanosecond = false; //Since we are about to give this to user, mark this data as stale + return (gpsNanosecond); +} + //Get the latest Position/Velocity/Time solution and fill all global variables boolean SFE_UBLOX_GPS::getPVT(uint16_t maxWait) { diff --git a/src/SparkFun_Ublox_Arduino_Library.h b/src/SparkFun_Ublox_Arduino_Library.h index aed420f..33440f8 100644 --- a/src/SparkFun_Ublox_Arduino_Library.h +++ b/src/SparkFun_Ublox_Arduino_Library.h @@ -71,6 +71,7 @@ //The catch-all default is 32 #define I2C_BUFFER_LENGTH 32 +//#define I2C_BUFFER_LENGTH 16 //For testing on Artemis #endif //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= @@ -169,7 +170,8 @@ const uint8_t VAL_ID_I2C_ADDRESS = 0x01; #ifndef MAX_PAYLOAD_SIZE -#define MAX_PAYLOAD_SIZE 64 //Some commands are larger than 64 bytes but this covers most +//Payload size must be big enough to cover the commands we want to get responses from +#define MAX_PAYLOAD_SIZE 128 //Increased to 128 to cover the PVT packet #endif @@ -252,6 +254,8 @@ class SFE_UBLOX_GPS uint8_t getHour(uint16_t maxWait = 250); uint8_t getMinute(uint16_t maxWait = 250); uint8_t getSecond(uint16_t maxWait = 250); + uint16_t getMillisecond(uint16_t maxWait = 250); + int32_t getNanosecond(uint16_t maxWait = 250); uint32_t getTimeOfWeek(uint16_t maxWait = 250); int32_t getHighResLatitude(uint16_t maxWait = 250); @@ -347,6 +351,8 @@ class SFE_UBLOX_GPS uint8_t gpsHour; uint8_t gpsMinute; uint8_t gpsSecond; + uint16_t gpsMillisecond; + int32_t gpsNanosecond; int32_t latitude; //Degrees * 10^-7 (more accurate than floats) int32_t longitude; //Degrees * 10^-7 (more accurate than floats) @@ -437,25 +443,27 @@ class SFE_UBLOX_GPS //depending on update rate struct { - uint16_t gpsYear : 1; - uint16_t gpsMonth : 1; - uint16_t gpsDay : 1; - uint16_t gpsHour : 1; - uint16_t gpsMinute : 1; - uint16_t gpsSecond : 1; - - uint16_t all : 1; - uint16_t longitude : 1; - uint16_t latitude : 1; - uint16_t altitude : 1; - uint16_t altitudeMSL : 1; - uint16_t SIV : 1; - uint16_t fixType : 1; - uint16_t carrierSolution : 1; - uint16_t groundSpeed : 1; - uint16_t headingOfMotion : 1; - uint16_t pDOP : 1; - uint16_t versionNumber : 1; + uint32_t gpsiTOW : 1; + uint32_t gpsYear : 1; + uint32_t gpsMonth : 1; + uint32_t gpsDay : 1; + uint32_t gpsHour : 1; + uint32_t gpsMinute : 1; + uint32_t gpsSecond : 1; + uint32_t gpsNanosecond : 1; + + uint32_t all : 1; + uint32_t longitude : 1; + uint32_t latitude : 1; + uint32_t altitude : 1; + uint32_t altitudeMSL : 1; + uint32_t SIV : 1; + uint32_t fixType : 1; + uint32_t carrierSolution : 1; + uint32_t groundSpeed : 1; + uint32_t headingOfMotion : 1; + uint32_t pDOP : 1; + uint32_t versionNumber : 1; } moduleQueried; struct