Recent Posts

TinyDuino / Re: GPS Logger No data returned
« Last post by lennevia on December 14, 2020, 11:10:13 AM »

You mentioned you found this program from the product page. I believe the full starting tutorial might help point you in the right direction:

It looks like the example you are using is from the "GPS Tracker and Data Logger" project tutorial that requires some additional hardware other than a processor and GPS TinyShield. Are you using all of the same hardware that is referenced in the tutorial? You can see the full tutorial here:

Let me know if that helps, or if you run into any other questions!

I noticed you had some other comments on multiple threads ranging from recently to a few years ago - to keep things organized I will work on responding to this thread that you started and disregard the other comments, so please make sure to ask any outstanding questions in this thread.

Thank you,


General Discussion / Re: GPS shield
« Last post by WillemH on December 14, 2020, 04:14:54 AM »
For the technical answer please refer to my earlier post “GPS TinyShield does not provide actual altitude” on this forum.

The 5 Hz command for the Telit JF2 GPS  has been taken from the chapter ” Enable 5Hz Update NMEA” from “Telit_Jupiter_JF2_EVK_User_Manual_r0.pdf” found on internet:

General Discussion / Re: ZOE GPS proto board / ZOE setup with examples
« Last post by WillemH on December 14, 2020, 03:58:19 AM »
Hi Ben,

with respect to existing examples of Arduino code to interface with u-blox modules I would like to mention the “Sparkfun Ublox Arduino Library”. This large code package is much more focused on the I2C interface than the UART, but it can provide some learning experience with the u-blox GNSS receivers.

If you plan to use the ZOE-M8Q instead of the ZOE-M8B, it means that the “normal” SPG 3.01 firmware version is applicable, so some peculiar default settings related to the “Super-E mode” of the ZOE-M8B have gone. This means that adaptation of power mode setup (PMS) and change of CFG-GNSS to include SBAS can be skipped.

If I am right, it also means 3.3 V supply instead of 1.8 V, so perhaps the level shifter could be left out.
If you include the ZOE-M8Q, is it perhaps possible to provide access to the I2C pins?
With my model rocket application with UART only I have shown that it is not strictly necessary to have access to the I2C, but access to both UART and I2C will certainly increase the attractiveness of the new board.

TinyDuino / GPS Logger No data returned
« Last post by yost87 on December 13, 2020, 07:43:25 PM »
I'm using the sketch below from your product page and am not receiving the data your product page says I should.  What is the problem with your sketch please?

This is what i see in serial monitor:

"Initializing Flash Memory...

Determining write/read start point...

Send 'y' to start read mode. Write mode will begin in waitTime seconds...

Now initiating write mode.

Attempting to wake GPS module.. done."

I've tried several times over several years to get your products working, and after another full afternoon (6-8 hours) of trying to get this working without success, I will likely put on shelf again.

This is the sketch I am using from your product page:
//  TinyCircuits GPS Tracker Tutorial Program
//  Last updated 27 February 2017 (1.02)
//  Using the GPS TinyShield, the Flash Memory TinyShield, and the TinyDuino,
//  this program turns the stack into a miniature GPS tracker and data logger.
//  The code detects which sentence is being read and formats the string accordingly.
//  In order to reduce the number of writes, we write one NMEA sentence per 10 seconds,
//  which can be modified.
//  With the Telit SE868 V2 module with Glonass support, some messages come through
//  as GN** sentences instead of GP**. These are changed back to GP** before logging
//  so that they don't cause problems with programs like Google Earth.
//  Some GPS modules have been shipped with 4800 baud instead of 9600- try this if
//  you see bad data.
//  The Software Serial library should be modified for a larger buffer- 256 is enough
//  for GGA and RMC sentences at 1Hz. In SoftwareSerial.cpp, the change looks like:
//  #define _SS_MAX_RX_BUFF 256
//  Written by Ben Rose & Lilith Freed for TinyCircuits,

//This may need to be set to 4800 baud
const int GPSBaud = 9600;
const int waitTime = 4000;

#include "SoftwareSerial256.h"
#include <SPIFlash.h>

// The chip/slave select pin is pin 5 for the Flash Memory TinyShield
const uint8_t flashCS = 5;
unsigned long address = 0;

// The SPIFlash object for the chip. Passed the chip select pin in the constructor.
SPIFlash flash(flashCS);

// The Arduino pins used by the GPS module
const uint8_t GPS_ONOFFPin = A3;
const uint8_t GPS_SYSONPin = A2;
const uint8_t GPS_RXPin = A1;
const uint8_t GPS_TXPin = A0;
const uint8_t chipSelect = 10;

// The GPS connection is attached with a software serial port
SoftwareSerial Gps_Serial(GPS_RXPin, GPS_TXPin);

// Set which sentences should be enabled on the GPS module
// GPGGA -
char nmea[] = {'1'/*GPGGA*/, '0'/*GNGLL*/, '0'/*GNGSA*/, '0'/*GPGSV/GLGSV*/, '1'/*GNRMC*/, '0'/*GNVTG*/, '0'/*not supported*/, '0'/*GNGNS*/};

void setup()
  static const int RXPin = A1, TXPin = A0;

  Serial.println("Initializing Flash Memory...");
  pinMode(flashCS, OUTPUT); // Ensure chip select pin is an output.
  flash.begin(); // Boots the flash memory

  Serial.println("Determining write/read start point...");
  uint8_t flashBuffer[256];
  uint8_t foundStart = false;
  while (!foundStart) {
    flash.readByteArray(address, flashBuffer, 256);
    int i;
    for (i = 0; !foundStart && i < 256; i++) {
      if (flashBuffer == 0xFF) // checks for the first logical 1
        foundStart = true;
    address += i;

  unsigned long timer = millis();
  Serial.println("Send 'y' to start read mode. Write mode will begin in waitTime seconds...");
  while(millis() < timer + waitTime) {
    if(Serial.available()) {
      if( == 'y') {
  Serial.println("Now initiating write mode.");
  // Init the GPS Module to wake mode
  pinMode(GPS_SYSONPin, INPUT);
  digitalWrite(GPS_ONOFFPin, LOW);
  pinMode(GPS_ONOFFPin, OUTPUT);
  Serial.print("Attempting to wake GPS module.. ");
  while (digitalRead( GPS_SYSONPin ) == LOW )
    // Need to wake the module
    digitalWrite( GPS_ONOFFPin, HIGH );
    digitalWrite( GPS_ONOFFPin, LOW );
  char command[] = "$PSRF103,00,00,00,01*xx\r\n";
  for (int i = 0; i < 8; i++) {
    command[10] = i + '0';
    command[16] = nmea;
    int c = 1;
    byte checksum = command[c++];
    while (command[c] != '*')
      checksum ^= command[c++];
    command[c + 1] = (checksum >> 4) + (((checksum >> 4) < 10) ? '0' : ('A' - 10));
    command[c + 2] = (checksum & 0xF) + (((checksum & 0xF) < 10) ? '0' : ('A' - 10));


void loop() {
  unsigned long startTime = millis();
  while ( != '$') {
    //do other stuff here
  while (Gps_Serial.available() < 5);;; //skip two characters
  char c =;
  //determine senetence type
  if (c == 'R' || c == 'G') {
    c =;
    if (c == 'M') {
    } else if (c == 'G') {
  // Waits waitTime seconds before reading next NMEA string
  while (millis() - startTime < 10000) {; // clears GPS serial buffer

void logNMEA(uint8_t type) {
  uint8_t buffer[82];
  // Initializes buffer to null terminators to ensure proper writing to flash memory
  for(int i = 0; i < 82; ++i) {
    buffer = '\0';

    // Writes NMEA string to buffer
  buffer[0] = '$';
  int counter = 1;
  char c = 0;
  while (!Gps_Serial.available());
  c =;
  while (c != '*') {
    buffer[counter++] = c;
    while (!Gps_Serial.available());
    c =;
  buffer[counter++] = c;
  while (!Gps_Serial.available());
  c =;
  buffer[counter++] = c;
  while (!Gps_Serial.available());
  c =;
  buffer[counter++] = c;
  buffer[counter++] = '\r';
  buffer[counter++] = '\n';

  buffer[2] = 'P'; // Changes GNRMC to GPRMC

  c = 1;
  byte checksum = buffer[c++];
  while (buffer[c] != '*')
    checksum ^= buffer[c++];
  buffer[c + 1] = (checksum >> 4) + (((checksum >> 4) < 10) ? '0' : ('A' - 10));
  buffer[c + 2] = (checksum & 0xF) + (((checksum & 0xF) < 10) ? '0' : ('A' - 10));

  // Writes buffer array to flash memory. Write length is variable to maximize memory.
  flash.writeCharArray(address, (char *)buffer, strlen((char *)buffer));
  address += strlen((char *)buffer); // Sets address ahead for length of the nmea string

void readFlash(unsigned long address) {
  char command;
  do {
    // Clear Serial write buffer to prepare for read
    while(Serial.available()) {;
    // Menu
    Serial.println("Read Mode | Please select a command (1, 2, 3):");
    Serial.println("1. Read to serial monitor.");
    Serial.println("2. Erase all data.");
    Serial.println("3. Exit read mode.");
    command =;
    // Command select
    switch(command) {
      case '1':
        // Handles empty flash
        if(address == 0) {
          Serial.println("No available data.");
        } else {
          // Reads all available data to the Serial monitor
          for(unsigned long i = 0; i < address; ++i) {
      case '2':
        // Erases data up until the first available byte.
        address = 0; // resets the first available byte address to 0
        Serial.println("All data erased.");
      case '3':
        // Exits read mode.
        // Passes by invalid input.
        Serial.println("That is not a recognized command.");
  } while(command != 3);

// Erases the flash memory in 4KB sectors.
// Minimizes excess erase "writes".
void eraseData(unsigned long address) {
  unsigned long index = 0;
  while(index < address) {
    index += 4096;
TinyDuino / Re: GPS TinyShield not getting location
« Last post by yost87 on December 13, 2020, 01:39:07 PM »
This solution worked for the "Simple Test" sketch.  I am now able to see location data in the serial monitor after following Pascaljedis advice.
My code for the setup section now loos like this:

"void setup()
  // Added this
  static const int RXPin = A1, TXPin = A0;
  while (!SerialMonitorInterface && millis() < 5000); //On TinyScreen+/SAMD21 platform, this will wait until the Serial Monitor is opened or until 5 seconds has passed
  SerialMonitorInterface.print("Simple TinyGPS library v. "); SerialMonitorInterface.println(TinyGPS::library_version());
  SerialMonitorInterface.println("by Mikal Hart");
  SerialMonitorInterface.print("Attempting to wake GPS module.. ");
  while (ss.available());

(NOTE: I added this: " static const int RXPin = A1, TXPin = A0;" to beginning of setup routine.  The text between the quotation marks.

I hope this helps.

General Discussion / Re: GPS shield
« Last post by yost87 on December 13, 2020, 01:00:27 PM »
Why hasn't the seller of this replied?  It would seem thy would answer your question since you bought their gear...
TinyDuino / Re: GPS Tracker
« Last post by yost87 on December 13, 2020, 12:52:01 PM »
Hi Ben, I hope you are well.
As mentioned, I endured same issue, I thought.  What I learned is that the stack was working, but I thought not because the serial monitor doesn't show the data.  When I checked the SD card, there was data being written I wasn't aware of.

So, if you encounter the situation where it appears the data isn't flowing, check your SD card.

Than you!
Be safe.
General Discussion / Re: ZOE GPS proto board / ZOE setup with examples
« Last post by Ben Rose on December 10, 2020, 05:56:11 PM »
Hi Willem,

I've just had time to fully read the post. This is great work and thanks for posting it. I've only skimmed the code, but it looks very helpful- I seem to recall finding very little Arduino example code to interface with the uBlox module, although maybe I just missed it. Like you say, the documentation is all 'there', but it's not easy to get started creating the commands. The method of listening to the u-center commands is a good workaround.

Somewhat unfortunately we decided to do a quick test with the ZOE-M8Q, which is only a minor hardware difference, before producing hardware. I'll update here with progress on that.

General Discussion / Re: ZOE GPS proto board / ZOE setup with examples
« Last post by WillemH on December 03, 2020, 07:39:36 AM »
Herewith the  5th attachment containing the first part of a logging on microSD as example of an output file.

General Discussion / ZOE GPS proto board / ZOE setup with examples
« Last post by WillemH on December 03, 2020, 07:29:24 AM »
In this post it is described how to change the configuration of an u-blox M8 GNSS receiver using UART communication. Focus is on the u-blox ZOE-M8B. Most examples are configuration changes necessary for model rocket applications.

Ben Rose  gave me the opportunity to test and evaluate a ZOE GPS prototype board, see the posts “GPS TinyShield does not provide actual altitude” and “ZOE GPS proto board in 35 mm model rocket application / Introduction” on the forum.

The ZOE GPS prototype board that I received is a bit bigger board, about TinyScreen+ size, with u-blox ZOE-M8B GNSS, Bosch BME280 (combined humidity and pressure sensor), ST LSM9DS1 (3D accelerometer, 3D gyroscope and 3D magnetometer) and microSD slot.

I connected the ZOE proto board with a TinyZero using the TinyShield expansion bus. Because of components on both ZOE proto board and TinyZero it is necessary to put another board in between. In my 35 mm model rocket application I finally used a Barometric pressure TinyShield between ZOE proto and TinyZero, but another board like the standard TinyShield proto board with both top and bottom bus expansion also works fine.

By default u-blox M8 GNSS receivers give 6 NMEA (GGA, GLL, GSA, GSV, RMC and VTG) messages at 1 Hz at 9600 baud rate and take into account  a “portable” platform model e.g. assuming low acceleration and a maximum vertical velocity of 50 m/s.

The ZOE-M8B has a bit different firmware (SPG 3.51) than most other u-blox M8 receivers optimizing a very low power consumption. It has “Aggressive with 1 Hz” as default power mode setup (PMS) related to its  “Super-E mode”.  With static tests I found that the ZOE, which I had given a 5Hz update rate, changed this automatically to 1 Hz after about 5 minutes presumably to reduce power consumption.

I also found that SBAS (Satellite-based augmentation system) is not enabled by default in the ZOE in contrast with e.g. the SAM-M8Q GNSS receiver, so if this is not changed, the ZOE will never provide a Differential GPS fix taking into account some provided corrections. In the ZOE-M8B datasheet, see [1],  it is stated “Tracking SBAS satellites uses power and requires a long decoding time. It is recommended to disable SBAS for Super-E mode.”

For many applications it will be necessary to modify the configuration of the ZOE-M8B (or another M8 GNSS receiver). In this post I will elaborate how to change the ZOE configuration in the setup part of the TinyZero code and how to gather the related evidence.

The I2C pins of the u-blox ZOE-M8B GNSS on the ZOE GPS prototype board  are not connected, so it is not possible to use I2C for control. The backup voltage pin is not connected either, so all commands (following the UBX protocol) to modify the default ZOE setup have to be given through the UART1 which is connected to IO0, IO1 and ground, so available at the TinyZero under the HW UART “Serial”.


For my 35 mm model rocket application I made the following changes:

-   Disable all NMEA messages (6 x UBX-CFG-MSG) in order to ease catching the ZOE responses (acknowledge, results of polling) after other UBX commands
-   Change the dynamic platform model (UBX-CFG-NAV5) to 8 (Airborne <4g)
-   Change power mode setup (PMS) to "balanced" (UBX-MSG-PMS)
-   Change the NMEA message rate to 5 Hz (200 ms) (UBX-MSG-RATE)
-   Change the baud rate to 57600 (UBX-MSG-PRT)
-   Enable NMEA messages GGA, GSA and VTG again (UART1 only) (3x UBX-CFG-MSG)

Additionally, I will also show how to enable SBAS by UBX-CFG-GNSS, because after this command the ZOE will reset and provide both acknowledge (in UBX format) and TXT strings (in NMEA format).

When enabling SBAS it is also important to check and perhaps change the SBAS satellite PRN masks to enable the right satellites depending on the area you are in. For Europe the right ones are already in the default configuration but it is advised to make the selection as small as possible. I have experimented myself with enabling EGNOS satellites PRN 123 and PRN136 only by UBX-CFG-SBAS.

In order to see if SBAS satellites are received by the ZOE I have included NMEA GSV messages and left the data rate at 1 Hz in the example code.

Connect with u-blox u-center

The u-blox M8 receiver description including protocol specification, see [2], provides a good overview and  a solid description of the M8 GNSS receiver family, NMEA protocol messages and UBX protocol messages.

However, it is not that easy to compose the UBX messages based on the document only. This holds especially for the long and more complicated commands like UBX-CFG-NAV5 and UBX-MSG-GNSS, but also for the shorter commands it is simpler and safer to use examples that can be derived from outputs from the u-blox program u-center, GNSS evaluation software for Windows [3].

To interface with u-center I used a simple passthrough code on the TinyZero (“SerialPassthrough_a.ino”, see first attachment) which is directly derived from the code from the examples in the Arduino program (tab File, Examples,  04.Communication, SerialPassthrough). Main adaptation is that Serial1 has been replaced by SerialUSB. The attached code can be used by the Arduino program for verification and upload to the TinyZero.

In this way all UART communication from ZOE to TinyZero is translated to communication from TinyZero to PC and vice versa. The u-center program has to be connected to the actual COM port, which should be the same as used to upload the TinyZero.

In u-center you can see the NMEA strings passing by on the Text console, but also the detailed configuration in the Configuration View. The configuration can be changed in a very user friendly way and checked by polling. These changes will be lost after switching off the ZOE, because local saving is not possible in case of the ZOE GPS prototype board.

However, you can save the actual configuration in a .txt file (Tools, Receiver Configuration, Configuration file (provide name) and Save configuration (push button Transfer GNSS -> File)) for reference.

The default configuration file of the ZOE-M8B that I saved can be found in the 2nd attachment.

The configuration file includes many UBX command kernels. By comparing the configuration file  after a change in u-center with the default one you can detect the difference(s).

Nearly all configuration changes can be worked out this way and even tested. An exception is changing the baud rate, which works fine in a direct connection with an u-blox M8 receiver, but does not in an indirect one with passthrough. In u-center it is possible to change the power mode setup (PMS), but this is not one-to-one reflected in a kernel of the UBX-CFG-PMS message, because that one is not in the list.

Compose a UBX command / example to disable NMEA GGA strings

Let us first disable the NMEA GGA message in u-center. In u-center we go to tab View, Configuration View, MSG(Messages), look for message F0-00 NMEA GxGGA and disable all ports (I2C, UART1, etc).

Then we push the Send button and check if all ports remain enabled by pushing the Poll button. When we save the configuration to file under another name, we can find in this file a line with text:

CFG-MSG - 06 01 08 00 F0 00 00 00 00 00 00 00
While the same line in the default configuration shows as:

CFG-MSG - 06 01 08 00 F0 00 01 01 00 01 01 00

In these lines stands “06 01” for CFG-MSG, “08 00” for the length (8 bytes) of the “payload” part of the UBX message and “F0” for GxGGA. The meaning of all bytes is described in [2], par.

We now have the kernel of the UBX message to disable the transmission of NMEA GGA over all ports:  06 01 08 00 F0 00 00 00 00 00 00 00 (all hexadecimal bytes 0x06 etc.)
We just need to add the UBX header with  “B5 62” in front of the kernel and to add the 2 byte standard UBX checksum, see [2], par. 32.2 and 32.4.

It is possible to calculate the checksum in the TinyZero code, but I have chosen to do it in a simple semi-manual excel file, see 3rd attachment for better understanding how it works.

The checksum is important. If the checksum is not correct, the ZOE does not react at all.

The total code for this message is (all (hexadecimal) bytes):
B5 62 06 01 08 00 F0 00 00 00 00 00 00 00 FF 23

In the setup code the char bufferMSG[16] is filled with this sequence and send to the ZOE with a “serial. write”, see for complete code, “GPS_Monitor_ZOE_a.ino”,  in the  4th attachment.

The composition of the other messages is done in the same way, so the code to enable NMEA GGA again for UART1 only is e.g.:
B5 62 06 01 08 00 F0 00 00 01 00 00 00 00 00 28

In some cases it also helps if the default configuration of another u-blox M8 GNSS receiver, e.g. SAM-M8Q is available for comparison.

Catching ZOE responses

After receiving a command the ZOE will react with an acknowledge message, also in UBX format. This can be an “ack-ack” or an “ack-nack”, depending on whether or not the message was processed correctly by the ZOE. See [2], par. 32.5.1.

The “ack-ack” of all CFG-MSG commands is the same:

B5 62 05 01 02 00 06 01 0F 38

So it is important to group commands in a logical way. The 4th byte 0x01 means that it is an “ack-ack”, 0x06 0x01 indicates CFG-MSG.

In the code (see attachment 4)  I have included a number of while loops to gather the response of the ZOE after a group of commands.

Most responses are in UBX format, so a series of bytes (hexadecimal), but in some cases there are still some NMEA strings coming (series of char), so it is important to try to distinguish between both formats. This is done in a oversimplified non-exhaustive way, just to ease the interpretation of the data. NMEA strings should start with $ (= 0x24), while UBX strings start with 0xB5. 0xB5 is not part of an NMEA string, but 0x24 can be part of an UBX message.

Furthermore, I have chosen to display UBX messages with commas between the bytes (and omitting leading zeros) to improve the readability and to simplify pasting e.g. in an excel file for comparison.

So “ack-ack” of CFG-MSG is transformed to:


After the UBX-CFG-GNSS command to enable SBAS (with bufferGNSS[68]), the ZOE does not react only with an “ack-ack” but also resets GNSS and gives 3 NMEA TXT messages:

$GNTXT,01,01,02,Resetting GNSS*3B

In some important cases I asked for confirmation of the execution of the command with more detail.
This is done by sending a polling message, e.g. to check if the dynamic platform model has been changed (in this case to 8), the polling message for CFG-NAV5, only 8 bytes, is sent:

B5 62  06 24  00 00 2A  84

The ZOE will react with the complete CFG-NAV5 and the related “ack-ack”(commas are added):


Example code for monitoring and logging ZOE output (setup and after)

As already mentioned, attachment 4 contains an example code “GPS_Monitor_ZOE_a.ino” for changing the ZOE code (in setup) and monitoring the results on PC or logging these on microSD or both at the same time.

The code includes many lines in void setup() and just a few in void loop ().

After first definitions and declarations Void setup() starts with lines to secure ZOE GPS SAFEBOOT_N and RESET_N pins in high state to avoid problems.

A string buffer (buffer1) is used to overcome waiting problems with writing the microSD card.

For the bulk logging process writing is only done in blocks of 512 bytes. The size of buffer1 is rather big, 2k Bytes, but the TinyZero can handle bigger data memories.

After opening the .txt logging file with an updated 3 digit number file name, the ZOE configuration is modified:

-   suppress all default NMEA strings (GGA, GLL, GSA, GSV, RMC and VTG) to be sure that acknowledge and polling messages are clearly received
-   Gather ZOE response (6x “ack-ack”), (with some NMEA strings in the pipeline)
-   Adaptation of CFG-GNSS to include SBAS (leading to reset GNSS)
-   Gather ZOE response (“ack-ack” and  3 $GNTXT strings),
-   Adaptation of dynamic platform model (->8 = Airborne <4g) using NAV5
-   Prepared for alternative PMS: Adaptation of power mode setup (PMS) to “full power”
-   Adaptation of power mode setup (PMS) to "balanced"
-   Gather ZOE response (2x “ack-ack”)
-   Polling NAV5 in order to check the correct adaptation of the dynamic platform model
-   Polling PMS in order to check the adaptation of the power mode setup
-   Polling GNSS in order to check the adaptation of the configuration to include SBAS
-   Prepared for: RATE -> 5 Hz (200ms) / Note: Prepared for, because of additional enabling of NMEA GSV will can result in many NMEA strings
-   Gather ZOE response (results of polling NAV5, PMS and GNSS plus 3x “ack-ack”)
-   Modification of baudrate to E1 (225) x 256 = 57600 using PRT
-   Enable NMEA strings GGA, GSA, GSV and VTG on UART1 only
-   Gather ZOE response (4x “ack-ack”), followed by first NMEA strings

Void loop() writes incoming char in buffer1. Buffer1 has overload protection. In case of overload some incoming char will not be written. Such an event will be visible in the output by some blank lines.

When the contents of buffer1 has reached 512 bytes it is checked if the microSD is available for write, and if so, a block is written.

A 5th attachment containing the first part of a logging on microSD will follow as example of an output file.

Final remark

If there are questions or errors found, please let me know.

[1] ZOE-M8B datasheet (ZOE-M8B_DataSheet_(UBX-17035164).pdf):
[2] u-blox8-M8_ReceiverDescrProtSpec_(UBX-13003221).pdf):
[3] u-blox program u-center:

SMF spam blocked by CleanTalk