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.
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.
- 1 × Raspberry Pi Pico W
- 1 × Capacitive touch, MPR121
- 1 × Power, 3.3 V
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 pin | Connects to |
|---|---|
| Capacitive touch, MPR121 pin SDA | Raspberry Pi Pico W pin GP6 |
| Capacitive touch, MPR121 pin SCL | Raspberry Pi Pico W pin GP7 |
| Capacitive touch, MPR121 pin VIN | 3.3 V |
| Capacitive touch, MPR121 pin GND | Ground |
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.
# 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: 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 address0x5A. 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.