Solana Badge v1 · rev lcd
Solana Badge v1, front face
77.6 × 116.3 mm · front face · 6 parts highlighted

to move between modules

03 / 09 · Input

Six buttons over I²C

A D-pad plus select and cancel, read through a TCA9534 expander rather than GPIO.

Buttons
6 tactile
Expander
TCA9534 (U10)
Address
0x20
Interrupt
GPIO4, active LOW

The six buttons are the only user controls on the badge, and none of them touch an ESP32 pin. They land on P0–P5 of U10, a TCA9534 8-bit I/O expander sitting on the shared I²C bus at address 0x20. That buys back six GPIO at the cost of a bus transaction per read.

Silkscreen on the front face labels them as a directional cluster — UP, LEFT, RIGHT, DOWN on the left, SELECT and CANCEL on the right — but the expander has no idea about that. Firmware reads the input port register and gets bits 0–5, active LOW.

You do not have to poll. U10 asserts its open-drain INT on GPIO4 whenever an input changes, so the usual pattern is to sleep on the interrupt and only touch the bus when something moved. P6 and P7 are unconnected.

Pins

PinNetRoleFunction
GPIO4PBINTINTChange interrupt from U10 pin 13. Active LOW, open-drain.
GPIO9SCLI²C CLKShared clock. 2K2 pull-up R10 to 3V3.
GPIO10SDAI²C DATAShared data. 2K2 pull-up R8 to 3V3.

Parts

  • PB1 SW_Push — UP P0 · bit 0
  • PB2 SW_Push — LEFT P1 · bit 1
  • PB3 SW_Push — RIGHT P2 · bit 2
  • PB4 SW_Push — DOWN P3 · bit 3
  • PB5 SW_Push — SELECT P4 · bit 4
  • PB6 SW_Push — CANCEL P5 · bit 5
  • U10 TCA9534 I/O expander — back face, address 0x20 (A2/A1/A0 all to GND)

Firmware

firmware/testkit/testkit.ino
constexpr int     PIN_BUTTON_INT   = 4;
constexpr uint8_t TCA9534_ADDR    = 0x20;
constexpr bool    BUTTON_ACTIVE_LOW = true;

Notes

  • Button labels come from the front silkscreen; the firmware test kit refers to them by port bit.
  • Flip to the back face to see U10 and its pull-up array next to the ESP32 module.
Solana Badge · DEF CON Generated from pcb/v1, pinout/ and firmware/testkit/testkit.ino