first commit
This commit is contained in:
commit
e6a42e28e9
4355 changed files with 4626605 additions and 0 deletions
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
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: October 18th, 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 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 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
|
||||
Select "Artemis MicroMod Processor" 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_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 the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
|
||||
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#else
|
||||
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
|
||||
#endif
|
||||
#else
|
||||
|
||||
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
|
||||
|
||||
#endif
|
||||
|
||||
#define packetLength 100 // NAV PVT is 92 + 8 bytes in length (including the sync chars, class, id, length and checksum bytes)
|
||||
uint8_t *myBuffer; // Use myBuffer to hold the data while we write it to SD card
|
||||
|
||||
// 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
|
||||
|
||||
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
|
||||
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
|
||||
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
|
||||
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
|
||||
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
|
||||
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
|
||||
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
|
||||
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
|
||||
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
|
||||
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
|
||||
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
|
||||
#endif
|
||||
#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);
|
||||
}
|
||||
|
||||
//myGNSS.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.
|
||||
myGNSS.setFileBufferSize(301); // 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 also disable any "auto" 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); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second
|
||||
|
||||
myGNSS.setAutoPVTcallbackPtr(&printPVTdata); // Enable automatic NAV PVT messages with callback to printPVTdata
|
||||
|
||||
myGNSS.logNAVPVT(); // Enable NAV PVT data logging
|
||||
|
||||
myBuffer = new uint8_t[packetLength]; // Create our own buffer to hold the data while we write it to SD card
|
||||
|
||||
Serial.println(F("Press any key to stop logging."));
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
if (myGNSS.fileBufferAvailable() >= packetLength) // Check to see if a new packetLength-byte NAV PVT message has been stored
|
||||
{
|
||||
myGNSS.extractFileBufferData(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("\r\nLogging 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,267 @@
|
|||
/*
|
||||
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: October 18th, 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 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 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
|
||||
Select "Artemis MicroMod Processor" 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_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 the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
|
||||
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#else
|
||||
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
|
||||
#endif
|
||||
#else
|
||||
|
||||
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
|
||||
|
||||
#endif
|
||||
|
||||
#define packetLength 36 // TIM TM2 is 28 + 8 bytes in length (including the sync chars, class, id, length and checksum bytes)
|
||||
uint8_t *myBuffer; // Use myBuffer to hold the data while we write it to SD card
|
||||
|
||||
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
|
||||
|
||||
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
|
||||
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
|
||||
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
|
||||
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
|
||||
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
|
||||
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
|
||||
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
|
||||
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
|
||||
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
|
||||
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
|
||||
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
|
||||
#endif
|
||||
#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);
|
||||
}
|
||||
|
||||
//myGNSS.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.
|
||||
myGNSS.setFileBufferSize(109); // 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 also disable any "auto" 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); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second
|
||||
|
||||
myGNSS.setAutoTIMTM2callbackPtr(&printTIMTM2data); // Enable automatic TIM TM2 messages with callback to printTIMTM2data
|
||||
|
||||
myGNSS.logTIMTM2(); // Enable TIM TM2 data logging
|
||||
|
||||
myBuffer = new uint8_t[packetLength]; // Create our own buffer to hold the data while we write it to SD card
|
||||
|
||||
Serial.println(F("Press any key to stop logging."));
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
if (myGNSS.fileBufferAvailable() >= packetLength) // Check to see if a new packetLength-byte TIM TM2 message has been stored
|
||||
{
|
||||
myGNSS.extractFileBufferData(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("\r\nLogging 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();
|
||||
}
|
||||
|
|
@ -0,0 +1,297 @@
|
|||
/*
|
||||
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: October 18th, 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 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 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
|
||||
Select "Artemis MicroMod Processor" 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_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 the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
|
||||
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#else
|
||||
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
|
||||
#endif
|
||||
#else
|
||||
|
||||
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
|
||||
|
||||
#endif
|
||||
|
||||
#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
|
||||
uint8_t *myBuffer; // Use myBuffer to hold the data while we write it to SD card
|
||||
|
||||
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
|
||||
|
||||
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
|
||||
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
|
||||
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
|
||||
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
|
||||
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
|
||||
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
|
||||
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
|
||||
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
|
||||
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
|
||||
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
|
||||
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
|
||||
#endif
|
||||
#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);
|
||||
}
|
||||
|
||||
//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, 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.
|
||||
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 also disable any "auto" 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); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second (that's plenty for Precise Point Positioning)
|
||||
|
||||
myGNSS.setAutoRXMSFRBXcallbackPtr(&newSFRBX); // Enable automatic RXM SFRBX messages with callback to newSFRBX
|
||||
|
||||
myGNSS.logRXMSFRBX(); // Enable RXM SFRBX data logging
|
||||
|
||||
myGNSS.setAutoRXMRAWXcallbackPtr(&newRAWX); // Enable automatic RXM RAWX messages with callback to newRAWX
|
||||
|
||||
myGNSS.logRXMRAWX(); // Enable RXM RAWX data logging
|
||||
|
||||
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
|
||||
|
||||
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.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
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
|
||||
|
||||
myGNSS.extractFileBufferData(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
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.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 = 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
|
||||
|
||||
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
|
||||
if (bytesToWrite > sdWriteSize)
|
||||
{
|
||||
bytesToWrite = sdWriteSize;
|
||||
}
|
||||
|
||||
myGNSS.extractFileBufferData(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
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
}
|
||||
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
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: October 18th, 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 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 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
|
||||
Select "Artemis MicroMod Processor" 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_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 the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
|
||||
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#else
|
||||
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
|
||||
#endif
|
||||
#else
|
||||
|
||||
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
|
||||
|
||||
#endif
|
||||
|
||||
#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
|
||||
uint8_t *myBuffer; // A buffer to hold the data while we write it to SD card
|
||||
|
||||
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
|
||||
|
||||
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
|
||||
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
|
||||
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
|
||||
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
|
||||
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
|
||||
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
|
||||
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
|
||||
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
|
||||
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
|
||||
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
|
||||
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
|
||||
#endif
|
||||
#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);
|
||||
}
|
||||
|
||||
//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, 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.
|
||||
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 also disable any "auto" 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); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second (that's plenty for Precise Point Positioning)
|
||||
|
||||
myGNSS.setAutoRXMSFRBX(true, false); // Enable automatic RXM SFRBX messages: without callback; without implicit update
|
||||
|
||||
myGNSS.logRXMSFRBX(); // Enable RXM SFRBX data logging
|
||||
|
||||
myGNSS.setAutoRXMRAWX(true, false); // Enable automatic RXM RAWX messages: without callback; without implicit update
|
||||
|
||||
myGNSS.logRXMRAWX(); // Enable RXM RAWX data logging
|
||||
|
||||
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
|
||||
|
||||
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
|
||||
|
||||
myGNSS.extractFileBufferData(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
|
||||
|
||||
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
|
||||
if (bytesToWrite > sdWriteSize)
|
||||
{
|
||||
bytesToWrite = sdWriteSize;
|
||||
}
|
||||
|
||||
myGNSS.extractFileBufferData(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,296 @@
|
|||
/*
|
||||
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: October 18th, 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 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 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
|
||||
Select "Artemis MicroMod Processor" 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_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 the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
|
||||
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#else
|
||||
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
|
||||
#endif
|
||||
#else
|
||||
|
||||
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
|
||||
|
||||
#endif
|
||||
|
||||
#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
|
||||
uint8_t *myBuffer; // A buffer to hold the data while we write it to SD card
|
||||
|
||||
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
|
||||
|
||||
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
|
||||
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
|
||||
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
|
||||
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
|
||||
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
|
||||
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
|
||||
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
|
||||
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
|
||||
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
|
||||
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
|
||||
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
|
||||
#endif
|
||||
#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);
|
||||
}
|
||||
|
||||
//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, 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.
|
||||
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 also disable any "auto" 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); //Set the I2C port to output UBX only (turn off NMEA noise)
|
||||
myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Save (only) the communications port settings to flash and BBR
|
||||
|
||||
// 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.
|
||||
myGNSS.enableGNSS(true, SFE_UBLOX_GNSS_ID_GPS); // Make sure GPS is enabled (we must leave at least one major GNSS enabled!)
|
||||
myGNSS.enableGNSS(false, SFE_UBLOX_GNSS_ID_SBAS); // Disable SBAS
|
||||
myGNSS.enableGNSS(false, SFE_UBLOX_GNSS_ID_GALILEO); // Disable Galileo
|
||||
myGNSS.enableGNSS(false, SFE_UBLOX_GNSS_ID_BEIDOU); // Disable BeiDou
|
||||
myGNSS.enableGNSS(false, SFE_UBLOX_GNSS_ID_IMES); // Disable IMES
|
||||
myGNSS.enableGNSS(false, SFE_UBLOX_GNSS_ID_QZSS); // Disable QZSS
|
||||
myGNSS.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.
|
||||
myGNSS.setNavigationFrequency(7);
|
||||
|
||||
myGNSS.setAutoRXMSFRBX(true, false); // Enable automatic RXM SFRBX messages: without callback; without implicit update
|
||||
|
||||
myGNSS.logRXMSFRBX(); // Enable RXM SFRBX data logging
|
||||
|
||||
myGNSS.setAutoRXMRAWX(true, false); // Enable automatic RXM RAWX messages: without callback; without implicit update
|
||||
|
||||
myGNSS.logRXMRAWX(); // Enable RXM RAWX data logging
|
||||
|
||||
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
|
||||
|
||||
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
|
||||
|
||||
myGNSS.extractFileBufferData(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
|
||||
{
|
||||
myGNSS.setAutoRXMSFRBX(false, false); // Disable the automatic RXM SFRBX messages
|
||||
myGNSS.setAutoRXMRAWX(false, false); // Disable the automatic RXM RAWX messages
|
||||
|
||||
delay(1000); // Allow time for any remaining messages to arrive
|
||||
myGNSS.checkUblox(); // Process any remaining data
|
||||
|
||||
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
|
||||
|
||||
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
|
||||
if (bytesToWrite > sdWriteSize)
|
||||
{
|
||||
bytesToWrite = sdWriteSize;
|
||||
}
|
||||
|
||||
myGNSS.extractFileBufferData(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 = myGNSS.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
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
}
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
Demonstrate how to log NMEA and UBX data simultaneously
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: October 18th, 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 2.2.0 of the Apollo3 boards on Arduino IDE 1.8.13.
|
||||
Select "Artemis MicroMod Processor" 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 the microSD (SPI) Chip Select pin. Adjust for your processor if necessary.
|
||||
#if defined(ARDUINO_ARCH_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1 or v2
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#define sdChipSelect SPI_CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_MICROMOD) // Check for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#define sdChipSelect CS // SPI (microSD) Chip Select for the Artemis MicroMod Processor Board on Apollo3 v1
|
||||
#else
|
||||
#define sdChipSelect CS // Catch-all for the other Artemis Boards - change this if required to match your hardware
|
||||
#endif
|
||||
#else
|
||||
|
||||
#define sdChipSelect CS // Catch-all for all non-Artemis boards - change this if required to match your hardware
|
||||
|
||||
#endif
|
||||
|
||||
#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
|
||||
uint8_t *myBuffer; // A buffer to hold the data while we write it to SD card
|
||||
|
||||
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
|
||||
|
||||
// On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
|
||||
#if defined(AM_PART_APOLLO3) // Check for SparkFun Apollo3 (Artemis) v1
|
||||
Wire.setPullups(0); // Disable the internal I2C pull-ups on Apollo3 v1
|
||||
#elif defined(ARDUINO_ARCH_APOLLO3) // Else check for SparkFun Apollo3 (Artemis) (v2)
|
||||
#if defined(ARDUINO_APOLLO3_SFE_ARTEMIS_MM_PB) // Check for the Artemis MicroMod Processor Board on Apollo3 v2
|
||||
// On Apollo3 v2 we can still disable the pull-ups but we need to do it manually
|
||||
// The IOM and pin numbers here are specific to the Artemis MicroMod Processor Board
|
||||
am_hal_gpio_pincfg_t sclPinCfg = g_AM_BSP_GPIO_IOM4_SCL; // Artemis MicroMod Processor Board uses IOM4 for I2C communication
|
||||
am_hal_gpio_pincfg_t sdaPinCfg = g_AM_BSP_GPIO_IOM4_SDA;
|
||||
sclPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE; // Disable the pull-ups
|
||||
sdaPinCfg.ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
|
||||
pin_config(PinName(39), sclPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 39 for SCL
|
||||
pin_config(PinName(40), sdaPinCfg); // Artemis MicroMod Processor Board uses Pin/Pad 40 for SDA
|
||||
#endif
|
||||
#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
|
||||
|
||||
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
|
||||
|
||||
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
|
||||
|
||||
myGNSS.extractFileBufferData(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
|
||||
|
||||
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
|
||||
if (bytesToWrite > sdWriteSize)
|
||||
{
|
||||
bytesToWrite = sdWriteSize;
|
||||
}
|
||||
|
||||
myGNSS.extractFileBufferData(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,340 @@
|
|||
/*
|
||||
Configuring the GNSS to automatically send RXM SFRBX and RAWX reports over SPI and log them to file on SD card using full 4-bit SDIO
|
||||
By: Paul Clark
|
||||
SparkFun Electronics
|
||||
Date: October 20th, 2022
|
||||
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.
|
||||
|
||||
This code is written for the OpenLog ESP32 (DEV-20594) - coming soon!
|
||||
|
||||
Hardware set-up:
|
||||
Close the DSEL jumper on the ZED-F9P breakout - to select SPI mode
|
||||
Connect:
|
||||
OpenLog ESP32 : ZED-F9P
|
||||
GND GND
|
||||
3V3_SW 3V3
|
||||
SCK (18) SCK
|
||||
PICO (23) PICO (MOSI)
|
||||
POCI (19) POCI (MISO)
|
||||
33 CS
|
||||
|
||||
** Please note: this example will only work on u-blox ADR or High Precision GNSS or Time Sync products **
|
||||
|
||||
Data is logged in u-blox UBX format.
|
||||
|
||||
Feel like supporting open source hardware?
|
||||
Buy a board from SparkFun!
|
||||
OpenLog ESP32: https://www.sparkfun.com/products/20594
|
||||
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
|
||||
NEO-M8P RTK: https://www.sparkfun.com/products/15005
|
||||
*/
|
||||
|
||||
#define GNSS_CS 33 // Connect the ZED-F9P CS pin to OpenLog ESP32 pin 33
|
||||
#define EN_3V3_SW 32 // The 3.3V_SW regulator Enable pin is connected to D32
|
||||
#define STAT_LED 25 // The OpenLog ESP32 STAT LED is connected to pin 25
|
||||
#define IMU_CS 5 // The ISM330 IMU CS is connected to pin 5
|
||||
#define MAG_CS 27 // The MMC5983 Mag CS is connected to pin 27
|
||||
|
||||
#include "FS.h"
|
||||
#include "SD_MMC.h"
|
||||
File myFile;
|
||||
|
||||
#include <SPI.h>
|
||||
#define spiPort SPI
|
||||
|
||||
#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;
|
||||
|
||||
#define sdWriteSize 2048 // Write data to the SD card in blocks of n*512 bytes
|
||||
#define fileBufferSize 65530 // Allocate just under 64KBytes of RAM for UBX message storage
|
||||
#define navRate 20 // Set the Nav Rate (Frequency) to 20Hz
|
||||
//#define ubxOnly // Uncomment this line to log UBX (RAWX and SFRBX) only
|
||||
uint8_t *myBuffer; // Use myBuffer to hold the data while we write it to SD card
|
||||
|
||||
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);
|
||||
|
||||
pinMode(STAT_LED, OUTPUT); // Flash the STAT LED each time we write to the SD card
|
||||
digitalWrite(STAT_LED, LOW);
|
||||
|
||||
pinMode(GNSS_CS, OUTPUT);
|
||||
digitalWrite(GNSS_CS, HIGH);
|
||||
pinMode(IMU_CS, OUTPUT);
|
||||
digitalWrite(IMU_CS, HIGH);
|
||||
pinMode(MAG_CS, OUTPUT);
|
||||
digitalWrite(MAG_CS, HIGH);
|
||||
|
||||
spiPort.begin();
|
||||
|
||||
// Do a fake transaction to initialize the SPI pins
|
||||
spiPort.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
spiPort.transfer(0);
|
||||
spiPort.endTransaction();
|
||||
|
||||
pinMode(EN_3V3_SW, OUTPUT); // Enable power for the microSD card and GNSS
|
||||
digitalWrite(EN_3V3_SW, HIGH);
|
||||
|
||||
delay(3000); // Allow time for the GNSS and SD card to start up and for Tera Term to reconnect
|
||||
Serial.println(F("SparkFun OpenLog ESP32 GNSS Logging : SPI and SDIO"));
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Initialize the GNSS
|
||||
|
||||
Serial.println(F("Initializing the GNSS..."));
|
||||
|
||||
//myGNSS.enableDebugging(); // Uncomment this line to see helpful debug messages on Serial
|
||||
|
||||
myGNSS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin
|
||||
|
||||
// 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:
|
||||
bool begun = false;
|
||||
do
|
||||
{
|
||||
begun = myGNSS.begin(spiPort, GNSS_CS, 4000000);
|
||||
if (!begun)
|
||||
{
|
||||
Serial.println(F("u-blox GNSS not detected on SPI bus."));
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
while (!begun);
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Wait for a 3D fix. Get the date and time for the log file
|
||||
|
||||
//myGNSS.factoryDefault(); delay(5000); // Uncomment this line to reset the module back to its factory defaults
|
||||
|
||||
#ifdef ubxOnly
|
||||
myGNSS.setSPIOutput(COM_TYPE_UBX); //Set the SPI port to output only UBX
|
||||
#else
|
||||
myGNSS.setSPIOutput(COM_TYPE_UBX | COM_TYPE_NMEA); //Set the SPI port to output both UBX and NMEA messages
|
||||
#endif
|
||||
|
||||
//myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Optional: save (only) the communications port settings to flash and BBR
|
||||
|
||||
Serial.print(F("Waiting for a 3D fix"));
|
||||
|
||||
uint8_t fix = 0;
|
||||
|
||||
do
|
||||
{
|
||||
fix = myGNSS.getFixType();
|
||||
delay(1000);
|
||||
Serial.print(F("."));
|
||||
}
|
||||
while ( fix != 3 ); // Wait for a 3D fix
|
||||
|
||||
Serial.println();
|
||||
|
||||
uint16_t y = myGNSS.getYear();
|
||||
uint8_t M = myGNSS.getMonth();
|
||||
uint8_t d = myGNSS.getDay();
|
||||
uint8_t h = myGNSS.getHour();
|
||||
uint8_t m = myGNSS.getMinute();
|
||||
uint8_t s = myGNSS.getSecond();
|
||||
|
||||
char szBuffer[40] = {'\0'};
|
||||
snprintf(szBuffer, sizeof(szBuffer), "/%04d%02d%02d%02d%02d%02d.ubx", y, M, d, h, m, s);
|
||||
|
||||
Serial.println(F("GNSS initialized."));
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Initialize the SD card. Open the log file
|
||||
|
||||
Serial.println(F("Initializing SD card..."));
|
||||
|
||||
// Begin the SD card
|
||||
if(!SD_MMC.begin())
|
||||
{
|
||||
Serial.println(F("Card mount failed. Freezing..."));
|
||||
while(1);
|
||||
}
|
||||
|
||||
// Open the log file for writing
|
||||
Serial.printf("Log file is: %s\r\n", szBuffer);
|
||||
myFile = SD_MMC.open((const char *)szBuffer, FILE_WRITE);
|
||||
if(!myFile)
|
||||
{
|
||||
Serial.println(F("Failed to open log file for writing. Freezing..."));
|
||||
while(1);
|
||||
}
|
||||
|
||||
Serial.println(F("SD card initialized."));
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Wait for a key press
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
// Enable RAWX and SFRBX
|
||||
|
||||
myGNSS.setAutoRXMSFRBXcallbackPtr(&newSFRBX); // Enable automatic RXM SFRBX messages with callback to newSFRBX
|
||||
|
||||
myGNSS.logRXMSFRBX(); // Enable RXM SFRBX data logging
|
||||
|
||||
myGNSS.setAutoRXMRAWXcallbackPtr(&newRAWX); // Enable automatic RXM RAWX messages with callback to newRAWX
|
||||
|
||||
myGNSS.logRXMRAWX(); // Enable RXM RAWX data logging
|
||||
|
||||
myBuffer = new uint8_t[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
|
||||
|
||||
#ifndef ubxOnly
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_SPI, navRate); // Ensure the GxGGA (Global positioning system fix data) message is enabled. Send every second.
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GSA, COM_PORT_SPI, navRate); // Ensure the GxGSA (GNSS DOP and Active satellites) message is enabled. Send every second.
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GSV, COM_PORT_SPI, navRate); // Ensure the GxGSV (GNSS satellites in view) message is enabled. Send every second.
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_GST, COM_PORT_SPI, navRate); // Ensure the GxGST (Position error statistics) message is enabled. Send every second.
|
||||
myGNSS.enableNMEAMessage(UBX_NMEA_RMC, COM_PORT_SPI, navRate); // Ensure the GxRMC (Recommended minimum: position, velocity and time) message is enabled. Send every second.
|
||||
myGNSS.setNMEALoggingMask(SFE_UBLOX_FILTER_NMEA_GGA | SFE_UBLOX_FILTER_NMEA_GSA | SFE_UBLOX_FILTER_NMEA_GSV | SFE_UBLOX_FILTER_NMEA_GST | SFE_UBLOX_FILTER_NMEA_RMC); // Log only these NMEA messages
|
||||
#endif
|
||||
|
||||
myGNSS.setNavigationFrequency(navRate); // Set navigation rate
|
||||
|
||||
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.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
while (myGNSS.fileBufferAvailable() >= sdWriteSize) // Check to see if we have at least sdWriteSize waiting in the buffer
|
||||
{
|
||||
digitalWrite(STAT_LED, HIGH); // Flash the STAT LED each time we write to the SD card
|
||||
|
||||
myGNSS.extractFileBufferData(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
|
||||
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
|
||||
myGNSS.checkCallbacks(); // Check if any callbacks are waiting to be processed.
|
||||
|
||||
digitalWrite(STAT_LED, LOW); // Turn the STAT LED off again
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
if (millis() > (lastPrint + 1000)) // Print the message count once per second
|
||||
{
|
||||
uint16_t maxBufferBytes = myGNSS.getMaxFileBufferAvail(); // Get how full the file buffer has been (not how full it is now)
|
||||
float bufferHigh = 100.0 * (float)maxBufferBytes / (float)fileBufferSize;
|
||||
|
||||
Serial.print(F("Message groups received: SFRBX: ")); // Print how many message groups have been received (see note above)
|
||||
Serial.print(numSFRBX);
|
||||
Serial.print(F(" RAWX: "));
|
||||
Serial.print(numRAWX);
|
||||
Serial.print(F(" \tBuffer high tide: "));
|
||||
Serial.print(bufferHigh, 1); // It is a fun thing to watch how full the buffer gets
|
||||
if (bufferHigh > 90.)
|
||||
Serial.println(F("%!!"));
|
||||
else if (bufferHigh > 80.)
|
||||
Serial.println(F("%!"));
|
||||
else
|
||||
Serial.println(F("%"));
|
||||
|
||||
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(STAT_LED, HIGH); // Flash the STAT LED while we write to the 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(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(STAT_LED, LOW); // Turn the STAT LED off
|
||||
|
||||
myFile.close(); // Close the data file
|
||||
|
||||
myGNSS.setNavigationFrequency(1); // Set navigation rate to 1Hz
|
||||
|
||||
myGNSS.disableMessage(UBX_CLASS_RXM, UBX_RXM_RAWX, COM_PORT_SPI);
|
||||
myGNSS.disableMessage(UBX_CLASS_RXM, UBX_RXM_SFRBX, COM_PORT_SPI);
|
||||
|
||||
myGNSS.setSPIOutput(COM_TYPE_UBX | COM_TYPE_NMEA); // Re-enable NMEA
|
||||
|
||||
Serial.println(F("Logging stopped. Freezing..."));
|
||||
while(1); // Do nothing more
|
||||
}
|
||||
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue