In addition to the USB-serial connection you use for the REPL, there is also a hardware UART you can use. This is handy to talk to UART devices like GPSs, some sensors, or other microcontrollers!
This quick-start example shows how you can create a UART device for communicating with hardware serial devices.
To use this example, you'll need something to generate the UART data. We've used a GPS! Note that the GPS will give you UART data without getting a fix on your location. You can use this example right from your desk! You'll have data to read, it simply won't include your actual location.
You'll need the adafruit_bus_device library folder if you don't already have it in your /lib folder! You can get it from the CircuitPython Library Bundle. If you need help installing the library, check out the CircuitPython Libraries page.
Copy and paste the code into code.py using your favorite editor, and save the file.
# CircuitPython Demo - USB/Serial echo import board import busio import digitalio led = digitalio.DigitalInOut(board.D13) led.direction = digitalio.Direction.OUTPUT uart = busio.UART(board.TX, board.RX, baudrate=9600) while True: data = uart.read(32) # read up to 32 bytes # print(data) # this is a bytearray type if data is not None: led.value = True # convert bytearray to string data_string = ''.join([chr(b) for b in data]) print(data_string, end="") led.value = False
The Code
First we create the UART object. We provide the pins we'd like to use, board.TX
and board.RX
, and we set the baudrate=9600
. While these pins are labeled on most of the boards, be aware that RX and TX are not labeled on Gemma, and are labeled on the bottom of Trinket. See the diagrams below for help with finding the correct pins on your board.
Once the object is created you read data in with read(numbytes)
where you can specify the max number of bytes. It will return a byte array type object if anything was received already. Note it will always return immediately because there is an internal buffer! So read as much data as you can 'digest'.
If there is no data available, read()
will return None
, so check for that before continuing.
The data that is returned is in a byte array, if you want to convert it to a string, you can use this handy line of code which will run chr()
on each byte:
datastr = ''.join([chr(b) for b in data]) # convert bytearray to string
Your results will look something like this:
Wire It Up
You'll need a couple of things to connect the GPS to your board.
For Gemma M0 and Circuit Playground Express, you can use use alligator clips to connect to the Flora Ultimate GPS Module.
For Trinket M0, Feather M0 Express, Metro M0 Express and ItsyBitsy M0 Express, you'll need a breadboard and jumper wires to connect to the Ultimate GPS Breakout.
We've included diagrams show you how to connect the GPS to your board. In these diagrams, the wire colors match the same pins on each board.
- The black wire connects between the ground pins.
- The red wire connects between the power pins on the GPS and your board.
- The blue wire connects from TX on the GPS to RX on your board.
- The white wire connects from RX on the GPS to TX on your board.
Check out the list below for a diagram of your specific board!
Circuit Playground Express and Circuit Playground Bluefruit
|
|
Trinket M0
|
|
Gemma M0
|
|
Feather M0 Express and Feather M4 Express
|
|
ItsyBitsy M0 Express and ItsyBitsy M4 Express
|
|
Metro M0 Express and Metro M4 Express
|
Where's my UART?
On the SAMD21, we have the flexibility of using a wide range of pins for UART. Compare this to some chips like the ESP8266 with fixed UART pins. The good news is you can use many but not all pins. Given the large number of SAMD boards we have, its impossible to guarantee anything other than the labeled 'TX' and 'RX'. So, if you want some other setup, or multiple UARTs, how will you find those pins? Easy! We've written a handy script.
All you need to do is copy this file to your board, rename it code.py, connect to the serial console and check out the output! The results print out a nice handy list of RX and TX pin pairs that you can use.
These are the results from a Trinket M0, your output may vary and it might be very long. For more details about UARTs and SERCOMs check out our detailed guide here
import board import busio from microcontroller import Pin def is_hardware_uart(tx, rx): try: p = busio.UART(tx, rx) p.deinit() return True except ValueError: return False def get_unique_pins(): exclude = ['NEOPIXEL', 'APA102_MOSI', 'APA102_SCK'] pins = [pin for pin in [ getattr(board, p) for p in dir(board) if p not in exclude] if isinstance(pin, Pin)] unique = [] for p in pins: if p not in unique: unique.append(p) return unique for tx_pin in get_unique_pins(): for rx_pin in get_unique_pins(): if rx_pin is tx_pin: continue else: if is_hardware_uart(tx_pin, rx_pin): print("RX pin:", rx_pin, "\t TX pin:", tx_pin) else: pass
Trinket M0: Create UART before I2C
On the Trinket M0 (only), if you are using both busio.UART
and busio.I2C
, you must create the UART object first, e.g.:
>>> import board,busio >>> uart = busio.UART(board.TX, board.RX) >>> i2c = busio.I2C(board.SCL, board.SDA)
Creating busio.I2C
first does not work:
>>> import board,busio >>> i2c = busio.I2C(board.SCL, board.SDA) >>> uart = busio.UART(board.TX, board.RX) Traceback (most recent call last): File "", line 1, in ValueError: Invalid pins