Initial commit - based on v2_candidate
This commit is contained in:
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
Configuring the GNSS to automatically send NAV PVT reports over I2C and log them to file on SD card
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: December 30th, 2020
|
||||
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 NAV PVT reports automatically
|
||||
and log the data to SD card in UBX format.
|
||||
|
||||
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.
|
||||
|
||||
Data is logged in u-blox UBX format. Please see the u-blox protocol specification for more details.
|
||||
You can replay and analyze the data using u-center:
|
||||
https://www.u-blox.com/en/product/u-center
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_Ublox_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GPS myGPS;
|
||||
|
||||
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 packetLength 100 // NAV PVT is 92 + 8 bytes in length (including the sync chars, class, id, length and checksum bytes)
|
||||
|
||||
// Callback: printPVTdata will be called when new NAV PVT data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_NAV_PVT_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoPVTcallback
|
||||
// / _____ This _must_ be UBX_NAV_PVT_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printPVTdata(UBX_NAV_PVT_data_t ubxDataStruct)
|
||||
{
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Time: ")); // Print the time
|
||||
uint8_t hms = ubxDataStruct.hour; // Print the hours
|
||||
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
|
||||
Serial.print(hms);
|
||||
Serial.print(F(":"));
|
||||
hms = ubxDataStruct.min; // Print the minutes
|
||||
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
|
||||
Serial.print(hms);
|
||||
Serial.print(F(":"));
|
||||
hms = ubxDataStruct.sec; // Print the seconds
|
||||
if (hms < 10) Serial.print(F("0")); // Print a leading zero if required
|
||||
Serial.print(hms);
|
||||
Serial.print(F("."));
|
||||
unsigned long millisecs = ubxDataStruct.iTOW % 1000; // Print the milliseconds
|
||||
if (millisecs < 100) Serial.print(F("0")); // Print the trailing zeros correctly
|
||||
if (millisecs < 10) Serial.print(F("0"));
|
||||
Serial.print(millisecs);
|
||||
|
||||
long latitude = ubxDataStruct.lat; // Print the latitude
|
||||
Serial.print(F(" Lat: "));
|
||||
Serial.print(latitude);
|
||||
|
||||
long longitude = ubxDataStruct.lon; // Print the longitude
|
||||
Serial.print(F(" Long: "));
|
||||
Serial.print(longitude);
|
||||
Serial.print(F(" (degrees * 10^-7)"));
|
||||
|
||||
long altitude = ubxDataStruct.hMSL; // Print the height above mean sea level
|
||||
Serial.print(F(" Height above MSL: "));
|
||||
Serial.print(altitude);
|
||||
Serial.println(F(" (mm)"));
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin(); // Start I2C communication with the GNSS
|
||||
|
||||
#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 "NAV_PVT.ubx" on the SD card.
|
||||
// If the file already exists, the new data is appended to the end of the file.
|
||||
myFile = SD.open("NAV_PVT.ubx", FILE_WRITE);
|
||||
if(!myFile)
|
||||
{
|
||||
Serial.println(F("Failed to create UBX data file! Freezing..."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
//myGPS.enableDebugging(); // Uncomment this line to enable helpful GNSS debug messages on Serial
|
||||
|
||||
// NAV PVT messages are 100 bytes long.
|
||||
// In this example, the data will arrive no faster than one message per second.
|
||||
// So, setting the file buffer size to 301 bytes should be more than adequate.
|
||||
// I.e. room for three messages plus an empty tail byte.
|
||||
myGPS.setFileBufferSize(301); // setFileBufferSize must be called _before_ .begin
|
||||
|
||||
if (myGPS.begin() == false) //Connect to the Ublox 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 also disable any "auto" messages that were enabled and saved by other examples and reduce the load on the I2C bus)
|
||||
//myGPS.factoryDefault(); delay(5000);
|
||||
|
||||
myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGPS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGPS.setNavigationFrequency(1); //Produce one navigation solution per second
|
||||
|
||||
myGPS.setAutoPVTcallback(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata
|
||||
|
||||
myGPS.logNAVPVT(); // Enable NAV PVT data logging
|
||||
|
||||
Serial.println(F("Press any key to stop logging."));
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGPS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGPS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
if (myGPS.fileBufferAvailable() >= packetLength) // Check to see if a new packetLength-byte NAV PVT message has been stored
|
||||
{
|
||||
uint8_t myBuffer[packetLength]; // Create our own buffer to hold the data while we write it to SD card
|
||||
|
||||
myGPS.extractFileBufferData((uint8_t *)&myBuffer, packetLength); // Extract exactly packetLength bytes from the UBX file buffer and put them into myBuffer
|
||||
|
||||
myFile.write(myBuffer, packetLength); // Write exactly packetLength bytes from myBuffer to the ubxDataFile on the SD card
|
||||
|
||||
//printBuffer(myBuffer); // Uncomment this line to print the data as Hexadecimal bytes
|
||||
}
|
||||
|
||||
if (Serial.available()) // Check if the user wants to stop logging
|
||||
{
|
||||
myFile.close(); // Close the data file
|
||||
Serial.println(F("Logging stopped. Freezing..."));
|
||||
while(1); // Do nothing more
|
||||
}
|
||||
|
||||
Serial.print(".");
|
||||
delay(50);
|
||||
}
|
||||
|
||||
// Print the buffer contents as Hexadecimal bytes
|
||||
// You should see:
|
||||
// SYNC CHAR 1: 0xB5
|
||||
// SYNC CHAR 2: 0x62
|
||||
// CLASS: 0x01 for NAV
|
||||
// ID: 0x07 for PVT
|
||||
// LENGTH: 2-bytes Little Endian (0x5C00 = 92 bytes for NAV PVT)
|
||||
// PAYLOAD: LENGTH bytes
|
||||
// CHECKSUM_A
|
||||
// CHECKSUM_B
|
||||
// Please see the u-blox protocol specification for more details
|
||||
void printBuffer(uint8_t *ptr)
|
||||
{
|
||||
for (int i = 0; i < packetLength; i++)
|
||||
{
|
||||
if (ptr[i] < 16) Serial.print("0"); // Print a leading zero if required
|
||||
Serial.print(ptr[i], HEX); // Print the byte as Hexadecimal
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
Configuring the GNSS to automatically send TIM TM2 reports over I2C and log them to file on SD card
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: December 30th, 2020
|
||||
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 TIM TM2 reports automatically
|
||||
and log the data to SD card in UBX format.
|
||||
|
||||
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.
|
||||
|
||||
Connecting the PPS (Pulse Per Second) breakout pin to the INT (Interrupt) pin with a jumper wire
|
||||
will cause a TIM TM2 message to be produced once per second. You can then study the timing of the
|
||||
pulse edges with nanosecond resolution!
|
||||
|
||||
Note: TIM TM2 can only capture the timing of one rising edge and one falling edge per
|
||||
navigation solution. So with setNavigationFrequency set to 1Hz, we can only see the timing
|
||||
of one rising and one falling edge per second. If the frequency of the signal on the INT pin
|
||||
is higher than 1Hz, we will only be able to see the timing of the most recent edges.
|
||||
However, the module can count the number of rising edges too, at rates faster than the navigation rate.
|
||||
|
||||
TIM TM2 messages are only produced when a rising or falling edge is detected on the INT pin.
|
||||
If you disconnect your PPS to INT jumper wire, the messages will stop.
|
||||
|
||||
Data is logged in u-blox UBX format. Please see the u-blox protocol specification for more details.
|
||||
You can replay and analyze the data using u-center:
|
||||
https://www.u-blox.com/en/product/u-center
|
||||
|
||||
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-M9N: https://www.sparkfun.com/products/17285
|
||||
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_Ublox_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GPS myGPS;
|
||||
|
||||
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 packetLength 36 // TIM TM2 is 28 + 8 bytes in length (including the sync chars, class, id, length and checksum bytes)
|
||||
|
||||
int dotsPrinted = 0; // Print dots in rows of 50 while waiting for a TIM TM2 message
|
||||
|
||||
// Callback: printTIMTM2data will be called when new TIM TM2 data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_TIM_TM2_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoTIMTM2callback
|
||||
// / _____ This _must_ be UBX_TIM_TM2_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void printTIMTM2data(UBX_TIM_TM2_data_t ubxDataStruct)
|
||||
{
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("newFallingEdge: ")); // 1 if a new falling edge was detected
|
||||
Serial.print(ubxDataStruct.flags.bits.newFallingEdge);
|
||||
|
||||
Serial.print(F(" newRisingEdge: ")); // 1 if a new rising edge was detected
|
||||
Serial.print(ubxDataStruct.flags.bits.newRisingEdge);
|
||||
|
||||
Serial.print(F(" Rising Edge Counter: ")); // Rising edge counter
|
||||
Serial.print(ubxDataStruct.count);
|
||||
|
||||
Serial.print(F(" towMsR: ")); // Time Of Week of rising edge (ms)
|
||||
Serial.print(ubxDataStruct.towMsR);
|
||||
|
||||
Serial.print(F(" towSubMsR: ")); // Millisecond fraction of Time Of Week of rising edge in nanoseconds
|
||||
Serial.print(ubxDataStruct.towSubMsR);
|
||||
|
||||
Serial.print(F(" towMsF: ")); // Time Of Week of falling edge (ms)
|
||||
Serial.print(ubxDataStruct.towMsF);
|
||||
|
||||
Serial.print(F(" towSubMsF: ")); // Millisecond fraction of Time Of Week of falling edge in nanoseconds
|
||||
Serial.println(ubxDataStruct.towSubMsF);
|
||||
|
||||
dotsPrinted = 0; // Reset dotsPrinted
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while (!Serial); //Wait for user to open terminal
|
||||
Serial.println("SparkFun u-blox Example");
|
||||
|
||||
Wire.begin(); // Start I2C communication with the GNSS
|
||||
|
||||
#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 "TIM_TM2.ubx" on the SD card.
|
||||
// If the file already exists, the new data is appended to the end of the file.
|
||||
myFile = SD.open("TIM_TM2.ubx", FILE_WRITE);
|
||||
if(!myFile)
|
||||
{
|
||||
Serial.println(F("Failed to create UBX data file! Freezing..."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
//myGPS.enableDebugging(); // Uncomment this line to enable helpful GNSS debug messages on Serial
|
||||
|
||||
// TIM TM2 messages are 36 bytes long.
|
||||
// In this example, the data will arrive no faster than one message per second.
|
||||
// So, setting the file buffer size to 109 bytes should be more than adequate.
|
||||
// I.e. room for three messages plus an empty tail byte.
|
||||
myGPS.setFileBufferSize(109); // setFileBufferSize must be called _before_ .begin
|
||||
|
||||
if (myGPS.begin() == false) //Connect to the Ublox 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 also disable any "auto" messages that were enabled and saved by other examples and reduce the load on the I2C bus)
|
||||
//myGPS.factoryDefault(); delay(5000);
|
||||
|
||||
myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGPS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGPS.setNavigationFrequency(1); //Produce one navigation solution per second
|
||||
|
||||
myGPS.setAutoTIMTM2callback(&printTIMTM2data); // Enable automatic TIM TM2 messages with callback to printTIMTM2data
|
||||
|
||||
myGPS.logTIMTM2(); // Enable TIM TM2 data logging
|
||||
|
||||
Serial.println(F("Press any key to stop logging."));
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGPS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGPS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
if (myGPS.fileBufferAvailable() >= packetLength) // Check to see if a new packetLength-byte TIM TM2 message has been stored
|
||||
{
|
||||
uint8_t myBuffer[packetLength]; // Create our own buffer to hold the data while we write it to SD card
|
||||
|
||||
myGPS.extractFileBufferData((uint8_t *)&myBuffer, packetLength); // Extract exactly packetLength bytes from the UBX file buffer and put them into myBuffer
|
||||
|
||||
myFile.write(myBuffer, packetLength); // Write exactly packetLength bytes from myBuffer to the ubxDataFile on the SD card
|
||||
|
||||
//printBuffer(myBuffer); // Uncomment this line to print the data
|
||||
}
|
||||
|
||||
if (Serial.available()) // Check if the user wants to stop logging
|
||||
{
|
||||
myFile.close(); // Close the data file
|
||||
Serial.println(F("Logging stopped. Freezing..."));
|
||||
while(1); // Do nothing more
|
||||
}
|
||||
|
||||
Serial.print("."); // Print dots in rows of 50
|
||||
delay(50);
|
||||
if (++dotsPrinted > 50)
|
||||
{
|
||||
Serial.println();
|
||||
dotsPrinted = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Print the buffer contents as Hexadecimal
|
||||
// You should see:
|
||||
// SYNC CHAR 1: 0xB5
|
||||
// SYNC CHAR 2: 0x62
|
||||
// CLASS: 0x0D for TIM
|
||||
// ID: 0x03 for TM2
|
||||
// LENGTH: 2-bytes Little Endian (0x1C00 = 28 bytes for TIM TM2)
|
||||
// PAYLOAD: LENGTH bytes
|
||||
// CHECKSUM_A
|
||||
// CHECKSUM_B
|
||||
// Please see the u-blox protocol specification for more details
|
||||
void printBuffer(uint8_t *ptr)
|
||||
{
|
||||
for (int i = 0; i < packetLength; i++)
|
||||
{
|
||||
if (ptr[i] < 16) Serial.print("0"); // Print a leading zero if required
|
||||
Serial.print(ptr[i], HEX); // Print the byte as Hexadecimal
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
+273
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
Configuring the GNSS to automatically send RXM SFRBX and RAWX reports over I2C and log them to file on SD card
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: December 30th, 2020
|
||||
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 RXM SFRBX and RAWX reports automatically
|
||||
and log the data to SD card in UBX format.
|
||||
|
||||
** Please note: this example will only work on u-blox ADR or High Precision GNSS or Time Sync products **
|
||||
|
||||
** Please note: this example will only work on processors like the Artemis which have plenty of RAM available **
|
||||
|
||||
Data is logged in u-blox UBX format. Please see the u-blox protocol specification for more details.
|
||||
You can replay and analyze the data using u-center:
|
||||
https://www.u-blox.com/en/product/u-center
|
||||
Or you can use (e.g.) RTKLIB to analyze the data and extract your precise location or produce
|
||||
Post-Processed Kinematic data:
|
||||
https://rtklibexplorer.wordpress.com/
|
||||
http://rtkexplorer.com/downloads/rtklib-code/
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_Ublox_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GPS myGPS;
|
||||
|
||||
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
|
||||
|
||||
// Note: we'll keep a count of how many SFRBX and RAWX messages arrive - but the count will not be completely accurate.
|
||||
// If two or more SFRBX messages arrive together as a group and are processed by one call to checkUblox, the count will
|
||||
// only increase by one.
|
||||
|
||||
int numSFRBX = 0; // Keep count of how many SFRBX message groups have been received (see note above)
|
||||
int numRAWX = 0; // Keep count of how many RAWX message groups have been received (see note above)
|
||||
|
||||
// Callback: newSFRBX will be called when new RXM SFRBX data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_RXMSFRBX_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoRXMSFRBXcallback
|
||||
// / _____ This _must_ be UBX_RXM_SFRBX_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void newSFRBX(UBX_RXM_SFRBX_data_t ubxDataStruct)
|
||||
{
|
||||
numSFRBX++; // Increment the count
|
||||
}
|
||||
|
||||
// Callback: newRAWX will be called when new RXM RAWX data arrives
|
||||
// See u-blox_structs.h for the full definition of UBX_RXMRAWX_data_t
|
||||
// _____ You can use any name you like for the callback. Use the same name when you call setAutoRXMRAWXcallback
|
||||
// / _____ This _must_ be UBX_RXM_RAWX_data_t
|
||||
// | / _____ You can use any name you like for the struct
|
||||
// | | /
|
||||
// | | |
|
||||
void newRAWX(UBX_RXM_RAWX_data_t ubxDataStruct)
|
||||
{
|
||||
numRAWX++; // Increment the count
|
||||
}
|
||||
|
||||
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 "RXM_RAWX.ubx" on the SD card.
|
||||
// If the file already exists, the new data is appended to the end of the file.
|
||||
myFile = SD.open("RXM_RAWX.ubx", FILE_WRITE);
|
||||
if(!myFile)
|
||||
{
|
||||
Serial.println(F("Failed to create UBX data file! Freezing..."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
//myGPS.enableDebugging(); // Uncomment this line to enable lots of helpful GNSS debug messages on Serial
|
||||
//myGPS.enableDebugging(Serial, true); // Or, uncomment this line to enable only the important GNSS debug messages on Serial
|
||||
|
||||
myGPS.disableUBX7Fcheck(); // RAWX data can legitimately contain 0x7F, so we need to disable the "7F" check in checkUbloxI2C
|
||||
|
||||
// RAWX messages can be over 2KBytes in size, so we need to make sure we allocate enough RAM to hold all the data.
|
||||
// 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.
|
||||
myGPS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin
|
||||
|
||||
if (myGPS.begin() == false) //Connect to the Ublox 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 also disable any "auto" messages that were enabled and saved by other examples and reduce the load on the I2C bus)
|
||||
//myGPS.factoryDefault(); delay(5000);
|
||||
|
||||
myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGPS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGPS.setNavigationFrequency(1); //Produce one navigation solution per second (that's plenty for Precise Point Positioning)
|
||||
|
||||
myGPS.setAutoRXMSFRBXcallback(&newSFRBX); // Enable automatic RXM SFRBX messages with callback to newSFRBX
|
||||
|
||||
myGPS.logRXMSFRBX(); // Enable RXM SFRBX data logging
|
||||
|
||||
myGPS.setAutoRXMRAWXcallback(&newRAWX); // Enable automatic RXM RAWX messages with callback to newRAWX
|
||||
|
||||
myGPS.logRXMRAWX(); // Enable RXM RAWX data logging
|
||||
|
||||
Serial.println(F("Press any key to stop logging."));
|
||||
|
||||
lastPrint = millis(); // Initialize lastPrint
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
myGPS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGPS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
while (myGPS.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
|
||||
|
||||
myGPS.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
|
||||
|
||||
// In case the SD writing is slow or there is a lot of data to write, keep checking for the arrival of new data
|
||||
myGPS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGPS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off again
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
if (millis() > (lastPrint + 1000)) // Print the message count once per second
|
||||
{
|
||||
Serial.print(F("Number of message groups received: SFRBX: ")); // Print how many message groups have been received (see note above)
|
||||
Serial.print(numSFRBX);
|
||||
Serial.print(F(" RAWX: "));
|
||||
Serial.println(numRAWX);
|
||||
|
||||
uint16_t maxBufferBytes = myGPS.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 = myGPS.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;
|
||||
}
|
||||
|
||||
myGPS.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
|
||||
|
||||
remainingBytes -= bytesToWrite; // Decrement remainingBytes
|
||||
}
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off
|
||||
|
||||
myFile.close(); // Close the data file
|
||||
|
||||
Serial.println(F("Logging stopped. Freezing..."));
|
||||
while(1); // Do nothing more
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
}
|
||||
+247
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
Configuring the GNSS to automatically send RXM SFRBX and RAWX reports over I2C and log them to file on SD card
|
||||
** without using callbacks **
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: December 30th, 2020
|
||||
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 RXM SFRBX and RAWX reports automatically
|
||||
and log the data to SD card in UBX format ** without using callbacks **
|
||||
|
||||
** Please note: this example will only work on u-blox ADR or High Precision GNSS or Time Sync products **
|
||||
|
||||
** Please note: this example will only work on processors like the Artemis which have plenty of RAM available **
|
||||
|
||||
Data is logged in u-blox UBX format. Please see the u-blox protocol specification for more details.
|
||||
You can replay and analyze the data using u-center:
|
||||
https://www.u-blox.com/en/product/u-center
|
||||
Or you can use (e.g.) RTKLIB to analyze the data and extract your precise location or produce
|
||||
Post-Processed Kinematic data:
|
||||
https://rtklibexplorer.wordpress.com/
|
||||
http://rtkexplorer.com/downloads/rtklib-code/
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_Ublox_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GPS myGPS;
|
||||
|
||||
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 "RXM_RAWX.ubx" on the SD card.
|
||||
// If the file already exists, the new data is appended to the end of the file.
|
||||
myFile = SD.open("RXM_RAWX.ubx", FILE_WRITE);
|
||||
if(!myFile)
|
||||
{
|
||||
Serial.println(F("Failed to create UBX data file! Freezing..."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
//myGPS.enableDebugging(); // Uncomment this line to enable lots of helpful GNSS debug messages on Serial
|
||||
//myGPS.enableDebugging(Serial, true); // Or, uncomment this line to enable only the important GNSS debug messages on Serial
|
||||
|
||||
myGPS.disableUBX7Fcheck(); // RAWX data can legitimately contain 0x7F, so we need to disable the "7F" check in checkUbloxI2C
|
||||
|
||||
// RAWX messages can be over 2KBytes in size, so we need to make sure we allocate enough RAM to hold all the data.
|
||||
// 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.
|
||||
myGPS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin
|
||||
|
||||
if (myGPS.begin() == false) //Connect to the Ublox 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 also disable any "auto" messages that were enabled and saved by other examples and reduce the load on the I2C bus)
|
||||
//myGPS.factoryDefault(); delay(5000);
|
||||
|
||||
myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGPS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGPS.setNavigationFrequency(1); //Produce one navigation solution per second (that's plenty for Precise Point Positioning)
|
||||
|
||||
myGPS.setAutoRXMSFRBX(true, false); // Enable automatic RXM SFRBX messages: without callback; without implicit update
|
||||
|
||||
myGPS.logRXMSFRBX(); // Enable RXM SFRBX data logging
|
||||
|
||||
myGPS.setAutoRXMRAWX(true, false); // Enable automatic RXM RAWX messages: without callback; without implicit update
|
||||
|
||||
myGPS.logRXMRAWX(); // Enable RXM RAWX data logging
|
||||
|
||||
Serial.println(F("Press any key to stop logging."));
|
||||
|
||||
lastPrint = millis(); // Initialize lastPrint
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
myGPS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
while (myGPS.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
|
||||
|
||||
myGPS.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
|
||||
myGPS.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 = myGPS.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 = myGPS.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;
|
||||
}
|
||||
|
||||
myGPS.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
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
Configuring the GNSS to automatically send RXM SFRBX and RAWX reports over I2C and log them to file on SD card
|
||||
without using callbacks and ** as fast as your module can go! **
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: December 30th, 2020
|
||||
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 RXM SFRBX and RAWX reports automatically
|
||||
and log the data to SD card in UBX format without using callbacks and ** as fast as your module can go! **
|
||||
|
||||
** Please note: this example will only work on u-blox ADR or High Precision GNSS or Time Sync products **
|
||||
|
||||
** Please note: this example will only work on processors like the Artemis which have plenty of RAM available **
|
||||
|
||||
Data is logged in u-blox UBX format. Please see the u-blox protocol specification for more details.
|
||||
You can replay and analyze the data using u-center:
|
||||
https://www.u-blox.com/en/product/u-center
|
||||
Or you can use (e.g.) RTKLIB to analyze the data and extract your precise location or produce
|
||||
Post-Processed Kinematic data:
|
||||
https://rtklibexplorer.wordpress.com/
|
||||
http://rtkexplorer.com/downloads/rtklib-code/
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include <Wire.h> //Needed for I2C to GNSS
|
||||
|
||||
#include <SparkFun_Ublox_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
|
||||
SFE_UBLOX_GPS myGPS;
|
||||
|
||||
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 32768 // Allocate 32KBytes 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 "Fast_RXM.ubx" on the SD card.
|
||||
// If the file already exists, the new data is appended to the end of the file.
|
||||
myFile = SD.open("Fast_RXM.ubx", FILE_WRITE);
|
||||
if(!myFile)
|
||||
{
|
||||
Serial.println(F("Failed to create UBX data file! Freezing..."));
|
||||
while (1);
|
||||
}
|
||||
|
||||
//myGPS.enableDebugging(); // Uncomment this line to enable lots of helpful GNSS debug messages on Serial
|
||||
//myGPS.enableDebugging(Serial, true); // Or, uncomment this line to enable only the important GNSS debug messages on Serial
|
||||
|
||||
myGPS.disableUBX7Fcheck(); // RAWX data can legitimately contain 0x7F, so we need to disable the "7F" check in checkUbloxI2C
|
||||
|
||||
// RAWX messages can be over 2KBytes in size, so we need to make sure we allocate enough RAM to hold all the data.
|
||||
// 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.
|
||||
myGPS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin
|
||||
|
||||
if (myGPS.begin() == false) //Connect to the Ublox 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 also disable any "auto" messages that were enabled and saved by other examples and reduce the load on the I2C bus)
|
||||
//myGPS.factoryDefault(); delay(5000);
|
||||
|
||||
myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGPS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
// Modules like the ZED-F9P can produce RAW navigation data at rates of up to 25Hz but not while using all of the GNSS constellations.
|
||||
// Please consult the data sheet for the Performance figures for your module.
|
||||
// In this example we make sure GPS is enabled and then disable Galileo, GLONASS, BeiDou, SBAS and QZSS to achieve 25Hz.
|
||||
myGPS.enableGNSS(true, SFE_UBLOX_GNSS_ID_GPS); // Make sure GPS is enabled (we must leave at least one major GNSS enabled!)
|
||||
myGPS.enableGNSS(false, SFE_UBLOX_GNSS_ID_SBAS); // Disable SBAS
|
||||
myGPS.enableGNSS(false, SFE_UBLOX_GNSS_ID_GALILEO); // Disable Galileo
|
||||
myGPS.enableGNSS(false, SFE_UBLOX_GNSS_ID_BEIDOU); // Disable BeiDou
|
||||
myGPS.enableGNSS(false, SFE_UBLOX_GNSS_ID_IMES); // Disable IMES
|
||||
myGPS.enableGNSS(false, SFE_UBLOX_GNSS_ID_QZSS); // Disable QZSS
|
||||
myGPS.enableGNSS(false, SFE_UBLOX_GNSS_ID_GLONASS); // Disable GLONASS
|
||||
|
||||
delay(2000); // Give the module some extra time to get ready
|
||||
|
||||
//Produce 7 navigation solutions per second. That's a lot of RAWX data - especially when using both GPS bands L1 and L2.
|
||||
//The SD library and card need to be able to cope with the data rate too. You may need a faster SD library to go above 7Hz.
|
||||
myGPS.setNavigationFrequency(7);
|
||||
|
||||
myGPS.setAutoRXMSFRBX(true, false); // Enable automatic RXM SFRBX messages: without callback; without implicit update
|
||||
|
||||
myGPS.logRXMSFRBX(); // Enable RXM SFRBX data logging
|
||||
|
||||
myGPS.setAutoRXMRAWX(true, false); // Enable automatic RXM RAWX messages: without callback; without implicit update
|
||||
|
||||
myGPS.logRXMRAWX(); // Enable RXM RAWX data logging
|
||||
|
||||
Serial.println(F("Press any key to stop logging."));
|
||||
|
||||
lastPrint = millis(); // Initialize lastPrint
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
myGPS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
while (myGPS.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
|
||||
|
||||
myGPS.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
|
||||
myGPS.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 = myGPS.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
|
||||
{
|
||||
myGPS.setAutoRXMSFRBX(false, false); // Disable the automatic RXM SFRBX messages
|
||||
myGPS.setAutoRXMRAWX(false, false); // Disable the automatic RXM RAWX messages
|
||||
|
||||
delay(1000); // Allow time for any remaining messages to arrive
|
||||
myGPS.checkUblox(); // Process any remaining data
|
||||
|
||||
uint16_t remainingBytes = myGPS.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;
|
||||
}
|
||||
|
||||
myGPS.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);
|
||||
|
||||
uint16_t maxBufferBytes = myGPS.getMaxFileBufferAvail(); // Show 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: "));
|
||||
Serial.println(maxBufferBytes);
|
||||
|
||||
myFile.close(); // Close the data file
|
||||
|
||||
Serial.println(F("Logging stopped. Freezing..."));
|
||||
while(1); // Do nothing more
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
}
|
||||
Reference in New Issue
Block a user