Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

4x4 keypad with Raspberry Pi Pico 2 W — MicroPython PIN lock that avoids erratum E9

Scan a 4x4 membrane keypad on a Pico 2 W (GP6–GP13) in MicroPython with rows driven LOW and column pull-ups, and check a PIN code — no pull-downs needed.

MicroPythonVerified — micropython (mpy-cross v1.29.0), 3 Nov 2026Compile-only

Community draft — report a mistake

A 4×4 membrane keypad is eight wires — four rows, four columns — and a scan loop. On the Pico 2 W the direction of that scan matters: drive the rows LOW and read the columns with pull-ups, so the RP2350’s pull-down erratum never comes into play.

Rows go to GP6–GP9, columns to GP10–GP13. The script prints each key and checks a four-digit PIN (# to enter, * to clear), lighting the on-board LED when it is right.

Wiring

Raspberry Pi Pico 2 WOnly the pins used are shown · 3.3 V logic4×4 matrix membrane keypadGP6GP7GP8GP9GP10GP11GP12GP13R1R2R3R4C1C2C3C4
Every connection
Raspberry Pi Pico 2 W4×4 matrix membrane keypadWireNotes
GP6R1redPhysical pin 9.
GP7R2orangePhysical pin 10.
GP8R3yellowPhysical pin 11.
GP9R4greenPhysical pin 12.
GP10C1bluePhysical pin 14.
GP11C2purplePhysical pin 15.
GP12C3whitePhysical pin 16.
GP13C4brownPhysical pin 17.

No supply — passive switch matrix part, 3.3 V board. The keypad has no electronics, so it works at 3.3 V or 5 V. It does need eight GPIOs; on ESP32 avoid the strapping pins (0, 2, 5, 12, 15) and the input-only pins (34–39) for the row outputs.

Board quirks

  • The scan drives one row LOW at a time and reads the columns with Pin.PULL_UP. Many online examples do the opposite (rows HIGH, columns PULL_DOWN) — on RP2350 A2 chips that hits erratum E9 and keys appear stuck.
  • The keypad is just switches, so it needs no power wire. Eight GPIOs in a row (GP6–GP13) keep the ribbon cable straight; GND pin 13 sits between them and is not used.
  • Pressing two keys in the same column at once can ghost a third. For PIN entry that never matters; for a game controller, add a diode per key.
  • This is a demo lock. A real door lock also needs a delay after wrong PINs and a relay or solenoid driver (with its own supply).

Code

main.pyMicroPython
# 4x4 membrane keypad on a Raspberry Pi Pico 2 W (MicroPython): scan keys and check a PIN code.
# Wiring: R1-R4 -> GP6-GP9 (pins 9, 10, 11, 12), C1-C4 -> GP10-GP13 (pins 14, 15, 16, 17).
# Rows are driven LOW one at a time; columns use the internal PULL-UPs and read LOW when pressed.
# (Many tutorials drive rows HIGH and use PULL_DOWN on columns - that fails on RP2350 A2 chips,
# erratum E9, where an internal pull-down can hold the pin at about 2 V.)
from machine import Pin
import time

SECRET = "1234"
KEYS = ("123A", "456B", "789C", "*0#D")

rows = [Pin(n, Pin.OUT, value=1) for n in (6, 7, 8, 9)]
cols = [Pin(n, Pin.IN, Pin.PULL_UP) for n in (10, 11, 12, 13)]
led = Pin("LED", Pin.OUT)


def scan():
    """Return the key held down, or None."""
    for r, row in enumerate(rows):
        row.value(0)
        time.sleep_us(10)  # let the line settle
        for c, col in enumerate(cols):
            if col.value() == 0:
                row.value(1)
                return KEYS[r][c]
        row.value(1)
    return None


print("Keypad ready. Type the PIN then #, * to clear")
entered = ""
last = None
while True:
    key = scan()
    if key and key != last:  # act once per press
        if key == "*":
            entered = ""
            print("Cleared")
        elif key == "#":
            if entered == SECRET:
                print("PIN OK - unlocked")
                led.on()
                time.sleep(3)
                led.off()
            else:
                print("Wrong PIN")
            entered = ""
        else:
            entered += key
            print("Key {}   entered: {}".format(key, "*" * len(entered)))
    last = key
    time.sleep_ms(30)  # also debounces

Expected serial output

REPL / Thonny shellOutput
Keypad ready. Type the PIN then #, * to clear
Key 1   entered: *
Key 2   entered: **
Key 3   entered: ***
Key 4   entered: ****
PIN OK - unlocked

Common errors

Keys come out as the wrong characters

Your keypad’s connector order differs. Check which pin is R1 with a multimeter (continuity while pressing “1”) and reorder the GP lists in code.

Whole row or column never responds

A loose jumper in the 8-pin connector. Press it home, or use a male header strip.

↑↓ to move · Enter to open