Built-in project · Raspberry Pi Pico W

Pico W MPR121 touch keyboard on I2C1

MicroPython on a Pico W: an MPR121 capacitive touch module on I2C1 (SDA GP6, SCL GP7) prints which of its twelve electrodes a finger is on. The whole build, a Raspberry Pi Pico W and 1 more part, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

Teaching? Assign it to your class in one click.

Intermediate About 15 minutes to build and run. Runs in your browser. Free, and no account needed.

The parts retail for about $9. On Mokxi they're free.

The circuit runs here once the page has loaded.

What you'll learn

  • Capacitive touch sensing
  • I2C on a Pico with SDA and SCL pins
  • Reading registers on an I2C chip
  • Using a bitmask for twelve inputs
  • Printing only when something changes
  • Difficulty: Intermediate
  • Time: About 15 minutes
  • Board: Raspberry Pi Pico W
  • Parts: 3

How it works

An MPR121 chip senses a finger on any of its twelve touch pads. It talks to the Pico W over I2C1, with SDA on GP6 and SCL on GP7. It is powered from 3.3 V.

At start-up, mpr121.py resets the chip and sets a touch threshold of 12 and a release threshold of 6 for every electrode. Then it turns all twelve electrodes on.

main.py reads which pads are touched every 20 ms. When the list changes and something is touched, it prints it, for example touched [3, 7].

Parts list

3 parts, plus the jumper wires. They retail for about $9; on Mokxi they're free.

Kits that can build it

This starter kit has every part in the circuit. Each kit's page lists what else it can build.

Wiring table

Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.

Part and pinConnects to
Capacitive touch, MPR121 pin SDARaspberry Pi Pico W pin GP6
Capacitive touch, MPR121 pin SCLRaspberry Pi Pico W pin GP7
Capacitive touch, MPR121 pin VIN3.3 V
Capacitive touch, MPR121 pin GNDGround

The code

The MicroPython code exactly as the editor opens it. Change a line there and press Run: the board runs it on the official MicroPython firmware, with nothing to compile.

main.py · Raspberry Pi Pico W
# Electrode keyboard: the MPR121 senses a finger on any of its twelve
# electrodes. It is on I2C1 (SDA GP6, SCL GP7); mpr121.py reads it.
from machine import I2C, Pin
from mpr121 import MPR121
import time

i2c = I2C(1, sda=Pin(6), scl=Pin(7), freq=400000)
touch = MPR121(i2c)
last = []

while True:
    pads = touch.pads()
    if pads != last:
        if pads:
            print("touched", pads)
        last = pads
    time.sleep_ms(20)
mpr121.py · Raspberry Pi Pico W
# mpr121.py: the MPR121 capacitive touch controller, the few registers
# a touch keyboard needs. touched() returns a 12-bit mask: electrode 0
# is bit 0.
import time

class MPR121:
    def __init__(self, i2c, addr=0x5A):
        self.i2c = i2c
        self.addr = addr
        self._set(0x80, 0x63)            # soft reset
        time.sleep_ms(1)
        self._set(0x5E, 0x00)            # stop, so the setup can be written
        for e in range(12):
            self._set(0x41 + 2 * e, 12)  # touch threshold
            self._set(0x42 + 2 * e, 6)   # release threshold
        self._set(0x5D, 0x04)            # sample timing
        self._set(0x5E, 0x8C)            # run all 12 electrodes

    def _set(self, reg, value):
        self.i2c.writeto_mem(self.addr, reg, bytes([value]))

    def touched(self):
        low, high = self.i2c.readfrom_mem(self.addr, 0x00, 2)
        return (low | high << 8) & 0x0FFF

    def pads(self):
        mask = self.touched()
        return [e for e in range(12) if mask & (1 << e)]

Troubleshooting

The usual mistakes with this circuit, and the fix for each.

  • Nothing is ever touched This project
    Check that SDA is on GP6 and SCL on GP7, and that VIN is on 3.3 V and GND on ground.
  • The program stops with an I2C error This project
    The sketch expects the chip at address 0x5A. A wrong address or bad wiring means the chip never answers.
  • The sensor is not found on I2C. Capacitive touch
    The default address is 0x5A, and the ADDR pin can change it to 0x5B, 0x5C or 0x5D. Check SDA, SCL, 3.3 V power and a shared ground. Run an I2C scanner to confirm.
  • Touches register randomly or never. Capacitive touch
    Keep electrode wires short and away from other wires. The chip sets its baseline at start up, so do not touch the pads while it powers up.
  • Pins are powered from 5 V, or a 5 V signal goes into a GPIO. The RP2040 pins are 3.3 V only and are not 5 V tolerant. Raspberry Pi Pico W
    Power the board from VBUS or VSYS at 5 V, but keep GPIO signals at 3.3 V. Use a level shifter or a divider for 5 V parts.
  • WiFi code fails to connect, or the on-board LED code does nothing. The LED on the Pico W is not on GP25 like on the plain Pico. Raspberry Pi Pico W
    Use the board's LED_BUILTIN name so the library drives it through the WiFi chip. Join a 2.4 GHz network only, with the right SSID and password, and wait for the link before sending.

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.