Trinket M0 comes preloaded with CircuitPython. If you've since used it to run Arduino code, or you'd like to upgrade to the latest version, follow the instructions here to install the latest CircuitPython.

Connect Trinket M0 to your computer using a micro USB Cable. A drive named CIRCUITPY should appear on your computer.

Open the CIRCUITPY drive and create a folder named lib inside (if it doesn't already exist).


The project code requires two code libraries. Click the link below to download the CircuitPython library bundle which matches the version of CircuitPython you are running. You can check the boot_out.txt file on the CIRCUITPY drive to determine the major version of CircuitPython you are using.

Unzip the library bundle, and open the lib folder inside.

You'll need to copy two libraries from this folder to the CIRCUITPY drive's lib folder:

  • Locate the folder named adafruit_hid and copy it to the CIRCUITPY drive's lib folder. 
  • Locate the file named adafruit_dotstar.mpy and copy it to the CIRCUITPY drive's lib folder.

Your CIRCUITPY drive's file structure should now look like this:

Project code

CircuitPython code for this project was adapted from the rather excellent MiniKbd by Andy Clymer.

Copy the code below and paste it into a new text file.

Save the text file as to the root of the CIRCUITPY drive, overwriting any preexisting file.

import board
from digitalio import DigitalInOut, Direction, Pull
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keycode import Keycode
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS

kbd = Keyboard(usb_hid.devices)
kbdLayout = KeyboardLayoutUS(kbd)
state = []
pins = {}
buttonMap = [
    dict(row="D4", col="D0", id=1),
    dict(row="D4", col="D1", id=2),
    dict(row="D4", col="D2", id=3),
    dict(row="D3", col="D2", id=4),
    dict(row="D3", col="D0", id=5),
    dict(row="D3", col="D1", id=6)]

# Set up row pins
for pin in ["D4", "D3"]:
    p = DigitalInOut(getattr(board, pin))
    p.direction = Direction.OUTPUT
    pins[pin] = p

# Set up column pins
for pin in ["D0", "D1", "D2"]:
    p = DigitalInOut(getattr(board, pin))
    p.direction = Direction.INPUT
    p.pull = Pull.DOWN
    pins[pin] = p

buttonIDtoKeycode = {
    1: Keycode.V,
    2: Keycode.O,
    3: Keycode.T,
    4: Keycode.E,
    5: Keycode.SPACE,
    6: Keycode.ENTER}

while True:
	# Compare old and new state
    oldState = state
    newState = []
    newBtn = None
    for button in buttonMap:
        r = pins[button["row"]]
        r.value = True
        if pins[button["col"]].value:
            newState += [button["id"]]
            if not button["id"] in oldState:
                newBtn = button["id"]
        r.value = False
    # Press & release keys
    for oldID in oldState:
        if not oldID in newState:
    if newBtn:[newBtn])
    state = newState

Usage & customization

Once you've saved to your Trinket M0 the code will start running and the board will be seen by your computer as any other USB keyboard – no reboots or special tricks required.

Want to make your keyboard say something other than "vote"? No sweat. You can easily change what keycodes are sent to your computer by editing the code.

Edit lines 37-42 of by swapping the current keycodes with the new ones you want. You can see a list of all possible keycodes using this reference in the CircuitPython documentation.

For example, if you wanted to be able to type "cool" and exchange the return key for a shift key, it would look like this:

Download: file
buttonIDtoKeycode = {
    1: Keycode.C,
    2: Keycode.O,
    3: Keycode.O,
    4: Keycode.L,
    5: Keycode.SPACE,
    6: Keycode.SHIFT}

This guide was first published on Jul 28, 2020. It was last updated on Jul 28, 2020.

This page (Software) was last updated on Jan 15, 2021.