Xiao-Ukulele
A versatile MIDI controller and keyboard interface using the XIAO RP2040 microcontroller with a 3×3 key matrix, 4 capacitive touch pads, and 7-LED NeoPixel strip.
Overview
Xiao-Ukulele is a 9-key programmable controller featuring a mechanical keyboard switch matrix and capacitive touch sensing. It can function as a MIDI instrument controller, HID keyboard, or customizable peripheral depending on the loaded firmware.
Key Features:
- 3×3 mechanical keyboard switch matrix (9 keys)
- 4 capacitive touch pads (tuned for G, C, E, A strings)
- 7-LED NeoPixel RGB strip for visual feedback
- XIAO RP2040 microcontroller
- Multiple firmware options: MIDI chords, HID keyboard, potentiometer modulation
- USB-C connection for power and data
Hardware Components
| Item # | Ref. | Component | Quantity | Description |
|---|---|---|---|---|
| 1 | M1 | XIAO RP2040 | 1 | Microcontroller board (Seeed Studio) |
| 2 | SW1-9 | Keyboard Switch | 9 | Mechanical keyboard switches (MX compatible) |
| 3 | D1-9 | 1N4148 Diode | 9 | Switching diodes (matrix debouncing) |
| 4 | R1-4 | 1MΩ Resistor | 4 | For capacitive touch sensing |
| 5 | J1 | XIAO Connector Pins | 2 | 1×7 pin headers for XIAO board |
| 6 | LED1 | NeoPixel Strip | 1 | 7 or 3-pin potentiometer (WS2812B compatible) |
| 7 | — | Key Caps | 9 | Printed or commercial keycaps for switches |
| 8 | PCB | Xiao-Ukulele PCB | 1 | Custom FR4 PCB |
PCB Layout
The PCB is a compact design optimized for keyboard-style layout with integrated capacitive touch sensing pads and power/communication routing.
Front Copper
Back Copper
Trace (Milling)
Assembly Guide
Soldering Order:
- Clean the PCB board with isopropyl alcohol if it has been milled/fabricated
- Check all traces for continuity and ensure no shorts before starting
- Solder diodes (D1-D9) first — they're small and go in quickly
- Solder resistors (R1-R4) for capacitive touch
- Solder XIAO connector pins carefully, ensuring proper alignment
- Insert XIAO RP2040 board into the connector pins
- Solder NeoPixel strip or potentiometer to the designated pins
- Insert mechanical switches into the PCB mounting points
- Verify all connections before programming
Testing: Use the debug/test code to verify all pads, switches, and LEDs are working correctly before loading the main firmware.
Firmware & Programming
Setup Instructions
- Download CircuitPython for XIAO RP2040
- Drag the downloaded .uf2 file into the XIAO RP2040 folder (appears as a drive when plugged in)
- The board will reset and appear as a CircuitPython device
- Download the Adafruit CircuitPython library bundle (matching your CircuitPython version)
- Extract and copy these folders to the
libfolder on your XIAO:adafruit_hid(for keyboard input)adafruit_midi(for MIDI output)neopixel.mpy(for LED control)
- Download and install Thonny IDE for code editing and uploading
- Run the debug code first to test all hardware components
Code Versions Available
Several firmware options are available depending on your use case:
- Debug/Test Code: Verifies all switches, touch pads, and LEDs are functioning
- MIDI with Chords: Full chord support with major, minor, 7th, and minor 7th modifiers using touch pads
- HID Keyboard: Works with web synths (e.g., TOUCHME) using Z-M keyboard input
- Potentiometer Mod: Adds pitch bend/slide capability with optional potentiometer
Operational Modes
MIDI Mode (Chord Controller)
In MIDI mode, the 9 keyboard keys provide root notes and modifiers for chord generation:
- Keys 1–7: Root note selection (C, D, E, F, G, A, B)
- Key 8: Minor key modifier
- Key 9: 7th chord modifier
- Touch Pads (G, C, E, A): Play individual chord tones with visual LED feedback
Chord combinations are generated dynamically. The NeoPixel strip provides visual feedback of the current mode and played notes, using different colors for major, minor, 7th, and minor 7th chords.
HID Keyboard Mode
Emulates a computer keyboard for use with web-based synths:
- Keys 1–7: Z, X, C, V, B, N, M (musical notes)
- Key 8: Comma (,) or L with modifier
- Key 9: Combo/shift key for accessing alternative functions
This mode works with web synths like WebSynth or TOUCHME that use keyboard input.
Potentiometer Mod
An optional potentiometer can be added to enable pitch bend/slide across up to 12 semitones. This allows smooth note transitions and creates expressive playing capabilities.
Debug Code Example
Use this code to test hardware components before running the full firmware:
# CircuitPython debug/test for Xiao-Ukulele PCB
# Checks matrix switches, capacitive pads, and NeoPixel strip
import board
import digitalio
import touchio
import neopixel
import time
# Pins
ROW_PINS = [board.D1, board.D2, board.D3]
COL_PINS = [board.D4, board.D5, board.D6]
TOUCH_PINS = [board.D7, board.D8, board.D9, board.D10]
PIXEL_PIN = board.D0
NUM_LEDS = 7
# Setup
rows = [digitalio.DigitalInOut(p) for p in ROW_PINS]
for r in rows:
r.direction = digitalio.Direction.INPUT
cols = [digitalio.DigitalInOut(p) for p in COL_PINS]
for c in cols:
c.direction = digitalio.Direction.INPUT
c.pull = digitalio.Pull.UP
touches = [touchio.TouchIn(p) for p in TOUCH_PINS]
for t in touches:
t.threshold = 1200
pixels = neopixel.NeoPixel(PIXEL_PIN, NUM_LEDS, brightness=0.4, auto_write=True)
# Test NeoPixel
print("Testing NeoPixel strip...")
for i in range(NUM_LEDS):
pixels.fill((0, 0, 0))
pixels[i] = (255, 100, 0)
print("LED", i + 1, "ON")
time.sleep(0.2)
pixels.fill((0, 0, 0))
print("LED test complete\n")
# Matrix scanning helper
def set_row_active(i):
for r in rows:
r.direction = digitalio.Direction.INPUT
rows[i].direction = digitalio.Direction.OUTPUT
rows[i].value = False
def release_rows():
for r in rows:
r.direction = digitalio.Direction.INPUT
# Test matrix and touch
print("Testing matrix and touch inputs...\n")
while True:
# Matrix keys
for r in range(len(rows)):
set_row_active(r)
time.sleep(0.001)
for c in range(len(cols)):
if not cols[c].value:
key_id = r * len(cols) + c
print("Key", key_id + 1, "pressed")
pixels.fill((0, 255, 0))
pixels[key_id % NUM_LEDS] = (255, 0, 0)
time.sleep(0.2)
pixels.fill((0, 0, 0))
release_rows()
# Touch pads
for i, t in enumerate(touches):
if t.value:
print("Touch Pad", i + 1, "active")
pixels.fill((0, 0, 255))
pixels[i % NUM_LEDS] = (255, 255, 255)
time.sleep(0.2)
pixels.fill((0, 0, 0))
time.sleep(0.01)
Use Cases & Applications
- MIDI Controller: Use with DAWs (Ableton, FL Studio, Logic Pro) for real-time music performance
- Chord Player: Simplified interface for learning chord progressions and music theory
- Web Synth Interface: Control online synthesizers and music tools with keyboard input
- Game Controller: Customize firmware for game input or interactive art projects
- Accessibility Tool: Programmable interface for accessibility-focused applications
Customization & Extension
The XIAO RP2040 offers many expansion possibilities:
- Additional Pads: Add more capacitive touch sensing points
- External Hardware: Connect sensors, displays, or output devices via I2C or SPI
- Firmware Variants: Modify code for different MIDI scales, alternate key layouts, or custom chord mappings
- RGB Feedback: Extend NeoPixel strip or add WS2812B-compatible addressable LEDs for richer visual feedback
- Wireless Option: Use a compatible RP2040 board with Bluetooth for wireless MIDI

