note: All of these examples have been tested with the latest version of CircuitPython, which as of this writing was 7.2.4. Some of these examples may require tweaks in older or later versions, due to change in the drivers.
The Seeed Wio Terminal is a nifty connected device development kit. Built around a SAMD51 Cortex-M4 microcontroller and a Realtek RTL8720DN for WiFi and Bluetooth, plus an integrated display and a collection of handy sensors, the Wio Terminal is a great platform for IoT and smart device development.
One of the nice things about the Wio Terminal is the number of options available for developement platforms. You can choose the long-time hardware hacking favorite Arudino, MicroPython or Ardupy, an interesting blend of MicroPython and Arduino. And there's support for my current go-to for Python on hardware, Adafruit's CircuitPython.
Seeed provides some info to get you started with the Wio Terminal and CircuitPython on their wiki. However they don't cover which the hunderds of CircuitPython modules from the library are required to work with the Wio Terminal. While the Wio Terminal has a pretty large amount of flash for a microcontroller, it would be nice to know what the minimal set of modules required would be. And that's what this gist attempts to capture: the list of modules needed to make the Wio Terminal and CircuitPython sing!
You can get the CircuitPython modules you need in a couple of ways: manually via the CircuitPython library bundle or on the command line with circup.
If you're doing things manually, grab the latest library bundle for your version of CircuitPython (I'm using version 7.2.4 here), unzip it, and drag the following modules into the lib
directory on your WIO Terminal:
- adafruit_bitmap_font
- adafruit_bus_device
- adafruit_display_text
- adafruit_irremote
- adafruit_lis3dh.mpy
- simpleio.mpy (this one is optional, but it can make working with some of the peripherals easier)
If you're using circup
(which I recommend) you can install all of these modules like this:
circup install adafruit_bitmap_font adafruit_bus_device adafruit_display_text adafruit_irremote adafruit_lis3dh simpleio
Note that this is currently no CircuitPython support for the WiFi and Bluetooth LE functions of the RTL8720D in the WIO Terminal. However, it works via embedded RPC over UART on the Arduino core for this device, so I'm working on seeing if I can make that work in CP, too.
- adafruit_bus_device - Handy for working with I2C and SPI peripherals, and a dependency for many of the modules
Support for displayio
, the CircuitPython display drawing library, is built into the UF2 image for the Wio Terminal. But if you really want to make the most of it, you will want some additional modules installed.
- adafruit_display_text
- adafruit_bitmap_font - you'll also need some CircuitPython-compatible bitmap font files
- adafruit_lis3dh
The onboard accelerometer is available at board.GYROSCOPE_SCL
and board.GYROSCOPE_SDA
, plus an "interrupt" at board.GYROSCOPE_INT
(that's in quotes because CircuitPython doesn't really support interrupts).
For basic use with LIS3DH driver module, try something like this:
Note: yeah, it's weird that the pins are called "gyroscope", not "accelerometer", but that's what the schematic called them, so that's how they got defined in CP. But rest assured, the Terminal has an accelerometer but does not have a gyro.
import board
import busio
import adafruit_lis3dh
gyro_i2c = busio.I2C(board.GYROSCOPE_SCL, board.GYROSCOPE_SDA)
accel = adafruit_lis3dh.LIS3DH_I2C(gyro_i2c)
To use the interrupt:
import board
import busio
from digitalio import DigitalInOut
import adafruit_lis3dh
gyro_i2c = busio.I2C(board.GYROSCOPE_SCL, board.GYROSCOPE_SDA)
gyro_int = DigitalInOut(board.GYROSCOPE_INT)
accel = adafruit_lis3dh.LIS3DH_I2C(gyro_i2c, int1=gyro_int)
You can Read The Docs for the full details on the configuration of this driver.
The PDM microphone in the Wio Terminal can be used with the built-in audiobusio
. You can initialize it like this:
import board
import audiobusio
pdm_mic = audiobusio.PDMin(board.I2S_BCLK, board.I2S_SDIN, sample_rate=16000, bit_depth=16)
The sample rate is a mimimum of 16Khz (16,000 Hz) and is approximate. (https://docs.circuitpython.org/en/latest/shared-bindings/audiobusio/index.html#audiobusio.PDMIn).
The three buttons across the top of the WIO Terminal are available as board.BUTTON_1
(right-most button), board.BUTTON_2
(middle button), and board.BUTTON_3
(left-most button).
Use them just like any other basic momentary switch in CircuitPython:
import board
from digitalio import DigitalInOut, Pull
b1 = DigitalInOut(board.Button_1)
b1.switch_to_impout(Pull.UP)
print(b1.value) # will be `True` if not pressed, `False` if pressed, thanks to the pullup resistor
In CircuitPython 7.2.4 and above, all of the buttons default to digitalio.Direction.INPUT
, so they'll behave like the above example with a little less code:
import board
from digitalio import DigitalInOut
b1 = DigitalInOut(board.Button_1)
print(b1.value) # will be `True` if not pressed, `False` if pressed, no need to call `switch_to_input`
The Wio Terminal buzzer is available at board.BUZZER
. To play simple tones, you can use pwmio.PWMOut
:
import board
import pwmio
OFF = 0
ON = 2**15
buzzer = pwmio.PWMOut(board.BUZZER, variable_frequency=True)
buzzer.frequency = 440 # set a note, like Middle C
buzzer.duty_cycle = ON # enable the buzzer to play the note
buzzer.duty_cycle = OFF # turn off the note
If you have the simpleio
module installed, you can use that to handle buzzer tasks, too.
import board
import simpleio
buzzer=board.BUZZER
simpleio.tone(buzzer, 440, duration=0.5) # play Middle C for 1/2 second
The five-way switch on the front of the device works just like a collection of momentary switches. It has five inputs defined: board.SWITCH_PRESS
, board.SWITCH_UP
, board.SWITCH_RIGHT
, board.SWITCH_DOWN
, and board.SWITCH_LEFT
. They can be used just like the buttons (see examples above) and at least in CP 7.2.4. and above, they default to digitalio.Direction.INPUT
so you can use them with the shorter code version consistently.
import board
from digitalio inport DigitalInOut
sw_center = DigitalInOut(board.SWITCH_PRESS)
sw_right = DigitalInOut(board.SWITCH_RIGHT)
sw_left = DigitalInOut(board.SWITCH_LEFT)
sw_up = DigitalInOut(board.SWITCH_UP)
sw_down = DigitalInOut(board.SWITCH_DOWN)
You can send via IR receiver with pulseio
. If what you're sending is standard remode codes, you'll probably want to use adafruit_irremote
, too. It's not bundled with CP, so you'll need to install it.
import board
from pulseio import PulseOut
import adafruit_irremote
ir_transmitter = PulseOut(board.IR, frequency=38000, duty_cycle=2 ** 15)
ir_encoder = adafruit_irremote.GenericTransmit(header=[9000, 4500],
one=[560, 1700],
zero=[560, 560],
trail=0)
ir_encoder.transmit(ir_transmitter, [255, 2, 255, 0])
Code adapted from https://learn.adafruit.com/infrared-ir-receive-transmit-circuit-playground-express-circuit-python/ir-from-cpx-to-cpx.
The onboard LED is available at board.LED
. Controlling it with digitalio.DigitalInOut
is pretty simple.
import board
from digitalio import DigitalInOut
led = DigitalInOut(board.LED)
led.switch_to_ouput
led.value = True // turn on the LED
led.value = False // turn off the LED
The light sensor is a board.LIGHT
. You'll want to connect to is using analogio.AnalogIn
.
import board
from analogio import AnalogIn
light_sensor = AnalogIn(board.LIGHT)
light_sensor.value # read the current light level
Using the SD card reader is fairly straightforward, thanks to the sdcardio
library included in CP (if you're using an older version of CP that doesn't have sdcardio
, you can use adafruit_sdcard
; see https://learn.adafruit.com/micropython-hardware-sd-cards/circuitpython)
import board
import busio
import sdcardio
import storage
sd_spi = busio.SPI(board.SD_SCK, MOSI=board.SD_MOSI, MISO=board.SD_MISO)
sd_cs = board.SD_CS
sd_card = sdcardio.SDCard(sd_spi, sd_cs)
vfs = storage.VfsFat(sd_card)
storage.mount(vfs, "/sd")
Note: Before you can mount the SD card, you'll need to create a directory in the root filesystem on the WIO terminal that you can use for a mount point. If you get an error like RuntimeError: Mount point directory missing
, not having creating the mount point first is probably the cause.
The simplest way to do this is via the mounted CIRCUITPY directory; just create the sd directory at the root and you're good to go. If you want to do this programmatically, it's a bit harder, since the CIRCUITPY drive is mounted read-only by default (from the CP side of things). You can use something like this:
import os
if not 'sd' in os.listdir('/'):
try:
os.mkdir('/sd')
except OSError as err:
if err.errno == 30:
print("/sd mount point folder does not exist, either create this folder")
print("from the host computer or configure CIRCUITPY for read/write by")
print("modifying the boot.py file, inserting the following:")
print('\nimport storage\nstorage.remount("/",False)')
else:
print(str(err))
(code from adafruit/circuitpython#8872 (comment))
There is currently no support for Wifi or Bluetooth via the Realtek chip in CircuitPython.
You can enumerate all of the onboard peripherals simply:
import board
print(dir(board))
Another useful resource: https://www.raspberryconnect.com/projects/39-programming/196-seeed-studio-wio-terminal-with-circuitpython