@

Xiao-Ukulele

Xiao-Ukulele Controller

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

Front Copper

Back Copper

Back Copper

Trace

Trace (Milling)

Assembly Guide

Soldering Order:

  1. Clean the PCB board with isopropyl alcohol if it has been milled/fabricated
  2. Check all traces for continuity and ensure no shorts before starting
  3. Solder diodes (D1-D9) first — they're small and go in quickly
  4. Solder resistors (R1-R4) for capacitive touch
  5. Solder XIAO connector pins carefully, ensuring proper alignment
  6. Insert XIAO RP2040 board into the connector pins
  7. Solder NeoPixel strip or potentiometer to the designated pins
  8. Insert mechanical switches into the PCB mounting points
  9. 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

  1. Download CircuitPython for XIAO RP2040
  2. Drag the downloaded .uf2 file into the XIAO RP2040 folder (appears as a drive when plugged in)
  3. The board will reset and appear as a CircuitPython device
  4. Download the Adafruit CircuitPython library bundle (matching your CircuitPython version)
  5. Extract and copy these folders to the lib folder on your XIAO:
    • adafruit_hid (for keyboard input)
    • adafruit_midi (for MIDI output)
    • neopixel.mpy (for LED control)
  6. Download and install Thonny IDE for code editing and uploading
  7. 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

# 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