Blog

M5Core2 + GNSS Module: Pocket-sized GPS Logging

5/12/2025 2 min read
M5Core2 + GNSS Module: Pocket-sized GPS Logging

Introduction

Some time ago, I discovered the M5Stack — for me, one of the most exciting innovations in the microcontroller field.
The stackable system is based on an ESP32 and combines a case, display, SD card reader, vibration motor, speaker, microphone, sensors, and five buttons into an incredibly compact format.

All this is offered at a fair price and opens up nearly endless possibilities for creative projects.
Of course, one could assemble something like this with almost any microcontroller, but that usually ends up as tinkering. With the M5Stack, everything looks neat and is extremely compact. This allows quick implementation of practical things for everyday use.


Hardware

For my first test with the GNSS module, I use the following hardware:

  • M5Stack Core2
  • GNSS module with pressure sensor, IMU, and magnetometer
  • M5GO Battery Bottom2 (only for Core2)

Code

#include 
#include 
#include 

TinyGPSPlus gps;
HardwareSerial SerialGPS(2);

// Position definitions for display
const int xCenter = 160; // Center alignment of values
const int yLatitude = 50;
const int yLongitude = 90;
const int yAltitude = 130;
const int ySpeed = 170;
const int ySatellites = 210;

void setup() {
  M5.begin();
  Serial.begin(115200);
  SerialGPS.begin(38400, SERIAL_8N1, 13, 14); // RX=13, TX=14

  // Background and static texts on the display
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextColor(WHITE, BLACK); // White text on black background

  displayStaticText();
}

void displayStaticText() {
  M5.Lcd.setTextSize(2);
  M5.Lcd.setCursor(10, 10);
  M5.Lcd.print("GNSS Data");

  M5.Lcd.setCursor(10, yLatitude);
  M5.Lcd.print("Latitude");
  M5.Lcd.drawLine(10, yLatitude + 20, 310, yLatitude + 20, WHITE);

  M5.Lcd.setCursor(10, yLongitude);
  M5.Lcd.print("Longitude");
  M5.Lcd.drawLine(10, yLongitude + 20, 310, yLongitude + 20, WHITE);

  M5.Lcd.setCursor(10, yAltitude);
  M5.Lcd.print("Altitude");
  M5.Lcd.drawLine(10, yAltitude + 20, 310, yAltitude + 20, WHITE);

  M5.Lcd.setCursor(10, ySpeed);
  M5.Lcd.print("Speed");
  M5.Lcd.drawLine(10, ySpeed + 20, 310, ySpeed + 20, WHITE);

  M5.Lcd.setCursor(10, ySatellites);
  M5.Lcd.print("Satellites");
  M5.Lcd.drawLine(10, ySatellites + 20, 310, ySatellites + 20, WHITE);
}

void updateGPSData() {
  // Latitude
  M5.Lcd.setCursor(xCenter, yLatitude);
  M5.Lcd.fillRect(xCenter, yLatitude, 140, 20, BLACK);
  M5.Lcd.printf("%.6f", gps.location.lat());

  // Longitude
  M5.Lcd.setCursor(xCenter, yLongitude);
  M5.Lcd.fillRect(xCenter, yLongitude, 140, 20, BLACK);
  M5.Lcd.printf("%.6f", gps.location.lng());

  // Altitude
  M5.Lcd.setCursor(xCenter, yAltitude);
  M5.Lcd.fillRect(xCenter, yAltitude, 140, 20, BLACK);
  M5.Lcd.printf("%.2f m", gps.altitude.meters());

  // Speed
  M5.Lcd.setCursor(xCenter, ySpeed);
  M5.Lcd.fillRect(xCenter, ySpeed, 140, 20, BLACK);
  M5.Lcd.printf("%.2f km/h", gps.speed.kmph());

  // Satellites
  M5.Lcd.setCursor(xCenter, ySatellites);
  M5.Lcd.fillRect(xCenter, ySatellites, 140, 20, BLACK);
  M5.Lcd.printf("%d", gps.satellites.value());
}

void updateTime() {
  // Adjust time (UTC+1 for winter time in Germany)
  int hour = gps.time.hour() + 1;
  if (hour >= 24) hour -= 24;

  M5.Lcd.setCursor(210, 10);
  M5.Lcd.fillRect(210, 10, 100, 20, BLACK);
  M5.Lcd.printf("%02d:%02d:%02d",
                hour,
                gps.time.minute(),
                gps.time.second());
}

void loop() {
  while (SerialGPS.available() > 0) {
    gps.encode(SerialGPS.read());

    if (gps.location.isUpdated()) {
      updateGPSData();
      updateTime();
      delay(1000);
    }
  }
}