From 2102cf2cea3216f0d511b9fa94d16e457c97db5e Mon Sep 17 00:00:00 2001 From: UT2UH Date: Mon, 21 Jun 2021 07:30:15 +0300 Subject: [PATCH 01/26] getTimeFullyResolved helper added --- .../Example24_GetUnixEpochAndMicros.ino | 6 ++++++ keywords.txt | 1 + src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 15 +++++++++++++++ src/SparkFun_u-blox_GNSS_Arduino_Library.h | 1 + 4 files changed, 23 insertions(+) diff --git a/examples/Example24_GetUnixEpochAndMicros/Example24_GetUnixEpochAndMicros.ino b/examples/Example24_GetUnixEpochAndMicros/Example24_GetUnixEpochAndMicros.ino index 2ebdc2a..8080f1a 100644 --- a/examples/Example24_GetUnixEpochAndMicros/Example24_GetUnixEpochAndMicros.ino +++ b/examples/Example24_GetUnixEpochAndMicros/Example24_GetUnixEpochAndMicros.ino @@ -91,6 +91,12 @@ void loop() Serial.print(myGNSS.getSecond()); Serial.print(" Time is "); + if (myGNSS.getTimeFullyResolved() == false) + { + Serial.print("not fully resolved but "); + } else { + Serial.print("fully resolved and "); + } if (myGNSS.getTimeValid() == false) { Serial.print("not "); diff --git a/keywords.txt b/keywords.txt index b2b7cab..3fad190 100644 --- a/keywords.txt +++ b/keywords.txt @@ -425,6 +425,7 @@ getNanosecond KEYWORD2 getUnixEpoch KEYWORD2 getDateValid KEYWORD2 getTimeValid KEYWORD2 +getTimeFullyResolved KEYWORD2 getConfirmedDate KEYWORD2 getConfirmedTime KEYWORD2 getFixType KEYWORD2 diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index bc45a0c..799a009 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -9782,6 +9782,21 @@ bool SFE_UBLOX_GNSS::getTimeValid(uint16_t maxWait) return ((bool)packetUBXNAVPVT->data.valid.bits.validTime); } +//Check to see if the UTC time has been fully resolved +bool SFE_UBLOX_GNSS::getTimeFullyResolved(uint16_t maxWait) +{ + if (packetUBXNAVPVT == NULL) initPacketUBXNAVPVT(); //Check that RAM has been allocated for the PVT data + if (packetUBXNAVPVT == NULL) //Bail if the RAM allocation failed + return (false); + + if (packetUBXNAVPVT->moduleQueried.moduleQueried1.bits.fullyResolved == false) + getPVT(maxWait); + packetUBXNAVPVT->moduleQueried.moduleQueried1.bits.fullyResolved = false; //Since we are about to give this to user, mark this data as stale + packetUBXNAVPVT->moduleQueried.moduleQueried1.bits.all = false; + return ((bool)packetUBXNAVPVT->data.valid.bits.fullyResolved); +} + + //Get the confirmed date validity bool SFE_UBLOX_GNSS:: getConfirmedDate(uint16_t maxWait) { diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index 42e72eb..b8b7e4f 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -1061,6 +1061,7 @@ class SFE_UBLOX_GNSS bool getDateValid(uint16_t maxWait = defaultMaxWait); bool getTimeValid(uint16_t maxWait = defaultMaxWait); + bool getTimeFullyResolved(uint16_t maxWait = defaultMaxWait); bool getConfirmedDate(uint16_t maxWait = defaultMaxWait); bool getConfirmedTime(uint16_t maxWait = defaultMaxWait); From 48ace0a29f460a102ada0cd666b9c7f1f784fb4a Mon Sep 17 00:00:00 2001 From: Andrew Berridge Date: Sun, 27 Jun 2021 06:00:16 +0100 Subject: [PATCH 02/26] Add support for SPI interface --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 121 +++++++++++++++++++ src/SparkFun_u-blox_GNSS_Arduino_Library.h | 18 ++- 2 files changed, 138 insertions(+), 1 deletion(-) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index bc45a0c..ae80176 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -451,6 +451,35 @@ boolean SFE_UBLOX_GNSS::begin(Stream &serialPort) return (connected); } +// Initialize for SPI +boolean SFE_UBLOX_GNSS::begin(SPIClass &spiPort, uint8_t ssPin, int spiSpeed) +{ + commType = COMM_TYPE_SPI; + _spiPort = &spiPort; + _ssPin = ssPin; + _spiSpeed = spiSpeed; + //New in v2.0: allocate memory for the packetCfg payload here - if required. (The user may have called setPacketCfgPayloadSize already) + if (packetCfgPayloadSize == 0) + setPacketCfgPayloadSize(MAX_PAYLOAD_SIZE); + Serial.println("Creating buffer"); + createFileBuffer(); + boolean connected = isConnected(); + if (!connected) + connected = isConnected(); + + if (!connected) + connected = isConnected(); + + // Initialize/clear the SPI buffer - fill it with 0xFF as this is what is received from the UBLOX module if there's no data to be processed + for (uint8_t i = 0; i < 20; i++) + { + spiBuffer[i] = 0xFF; + } + + return (connected); +} + + // Allow the user to change I2C polling wait (the minimum interval between I2C data requests - to avoid pounding the bus) // i2cPollingWait defaults to 100ms and is adjusted automatically when setNavigationFrequency() // or setHNRNavigationRate() are called. But if the user is using callbacks, it might be advantageous @@ -598,6 +627,8 @@ boolean SFE_UBLOX_GNSS::checkUbloxInternal(ubxPacket *incomingUBX, uint8_t reque return (checkUbloxI2C(incomingUBX, requestedClass, requestedID)); else if (commType == COMM_TYPE_SERIAL) return (checkUbloxSerial(incomingUBX, requestedClass, requestedID)); + else if (commType == COMM_TYPE_SPI) + return (checkUbloxSpi(incomingUBX, requestedClass, requestedID)); return false; } @@ -755,6 +786,42 @@ boolean SFE_UBLOX_GNSS::checkUbloxSerial(ubxPacket *incomingUBX, uint8_t request } //end checkUbloxSerial() + +//Checks SPI for data, passing any new bytes to process() +boolean SFE_UBLOX_GNSS::checkUbloxSpi(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) +{ + // process the contents of the SPI buffer if not empty! + uint8_t bufferByte = spiBuffer[0]; + uint8_t bufferIndex = 0; + + while (bufferByte != 0xFF) { + process(bufferByte, incomingUBX, requestedClass, requestedID); + bufferIndex++; + bufferByte = spiBuffer[bufferIndex]; + } + + // reset the contents of the SPI buffer + for(uint8_t i = 0; i < bufferIndex; i++) + { + spiBuffer[i] = 0xFF; + } + + SPISettings settingsA(_spiSpeed, MSBFIRST, SPI_MODE0); + _spiPort->beginTransaction(settingsA); + digitalWrite(_ssPin, LOW); + uint8_t byteReturned = _spiPort->transfer(0x0A); + while (byteReturned != 0xFF || currentSentence != NONE) + { + process(byteReturned, incomingUBX, requestedClass, requestedID); + byteReturned = _spiPort->transfer(0x0A); + } + digitalWrite(_ssPin, HIGH); + _spiPort->endTransaction(); + return (true); + +} //end checkUbloxSpi() + + //PRIVATE: Check if we have storage allocated for an incoming "automatic" message boolean SFE_UBLOX_GNSS::checkAutomatic(uint8_t Class, uint8_t ID) { @@ -2675,6 +2742,10 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::sendCommand(ubxPacket *outgoingUBX, uint16_t { sendSerialCommand(outgoingUBX); } + else if (commType == COMM_TYPE_SPI) + { + sendSpiCommand(outgoingUBX); + } if (maxWait > 0) { @@ -2781,6 +2852,56 @@ void SFE_UBLOX_GNSS::sendSerialCommand(ubxPacket *outgoingUBX) _serialPort->write(outgoingUBX->checksumB); } + +// Transfer a byte to SPI. Also capture any bytes received from the UBLOX device during sending and capture them in a small buffer so that +// they can be processed later with process +void SFE_UBLOX_GNSS::spiTransfer(uint8_t byteToTransfer) +{ + uint8_t returnedByte = _spiPort->transfer(byteToTransfer); + if (returnedByte != 0xFF) + { + spiBuffer[spiBufferIndex] = returnedByte; + spiBufferIndex++; + } +} + +// Send a command via SPI +void SFE_UBLOX_GNSS::sendSpiCommand(ubxPacket *outgoingUBX) +{ + SPISettings settingsA(_spiSpeed, MSBFIRST, SPI_MODE0); + _spiPort->beginTransaction(settingsA); + digitalWrite(_ssPin, LOW); + //Write header bytes + spiTransfer(UBX_SYNCH_1); //μ - oh ublox, you're funny. I will call you micro-blox from now on. + if (_printDebug) _debugSerial->printf("%x ", UBX_SYNCH_1); + spiTransfer(UBX_SYNCH_2); //b + if (_printDebug) _debugSerial->printf("%x ", UBX_SYNCH_2); + + spiTransfer(outgoingUBX->cls); + if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->cls); + spiTransfer(outgoingUBX->id); + if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->id); + spiTransfer(outgoingUBX->len & 0xFF); //LSB + if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->len & 0xFF); + spiTransfer(outgoingUBX->len >> 8); + if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->len >> 8); + + //Write payload. + for (uint16_t i = 0; i < outgoingUBX->len; i++) + { + spiTransfer(outgoingUBX->payload[i]); + if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->payload[i]); + } + + //Write checksum + spiTransfer(outgoingUBX->checksumA); + if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->checksumA); + spiTransfer(outgoingUBX->checksumB); + if (_printDebug) _debugSerial->printf("%x \n", outgoingUBX->checksumB); + digitalWrite(_ssPin, HIGH); + _spiPort->endTransaction(); +} + //Pretty prints the current ubxPacket void SFE_UBLOX_GNSS::printPacket(ubxPacket *packet, boolean alwaysPrintPayload) { diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index 42e72eb..015ba3f 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -51,6 +51,8 @@ #include +#include + #include "u-blox_config_keys.h" #include "u-blox_structs.h" @@ -560,6 +562,8 @@ class SFE_UBLOX_GNSS boolean begin(TwoWire &wirePort = Wire, uint8_t deviceAddress = 0x42); //Returns true if module is detected //serialPort needs to be perviously initialized to correct baud rate boolean begin(Stream &serialPort); //Returns true if module is detected + //SPI - supply instance of SPIClass, slave select pin and SPI speed (in Hz) + boolean begin(SPIClass &spiPort, uint8_t ssPin, int spiSpeed); void end(void); //Stop all automatic message processing. Free all used RAM @@ -612,6 +616,7 @@ class SFE_UBLOX_GNSS boolean checkUbloxI2C(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Method for I2C polling of data, passing any new bytes to process() boolean checkUbloxSerial(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Method for serial polling of data, passing any new bytes to process() + boolean checkUbloxSpi(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Method for spi polling of data, passing any new bytes to process() // Process the incoming data @@ -622,12 +627,13 @@ class SFE_UBLOX_GNSS void processUBX(uint8_t incoming, ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID); //Given a character, file it away into the uxb packet structure void processUBXpacket(ubxPacket *msg); //Once a packet has been received and validated, identify this packet's class/id and update internal flags - // Send I2C/Serial commands to the module + // Send I2C/Serial/SPI commands to the module void calcChecksum(ubxPacket *msg); //Sets the checksumA and checksumB of a given messages sfe_ublox_status_e sendCommand(ubxPacket *outgoingUBX, uint16_t maxWait = defaultMaxWait, boolean expectACKonly = false); //Given a packet and payload, send everything including CRC bytes, return true if we got a response sfe_ublox_status_e sendI2cCommand(ubxPacket *outgoingUBX, uint16_t maxWait = defaultMaxWait); void sendSerialCommand(ubxPacket *outgoingUBX); + void sendSpiCommand(ubxPacket *outgoingUBX); void printPacket(ubxPacket *packet, boolean alwaysPrintPayload = false); //Useful for debugging @@ -1235,6 +1241,9 @@ class SFE_UBLOX_GNSS //Calculate how much RAM is needed to store the payload for a given automatic message uint16_t getMaxPayloadSize(uint8_t Class, uint8_t ID); + //Do the actual transfer to SPI + void spiTransfer(uint8_t byteToTransfer); + boolean initGeofenceParams(); // Allocate RAM for currentGeofenceParams and initialize it boolean initModuleSWVersion(); // Allocate RAM for moduleSWVersion and initialize it @@ -1273,6 +1282,10 @@ class SFE_UBLOX_GNSS Stream *_nmeaOutputPort = NULL; //The user can assign an output port to print NMEA sentences if they wish Stream *_debugSerial; //The stream to send debug messages to if enabled + SPIClass *_spiPort; //The instance of SPIClass + uint8_t _ssPin; //The slave select pin + int _spiSpeed; //The speed to use for SPI (Hz) + uint8_t _gpsI2Caddress = 0x42; //Default 7-bit unshifted address of the ublox 6/7/8/M8/F9 series //This can be changed using the ublox configuration software @@ -1292,6 +1305,9 @@ class SFE_UBLOX_GNSS uint8_t *payloadCfg = NULL; uint8_t *payloadAuto = NULL; + uint8_t spiBuffer[20]; // A small buffer to store any bytes being recieved back from the device while we are sending via SPI + uint8_t spiBufferIndex = 0; // The index into the SPI buffer + //Init the packet structures and init them with pointers to the payloadAck, payloadCfg, payloadBuf and payloadAuto arrays ubxPacket packetAck = {0, 0, 0, 0, 0, payloadAck, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; ubxPacket packetBuf = {0, 0, 0, 0, 0, payloadBuf, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; From b7e90c6925c434d67d5d5887fc72dde0f1d8c091 Mon Sep 17 00:00:00 2001 From: Andrew Berridge Date: Sun, 27 Jun 2021 12:52:36 +0100 Subject: [PATCH 03/26] Commits as suggested by Paul --- keywords.txt | 1 + src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 52 +++++++++++--------- src/SparkFun_u-blox_GNSS_Arduino_Library.h | 13 +++-- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/keywords.txt b/keywords.txt index b2b7cab..831b4c2 100644 --- a/keywords.txt +++ b/keywords.txt @@ -66,6 +66,7 @@ disableUBX7Fcheck KEYWORD2 checkUblox KEYWORD2 checkUbloxI2C KEYWORD2 checkUbloxSerial KEYWORD2 +checkUbloxSPI KEYWORD2 process KEYWORD2 processNMEA KEYWORD2 diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index ae80176..c50645b 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -452,12 +452,15 @@ boolean SFE_UBLOX_GNSS::begin(Stream &serialPort) } // Initialize for SPI -boolean SFE_UBLOX_GNSS::begin(SPIClass &spiPort, uint8_t ssPin, int spiSpeed) +boolean SFE_UBLOX_GNSS::begin(SPIClass &spiPort, uint8_t csPin, uint32_t spiSpeed) { commType = COMM_TYPE_SPI; _spiPort = &spiPort; - _ssPin = ssPin; + _csPin = csPin; _spiSpeed = spiSpeed; + // Initialize the chip select pin + pinMode(_csPin, OUTPUT); + digitalWrite(_csPin, HIGH); //New in v2.0: allocate memory for the packetCfg payload here - if required. (The user may have called setPacketCfgPayloadSize already) if (packetCfgPayloadSize == 0) setPacketCfgPayloadSize(MAX_PAYLOAD_SIZE); @@ -790,32 +793,22 @@ boolean SFE_UBLOX_GNSS::checkUbloxSerial(ubxPacket *incomingUBX, uint8_t request //Checks SPI for data, passing any new bytes to process() boolean SFE_UBLOX_GNSS::checkUbloxSpi(ubxPacket *incomingUBX, uint8_t requestedClass, uint8_t requestedID) { - // process the contents of the SPI buffer if not empty! - uint8_t bufferByte = spiBuffer[0]; - uint8_t bufferIndex = 0; - - while (bufferByte != 0xFF) { - process(bufferByte, incomingUBX, requestedClass, requestedID); - bufferIndex++; - bufferByte = spiBuffer[bufferIndex]; + // Process the contents of the SPI buffer if not empty! + for (uint8_t i = 0; i < spiBufferIndex; i++) { + process(spiBuffer[i], incomingUBX, requestedClass, requestedID); } - - // reset the contents of the SPI buffer - for(uint8_t i = 0; i < bufferIndex; i++) - { - spiBuffer[i] = 0xFF; - } - + spiBufferIndex = 0; + SPISettings settingsA(_spiSpeed, MSBFIRST, SPI_MODE0); _spiPort->beginTransaction(settingsA); - digitalWrite(_ssPin, LOW); + digitalWrite(_csPin, LOW); uint8_t byteReturned = _spiPort->transfer(0x0A); while (byteReturned != 0xFF || currentSentence != NONE) { process(byteReturned, incomingUBX, requestedClass, requestedID); byteReturned = _spiPort->transfer(0x0A); } - digitalWrite(_ssPin, HIGH); + digitalWrite(_csPin, HIGH); _spiPort->endTransaction(); return (true); @@ -2858,7 +2851,7 @@ void SFE_UBLOX_GNSS::sendSerialCommand(ubxPacket *outgoingUBX) void SFE_UBLOX_GNSS::spiTransfer(uint8_t byteToTransfer) { uint8_t returnedByte = _spiPort->transfer(byteToTransfer); - if (returnedByte != 0xFF) + if (returnedByte != 0xFF || currentSentence != NONE) { spiBuffer[spiBufferIndex] = returnedByte; spiBufferIndex++; @@ -2868,9 +2861,24 @@ void SFE_UBLOX_GNSS::spiTransfer(uint8_t byteToTransfer) // Send a command via SPI void SFE_UBLOX_GNSS::sendSpiCommand(ubxPacket *outgoingUBX) { + if (spiBuffer == NULL) //Memory has not yet been allocated - so use new + { + spiBuffer = new uint8_t[SPI_BUFFER_SIZE]; + } + + if (spiBuffer == NULL) { + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + { + _debugSerial->print(F("process: memory allocation failed for SPI Buffer!")); + } + } + + // Start at the beginning of the SPI buffer + spiBufferIndex = 0; + SPISettings settingsA(_spiSpeed, MSBFIRST, SPI_MODE0); _spiPort->beginTransaction(settingsA); - digitalWrite(_ssPin, LOW); + digitalWrite(_csPin, LOW); //Write header bytes spiTransfer(UBX_SYNCH_1); //μ - oh ublox, you're funny. I will call you micro-blox from now on. if (_printDebug) _debugSerial->printf("%x ", UBX_SYNCH_1); @@ -2898,7 +2906,7 @@ void SFE_UBLOX_GNSS::sendSpiCommand(ubxPacket *outgoingUBX) if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->checksumA); spiTransfer(outgoingUBX->checksumB); if (_printDebug) _debugSerial->printf("%x \n", outgoingUBX->checksumB); - digitalWrite(_ssPin, HIGH); + digitalWrite(_csPin, HIGH); _spiPort->endTransaction(); } diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index 015ba3f..6f75034 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -494,6 +494,9 @@ enum sfe_ublox_ls_src_e //#define MAX_PAYLOAD_SIZE 768 //Worst case: UBX_CFG_VALSET packet with 64 keyIDs each with 64 bit values #endif +// For storing SPI bytes received during sendSpiCommand +#define SPI_BUFFER_SIZE 128 + //-=-=-=-=- UBX binary specific variables struct ubxPacket { @@ -562,8 +565,8 @@ class SFE_UBLOX_GNSS boolean begin(TwoWire &wirePort = Wire, uint8_t deviceAddress = 0x42); //Returns true if module is detected //serialPort needs to be perviously initialized to correct baud rate boolean begin(Stream &serialPort); //Returns true if module is detected - //SPI - supply instance of SPIClass, slave select pin and SPI speed (in Hz) - boolean begin(SPIClass &spiPort, uint8_t ssPin, int spiSpeed); + //SPI - supply instance of SPIClass, chip select pin and SPI speed (in Hz) + boolean begin(SPIClass &spiPort, uint8_t csPin, uint32_t spiSpeed); void end(void); //Stop all automatic message processing. Free all used RAM @@ -1283,7 +1286,7 @@ class SFE_UBLOX_GNSS Stream *_debugSerial; //The stream to send debug messages to if enabled SPIClass *_spiPort; //The instance of SPIClass - uint8_t _ssPin; //The slave select pin + uint8_t _csPin; //The chip select pin int _spiSpeed; //The speed to use for SPI (Hz) uint8_t _gpsI2Caddress = 0x42; //Default 7-bit unshifted address of the ublox 6/7/8/M8/F9 series @@ -1305,8 +1308,8 @@ class SFE_UBLOX_GNSS uint8_t *payloadCfg = NULL; uint8_t *payloadAuto = NULL; - uint8_t spiBuffer[20]; // A small buffer to store any bytes being recieved back from the device while we are sending via SPI - uint8_t spiBufferIndex = 0; // The index into the SPI buffer + uint8_t *spiBuffer = NULL; // A buffer to store any bytes being recieved back from the device while we are sending via SPI + uint8_t spiBufferIndex = 0; // Index into the SPI buffer //Init the packet structures and init them with pointers to the payloadAck, payloadCfg, payloadBuf and payloadAuto arrays ubxPacket packetAck = {0, 0, 0, 0, 0, payloadAck, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; From cb24b642de59db16bb37aa5c21b9340d003c2cf1 Mon Sep 17 00:00:00 2001 From: Andrew Berridge Date: Sun, 27 Jun 2021 14:53:01 +0100 Subject: [PATCH 04/26] Added spi transaction size :-) It still defaults to 128... please adjust downwards if you feel necessary. --- keywords.txt | 2 ++ src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 19 ++++++++++++++++--- src/SparkFun_u-blox_GNSS_Arduino_Library.h | 6 ++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/keywords.txt b/keywords.txt index 831b4c2..a1556c3 100644 --- a/keywords.txt +++ b/keywords.txt @@ -55,6 +55,8 @@ end KEYWORD2 setI2CpollingWait KEYWORD2 setI2CTransactionSize KEYWORD2 getI2CTransactionSize KEYWORD2 +setSpiTransactionSize KEYWORD2 +getSpiTransactionSize KEYWORD2 isConnected KEYWORD2 enableDebugging KEYWORD2 disableDebugging KEYWORD2 diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index c50645b..dda1e27 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -505,6 +505,19 @@ uint8_t SFE_UBLOX_GNSS::getI2CTransactionSize(void) return (i2cTransactionSize); } +//Sets the global size for the SPI buffer/transactions. +//Call this before begin()! +//Note: if the buffer size is too small, incoming characters may be lost if the message sent +//is larger than this buffer. If too big, you may run out of SRAM on constrained architectures! +void SFE_UBLOX_GNSS::setSpiTransactionSize(uint8_t transactionSize) +{ + spiTransactionSize = transactionSize; +} +uint8_t SFE_UBLOX_GNSS::getSpiTransactionSize(void) +{ + return (spiTransactionSize); +} + //Returns true if I2C device ack's boolean SFE_UBLOX_GNSS::isConnected(uint16_t maxWait) { @@ -2851,7 +2864,7 @@ void SFE_UBLOX_GNSS::sendSerialCommand(ubxPacket *outgoingUBX) void SFE_UBLOX_GNSS::spiTransfer(uint8_t byteToTransfer) { uint8_t returnedByte = _spiPort->transfer(byteToTransfer); - if (returnedByte != 0xFF || currentSentence != NONE) + if ((spiBufferIndex < getSpiTransactionSize()) && (returnedByte != 0xFF || currentSentence != NONE)) { spiBuffer[spiBufferIndex] = returnedByte; spiBufferIndex++; @@ -2863,13 +2876,13 @@ void SFE_UBLOX_GNSS::sendSpiCommand(ubxPacket *outgoingUBX) { if (spiBuffer == NULL) //Memory has not yet been allocated - so use new { - spiBuffer = new uint8_t[SPI_BUFFER_SIZE]; + spiBuffer = new uint8_t[getSpiTransactionSize()]; } if (spiBuffer == NULL) { if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging { - _debugSerial->print(F("process: memory allocation failed for SPI Buffer!")); + _debugSerial->print(F("sendSpiCommand: memory allocation failed for SPI Buffer!")); } } diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index 6f75034..f67510e 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -576,6 +576,11 @@ class SFE_UBLOX_GNSS void setI2CTransactionSize(uint8_t bufferSize); uint8_t getI2CTransactionSize(void); + //Control the size of the spi buffer. If the buffer isn't big enough, we'll start to lose bytes + //That we receive if the buffer is full! + void setSpiTransactionSize(uint8_t bufferSize); + uint8_t getSpiTransactionSize(void); + //Set the max number of bytes set in a given I2C transaction uint8_t i2cTransactionSize = 32; //Default to ATmega328 limit @@ -1310,6 +1315,7 @@ class SFE_UBLOX_GNSS uint8_t *spiBuffer = NULL; // A buffer to store any bytes being recieved back from the device while we are sending via SPI uint8_t spiBufferIndex = 0; // Index into the SPI buffer + uint8_t spiTransactionSize = SPI_BUFFER_SIZE; //Default size of the SPI buffer //Init the packet structures and init them with pointers to the payloadAck, payloadCfg, payloadBuf and payloadAuto arrays ubxPacket packetAck = {0, 0, 0, 0, 0, payloadAck, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; From b3929ff9eba6a7e17da62960a30c2e933120f6df Mon Sep 17 00:00:00 2001 From: Andrew Berridge Date: Sun, 27 Jun 2021 21:05:28 +0100 Subject: [PATCH 05/26] Initial commit --- .../Example29_SPIGetPositionESP32.ino | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 examples/Example29_SPIGetPositionESP32/Example29_SPIGetPositionESP32.ino diff --git a/examples/Example29_SPIGetPositionESP32/Example29_SPIGetPositionESP32.ino b/examples/Example29_SPIGetPositionESP32/Example29_SPIGetPositionESP32.ino new file mode 100644 index 0000000..cc081c9 --- /dev/null +++ b/examples/Example29_SPIGetPositionESP32/Example29_SPIGetPositionESP32.ino @@ -0,0 +1,111 @@ +/* + Reading lat and long via UBX binary commands over SPI + By: Andrew Berridge + Date: 27th June 2021 + 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 u-blox module for its lat/long/altitude over SPI. We also + turn off the NMEA output on the SPI port. This decreases the amount of SPI traffic + dramatically. + + Note: Long/lat are large numbers because they are * 10^7. To convert lat/long + to something google maps understands simply divide the numbers by 10,000,000. We + do this so that we don't have to use floating point numbers. + + 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: + You need to connect the SPI pins from your microcontroller to the specific pins on your SparkFun product. + Connections will vary based on your microcontroller, but for reference please refer to this tutorial on SPI: + https://learn.sparkfun.com/tutorials/serial-peripheral-interface-spi/all + + Most new boards now use the terms: + CS - Chip Select + COP - Controller Out, Peripheral In + CIPO - Controller in, Peripheral Out + SCK - Serial Clock + + You can choose any pin for Chip Select, but the others are likely either defined by the library you are using + (see here for the standard Arduino one: https://www.arduino.cc/en/reference/SPI) or the microcontroller. The + ESP32 has two standard, selectable SPI ports, for example. + + IMPORTANT: there have been reports that some ublox devices do not respond to the UBX protocol over SPI + with the factory settings. You may find you need to connect to the device via USB and u-center and set + the incoming protocol to UBX only. Make sure you disable all other protocols as inputs if you can't + get things to work! Hopefully this is just a bug in the ublox firmware that will be fixed soon ;-) + +*/ + +#include //Needed for SPI to GNSS + +#include //http://librarymanager/All#SparkFun_u-blox_GNSS +SFE_UBLOX_GNSS myGNSS; + +// Instantiate an instance of the SPI class. +// This is the default ESP32 SPI interface. Your configuration may be different, depending on the microcontroller you are using! +SPIClass spiPort (HSPI); +const uint8_t csPin = 15; // Change this to suit your own connection for the chip select pin + +long lastTime = 0; //Simple local timer. Limits amount of SPI traffic to u-blox module. + +void setup() +{ + Serial.begin(115200); + while (!Serial); //Wait for user to open terminal + Serial.println("SparkFun u-blox Example"); + + spiPort.begin(); + + myGNSS.setFileBufferSize(100); // set the file buffer size + + // Connect to the u-blox module using SPI port, csPin and speed setting + // ublox devices generally work up to 5Mhz. We'll use 4Mhz for this example: + if (myGNSS.begin(spiPort, csPin, 4000000) == false) + { + Serial.println(F("u-blox GNSS not detected on SPI bus. Please check wiring. Freezing.")); + while (1); + } + myGNSS.disableMessage(UBX_CLASS_HNR, UBX_HNR_PVT, 0x04); + myGNSS.disableMessage(UBX_CLASS_HNR, UBX_HNR_ATT, 0x04); + myGNSS.disableMessage(UBX_CLASS_HNR, UBX_HNR_INS, 0x04); + myGNSS.setAutoPVT(false); //Tell the GNSS to "send" each solution + myGNSS.setPortInput(COM_PORT_SPI, COM_TYPE_UBX); //Set the SPI 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 +} + +void loop() +{ + //Query module only every second. Doing it more often will just cause SPI traffic. + //The module only responds when a new position is available + if (millis() - lastTime > 1000) + { + lastTime = millis(); //Update the timer + + long latitude = myGNSS.getLatitude(); + Serial.print(F("Lat: ")); + Serial.print(latitude); + + long longitude = myGNSS.getLongitude(); + Serial.print(F(" Long: ")); + Serial.print(longitude); + Serial.print(F(" (degrees * 10^-7)")); + + long altitude = myGNSS.getAltitude(); + Serial.print(F(" Alt: ")); + Serial.print(altitude); + Serial.print(F(" (mm)")); + + byte SIV = myGNSS.getSIV(); + Serial.print(F(" SIV: ")); + Serial.print(SIV); + + Serial.println(); + } +} \ No newline at end of file From 30e7dea6445ac8991862980e25c94ed03378c87e Mon Sep 17 00:00:00 2001 From: Andrew Berridge Date: Sun, 27 Jun 2021 21:09:33 +0100 Subject: [PATCH 06/26] Comment update --- .../Example29_SPIGetPositionESP32.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Example29_SPIGetPositionESP32/Example29_SPIGetPositionESP32.ino b/examples/Example29_SPIGetPositionESP32/Example29_SPIGetPositionESP32.ino index cc081c9..1030d42 100644 --- a/examples/Example29_SPIGetPositionESP32/Example29_SPIGetPositionESP32.ino +++ b/examples/Example29_SPIGetPositionESP32/Example29_SPIGetPositionESP32.ino @@ -1,5 +1,5 @@ /* - Reading lat and long via UBX binary commands over SPI + Reading lat and long via UBX binary commands over SPI (ESP32 specific example) By: Andrew Berridge Date: 27th June 2021 License: MIT. See license file for more information but you can From 6ed769f2885ca55e33b86ed4515bc8817503ad09 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Mon, 28 Jun 2021 10:20:38 +0100 Subject: [PATCH 07/26] Change printf's to prints (ATmega328 does not support printf) --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 41 +++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index 06eb84f..8ead69e 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -2482,7 +2482,7 @@ void SFE_UBLOX_GNSS::processUBXpacket(ubxPacket *msg) { packetUBXESFMEAS->data.data[i].data.all = extractLong(msg, 8 + (i * 4)); } - if (msg->len > (8 + (packetUBXESFMEAS->data.flags.bits.numMeas * 4))) + if (msg->len > (8 + (packetUBXESFMEAS->data.flags.bits.numMeas * 4))) // IGNORE COMPILER WARNING comparison between signed and unsigned integer expressions packetUBXESFMEAS->data.calibTtag = extractLong(msg, 8 + (packetUBXESFMEAS->data.flags.bits.numMeas * 4)); //Mark all datums as fresh (not read before) @@ -2894,33 +2894,54 @@ void SFE_UBLOX_GNSS::sendSpiCommand(ubxPacket *outgoingUBX) digitalWrite(_csPin, LOW); //Write header bytes spiTransfer(UBX_SYNCH_1); //μ - oh ublox, you're funny. I will call you micro-blox from now on. - if (_printDebug) _debugSerial->printf("%x ", UBX_SYNCH_1); spiTransfer(UBX_SYNCH_2); //b - if (_printDebug) _debugSerial->printf("%x ", UBX_SYNCH_2); spiTransfer(outgoingUBX->cls); - if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->cls); spiTransfer(outgoingUBX->id); - if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->id); spiTransfer(outgoingUBX->len & 0xFF); //LSB - if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->len & 0xFF); spiTransfer(outgoingUBX->len >> 8); - if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->len >> 8); + + if (_printDebug) + { + _debugSerial->print(F("sendSpiCommand: 0x")); + _debugSerial->print(UBX_SYNCH_1, HEX); + _debugSerial->print(F(" ")); + _debugSerial->print(UBX_SYNCH_2, HEX); + _debugSerial->print(F(" ")); + _debugSerial->print(outgoingUBX->cls, HEX); + _debugSerial->print(F(" ")); + _debugSerial->print(outgoingUBX->id, HEX); + _debugSerial->print(F(" ")); + _debugSerial->print(outgoingUBX->len & 0xFF, HEX); + _debugSerial->print(F(" ")); + _debugSerial->print(outgoingUBX->len >> 8, HEX); + _debugSerial->print(F(" ")); + } //Write payload. for (uint16_t i = 0; i < outgoingUBX->len; i++) { spiTransfer(outgoingUBX->payload[i]); - if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->payload[i]); + if (_printDebug) + { + _debugSerial->print(F(" ")); + _debugSerial->print(outgoingUBX->payload[i], HEX); + } } //Write checksum spiTransfer(outgoingUBX->checksumA); - if (_printDebug) _debugSerial->printf("%x ", outgoingUBX->checksumA); spiTransfer(outgoingUBX->checksumB); - if (_printDebug) _debugSerial->printf("%x \n", outgoingUBX->checksumB); digitalWrite(_csPin, HIGH); _spiPort->endTransaction(); + + if (_printDebug) + { + _debugSerial->print(F(" ")); + _debugSerial->print(outgoingUBX->checksumA, HEX); + _debugSerial->print(F(" ")); + _debugSerial->println(outgoingUBX->checksumB, HEX); + } } //Pretty prints the current ubxPacket From 1d8a635dd2fbe03445cac829f240d11cd4a19c83 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Mon, 28 Jun 2021 10:23:44 +0100 Subject: [PATCH 08/26] Tidy up SPI begin --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index 8ead69e..34c510c 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -458,15 +458,20 @@ boolean SFE_UBLOX_GNSS::begin(SPIClass &spiPort, uint8_t csPin, uint32_t spiSpee _spiPort = &spiPort; _csPin = csPin; _spiSpeed = spiSpeed; + // Initialize the chip select pin pinMode(_csPin, OUTPUT); digitalWrite(_csPin, HIGH); + //New in v2.0: allocate memory for the packetCfg payload here - if required. (The user may have called setPacketCfgPayloadSize already) if (packetCfgPayloadSize == 0) setPacketCfgPayloadSize(MAX_PAYLOAD_SIZE); - Serial.println("Creating buffer"); + createFileBuffer(); + + // Call isConnected up to three times boolean connected = isConnected(); + if (!connected) connected = isConnected(); From 1e479b9ad37b03576bc8dac126d82ab3042061f3 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Mon, 28 Jun 2021 10:44:02 +0100 Subject: [PATCH 09/26] Move SPI buffer new (memory allocation) into begin --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 31 ++++++++++++++------ src/SparkFun_u-blox_GNSS_Arduino_Library.h | 4 +-- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index 34c510c..ebb119a 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -478,10 +478,26 @@ boolean SFE_UBLOX_GNSS::begin(SPIClass &spiPort, uint8_t csPin, uint32_t spiSpee if (!connected) connected = isConnected(); - // Initialize/clear the SPI buffer - fill it with 0xFF as this is what is received from the UBLOX module if there's no data to be processed - for (uint8_t i = 0; i < 20; i++) + //Create the SPI buffer + if (spiBuffer == NULL) //Memory has not yet been allocated - so use new + { + spiBuffer = new uint8_t[getSpiTransactionSize()]; + } + + if (spiBuffer == NULL) + { + if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging + { + _debugSerial->print(F("begin (SPI): memory allocation failed for SPI Buffer!")); + } + } + else { - spiBuffer[i] = 0xFF; + // Initialize/clear the SPI buffer - fill it with 0xFF as this is what is received from the UBLOX module if there's no data to be processed + for (uint8_t i = 0; i < getSpiTransactionSize(); i++) + { + spiBuffer[i] = 0xFF; + } } return (connected); @@ -2879,16 +2895,13 @@ void SFE_UBLOX_GNSS::spiTransfer(uint8_t byteToTransfer) // Send a command via SPI void SFE_UBLOX_GNSS::sendSpiCommand(ubxPacket *outgoingUBX) { - if (spiBuffer == NULL) //Memory has not yet been allocated - so use new - { - spiBuffer = new uint8_t[getSpiTransactionSize()]; - } - - if (spiBuffer == NULL) { + if (spiBuffer == NULL) + { if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging { _debugSerial->print(F("sendSpiCommand: memory allocation failed for SPI Buffer!")); } + return; } // Start at the beginning of the SPI buffer diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index ddfeb5d..449850c 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -495,7 +495,7 @@ enum sfe_ublox_ls_src_e #endif // For storing SPI bytes received during sendSpiCommand -#define SPI_BUFFER_SIZE 128 +#define SFE_UBLOX_SPI_BUFFER_SIZE 128 //-=-=-=-=- UBX binary specific variables struct ubxPacket @@ -1316,7 +1316,7 @@ class SFE_UBLOX_GNSS uint8_t *spiBuffer = NULL; // A buffer to store any bytes being recieved back from the device while we are sending via SPI uint8_t spiBufferIndex = 0; // Index into the SPI buffer - uint8_t spiTransactionSize = SPI_BUFFER_SIZE; //Default size of the SPI buffer + uint8_t spiTransactionSize = SFE_UBLOX_SPI_BUFFER_SIZE; //Default size of the SPI buffer //Init the packet structures and init them with pointers to the payloadAck, payloadCfg, payloadBuf and payloadAuto arrays ubxPacket packetAck = {0, 0, 0, 0, 0, payloadAck, 0, 0, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED, SFE_UBLOX_PACKET_VALIDITY_NOT_DEFINED}; From 2c35e729e70b70e360062f75901e75e4cec3bcd3 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Mon, 28 Jun 2021 10:59:57 +0100 Subject: [PATCH 10/26] Move SPI buffer new (memory allocation) to before isConnected --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 21 ++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index ebb119a..441d902 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -469,15 +469,6 @@ boolean SFE_UBLOX_GNSS::begin(SPIClass &spiPort, uint8_t csPin, uint32_t spiSpee createFileBuffer(); - // Call isConnected up to three times - boolean connected = isConnected(); - - if (!connected) - connected = isConnected(); - - if (!connected) - connected = isConnected(); - //Create the SPI buffer if (spiBuffer == NULL) //Memory has not yet been allocated - so use new { @@ -488,7 +479,8 @@ boolean SFE_UBLOX_GNSS::begin(SPIClass &spiPort, uint8_t csPin, uint32_t spiSpee { if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging { - _debugSerial->print(F("begin (SPI): memory allocation failed for SPI Buffer!")); + _debugSerial->print(F("begin (SPI): memory allocation failed for SPI Buffer!")); + return (false); } } else @@ -500,6 +492,15 @@ boolean SFE_UBLOX_GNSS::begin(SPIClass &spiPort, uint8_t csPin, uint32_t spiSpee } } + // Call isConnected up to three times + boolean connected = isConnected(); + + if (!connected) + connected = isConnected(); + + if (!connected) + connected = isConnected(); + return (connected); } From 1ce0be8946325f80fc8e26c81d396a90f438e8af Mon Sep 17 00:00:00 2001 From: PaulZC Date: Mon, 28 Jun 2021 11:31:20 +0100 Subject: [PATCH 11/26] Update SPI command debug prints --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index 441d902..fa7a53c 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -2900,7 +2900,7 @@ void SFE_UBLOX_GNSS::sendSpiCommand(ubxPacket *outgoingUBX) { if ((_printDebug == true) || (_printLimitedDebug == true)) // This is important. Print this if doing limited debugging { - _debugSerial->print(F("sendSpiCommand: memory allocation failed for SPI Buffer!")); + _debugSerial->print(F("sendSpiCommand: no memory allocation for SPI Buffer!")); } return; } @@ -2922,19 +2922,18 @@ void SFE_UBLOX_GNSS::sendSpiCommand(ubxPacket *outgoingUBX) if (_printDebug) { - _debugSerial->print(F("sendSpiCommand: 0x")); + _debugSerial->print(F("sendSpiCommand: ")); _debugSerial->print(UBX_SYNCH_1, HEX); _debugSerial->print(F(" ")); _debugSerial->print(UBX_SYNCH_2, HEX); - _debugSerial->print(F(" ")); + _debugSerial->print(F(" ")); _debugSerial->print(outgoingUBX->cls, HEX); _debugSerial->print(F(" ")); _debugSerial->print(outgoingUBX->id, HEX); - _debugSerial->print(F(" ")); + _debugSerial->print(F(" ")); _debugSerial->print(outgoingUBX->len & 0xFF, HEX); _debugSerial->print(F(" ")); _debugSerial->print(outgoingUBX->len >> 8, HEX); - _debugSerial->print(F(" ")); } //Write payload. @@ -2956,7 +2955,7 @@ void SFE_UBLOX_GNSS::sendSpiCommand(ubxPacket *outgoingUBX) if (_printDebug) { - _debugSerial->print(F(" ")); + _debugSerial->print(F(" ")); _debugSerial->print(outgoingUBX->checksumA, HEX); _debugSerial->print(F(" ")); _debugSerial->println(outgoingUBX->checksumB, HEX); From 402eca64ce0d9245ec68868d5cb8dd5e896ddbe2 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Mon, 28 Jun 2021 11:34:56 +0100 Subject: [PATCH 12/26] Add SPI to pushRawData (not currently supported) --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index fa7a53c..6d2e434 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -3585,7 +3585,7 @@ boolean SFE_UBLOX_GNSS::pushRawData(uint8_t *dataBytes, size_t numDataBytes, boo size_t bytesWritten = _serialPort->write(dataBytes, numDataBytes); return (bytesWritten == numDataBytes); } - else + else if (commType == COMM_TYPE_I2C) { // I2C: split the data up into packets of i2cTransactionSize size_t bytesLeftToWrite = numDataBytes; @@ -3620,6 +3620,13 @@ boolean SFE_UBLOX_GNSS::pushRawData(uint8_t *dataBytes, size_t numDataBytes, boo return (bytesWrittenTotal == numDataBytes); } + else // SPI + { + if (_printDebug == true) + { + _debugSerial->println(F("pushRawData: SPI not currently supported")); + } + } } // Support for data logging From da1cfc563e0ff9afda1953a61dff0800e61d8e90 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Mon, 28 Jun 2021 11:41:49 +0100 Subject: [PATCH 13/26] Add note to future self --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index 6d2e434..55826c1 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -838,6 +838,8 @@ boolean SFE_UBLOX_GNSS::checkUbloxSpi(ubxPacket *incomingUBX, uint8_t requestedC _spiPort->beginTransaction(settingsA); digitalWrite(_csPin, LOW); uint8_t byteReturned = _spiPort->transfer(0x0A); + // Note to future self: I think the 0xFF check will cause problems when attempting to process (e.g.) RAWX data + // which could legitimately contain 0xFF within the data stream while (byteReturned != 0xFF || currentSentence != NONE) { process(byteReturned, incomingUBX, requestedClass, requestedID); From 8f93c6a897fde9ae385630553e592108ee94f825 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Mon, 28 Jun 2021 11:53:07 +0100 Subject: [PATCH 14/26] Only change spiTransactionSize if spiBuffer is NULL --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index 55826c1..790271a 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -528,12 +528,22 @@ uint8_t SFE_UBLOX_GNSS::getI2CTransactionSize(void) } //Sets the global size for the SPI buffer/transactions. -//Call this before begin()! +//Call this **before** begin()! //Note: if the buffer size is too small, incoming characters may be lost if the message sent //is larger than this buffer. If too big, you may run out of SRAM on constrained architectures! void SFE_UBLOX_GNSS::setSpiTransactionSize(uint8_t transactionSize) { - spiTransactionSize = transactionSize; + if (spiBuffer == NULL) + { + spiTransactionSize = transactionSize; + } + else + { + if (_printDebug == true) + { + _debugSerial->println(F("setSpiTransactionSize: you need to call setSpiTransactionSize _before_ begin!")); + } + } } uint8_t SFE_UBLOX_GNSS::getSpiTransactionSize(void) { From faaf6d002ed44d74e19399e9babd3ddaba572988 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Mon, 28 Jun 2021 11:54:59 +0100 Subject: [PATCH 15/26] Add return(false) for pushRawData when using SPI --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index 790271a..ad0ae84 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -3638,6 +3638,7 @@ boolean SFE_UBLOX_GNSS::pushRawData(uint8_t *dataBytes, size_t numDataBytes, boo { _debugSerial->println(F("pushRawData: SPI not currently supported")); } + return (false); } } From e280f2200503afb2ef9c917c64a06bfcf6a0557a Mon Sep 17 00:00:00 2001 From: PaulZC Date: Mon, 28 Jun 2021 12:04:05 +0100 Subject: [PATCH 16/26] Add note to future self --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index ad0ae84..1d6e18b 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -843,6 +843,9 @@ boolean SFE_UBLOX_GNSS::checkUbloxSpi(ubxPacket *incomingUBX, uint8_t requestedC process(spiBuffer[i], incomingUBX, requestedClass, requestedID); } spiBufferIndex = 0; + + //Note to future self: maybe we need the equivalent of "if (millis() - lastCheck >= i2cPollingWait)" here? + //At the moment the code will pound the SPI bus while waiting for data... SPISettings settingsA(_spiSpeed, MSBFIRST, SPI_MODE0); _spiPort->beginTransaction(settingsA); From e4dbf7ae3a04c11442d610d21e0842fdd81e2e08 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Mon, 28 Jun 2021 14:37:17 +0100 Subject: [PATCH 17/26] Move SPI example into its own folder. Make it generic so it will run on ATmega328 --- .../Example1_GetPosition.ino} | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) rename examples/{Example29_SPIGetPositionESP32/Example29_SPIGetPositionESP32.ino => SPI/Example1_GetPosition/Example1_GetPosition.ino} (69%) diff --git a/examples/Example29_SPIGetPositionESP32/Example29_SPIGetPositionESP32.ino b/examples/SPI/Example1_GetPosition/Example1_GetPosition.ino similarity index 69% rename from examples/Example29_SPIGetPositionESP32/Example29_SPIGetPositionESP32.ino rename to examples/SPI/Example1_GetPosition/Example1_GetPosition.ino index 1030d42..5c582e9 100644 --- a/examples/Example29_SPIGetPositionESP32/Example29_SPIGetPositionESP32.ino +++ b/examples/SPI/Example1_GetPosition/Example1_GetPosition.ino @@ -1,5 +1,5 @@ /* - Reading lat and long via UBX binary commands over SPI (ESP32 specific example) + Reading lat and long via UBX binary commands over SPI By: Andrew Berridge Date: 27th June 2021 License: MIT. See license file for more information but you can @@ -19,7 +19,8 @@ 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 + NEO-M8U: https://www.sparkfun.com/products/16329 + NEO-M9N: https://www.sparkfun.com/products/17285 Hardware Connections: You need to connect the SPI pins from your microcontroller to the specific pins on your SparkFun product. @@ -28,7 +29,7 @@ Most new boards now use the terms: CS - Chip Select - COP - Controller Out, Peripheral In + COPI - Controller Out, Peripheral In CIPO - Controller in, Peripheral Out SCK - Serial Clock @@ -36,11 +37,13 @@ (see here for the standard Arduino one: https://www.arduino.cc/en/reference/SPI) or the microcontroller. The ESP32 has two standard, selectable SPI ports, for example. - IMPORTANT: there have been reports that some ublox devices do not respond to the UBX protocol over SPI + To enable SPI communication, you will need to solder the DSEL/SPI jumper closed on your u-blox board. + + IMPORTANT: there have been reports that some u-blox devices do not respond to the UBX protocol over SPI with the factory settings. You may find you need to connect to the device via USB and u-center and set the incoming protocol to UBX only. Make sure you disable all other protocols as inputs if you can't - get things to work! Hopefully this is just a bug in the ublox firmware that will be fixed soon ;-) - + get things to work! Hopefully this is just a bug in the u-blox firmware that will be fixed soon ;-) + */ #include //Needed for SPI to GNSS @@ -48,10 +51,20 @@ #include //http://librarymanager/All#SparkFun_u-blox_GNSS SFE_UBLOX_GNSS myGNSS; +// ######################################### + // Instantiate an instance of the SPI class. -// This is the default ESP32 SPI interface. Your configuration may be different, depending on the microcontroller you are using! -SPIClass spiPort (HSPI); -const uint8_t csPin = 15; // Change this to suit your own connection for the chip select pin +// Your configuration may be different, depending on the microcontroller you are using! + +#define spiPort SPI // This is the SPI port on standard Ardino boards. Comment this line if you want to use a different port. + +//SPIClass spiPort (HSPI); // This is the default SPI interface on some ESP32 boards. Uncomment this line if you are using ESP32. + +// ######################################### + +const uint8_t csPin = 10; // On ATmega328 boards, SPI Chip Select is usually pin 10. Change this to match your board. + +// ######################################### long lastTime = 0; //Simple local timer. Limits amount of SPI traffic to u-blox module. @@ -59,24 +72,21 @@ void setup() { Serial.begin(115200); while (!Serial); //Wait for user to open terminal - Serial.println("SparkFun u-blox Example"); + Serial.println(F("SparkFun u-blox Example")); - spiPort.begin(); + spiPort.begin(); // begin the SPI port + + //myGNSS.enableDebugging(); // Uncomment this line to see helpful debug messages on Serial - myGNSS.setFileBufferSize(100); // set the file buffer size - // Connect to the u-blox module using SPI port, csPin and speed setting - // ublox devices generally work up to 5Mhz. We'll use 4Mhz for this example: + // ublox devices generally work up to 5MHz. We'll use 4MHz for this example: if (myGNSS.begin(spiPort, csPin, 4000000) == false) { Serial.println(F("u-blox GNSS not detected on SPI bus. Please check wiring. Freezing.")); while (1); } - myGNSS.disableMessage(UBX_CLASS_HNR, UBX_HNR_PVT, 0x04); - myGNSS.disableMessage(UBX_CLASS_HNR, UBX_HNR_ATT, 0x04); - myGNSS.disableMessage(UBX_CLASS_HNR, UBX_HNR_INS, 0x04); - myGNSS.setAutoPVT(false); //Tell the GNSS to "send" each solution - myGNSS.setPortInput(COM_PORT_SPI, COM_TYPE_UBX); //Set the SPI port to output UBX only (turn off NMEA noise) + + myGNSS.setPortOutput(COM_PORT_SPI, COM_TYPE_UBX); //Set the SPI 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 } @@ -108,4 +118,4 @@ void loop() Serial.println(); } -} \ No newline at end of file +} From 81003bf37120258cabaa87d1195e8bccdf5a6cbd Mon Sep 17 00:00:00 2001 From: PaulZC Date: Mon, 28 Jun 2021 17:24:16 +0100 Subject: [PATCH 18/26] Change COPI data from 0x0A to 0xFF during 'read' transactions --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index 1d6e18b..a8f6fdd 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -850,13 +850,13 @@ boolean SFE_UBLOX_GNSS::checkUbloxSpi(ubxPacket *incomingUBX, uint8_t requestedC SPISettings settingsA(_spiSpeed, MSBFIRST, SPI_MODE0); _spiPort->beginTransaction(settingsA); digitalWrite(_csPin, LOW); - uint8_t byteReturned = _spiPort->transfer(0x0A); + uint8_t byteReturned = _spiPort->transfer(0xFF); // Note to future self: I think the 0xFF check will cause problems when attempting to process (e.g.) RAWX data // which could legitimately contain 0xFF within the data stream while (byteReturned != 0xFF || currentSentence != NONE) { process(byteReturned, incomingUBX, requestedClass, requestedID); - byteReturned = _spiPort->transfer(0x0A); + byteReturned = _spiPort->transfer(0xFF); } digitalWrite(_csPin, HIGH); _spiPort->endTransaction(); From 28c71ae49c826f406d38c0f1dbee1df01af762ba Mon Sep 17 00:00:00 2001 From: PaulZC Date: Tue, 29 Jun 2021 06:40:57 +0100 Subject: [PATCH 19/26] Change maxNMEAByteCount to 88. Add set/getMaxNMEAByteCount --- keywords.txt | 2 ++ src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 10 ++++++++++ src/SparkFun_u-blox_GNSS_Arduino_Library.h | 18 +++++++++++++++--- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/keywords.txt b/keywords.txt index f43de34..387057a 100644 --- a/keywords.txt +++ b/keywords.txt @@ -57,6 +57,8 @@ setI2CTransactionSize KEYWORD2 getI2CTransactionSize KEYWORD2 setSpiTransactionSize KEYWORD2 getSpiTransactionSize KEYWORD2 +setMaxNMEAByteCount KEYWORD2 +getMaxNMEAByteCount KEYWORD2 isConnected KEYWORD2 enableDebugging KEYWORD2 disableDebugging KEYWORD2 diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index a8f6fdd..5b45143 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -550,6 +550,16 @@ uint8_t SFE_UBLOX_GNSS::getSpiTransactionSize(void) return (spiTransactionSize); } +//Sets the size of maxNMEAByteCount +void SFE_UBLOX_GNSS::setMaxNMEAByteCount(int8_t newMax) +{ + maxNMEAByteCount = newMax; +} +int8_t SFE_UBLOX_GNSS::getMaxNMEAByteCount(void) +{ + return (maxNMEAByteCount); +} + //Returns true if I2C device ack's boolean SFE_UBLOX_GNSS::isConnected(uint16_t maxWait) { diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index 449850c..e42abd2 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -497,6 +497,12 @@ enum sfe_ublox_ls_src_e // For storing SPI bytes received during sendSpiCommand #define SFE_UBLOX_SPI_BUFFER_SIZE 128 +// Default maximum NMEA byte count +// maxNMEAByteCount was set to 82: https://en.wikipedia.org/wiki/NMEA_0183#Message_structure +// but the u-blox HP (RTK) GGA messages are 88 bytes long +// The user can adjust maxNMEAByteCount by calling setMaxNMEAByteCount +#define SFE_UBLOX_MAX_NMEA_BYTE_COUNT 88 + //-=-=-=-=- UBX binary specific variables struct ubxPacket { @@ -572,6 +578,9 @@ class SFE_UBLOX_GNSS void setI2CpollingWait(uint8_t newPollingWait_ms); // Allow the user to change the I2C polling wait if required + //Set the max number of bytes set in a given I2C transaction + uint8_t i2cTransactionSize = 32; //Default to ATmega328 limit + //Control the size of the internal I2C transaction amount void setI2CTransactionSize(uint8_t bufferSize); uint8_t getI2CTransactionSize(void); @@ -581,8 +590,9 @@ class SFE_UBLOX_GNSS void setSpiTransactionSize(uint8_t bufferSize); uint8_t getSpiTransactionSize(void); - //Set the max number of bytes set in a given I2C transaction - uint8_t i2cTransactionSize = 32; //Default to ATmega328 limit + //Control the size of maxNMEAByteCount + void setMaxNMEAByteCount(int8_t newMax); + int8_t getMaxNMEAByteCount(void); //Returns true if device answers on _gpsI2Caddress address or via Serial boolean isConnected(uint16_t maxWait = 1100); @@ -1345,7 +1355,9 @@ class SFE_UBLOX_GNSS uint8_t rollingChecksumB; //Rolls forward as we receive incoming bytes. Checked against the last two A/B checksum bytes int8_t nmeaByteCounter; //Count all NMEA message bytes. - const int8_t maxNMEAByteCount = 82; // Abort NMEA message reception if nmeaByteCounter exceeds this (https://en.wikipedia.org/wiki/NMEA_0183#Message_structure) + // Abort NMEA message reception if nmeaByteCounter exceeds maxNMEAByteCount. + // The user can adjust maxNMEAByteCount by calling setMaxNMEAByteCount + int8_t maxNMEAByteCount = SFE_UBLOX_MAX_NMEA_BYTE_COUNT; uint8_t nmeaAddressField[6]; // NMEA Address Field - includes the start character (*) boolean logThisNMEA(); // Return true if we should log this NMEA message boolean processThisNMEA(); // Return true if we should pass this NMEA message to processNMEA From 4381497e689c8a2531a54c1fc3c0799377f31e58 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Tue, 29 Jun 2021 08:28:24 +0100 Subject: [PATCH 20/26] Create SPI Example2 Auto PVT --- .../SPI/Example2_AutoPVT/Example2_AutoPVT.ino | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 examples/SPI/Example2_AutoPVT/Example2_AutoPVT.ino diff --git a/examples/SPI/Example2_AutoPVT/Example2_AutoPVT.ino b/examples/SPI/Example2_AutoPVT/Example2_AutoPVT.ino new file mode 100644 index 0000000..b6fc355 --- /dev/null +++ b/examples/SPI/Example2_AutoPVT/Example2_AutoPVT.ino @@ -0,0 +1,177 @@ +/* + Configuring the GNSS to automatically send position reports over SPI + Based on code by: Nathan Seidle and Thorsten von Eicken + SparkFun Electronics + Date: January 3rd, 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 configure the U-Blox GNSS the send navigation reports automatically + and retrieving the latest one via getPVT. This eliminates the blocking in getPVT while the GNSS + produces a fresh navigation solution at the expense of returning a slighly old solution. + + 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 + NEO-M8U: https://www.sparkfun.com/products/16329 + NEO-M9N: https://www.sparkfun.com/products/17285 + + Hardware Connections: + You need to connect the SPI pins from your microcontroller to the specific pins on your SparkFun product. + Connections will vary based on your microcontroller, but for reference please refer to this tutorial on SPI: + https://learn.sparkfun.com/tutorials/serial-peripheral-interface-spi/all + + Most new boards now use the terms: + CS - Chip Select + COPI - Controller Out, Peripheral In + CIPO - Controller in, Peripheral Out + SCK - Serial Clock + + You can choose any pin for Chip Select, but the others are likely either defined by the library you are using + (see here for the standard Arduino one: https://www.arduino.cc/en/reference/SPI) or the microcontroller. The + ESP32 has two standard, selectable SPI ports, for example. + + To enable SPI communication, you will need to solder the DSEL/SPI jumper closed on your u-blox board. + + IMPORTANT: there have been reports that some u-blox devices do not respond to the UBX protocol over SPI + with the factory settings. You may find you need to connect to the device via USB and u-center and set + the incoming protocol to UBX only. Make sure you disable all other protocols as inputs if you can't + get things to work! Hopefully this is just a bug in the u-blox firmware that will be fixed soon ;-) + +*/ + +#include //Needed for SPI to GNSS + +#include //http://librarymanager/All#SparkFun_u-blox_GNSS +SFE_UBLOX_GNSS myGNSS; + +// ######################################### + +// Instantiate an instance of the SPI class. +// Your configuration may be different, depending on the microcontroller you are using! + +#define spiPort SPI // This is the SPI port on standard Ardino boards. Comment this line if you want to use a different port. + +//SPIClass spiPort (HSPI); // This is the default SPI interface on some ESP32 boards. Uncomment this line if you are using ESP32. + +// ######################################### + +const uint8_t csPin = 10; // On ATmega328 boards, SPI Chip Select is usually pin 10. Change this to match your board. + +// ######################################### + +void setup() +{ + Serial.begin(115200); + while (!Serial); //Wait for user to open terminal + Serial.println("SparkFun u-blox Example"); + + spiPort.begin(); // begin the SPI port + + //myGNSS.enableDebugging(); // Uncomment this line to see helpful debug messages on Serial + + // Connect to the u-blox module using SPI port, csPin and speed setting + // ublox devices generally work up to 5MHz. We'll use 4MHz for this example: + if (myGNSS.begin(spiPort, csPin, 4000000) == false) + { + Serial.println(F("u-blox GNSS not detected on SPI bus. Please check wiring. Freezing.")); + while (1); + } + + myGNSS.setPortOutput(COM_PORT_SPI, COM_TYPE_UBX); //Set the SPI 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(2); //Produce two solutions per second + myGNSS.setAutoPVT(true); //Tell the GNSS to "send" each solution + //myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR +} + +void loop() +{ + // Calling getPVT returns true if there actually is a fresh navigation solution available. + // Start the reading only when valid LLH is available + if (myGNSS.getPVT() && (myGNSS.getInvalidLlh() == false)) + { + Serial.println(); + long latitude = myGNSS.getLatitude(); + Serial.print(F("Lat: ")); + Serial.print(latitude); + + long longitude = myGNSS.getLongitude(); + Serial.print(F(" Long: ")); + Serial.print(longitude); + Serial.print(F(" (degrees * 10^-7)")); + + long altitude = myGNSS.getAltitude(); + Serial.print(F(" Alt: ")); + Serial.print(altitude); + Serial.print(F(" (mm)")); + + byte SIV = myGNSS.getSIV(); + Serial.print(F(" SIV: ")); + Serial.print(SIV); + + int PDOP = myGNSS.getPDOP(); + Serial.print(F(" PDOP: ")); + Serial.print(PDOP); + Serial.print(F(" (10^-2)")); + + int nedNorthVel = myGNSS.getNedNorthVel(); + Serial.print(F(" VelN: ")); + Serial.print(nedNorthVel); + Serial.print(F(" (mm/s)")); + + int nedEastVel = myGNSS.getNedEastVel(); + Serial.print(F(" VelE: ")); + Serial.print(nedEastVel); + Serial.print(F(" (mm/s)")); + + int nedDownVel = myGNSS.getNedDownVel(); + Serial.print(F(" VelD: ")); + Serial.print(nedDownVel); + Serial.print(F(" (mm/s)")); + + int verticalAccEst = myGNSS.getVerticalAccEst(); + Serial.print(F(" VAccEst: ")); + Serial.print(verticalAccEst); + Serial.print(F(" (mm)")); + + int horizontalAccEst = myGNSS.getHorizontalAccEst(); + Serial.print(F(" HAccEst: ")); + Serial.print(horizontalAccEst); + Serial.print(F(" (mm)")); + + int speedAccEst = myGNSS.getSpeedAccEst(); + Serial.print(F(" SpeedAccEst: ")); + Serial.print(speedAccEst); + Serial.print(F(" (mm/s)")); + + int headAccEst = myGNSS.getHeadingAccEst(); + Serial.print(F(" HeadAccEst: ")); + Serial.print(headAccEst); + Serial.print(F(" (degrees * 10^-5)")); + + if (myGNSS.getHeadVehValid() == true) { + int headVeh = myGNSS.getHeadVeh(); + Serial.print(F(" HeadVeh: ")); + Serial.print(headVeh); + Serial.print(F(" (degrees * 10^-5)")); + + int magDec = myGNSS.getMagDec(); + Serial.print(F(" MagDec: ")); + Serial.print(magDec); + Serial.print(F(" (degrees * 10^-2)")); + + int magAcc = myGNSS.getMagAcc(); + Serial.print(F(" MagAcc: ")); + Serial.print(magAcc); + Serial.print(F(" (degrees * 10^-2)")); + } + + Serial.println(); + } else { + Serial.print("."); + delay(50); + } +} From 794966bc9cd795fa598dcf9b58a307e7078cfc97 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Tue, 29 Jun 2021 15:35:08 +0100 Subject: [PATCH 21/26] Remove !!! from examples 18 and 19 (!!! can cause avrdude to crash!) --- .../Example18_PowerSaveMode/Example18_PowerSaveMode.ino | 6 +++--- examples/Example19_DynamicModel/Example19_DynamicModel.ino | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/Example18_PowerSaveMode/Example18_PowerSaveMode.ino b/examples/Example18_PowerSaveMode/Example18_PowerSaveMode.ino index fc24259..fdef442 100644 --- a/examples/Example18_PowerSaveMode/Example18_PowerSaveMode.ino +++ b/examples/Example18_PowerSaveMode/Example18_PowerSaveMode.ino @@ -85,7 +85,7 @@ void loop() if (myGNSS.powerSaveMode()) // Defaults to true Serial.println(F("Power Save Mode enabled.")); else - Serial.println(F("***!!! Power Save Mode FAILED !!!***")); + Serial.println(F("*** Power Save Mode FAILED ***")); } else if (incoming == '2') { @@ -93,14 +93,14 @@ void loop() if (myGNSS.powerSaveMode(false)) Serial.println(F("Power Save Mode disabled.")); else - Serial.println(F("***!!! Power Save Disable FAILED !!!***")); + Serial.println(F("*** Power Save Disable FAILED ***")); } // Read and print the new low power mode uint8_t lowPowerMode = myGNSS.getPowerSaveMode(); if (lowPowerMode == 255) { - Serial.println(F("***!!! getPowerSaveMode FAILED !!!***")); + Serial.println(F("*** getPowerSaveMode FAILED ***")); } else { diff --git a/examples/Example19_DynamicModel/Example19_DynamicModel.ino b/examples/Example19_DynamicModel/Example19_DynamicModel.ino index 9915647..1ccfc1b 100644 --- a/examples/Example19_DynamicModel/Example19_DynamicModel.ino +++ b/examples/Example19_DynamicModel/Example19_DynamicModel.ino @@ -68,7 +68,7 @@ void setup() if (myGNSS.setDynamicModel(DYN_MODEL_PORTABLE) == false) // Set the dynamic model to PORTABLE { - Serial.println(F("***!!! Warning: setDynamicModel failed !!!***")); + Serial.println(F("*** Warning: setDynamicModel failed ***")); } else { @@ -79,7 +79,7 @@ void setup() uint8_t newDynamicModel = myGNSS.getDynamicModel(); if (newDynamicModel == DYN_MODEL_UNKNOWN) { - Serial.println(F("***!!! Warning: getDynamicModel failed !!!***")); + Serial.println(F("*** Warning: getDynamicModel failed ***")); } else { From bf7b29199d87964ae017ef99eecef97a3e861863 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Tue, 29 Jun 2021 17:13:05 +0100 Subject: [PATCH 22/26] Ensure NMEA messages are enabled in Examples 1 and 2 --- examples/Example1_BasicNMEARead/Example1_BasicNMEARead.ino | 3 +++ examples/Example2_NMEAParsing/Example2_NMEAParsing.ino | 3 +++ 2 files changed, 6 insertions(+) diff --git a/examples/Example1_BasicNMEARead/Example1_BasicNMEARead.ino b/examples/Example1_BasicNMEARead/Example1_BasicNMEARead.ino index f2c2368..55a7a23 100644 --- a/examples/Example1_BasicNMEARead/Example1_BasicNMEARead.ino +++ b/examples/Example1_BasicNMEARead/Example1_BasicNMEARead.ino @@ -39,6 +39,9 @@ void setup() while (1); } + myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA); //Set the I2C port to output both NMEA and UBX messages + myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR + //This will pipe all NMEA sentences to the serial port so we can see them myGNSS.setNMEAOutputPort(Serial); } diff --git a/examples/Example2_NMEAParsing/Example2_NMEAParsing.ino b/examples/Example2_NMEAParsing/Example2_NMEAParsing.ino index 48b691b..cf329a5 100644 --- a/examples/Example2_NMEAParsing/Example2_NMEAParsing.ino +++ b/examples/Example2_NMEAParsing/Example2_NMEAParsing.ino @@ -46,6 +46,9 @@ void setup() while (1); } + myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA); //Set the I2C port to output both NMEA and UBX messages + myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR + myGNSS.setProcessNMEAMask(SFE_UBLOX_FILTER_NMEA_ALL); // Make sure the library is passing all NMEA messages to processNMEA myGNSS.setProcessNMEAMask(SFE_UBLOX_FILTER_NMEA_GGA); // Or, we can be kind to MicroNMEA and _only_ pass the GGA messages to it From c1db2f57454a28ad3b96386904c00f1534cf4bc8 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Wed, 30 Jun 2021 16:28:17 +0100 Subject: [PATCH 23/26] Change _spiSpeed to uint32_t --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 6 ++---- src/SparkFun_u-blox_GNSS_Arduino_Library.h | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index 5b45143..2d17bff 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -857,8 +857,7 @@ boolean SFE_UBLOX_GNSS::checkUbloxSpi(ubxPacket *incomingUBX, uint8_t requestedC //Note to future self: maybe we need the equivalent of "if (millis() - lastCheck >= i2cPollingWait)" here? //At the moment the code will pound the SPI bus while waiting for data... - SPISettings settingsA(_spiSpeed, MSBFIRST, SPI_MODE0); - _spiPort->beginTransaction(settingsA); + _spiPort->beginTransaction(SPISettings(_spiSpeed, MSBFIRST, SPI_MODE0)); digitalWrite(_csPin, LOW); uint8_t byteReturned = _spiPort->transfer(0xFF); // Note to future self: I think the 0xFF check will cause problems when attempting to process (e.g.) RAWX data @@ -2933,8 +2932,7 @@ void SFE_UBLOX_GNSS::sendSpiCommand(ubxPacket *outgoingUBX) // Start at the beginning of the SPI buffer spiBufferIndex = 0; - SPISettings settingsA(_spiSpeed, MSBFIRST, SPI_MODE0); - _spiPort->beginTransaction(settingsA); + _spiPort->beginTransaction(SPISettings(_spiSpeed, MSBFIRST, SPI_MODE0)); digitalWrite(_csPin, LOW); //Write header bytes spiTransfer(UBX_SYNCH_1); //μ - oh ublox, you're funny. I will call you micro-blox from now on. diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index e42abd2..b274320 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -1303,7 +1303,7 @@ class SFE_UBLOX_GNSS SPIClass *_spiPort; //The instance of SPIClass uint8_t _csPin; //The chip select pin - int _spiSpeed; //The speed to use for SPI (Hz) + uint32_t _spiSpeed; //The speed to use for SPI (Hz) uint8_t _gpsI2Caddress = 0x42; //Default 7-bit unshifted address of the ublox 6/7/8/M8/F9 series //This can be changed using the ublox configuration software From 79f44129d0ea309eb1b54beb053e6d3e94c780d0 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Wed, 30 Jun 2021 19:13:45 +0100 Subject: [PATCH 24/26] Add spiPollingWait and setSPIpollingWait. Change delayMicroseconds(500) to delay(1) --- .../Example1_GetPosition.ino | 2 ++ .../SPI/Example2_AutoPVT/Example2_AutoPVT.ino | 4 ++- keywords.txt | 1 + src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 29 +++++++++++++++---- src/SparkFun_u-blox_GNSS_Arduino_Library.h | 7 ++++- 5 files changed, 36 insertions(+), 7 deletions(-) diff --git a/examples/SPI/Example1_GetPosition/Example1_GetPosition.ino b/examples/SPI/Example1_GetPosition/Example1_GetPosition.ino index 5c582e9..108a5ef 100644 --- a/examples/SPI/Example1_GetPosition/Example1_GetPosition.ino +++ b/examples/SPI/Example1_GetPosition/Example1_GetPosition.ino @@ -86,6 +86,8 @@ void setup() while (1); } + //myGNSS.factoryDefault(); delay(5000); // Uncomment this line to reset the module back to its factory defaults + myGNSS.setPortOutput(COM_PORT_SPI, COM_TYPE_UBX); //Set the SPI 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 } diff --git a/examples/SPI/Example2_AutoPVT/Example2_AutoPVT.ino b/examples/SPI/Example2_AutoPVT/Example2_AutoPVT.ino index b6fc355..ff9d930 100644 --- a/examples/SPI/Example2_AutoPVT/Example2_AutoPVT.ino +++ b/examples/SPI/Example2_AutoPVT/Example2_AutoPVT.ino @@ -79,12 +79,14 @@ void setup() while (1); } + //myGNSS.factoryDefault(); delay(5000); // Uncomment this line to reset the module back to its factory defaults + myGNSS.setPortOutput(COM_PORT_SPI, COM_TYPE_UBX); //Set the SPI 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(2); //Produce two solutions per second myGNSS.setAutoPVT(true); //Tell the GNSS to "send" each solution - //myGNSS.saveConfiguration(); //Optional: Save the current settings to flash and BBR + //myGNSS.saveConfiguration(); //Optional: Save _all_ the current settings to flash and BBR } void loop() diff --git a/keywords.txt b/keywords.txt index 387057a..9862fb0 100644 --- a/keywords.txt +++ b/keywords.txt @@ -53,6 +53,7 @@ setPacketCfgPayloadSize KEYWORD2 begin KEYWORD2 end KEYWORD2 setI2CpollingWait KEYWORD2 +setSPIpollingWait KEYWORD2 setI2CTransactionSize KEYWORD2 getI2CTransactionSize KEYWORD2 setSpiTransactionSize KEYWORD2 diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index 2d17bff..4f623ee 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -514,6 +514,13 @@ void SFE_UBLOX_GNSS::setI2CpollingWait(uint8_t newPollingWait_ms) i2cPollingWait = newPollingWait_ms; } +// Allow the user to change SPI polling wait +// (the minimum interval between SPI data requests when no data is available - to avoid pounding the bus) +void SFE_UBLOX_GNSS::setSPIpollingWait(uint8_t newPollingWait_ms) +{ + spiPollingWait = newPollingWait_ms; +} + //Sets the global size for I2C transactions //Most platforms use 32 bytes (the default) but this allows users to increase the transaction //size if the platform supports it @@ -664,7 +671,7 @@ const char *SFE_UBLOX_GNSS::statusString(sfe_ublox_status_e stat) return "None"; } -// Check for the arrival of new I2C/Serial data +// Check for the arrival of new I2C/Serial/SPI data //Allow the user to disable the "7F" check (e.g.) when logging RAWX data void SFE_UBLOX_GNSS::disableUBX7Fcheck(boolean disabled) @@ -860,8 +867,20 @@ boolean SFE_UBLOX_GNSS::checkUbloxSpi(ubxPacket *incomingUBX, uint8_t requestedC _spiPort->beginTransaction(SPISettings(_spiSpeed, MSBFIRST, SPI_MODE0)); digitalWrite(_csPin, LOW); uint8_t byteReturned = _spiPort->transfer(0xFF); - // Note to future self: I think the 0xFF check will cause problems when attempting to process (e.g.) RAWX data - // which could legitimately contain 0xFF within the data stream + + // Note to future self: I think the 0xFF check might cause problems when attempting to process (e.g.) RAWX data + // which could legitimately contain 0xFF within the data stream. But the currentSentence check will certainly help! + + // If we are not receiving a sentence (currentSentence == NONE) and the byteReturned is 0xFF, + // i.e. the module has no data for us, then delay for + if ((byteReturned == 0xFF) && (currentSentence == NONE)) + { + digitalWrite(_csPin, HIGH); + _spiPort->endTransaction(); + delay(spiPollingWait); + return (true); + } + while (byteReturned != 0xFF || currentSentence != NONE) { process(byteReturned, incomingUBX, requestedClass, requestedID); @@ -3208,7 +3227,7 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForACKResponse(ubxPacket *outgoingUBX, ui } //checkUbloxInternal == true - delayMicroseconds(500); + delay(1); // Allow an RTOS to get an elbow in (#11) } //while (millis() - startTime < maxTime) // We have timed out... @@ -3318,7 +3337,7 @@ sfe_ublox_status_e SFE_UBLOX_GNSS::waitForNoACKResponse(ubxPacket *outgoingUBX, } } - delayMicroseconds(500); + delay(1); // Allow an RTOS to get an elbow in (#11) } if (_printDebug == true) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.h b/src/SparkFun_u-blox_GNSS_Arduino_Library.h index b274320..691b6a9 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.h +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.h @@ -577,6 +577,7 @@ class SFE_UBLOX_GNSS void end(void); //Stop all automatic message processing. Free all used RAM void setI2CpollingWait(uint8_t newPollingWait_ms); // Allow the user to change the I2C polling wait if required + void setSPIpollingWait(uint8_t newPollingWait_ms); // Allow the user to change the SPI polling wait if required //Set the max number of bytes set in a given I2C transaction uint8_t i2cTransactionSize = 32; //Default to ATmega328 limit @@ -1344,10 +1345,14 @@ class SFE_UBLOX_GNSS sfe_ublox_packet_buffer_e activePacketBuffer = SFE_UBLOX_PACKET_PACKETBUF; //Limit checking of new data to every X ms - //If we are expecting an update every X Hz then we should check every half that amount of time + //If we are expecting an update every X Hz then we should check every quarter that amount of time //Otherwise we may block ourselves from seeing new data uint8_t i2cPollingWait = 100; //Default to 100ms. Adjusted when user calls setNavigationFrequency() or setHNRNavigationRate() or setMeasurementRate() + //The SPI polling wait is a little different. checkUbloxSpi will delay for this amount before returning if + //there is no data waiting to be read. This prevents waitForACKResponse from pounding the SPI bus too hard. + uint8_t spiPollingWait = 9; //Default to 9ms; waitForACKResponse delays for 1ms on top of this. User can adjust with setSPIPollingWait. + unsigned long lastCheck = 0; uint16_t ubxFrameCounter; //Count all UBX frame bytes. [Fixed header(2bytes), CLS(1byte), ID(1byte), length(2bytes), payload(x bytes), checksums(2bytes)] From aa8987e714531d4a54cfcfc27e26b7f8bfb0aa9e Mon Sep 17 00:00:00 2001 From: PaulZC Date: Wed, 30 Jun 2021 19:20:39 +0100 Subject: [PATCH 25/26] Remove note to future self! --- src/SparkFun_u-blox_GNSS_Arduino_Library.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp index 4f623ee..a3eb754 100644 --- a/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_GNSS_Arduino_Library.cpp @@ -861,9 +861,6 @@ boolean SFE_UBLOX_GNSS::checkUbloxSpi(ubxPacket *incomingUBX, uint8_t requestedC } spiBufferIndex = 0; - //Note to future self: maybe we need the equivalent of "if (millis() - lastCheck >= i2cPollingWait)" here? - //At the moment the code will pound the SPI bus while waiting for data... - _spiPort->beginTransaction(SPISettings(_spiSpeed, MSBFIRST, SPI_MODE0)); digitalWrite(_csPin, LOW); uint8_t byteReturned = _spiPort->transfer(0xFF); @@ -881,7 +878,7 @@ boolean SFE_UBLOX_GNSS::checkUbloxSpi(ubxPacket *incomingUBX, uint8_t requestedC return (true); } - while (byteReturned != 0xFF || currentSentence != NONE) + while ((byteReturned != 0xFF) || (currentSentence != NONE)) { process(byteReturned, incomingUBX, requestedClass, requestedID); byteReturned = _spiPort->transfer(0xFF); From e3d9bc3c4017b8f610c25713a4a620de50c9ed13 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Thu, 1 Jul 2021 13:12:46 +0100 Subject: [PATCH 26/26] v2.0.8 - add SPI support --- README.md | 14 +++++++++++++- library.properties | 4 ++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1eb267f..541f74d 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ -u-blox makes some incredible GNSS receivers covering everything from low-cost, highly configurable modules such as the SAM-M8Q all the way up to the surveyor grade ZED-F9P with precision of the diameter of a dime. This library focuses on configuration and control of u-blox devices over I2C (called DDC by u-blox) and Serial. The UBX protocol is supported over both I2C and serial, and is a much easier and lighterweight interface to a GNSS module. Stop polling messages and parsing NMEA data! Simply ask for the datums you need and receive an automatic callback when they arrive. +u-blox makes some incredible GNSS receivers covering everything from low-cost, highly configurable modules such as the SAM-M8Q all the way up to the surveyor grade ZED-F9P with precision of the diameter of a dime. This library supports configuration and control of u-blox devices over I2C (called DDC by u-blox), Serial and - as of v2.0.8 (thank you @aberridg) - SPI too! The UBX protocol is a much easier and lighterweight interface to a GNSS module. Stop polling messages and parsing NMEA data! Simply ask for the datums you need and receive an automatic callback when they arrive. This library can be installed via the Arduino Library manager. Search for **SparkFun u-blox GNSS**. @@ -53,6 +53,18 @@ Migrating to v2.0 is easy. There are two small changes all users will need to ma If you are using the Dead Reckoning Sensor Fusion or High Dynamic Rate messages, you will need to make more small changes to your code. Please see the [dead reckoning examples](./examples/Dead_Reckoning) for more details. There is more detail available in [Theory.md](./Theory.md#migrating-your-code-to-v20) if you need it. +## SPI Support + +In v2.0.8 we added support for SPI, based on a contribution by @aberridg. Thank you Andrew! + +We have tested the SPI interface on as many platforms and modules as we could pull together. It works perfectly on most but not quite all combinations. +For reasons we don't understand yet, the ZED-F9P and Teensy 3.2 don't seem to get along. But Teensy 3.2 and the ZOE-M8Q do play nicely together. +If you notice a combination that does not seem to work, please raise an [issue](https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library/issues) and we will investigate. + +The SPI examples have their [own folder](./examples/SPI). + +Please check the module datasheets for details on what clock speeds and data rates each module supports. The maximum clock speed is typically 5.5MHz and the maximum transfer rate is typically 125kBytes/s. + ## Max (400kHz) I2C Support To achieve 400kHz I2C speed please be sure to remove all pull-ups on the I2C bus. Most, if not all, u-blox modules include internal pull ups on the I2C lines (sometimes called DDC in their manuals). Cut all I2C pull up jumpers and/or remove them from peripheral boards. Otherwise, various data glitches can occur. See issues [38](https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/issues/38) and [40](https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/issues/40) for more information. If possible, run the I2C bus at 100kHz. diff --git a/library.properties b/library.properties index ac25b7a..8ea9e6c 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=SparkFun u-blox GNSS Arduino Library -version=2.0.7 +version=2.0.8 author=SparkFun Electronics maintainer=SparkFun Electronics sentence=Library for I2C and Serial Communication with u-blox GNSS modules

-paragraph=An Arduino Library to enable both I2C and Serial communication for both NMEA reception and binary UBX sending to u-blox modules. Useful for interfacing to the SparkFun GPS-RTK2 ZED-F9P, SparkFun GPS-RTK NEO-M8P-2, the SparkFun SAM-M8Q, and the SparkFun ZOE-M8Q. Library also works with other u-blox based boards.

The ZED-F9P and NEO-M8P-2 modules are top-of-the-line modules for high accuracy GNSS and GPS location solutions including RTK. The ZED-F9P is unique in that it is capable of both rover and base station operations allowing the module to become a base station and produce RTCM 3.x correction data.
+paragraph=An Arduino Library to enable I2C, Serial and SPI communication for both NMEA reception and binary UBX sending to u-blox modules. Useful for interfacing to the SparkFun GPS-RTK2 ZED-F9P, SparkFun GPS-RTK NEO-M8P-2, the SparkFun SAM-M8Q, and the SparkFun ZOE-M8Q. Library also works with other u-blox based boards.

The ZED-F9P and NEO-M8P-2 modules are top-of-the-line modules for high accuracy GNSS and GPS location solutions including RTK. The ZED-F9P is unique in that it is capable of both rover and base station operations allowing the module to become a base station and produce RTCM 3.x correction data.
category=Sensors url=https://github.com/sparkfun/SparkFun_u-blox_GNSS_Arduino_Library architectures=*