To demonstrate the usage of the GPS module in CircuitPython using I2C, let's look at a complete program example, the gps_echotest.py file from the module's examples.

To use this example with I2C, you must make some changes to the code.

To use this example with I2C, you need to change four separate lines of code found towards the beginning of the initialisation section of the example.

First, comment out the following lines by adding a # to the beginning of each line:

uart = busio.UART(board.TX, board.RX, baudrate=9600, timeout=10)

gps = adafruit_gps.GPS(uart, debug=False)

Then, uncomment the following lines by removing the # from the beginning of each line:

#i2c = busio.I2C(board.SCL, board.SDA)

#gps = adafruit_gps.GPS_GtopI2C(i2c, debug=False) # Use I2C interface

Once these changes are made, you are ready to continue.

CircuitPython Microcontroller Usage

With a CircuitPython microcontroller, save the gps_echotest.py file as code.py on your CIRCUITPY drive. Then connect to the serial console to see the output.

Linux, Computer or Raspberry Pi Usage

From the command line, run the following command:

python3 gps_echotest.py

Echotest Example

# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

# Simple GPS module demonstration.
# Will print NMEA sentences received from the GPS, great for testing connection
# Uses the GPS to send some commands, then reads directly from the GPS
import time
import board
import busio

import adafruit_gps

# Create a serial connection for the GPS connection using default speed and
# a slightly higher timeout (GPS modules typically update once a second).
# These are the defaults you should use for the GPS FeatherWing.
# For other boards set RX = GPS module TX, and TX = GPS module RX pins.
uart = busio.UART(board.TX, board.RX, baudrate=9600, timeout=10)

# for a computer, use the pyserial library for uart access
# import serial
# uart = serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=10)

# If using I2C, we'll create an I2C interface to talk to using default pins
# i2c = board.I2C()  # uses board.SCL and board.SDA
# i2c = board.STEMMA_I2C()  # For using the built-in STEMMA QT connector on a microcontroller

# Create a GPS module instance.
gps = adafruit_gps.GPS(uart)  # Use UART/pyserial
# gps = adafruit_gps.GPS_GtopI2C(i2c)  # Use I2C interface

# Initialize the GPS module by changing what data it sends and at what rate.
# These are NMEA extensions for PMTK_314_SET_NMEA_OUTPUT and
# PMTK_220_SET_NMEA_UPDATERATE but you can send anything from here to adjust
# the GPS module behavior:
#   https://cdn-shop.adafruit.com/datasheets/PMTK_A11.pdf

# Turn on the basic GGA and RMC info (what you typically want)
gps.send_command(b"PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0")
# Turn on just minimum info (RMC only, location):
# gps.send_command(b'PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0')
# Turn off everything:
# gps.send_command(b'PMTK314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0')
# Tuen on everything (not all of it is parsed!)
# gps.send_command(b'PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0')

# Set update rate to once a second (1hz) which is what you typically want.
gps.send_command(b"PMTK220,1000")
# Or decrease to once every two seconds by doubling the millisecond value.
# Be sure to also increase your UART timeout above!
# gps.send_command(b'PMTK220,2000')
# You can also speed up the rate, but don't go too fast or else you can lose
# data during parsing.  This would be twice a second (2hz, 500ms delay):
# gps.send_command(b'PMTK220,500')

# Main loop runs forever printing data as it comes in
timestamp = time.monotonic()
while True:
    data = gps.read(32)  # read up to 32 bytes
    # print(data)  # this is a bytearray type

    if data is not None:
        # convert bytearray to string
        data_string = "".join([chr(b) for b in data])
        print(data_string, end="")

    if time.monotonic() - timestamp > 5:
        # every 5 seconds...
        gps.send_command(b"PMTK605")  # request firmware version
        timestamp = time.monotonic()

Connect to the serial console. You should see something like the following output.

This is the raw GPS "NMEA sentence" output from the module. There are a few different kinds of NMEA sentences, the most common ones people use are the $GPRMC (Global Positioning RecommendedMinimum Coordinates or something like that) and the $GPGGA sentences. These two provide the time, date, latitude, longitude, altitude, estimated land speed, and fix type. Fix type indicates whether the GPS has locked onto the satellite data and received enough data to determine the location (2D fix) or location+altitude (3D fix).

For more details about NMEA sentences and what data they contain, check out this site

If you look at the data in the above window, you can see that there are a lot of commas, with no data in between them. That's because this module is on my desk, indoors, and does not have a 'fix'. To get a fix, we need to put the module outside.

Note: Due to the antenna being built in, the PA1010D Mini GPS module may need a more unobstructed view of the sky than other GPS modules with eternal antennae. If you are having trouble getting a fix, try moving the module to a more ideal location.

GPS modules will always send data EVEN IF THEY DO NOT HAVE A FIX! In order to get 'valid' (not-blank) data you must have the GPS module directly outside, with the square GPS module pointing up with a clear sky view. In ideal conditions, the module can get a fix in under 45 seconds. however depending on your location, satellite configuration, solar flares, tall buildings nearby, RF noise, etc it may take up to half an hour (or more) to get a fix! This does not mean your GPS module is broken, the GPS module will always work as fast as it can to get a fix.

For an explanation of the rest of the setup in this example, see the GPS Example Code Explained section of the CircuitPython & Python UART Usage page.

Following setup is the main loop.

while True:
    data = gps.read(32)  # read up to 32 bytes
    # print(data)  # this is a bytearray type

    if data is not None:
        # convert bytearray to string
        data_string = ''.join([chr(b) for b in data])
        print(data_string, end="")

    if time.monotonic() - timestamp > 5:
        # every 5 seconds...
        gps.send_command(b'PMTK605')  # request firmware version
        timestamp = time.monotonic()

First we read up to 32 bytes directly from the GPS and save it to data as a bytearray.

Next, we check to see that data has been read by verifying that it is not equal to None - this avoids the code failing when no data is returned. Then we convert the bytearray into a string and print it out.

Lastly, every 5 seconds, we request the firmware version.

Once you've used the Echotest to verify that your Mini GPS module is connected and working, you can switch to the Simpletest example to get a more readable version of the data. To use the gps_simpletest.py example with I2C, you must make the same changes shown above that you made to the Echotest example. Comment out the UART setup lines and uncomment the I2C setup lines. Once the changes are made, you can follow along with the code explanation found in the CircuitPython & Python UART Usage: Example Parsing Code section.

This guide was first published on Nov 19, 2019. It was last updated on Mar 29, 2024.

This page (CircuitPython & Python I2C Usage) was last updated on Mar 26, 2024.

Text editor powered by tinymce.