242 lines
10 KiB
Arduino
242 lines
10 KiB
Arduino
/*
|
|
Demonstrate how to log NMEA and UBX data simultaneously
|
|
By: Paul Clark
|
|
SparkFun Electronics
|
|
Date: April 13th, 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 configure the u-blox GNSS to send PVT reports automatically
|
|
and log those and any incoming NMEA messages to SD card in UBX format
|
|
|
|
** Please note: this example will only work on processors like the Artemis which have plenty of RAM available **
|
|
|
|
This code is intended to be run on the MicroMod Data Logging Carrier Board using the Artemis Processor
|
|
but can be adapted by changing the chip select pin and SPI definitions:
|
|
https://www.sparkfun.com/products/16829
|
|
https://www.sparkfun.com/products/16401
|
|
|
|
Hardware Connections:
|
|
Please see: https://learn.sparkfun.com/tutorials/micromod-data-logging-carrier-board-hookup-guide
|
|
Insert the Artemis Processor into the MicroMod Data Logging Carrier Board and secure with the screw.
|
|
Connect your GNSS breakout to the Carrier Board using a Qwiic cable.
|
|
Connect an antenna to your GNSS board if required.
|
|
Insert a formatted micro-SD card into the socket on the Carrier Board.
|
|
Connect the Carrier Board to your computer using a USB-C cable.
|
|
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
|
|
This code has been tested using version 1.2.1 of the Apollo3 boards on Arduino IDE 1.8.13.
|
|
Select "SparkFun Artemis MicroMod" as the board type.
|
|
Press upload to upload the code onto the Artemis.
|
|
Open the Serial Monitor at 115200 baud to see the output.
|
|
|
|
To minimise I2C bus errors, it is a good idea to open the I2C pull-up split pad links on
|
|
both the MicroMod Data Logging Carrier Board and the u-blox module breakout.
|
|
|
|
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
|
|
ZOE-M8Q: https://www.sparkfun.com/products/15193
|
|
SAM-M8Q: https://www.sparkfun.com/products/15210
|
|
*/
|
|
|
|
#include <SPI.h>
|
|
#include <SD.h>
|
|
#include <Wire.h> //Needed for I2C to GNSS
|
|
|
|
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
|
SFE_UBLOX_GNSS myGNSS;
|
|
|
|
File myFile; //File that all GNSS data is written to
|
|
|
|
#define sdChipSelect CS //Primary SPI Chip Select is CS for the MicroMod Artemis Processor. Adjust for your processor if necessary.
|
|
|
|
#define sdWriteSize 512 // Write data to the SD card in blocks of 512 bytes
|
|
#define fileBufferSize 16384 // Allocate 16KBytes of RAM for UBX message storage
|
|
|
|
unsigned long lastPrint; // Record when the last Serial print took place
|
|
unsigned long bytesWritten = 0; // Record how many bytes have been written to SD card
|
|
|
|
void setup()
|
|
{
|
|
Serial.begin(115200);
|
|
while (!Serial); //Wait for user to open terminal
|
|
Serial.println("SparkFun u-blox Example");
|
|
|
|
pinMode(LED_BUILTIN, OUTPUT); // Flash LED_BUILTIN each time we write to the SD card
|
|
digitalWrite(LED_BUILTIN, LOW);
|
|
|
|
Wire.begin(); // Start I2C communication
|
|
|
|
#if defined(AM_PART_APOLLO3)
|
|
Wire.setPullups(0); // On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
|
|
#endif
|
|
|
|
while (Serial.available()) // Make sure the Serial buffer is empty
|
|
{
|
|
Serial.read();
|
|
}
|
|
|
|
Serial.println(F("Press any key to start logging."));
|
|
|
|
while (!Serial.available()) // Wait for the user to press a key
|
|
{
|
|
; // Do nothing
|
|
}
|
|
|
|
delay(100); // Wait, just in case multiple characters were sent
|
|
|
|
while (Serial.available()) // Empty the Serial buffer
|
|
{
|
|
Serial.read();
|
|
}
|
|
|
|
Serial.println("Initializing SD card...");
|
|
|
|
// See if the card is present and can be initialized:
|
|
if (!SD.begin(sdChipSelect))
|
|
{
|
|
Serial.println("Card failed, or not present. Freezing...");
|
|
// don't do anything more:
|
|
while (1);
|
|
}
|
|
Serial.println("SD card initialized.");
|
|
|
|
// Create or open a file called "PVT_NMEA.ubx" on the SD card.
|
|
// If the file already exists, the new data is appended to the end of the file.
|
|
myFile = SD.open("PVT_NMEA.ubx", FILE_WRITE);
|
|
if(!myFile)
|
|
{
|
|
Serial.println(F("Failed to create UBX data file! Freezing..."));
|
|
while (1);
|
|
}
|
|
|
|
//myGNSS.enableDebugging(); // Uncomment this line to enable lots of helpful GNSS debug messages on Serial
|
|
//myGNSS.enableDebugging(Serial, true); // Or, uncomment this line to enable only the important GNSS debug messages on Serial
|
|
|
|
//myGNSS.disableUBX7Fcheck(); // RAWX data can legitimately contain 0x7F. Uncomment this line to disable the "7F" check in checkUbloxI2C
|
|
|
|
// SD cards can occasionally 'hiccup' and a write takes much longer than usual. The buffer needs to be big enough
|
|
// to hold the backlog of data if/when this happens.
|
|
// getMaxFileBufferAvail will tell us the maximum number of bytes which the file buffer has contained.
|
|
myGNSS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin
|
|
|
|
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
|
|
{
|
|
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing..."));
|
|
while (1);
|
|
}
|
|
|
|
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
|
|
// This will (re)enable the standard NMEA messages too
|
|
// This will also disable any "auto" UBX messages that were enabled and saved by other examples and reduce the load on the I2C bus
|
|
//myGNSS.factoryDefault(); delay(5000);
|
|
|
|
myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA); //Set the I2C port to output both UBX and NMEA messages
|
|
|
|
//myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Optional: save (only) the communications port settings to flash and BBR
|
|
|
|
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second
|
|
|
|
myGNSS.setAutoPVT(true, false); // Enable automatic NAV PVT messages: without callback; without implicit update
|
|
myGNSS.logNAVPVT(); // Enable NAV PVT data logging
|
|
|
|
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C, 1); // Ensure the GxGGA (Global positioning system fix data) message is enabled. Send every measurement.
|
|
myGNSS.enableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C, 1); // Ensure the GxGSA (GNSS DOP and Active satellites) message is enabled. Send every measurement.
|
|
myGNSS.enableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C, 1); // Ensure the GxGSV (GNSS satellites in view) message is enabled. Send every measurement.
|
|
|
|
myGNSS.setNMEALoggingMask(SFE_UBLOX_FILTER_NMEA_ALL); // Enable logging of all enabled NMEA messages
|
|
//myGNSS.setNMEALoggingMask(SFE_UBLOX_FILTER_NMEA_GGA | SFE_UBLOX_FILTER_NMEA_GSA); // Or we can, for example, log only GxGGA & GxGSA and ignore GxGSV
|
|
|
|
Serial.println(F("Press any key to stop logging."));
|
|
|
|
lastPrint = millis(); // Initialize lastPrint
|
|
}
|
|
|
|
void loop()
|
|
{
|
|
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
|
|
|
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
while (myGNSS.fileBufferAvailable() >= sdWriteSize) // Check to see if we have at least sdWriteSize waiting in the buffer
|
|
{
|
|
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN each time we write to the SD card
|
|
|
|
uint8_t myBuffer[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
|
|
|
|
myGNSS.extractFileBufferData((uint8_t *)&myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
|
|
|
|
myFile.write(myBuffer, sdWriteSize); // Write exactly sdWriteSize bytes from myBuffer to the ubxDataFile on the SD card
|
|
|
|
bytesWritten += sdWriteSize; // Update bytesWritten
|
|
|
|
// In case the SD writing is slow or there is a lot of data to write, keep checking for the arrival of new data
|
|
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
|
|
|
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off again
|
|
}
|
|
|
|
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
if (millis() > (lastPrint + 1000)) // Print bytesWritten once per second
|
|
{
|
|
Serial.print(F("The number of bytes written to SD card is ")); // Print how many bytes have been written to SD card
|
|
Serial.println(bytesWritten);
|
|
|
|
uint16_t maxBufferBytes = myGNSS.getMaxFileBufferAvail(); // Get how full the file buffer has been (not how full it is now)
|
|
|
|
//Serial.print(F("The maximum number of bytes which the file buffer has contained is: ")); // It is a fun thing to watch how full the buffer gets
|
|
//Serial.println(maxBufferBytes);
|
|
|
|
if (maxBufferBytes > ((fileBufferSize / 5) * 4)) // Warn the user if fileBufferSize was more than 80% full
|
|
{
|
|
Serial.println(F("Warning: the file buffer has been over 80% full. Some data may have been lost."));
|
|
}
|
|
|
|
lastPrint = millis(); // Update lastPrint
|
|
}
|
|
|
|
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
if (Serial.available()) // Check if the user wants to stop logging
|
|
{
|
|
uint16_t remainingBytes = myGNSS.fileBufferAvailable(); // Check if there are any bytes remaining in the file buffer
|
|
|
|
while (remainingBytes > 0) // While there is still data in the file buffer
|
|
{
|
|
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN while we write to the SD card
|
|
|
|
uint8_t myBuffer[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
|
|
|
|
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
|
|
if (bytesToWrite > sdWriteSize)
|
|
{
|
|
bytesToWrite = sdWriteSize;
|
|
}
|
|
|
|
myGNSS.extractFileBufferData((uint8_t *)&myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
|
|
|
|
myFile.write(myBuffer, bytesToWrite); // Write bytesToWrite bytes from myBuffer to the ubxDataFile on the SD card
|
|
|
|
bytesWritten += bytesToWrite; // Update bytesWritten
|
|
|
|
remainingBytes -= bytesToWrite; // Decrement remainingBytes
|
|
}
|
|
|
|
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off
|
|
|
|
Serial.print(F("The total number of bytes written to SD card is ")); // Print how many bytes have been written to SD card
|
|
Serial.println(bytesWritten);
|
|
|
|
myFile.close(); // Close the data file
|
|
|
|
Serial.println(F("Logging stopped. Freezing..."));
|
|
while(1); // Do nothing more
|
|
}
|
|
|
|
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
}
|