Skip to content

Commit cc2e75f

Browse files
committed
Add logNMEA and an example
1 parent 63d8b60 commit cc2e75f

File tree

4 files changed

+261
-0
lines changed

4 files changed

+261
-0
lines changed
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
/*
2+
Demonstrate how to log NMEA and UBX data simultaneously
3+
By: Paul Clark
4+
SparkFun Electronics
5+
Date: April 13th, 2021
6+
License: MIT. See license file for more information but you can
7+
basically do whatever you want with this code.
8+
9+
This example shows how to configure the u-blox GNSS to send PVT reports automatically
10+
and log those and any incoming NMEA messages to SD card in UBX format
11+
12+
** Please note: NMEA logging relies upon processNMEA **
13+
** You will not be able to log NMEA data automatically through the library if you overwrite processNMEA with your own function **
14+
15+
** Please note: this example will only work on processors like the Artemis which have plenty of RAM available **
16+
17+
This code is intended to be run on the MicroMod Data Logging Carrier Board using the Artemis Processor
18+
but can be adapted by changing the chip select pin and SPI definitions:
19+
https://www.sparkfun.com/products/16829
20+
https://www.sparkfun.com/products/16401
21+
22+
Hardware Connections:
23+
Please see: https://learn.sparkfun.com/tutorials/micromod-data-logging-carrier-board-hookup-guide
24+
Insert the Artemis Processor into the MicroMod Data Logging Carrier Board and secure with the screw.
25+
Connect your GNSS breakout to the Carrier Board using a Qwiic cable.
26+
Connect an antenna to your GNSS board if required.
27+
Insert a formatted micro-SD card into the socket on the Carrier Board.
28+
Connect the Carrier Board to your computer using a USB-C cable.
29+
Ensure you have the SparkFun Apollo3 boards installed: http://boardsmanager/All#SparkFun_Apollo3
30+
This code has been tested using version 1.2.1 of the Apollo3 boards on Arduino IDE 1.8.13.
31+
Select "SparkFun Artemis MicroMod" as the board type.
32+
Press upload to upload the code onto the Artemis.
33+
Open the Serial Monitor at 115200 baud to see the output.
34+
35+
To minimise I2C bus errors, it is a good idea to open the I2C pull-up split pad links on
36+
both the MicroMod Data Logging Carrier Board and the u-blox module breakout.
37+
38+
Feel like supporting open source hardware?
39+
Buy a board from SparkFun!
40+
ZED-F9P RTK2: https://www.sparkfun.com/products/15136
41+
NEO-M8P RTK: https://www.sparkfun.com/products/15005
42+
ZOE-M8Q: https://www.sparkfun.com/products/15193
43+
SAM-M8Q: https://www.sparkfun.com/products/15210
44+
*/
45+
46+
#include <SPI.h>
47+
#include <SD.h>
48+
#include <Wire.h> //Needed for I2C to GNSS
49+
50+
#include <SparkFun_u-blox_GNSS_Arduino_Library.h> //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_GNSS
51+
SFE_UBLOX_GNSS myGNSS;
52+
53+
File myFile; //File that all GNSS data is written to
54+
55+
#define sdChipSelect CS //Primary SPI Chip Select is CS for the MicroMod Artemis Processor. Adjust for your processor if necessary.
56+
57+
#define sdWriteSize 512 // Write data to the SD card in blocks of 512 bytes
58+
#define fileBufferSize 16384 // Allocate 16KBytes of RAM for UBX message storage
59+
60+
unsigned long lastPrint; // Record when the last Serial print took place
61+
unsigned long bytesWritten = 0; // Record how many bytes have been written to SD card
62+
63+
void setup()
64+
{
65+
Serial.begin(115200);
66+
while (!Serial); //Wait for user to open terminal
67+
Serial.println("SparkFun u-blox Example");
68+
69+
pinMode(LED_BUILTIN, OUTPUT); // Flash LED_BUILTIN each time we write to the SD card
70+
digitalWrite(LED_BUILTIN, LOW);
71+
72+
Wire.begin(); // Start I2C communication
73+
74+
#if defined(AM_PART_APOLLO3)
75+
Wire.setPullups(0); // On the Artemis, we can disable the internal I2C pull-ups too to help reduce bus errors
76+
#endif
77+
78+
while (Serial.available()) // Make sure the Serial buffer is empty
79+
{
80+
Serial.read();
81+
}
82+
83+
Serial.println(F("Press any key to start logging."));
84+
85+
while (!Serial.available()) // Wait for the user to press a key
86+
{
87+
; // Do nothing
88+
}
89+
90+
delay(100); // Wait, just in case multiple characters were sent
91+
92+
while (Serial.available()) // Empty the Serial buffer
93+
{
94+
Serial.read();
95+
}
96+
97+
Serial.println("Initializing SD card...");
98+
99+
// See if the card is present and can be initialized:
100+
if (!SD.begin(sdChipSelect))
101+
{
102+
Serial.println("Card failed, or not present. Freezing...");
103+
// don't do anything more:
104+
while (1);
105+
}
106+
Serial.println("SD card initialized.");
107+
108+
// Create or open a file called "PVT_NMEA.ubx" on the SD card.
109+
// If the file already exists, the new data is appended to the end of the file.
110+
myFile = SD.open("PVT_NMEA.ubx", FILE_WRITE);
111+
if(!myFile)
112+
{
113+
Serial.println(F("Failed to create UBX data file! Freezing..."));
114+
while (1);
115+
}
116+
117+
//myGNSS.enableDebugging(); // Uncomment this line to enable lots of helpful GNSS debug messages on Serial
118+
//myGNSS.enableDebugging(Serial, true); // Or, uncomment this line to enable only the important GNSS debug messages on Serial
119+
120+
//myGNSS.disableUBX7Fcheck(); // RAWX data can legitimately contain 0x7F. Uncomment this line to disable the "7F" check in checkUbloxI2C
121+
122+
// SD cards can occasionally 'hiccup' and a write takes much longer than usual. The buffer needs to be big enough
123+
// to hold the backlog of data if/when this happens.
124+
// getMaxFileBufferAvail will tell us the maximum number of bytes which the file buffer has contained.
125+
myGNSS.setFileBufferSize(fileBufferSize); // setFileBufferSize must be called _before_ .begin
126+
127+
if (myGNSS.begin() == false) //Connect to the u-blox module using Wire port
128+
{
129+
Serial.println(F("u-blox GNSS not detected at default I2C address. Please check wiring. Freezing..."));
130+
while (1);
131+
}
132+
133+
// Uncomment the next line if you want to reset your module back to the default settings with 1Hz navigation rate
134+
// This will (re)enable the standard NMEA messages too
135+
// This will also disable any "auto" UBX messages that were enabled and saved by other examples and reduce the load on the I2C bus
136+
//myGNSS.factoryDefault(); delay(5000);
137+
138+
myGNSS.setI2COutput(COM_TYPE_UBX | COM_TYPE_NMEA); //Set the I2C port to output both UBX and NMEA messages
139+
140+
//myGNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT); //Optional: save (only) the communications port settings to flash and BBR
141+
142+
myGNSS.setNavigationFrequency(1); //Produce one navigation solution per second
143+
144+
myGNSS.setAutoPVT(true, false); // Enable automatic NAV PVT messages: without callback; without implicit update
145+
myGNSS.logNAVPVT(); // Enable NAV PVT data logging
146+
147+
myGNSS.enableNMEAMessage(UBX_NMEA_GGA, COM_PORT_I2C, 1); // Ensure the GxGGA (Global positioning system fix data) message is enabled. Send every measurement.
148+
myGNSS.enableNMEAMessage(UBX_NMEA_GSA, COM_PORT_I2C, 1); // Ensure the GxGSA (GNSS DOP and Active satellites) message is enabled. Send every measurement.
149+
myGNSS.enableNMEAMessage(UBX_NMEA_GSV, COM_PORT_I2C, 1); // Ensure the GxGSV (GNSS satellites in view) message is enabled. Send every measurement.
150+
myGNSS.logNMEA(); // Enable NMEA logging
151+
152+
Serial.println(F("Press any key to stop logging."));
153+
154+
lastPrint = millis(); // Initialize lastPrint
155+
}
156+
157+
void loop()
158+
{
159+
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
160+
161+
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
162+
163+
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
164+
165+
while (myGNSS.fileBufferAvailable() >= sdWriteSize) // Check to see if we have at least sdWriteSize waiting in the buffer
166+
{
167+
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN each time we write to the SD card
168+
169+
uint8_t myBuffer[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
170+
171+
myGNSS.extractFileBufferData((uint8_t *)&myBuffer, sdWriteSize); // Extract exactly sdWriteSize bytes from the UBX file buffer and put them into myBuffer
172+
173+
myFile.write(myBuffer, sdWriteSize); // Write exactly sdWriteSize bytes from myBuffer to the ubxDataFile on the SD card
174+
175+
bytesWritten += sdWriteSize; // Update bytesWritten
176+
177+
// In case the SD writing is slow or there is a lot of data to write, keep checking for the arrival of new data
178+
myGNSS.checkUblox(); // Check for the arrival of new data and process it.
179+
180+
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off again
181+
}
182+
183+
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
184+
185+
if (millis() > (lastPrint + 1000)) // Print bytesWritten once per second
186+
{
187+
Serial.print(F("The number of bytes written to SD card is ")); // Print how many bytes have been written to SD card
188+
Serial.println(bytesWritten);
189+
190+
uint16_t maxBufferBytes = myGNSS.getMaxFileBufferAvail(); // Get how full the file buffer has been (not how full it is now)
191+
192+
//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
193+
//Serial.println(maxBufferBytes);
194+
195+
if (maxBufferBytes > ((fileBufferSize / 5) * 4)) // Warn the user if fileBufferSize was more than 80% full
196+
{
197+
Serial.println(F("Warning: the file buffer has been over 80% full. Some data may have been lost."));
198+
}
199+
200+
lastPrint = millis(); // Update lastPrint
201+
}
202+
203+
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
204+
205+
if (Serial.available()) // Check if the user wants to stop logging
206+
{
207+
uint16_t remainingBytes = myGNSS.fileBufferAvailable(); // Check if there are any bytes remaining in the file buffer
208+
209+
while (remainingBytes > 0) // While there is still data in the file buffer
210+
{
211+
digitalWrite(LED_BUILTIN, HIGH); // Flash LED_BUILTIN while we write to the SD card
212+
213+
uint8_t myBuffer[sdWriteSize]; // Create our own buffer to hold the data while we write it to SD card
214+
215+
uint16_t bytesToWrite = remainingBytes; // Write the remaining bytes to SD card sdWriteSize bytes at a time
216+
if (bytesToWrite > sdWriteSize)
217+
{
218+
bytesToWrite = sdWriteSize;
219+
}
220+
221+
myGNSS.extractFileBufferData((uint8_t *)&myBuffer, bytesToWrite); // Extract bytesToWrite bytes from the UBX file buffer and put them into myBuffer
222+
223+
myFile.write(myBuffer, bytesToWrite); // Write bytesToWrite bytes from myBuffer to the ubxDataFile on the SD card
224+
225+
bytesWritten += bytesToWrite; // Update bytesWritten
226+
227+
remainingBytes -= bytesToWrite; // Decrement remainingBytes
228+
}
229+
230+
digitalWrite(LED_BUILTIN, LOW); // Turn LED_BUILTIN off
231+
232+
Serial.print(F("The total number of bytes written to SD card is ")); // Print how many bytes have been written to SD card
233+
Serial.println(bytesWritten);
234+
235+
myFile.close(); // Close the data file
236+
237+
Serial.println(F("Logging stopped. Freezing..."));
238+
while(1); // Do nothing more
239+
}
240+
241+
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
242+
}

keywords.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,8 @@ initPacketUBXHNRPVT KEYWORD2
382382
flushHNRPVT KEYWORD2
383383
logHNRPVT KEYWORD2
384384

385+
logNMEA KEYWORD2
386+
385387
setNavigationFrequency KEYWORD2
386388
getNavigationFrequency KEYWORD2
387389
setMeasurementRate KEYWORD2

src/SparkFun_u-blox_GNSS_Arduino_Library.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,6 +1259,10 @@ void SFE_UBLOX_GNSS::processNMEA(char incoming)
12591259
//If user has assigned an output port then pipe the characters there
12601260
if (_nmeaOutputPort != NULL)
12611261
_nmeaOutputPort->write(incoming); //Echo this byte to the serial port
1262+
1263+
//If _logNMEA is true, attempt to store incoming in the file buffer
1264+
if (_logNMEA)
1265+
storeFileBytes((uint8_t *)&incoming, 1);
12621266
}
12631267

12641268
//We need to be able to identify an RTCM packet and then the length
@@ -9073,6 +9077,14 @@ void SFE_UBLOX_GNSS::logHNRPVT(boolean enabled)
90739077
packetUBXHNRPVT->automaticFlags.flags.bits.addToFileBuffer = (uint8_t)enabled;
90749078
}
90759079

9080+
// ***** Helper Functions for NMEA Logging
9081+
9082+
//Log NMEA data in file buffer - if it exists! User needs to call setFileBufferSize before .begin
9083+
void SFE_UBLOX_GNSS::logNMEA(boolean enabled)
9084+
{
9085+
_logNMEA = enabled;
9086+
}
9087+
90769088
// ***** CFG RATE Helper Functions
90779089

90789090
//Set the rate at which the module will give us an updated navigation solution

src/SparkFun_u-blox_GNSS_Arduino_Library.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,9 @@ class SFE_UBLOX_GNSS
928928
void flushHNRPVT(); //Mark all the data as read/stale
929929
void logHNRPVT(boolean enabled = true); // Log data to file buffer
930930

931+
// Helper function for NMEA logging
932+
void logNMEA(boolean enabled = true); // Log NMEA data to file buffer
933+
931934
// Helper functions for CFG RATE
932935

933936
boolean setNavigationFrequency(uint8_t navFreq, uint16_t maxWait = defaultMaxWait); //Set the number of nav solutions sent per second
@@ -1183,6 +1186,8 @@ class SFE_UBLOX_GNSS
11831186

11841187
boolean ubx7FcheckDisabled = false; // Flag to indicate if the "7F" check should be ignored in checkUbloxI2C
11851188

1189+
boolean _logNMEA = false; // Flag to indicate if NMEA data should be added to the file buffer
1190+
11861191
//The packet buffers
11871192
//These are pointed at from within the ubxPacket
11881193
uint8_t payloadAck[2]; // Holds the requested ACK/NACK

0 commit comments

Comments
 (0)