Next we'll work on getting Serial UART working. To get UART working, you will first need to make sure the correct serial ports are enabled. The exact method to enable it can vary from manufacturer to manufacturer. For the Pine64, we used armbian-config and enabled uart2, uart3, and uart4. You can check which serial ports are enabled by typing the following command:
ls /dev/tty*
You'll likely see a lot of ports listed. Finding which port is the proper one is usually found with searching the internet. They often have a letter between the tty part and the number. Here's what we have on the Pine64:
The only ones that have a letter between the tty and number are /dev/ttyS0, /dev/ttyS2, and /dev/ttyS3, which are in fact the correct ones for this board. The reason there is no /dev/ttyS1 is because that port is being used for the Serial Console, so we didn't enable it. You could try narrowing it down with the following command:
ls /dev/tty[a-zA-Z]*
This will list only ports with a letter A-Z (lower case or capital) after the tty part.
Parts Used
To test, we'll need a serial controlled board such as a GPS module, along with a couple other parts to connect it to the board. There's a couple version of the GPS module that are useful. The breakout version is useful for hooking up to GPIO and the USB version makes it easy to test serial via the USB port. For the purposes of this guide though, the breakout version is more useful as it can be connected to a USB to TTL serial cable.
Testing Serial over Built-in UART
For the purposes of adding a new board, we only need to be concerned with whether the Serial over GPIO pins is working as there isn't really anything to configure to get Serial working over USB.
- Connect the SBC 3.3V power pin to V+ Rail
- Connect the SBC GND pin to GND Rail
- Connect the SBC TX pin to the GPS RX
- Connect the SBC RX pin to to the GPS TX
- Connect the GPS Vin power pin to V+ Rail
- Connect the GPS GND pin to GND Rail
Run the Test Script
After wiring it up, double-check your connections. Next, make sure PySerial and the GPS library are installed. If you chose a different sensor, make sure that library is installed:
sudo pip3 install pyserial adafruit-circuitpython-gps
Next save the simpletest code to your board as gps_simpletest.py:
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT # Simple GPS module demonstration. # Will wait for a fix and print a message every second with the current location # and other details. 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, debug=False) # Use UART/pyserial # gps = adafruit_gps.GPS_GtopI2C(i2c, debug=False) # 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 the basic GGA and RMC info + VTG for speed in km/h # gps.send_command(b"PMTK314,0,1,1,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') # Turn 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 the location, etc. every second. last_print = time.monotonic() while True: # Make sure to call gps.update() every loop iteration and at least twice # as fast as data comes from the GPS unit (usually every second). # This returns a bool that's true if it parsed new data (you can ignore it # though if you don't care and instead look at the has_fix property). gps.update() # Every second print out current location details if there's a fix. current = time.monotonic() if current - last_print >= 1.0: last_print = current if not gps.has_fix: # Try again if we don't have a fix yet. print("Waiting for fix...") continue # We have a fix! (gps.has_fix is true) # Print out details about the fix like location, date, etc. print("=" * 40) # Print a separator line. print( "Fix timestamp: {}/{}/{} {:02}:{:02}:{:02}".format( gps.timestamp_utc.tm_mon, # Grab parts of the time from the gps.timestamp_utc.tm_mday, # struct_time object that holds gps.timestamp_utc.tm_year, # the fix time. Note you might gps.timestamp_utc.tm_hour, # not get all data like year, day, gps.timestamp_utc.tm_min, # month! gps.timestamp_utc.tm_sec, ) ) print("Latitude: {0:.6f} degrees".format(gps.latitude)) print("Longitude: {0:.6f} degrees".format(gps.longitude)) print( "Precise Latitude: {} degs, {:2.4f} mins".format( gps.latitude_degrees, gps.latitude_minutes ) ) print( "Precise Longitude: {} degs, {:2.4f} mins".format( gps.longitude_degrees, gps.longitude_minutes ) ) print("Fix quality: {}".format(gps.fix_quality)) # Some attributes beyond latitude, longitude and timestamp are optional # and might not be present. Check if they're None before trying to use! if gps.satellites is not None: print("# satellites: {}".format(gps.satellites)) if gps.altitude_m is not None: print("Altitude: {} meters".format(gps.altitude_m)) if gps.speed_knots is not None: print("Speed: {} knots".format(gps.speed_knots)) if gps.speed_kmh is not None: print("Speed: {} km/h".format(gps.speed_kmh)) if gps.track_angle_deg is not None: print("Track angle: {} degrees".format(gps.track_angle_deg)) if gps.horizontal_dilution is not None: print("Horizontal dilution: {}".format(gps.horizontal_dilution)) if gps.height_geoid is not None: print("Height geoid: {} meters".format(gps.height_geoid))
Next, we need to make a few changes to the test script:
-
Comment out the lines that reference
board.TX
,board.RX
andbusio.uart
-
Uncomment the line to
import serial
-
Uncomment the line to define the
serial
device. - Change the Serial port to the one you are testing
Now go ahead and run that code using the following command:
sudo python3 gps_simpletest.py
You should see it outputting some NMEA sentences about every 5 seconds or so:
Text editor powered by tinymce.