

Button grid
An ESP32-S3 controller board for an 8×8 button matrix with 64 individually switched 12 V LEDs. It's designed in KiCad 9 and made to be ordered from JLCPCB.
- Size
- 208 × 110 mm
- Copper layers
- 2
- Thickness
- 1.6 mm
- Parts
- 108
- Nets
- 204
- Pads
- 606
- Tracks, vias
- 2,031, 545
- Pours
- 2
- Routed
- Yes
- KiCad
- KiCad 9.0 (file 20241229)
- Created
- 14 Oct 2026
- Updated
- 14 Oct 2026
Overview
Button grid is an open-source printed circuit board by paulsonnentag, from the paulsonnentag/button-grid repository on GitHub. It is a 2-layer board of 208 × 110 mm with 108 parts on 204 nets, routed with 2,031 tracks and 545 vias.
It is built around the ESP32-S3-WROOM-1-N8, 74HC595 and ULN2803A, with the TPS54202HDDC, SS34 and SS54 among its other parts. Its parts include 40 resistors, 26 capacitors, 18 ICs, 13 connectors and 4 diodes. It belongs with the ESP32 boards of this library.
Main components
6ESP32-S3-WROOM-1-N8
SMD,25.5x18mm-40℃~+85℃ -98.2dBm 2.4GHz 20.5dBm 355mA 3V~3.6V 95mA Bluetooth5.0 ESP32-S3 Chip On-board PCB Antenna UART、SPI、I2C、I2S、USB SMD,25.5x18mm WiFi Modules ROHSEspressif SystemsWiFi Modules74HC595
SOP-16-40℃~+85℃ 1 100ns@5V,50pF 10MHz 2V~6V 74HC 8 Serial-to-Serial or Parallel Tri-State SOP-16 Shift Registers ROHSGRShift RegistersULN2803A
SOP-18-300mil-40℃~+85℃ 0.93mA 100uA 15pF 20uA 30V 500mA 50V 8 SOP-18-300mil Darlington Transistor Arrays ROHSUMWDarlington Transistor ArraysTPS54202HDDC
UncategorisedTexas InstrumentsSS34
SMA(DO-214AC)-55℃~+125℃ 3A 40V 500uA@40V 550mV@3A Independent SMA(DO-214AC) Schottky Diodes ROHSMDDSchottky DiodesSS54
SMA(DO-214AC)-55℃~+125℃ 1mA@40V 40V 550mV@5A 5A Independent SMA(DO-214AC) Schottky Diodes ROHSMDDSchottky Diodes
README
README.mdbutton-grid
An ESP32-S3 controller board for an 8×8 button matrix with 64 individually switched 12 V LEDs. It's designed in KiCad 9 and made to be ordered from JLCPCB.
Site with the design viewer, test results and JLCPCB downloads: GitHub Pages
for this repo, built by .github/workflows/pages.yml.
What's on the board
| Function | Implementation |
|---|---|
| MCU | ESP32-S3-WROOM-1-N8, native USB-C for flashing and serial |
| LEDs (64, not multiplexed) | 8× 74HC595 in one chain → 8× ULN2803A low-side drivers → screw terminals |
| Buttons (your diode matrix) | 8 rows + 8 columns directly on GPIOs, 100 Ω series resistors, 22 kΩ pull-ups |
| Power | 12 V wall adapter (5.5×2.1 mm, centre +, ≥ 2 A) → SS54 reverse-polarity diode → LED supply; TPS54202 buck converter → 3.3 V |
| Size | 208 × 110 mm, 2 layers |
Wiring
- LED terminals J11–J18 (10-pole, 3.5 mm pitch, along the top and bottom edges). Pins 1–8 take the cathode (−) wire of 8 LEDs. Pins 9–10 are +12 V for the anode (+) wires. Each LED must keep its own series resistor. Twist or daisy-chain the + wires of a bank so that at most 2 wires go into one screw. Bank 1 (J11) is LEDs 0–7, bank 2 is LEDs 8–15, and so on.
- ROWS J3 / COLS J4 (8-pole, left edge): connect the 8 row wires and 8 column wires of your matrix. Which way the diodes point is set in firmware, so either orientation works.
- 12 V goes into the barrel jack. USB-C alone powers only the logic (enough to flash firmware). The LEDs need 12 V.
ESP32 pin map (for the firmware)
| Signal | GPIO |
|---|---|
| ROW0…ROW7 | 4, 5, 6, 7, 15, 16, 17, 18 |
| COL0…COL7 | 8, 9, 10, 11, 12, 13, 14, 21 |
| 74HC595 SER (data in) / SRCLK / RCLK (latch) / OE (active low, pulled high) | 38 / 39 / 40 / 41 |
| Chain return (last 74HC595 QH′), used to self-test the chain | 42 |
| Status LED | 2 |
| USB D− / D+ | 19 / 20 |
To set LEDs, shift out 64 bits, with the bits for bank 8 first, then pulse RCLK. A 1 turns the LED on. Drive OE low to enable the outputs. PWM on OE dims all LEDs.
Repository layout
hardware/
button-grid.kicad_pro/.kicad_sch/.kicad_pcb, led_bank.kicad_sch <- open these in KiCad 9
gen/ generators: build_schematic.py, build_pcb.py (placement), finish_pcb.py (pours)
scripts/ build.sh, route.sh, check.sh, export.sh, check_netlist.py, jlc_bom_cpl.py
site/ build_site.py -> static GitHub Pages siteThe design was generated from Python. It uses one "LED bank" sheet that is reused 8 times as a KiCad hierarchical sheet, so a change to that sheet applies to all 64 channels. The output is an ordinary KiCad project:
- Editing by hand in KiCad: just do it, then run
hardware/scripts/check.sh. Once you've edited by hand, don't re-run the generators, because they overwrite the files. - Editing through the generators: change
hardware/gen/*.py, then runbuild.sh→route.sh→check.sh.
Every script runs KiCad from the official kicad/kicad:9.0 Docker image when
KiCad isn't installed locally. route.sh also needs Java 25 and the
Freerouting jar.
How the design is checked
hardware/scripts/check.sh runs on every push, and the results are shown on the site:
- ERC. KiCad's electrical rules check on the schematic.
- Connectivity assertions (
check_netlist.py). These check the intended circuit pin by pin: all 64 LED channels, the 74HC595 chain order, the clock/latch/enable fan-out, every matrix line, USB-C CC resistors, the buck converter's feedback voltage, strapping pins, and LCSC numbers on every assembled part. The checker was tested by feeding it deliberately broken netlists (swapped LED wires, a broken chain), and it catches them. - DRC with schematic parity. Manufacturing limits that are safe for JLCPCB, a check that every net is routed, and a check that the PCB matches the schematic.
Recommended before ordering:
- Breadboard test of one channel: an ESP32 dev board, a 74HC595, a ULN2803 and one of your LEDs at 12 V.
- First power-up: connect 12 V with no LEDs attached and measure 3.3 V. Then flash a test firmware that walks one LED at a time, checks the chain through GPIO42, and prints matrix presses over USB.
Ordering (see the site for the files)
Upload the gerber zip, then turn on PCB Assembly with the BOM and CPL files, 2
boards assembled. The screw terminals, barrel jack, buttons and header are
through-hole parts that you solder yourself (hand-solder-parts.csv). On
JLCPCB's placement preview, check that the chips and the USB-C connector are
rotated correctly.
Part numbers: the LCSC numbers were picked from JLCPCB's catalogue but couldn't be checked against live stock while building. Check them when you upload the BOM. Any part flagged as out of stock can be swapped for one with the same footprint.
Parts
108| Qty | Value | Footprint | References |
|---|---|---|---|
| 19 | 100nF | Capacitor_SMD:C_0603_1608Metric | C10, C11, C12, C13, C14, C15, C16, C17, C18, C21, C22, C23, C24, C25, C26, C27 +3 |
| 17 | 22k | Resistor_SMD:R_0603_1608Metric | R2, R30, R31, R32, R33, R34, R35, R36, R37, R40, R41, R42, R43, R44, R45, R46 +1 |
| 16 | 100 | Resistor_SMD:R_0603_1608Metric | R10, R11, R12, R13, R14, R15, R16, R17, R20, R21, R22, R23, R24, R25, R26, R27 |
| 8 | 74HC595 | Package_SO:SOIC-16_3.9x9.9mm_P1.27mm | U11, U12, U13, U14, U15, U16, U17, U18 |
| 8 | LEDs | TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-10-3.5-H_1x10_P3.50mm_Horizontal | J11, J12, J13, J14, J15, J16, J17, J18 |
| 8 | ULN2803A | Package_SO:SOIC-18W_7.5x11.6mm_P1.27mm | U21, U22, U23, U24, U25, U26, U27, U28 |
| 4 | 10uF 25V | Capacitor_SMD:C_0805_2012Metric | C1, C2, C3, C9 |
| 4 | M3 | MountingHole:MountingHole_3.2mm_M3 | H1, H2, H3, H4 |
| 3 | 10k | Resistor_SMD:R_0603_1608Metric | R3, R4, R5 |
| 2 | 22uF | Capacitor_SMD:C_0805_2012Metric | C6, C7 |
| 2 | 5.1k | Resistor_SMD:R_0603_1608Metric | R7, R8 |
| 2 | SS34 | Diode_SMD:D_SMA | D2, D3 |
| 1 | 100k | Resistor_SMD:R_0603_1608Metric | R1 |
| 1 | 10uH | Inductor_SMD:L_Sunlord_SWPA4030S | L1 |
| 1 | 12V DC | Connector_BarrelJack:BarrelJack_Horizontal | J1 |
| 1 | 1k | Resistor_SMD:R_0603_1608Metric | R6 |
| 1 | 1uF | Capacitor_SMD:C_0603_1608Metric | C8 |
| 1 | BOOT | Button_Switch_THT:SW_PUSH_6mm | SW2 |
| 1 | COLS | TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-8-3.5-H_1x08_P3.50mm_Horizontal | J4 |
| 1 | ESP32-S3-WROOM-1-N8 | RF_Module:ESP32-S3-WROOM-1 | U1 |
| 1 | RESET | Button_Switch_THT:SW_PUSH_6mm | SW1 |
| 1 | ROWS | TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-8-3.5-H_1x08_P3.50mm_Horizontal | J3 |
| 1 | SS54 | Diode_SMD:D_SMA | D1 |
| 1 | TPS54202H | Package_TO_SOT_SMD:TSOT-23-6 | U2 |
| 1 | UART | Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical | J5 |
| 1 | USB-C | Connector_USB:USB_C_Receptacle_HRO_TYPE-C-31-M-12 | J2 |
| 1 | status | LED_SMD:LED_0603_1608Metric | D4 |
Questions
How big is the Button grid PCB?
It measures 208 × 110 mm and has 2 copper layers, 1.6 mm thick.
What parts does the Button grid use?
108 parts, built around the ESP32-S3-WROOM-1-N8, 74HC595, ULN2803A and TPS54202HDDC. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.
Where can I download the Button grid KiCad files?
From the paulsonnentag/button-grid repository on GitHub, at the commit this page was made from: the board is hardware/button-grid.kicad_pcb and its schematic hardware/button-grid.kicad_sch. PCBKit opens the board in the browser, with nothing to install.
Can I use the Button grid design in my own project?
Its repository states no licence, so its author keeps all rights: ask paulsonnentag before reusing the design.
Similar boards
- 2 layers100 × 89 mm

- 2 layers210 × 120 mm

Relay24 ESP32
renatorgr/Boards
Hardware and firmware for the AgOpenGPS AiO v4.5 autosteer boards: Teensy 4.1 firmware with its own web page (GPS, IMU, autosteer), a XIAO ESP32 Wi-Fi status page, XIAO adapter boards, and an Arduino Nano sprayer…
164 parts2GPL-3.0 - 2 layers100 × 89.5 mm

Led processor board
eelstretching/led-processor-board
A board with a processor and a couple of other things that can talk to an LED output board.
128 parts - 2 layers50 × 62 mm

IotDisplay
BerkeleyHCI/PolymorphicBlocks
A Python-based hardware description language for PCBs for higher-level (block-diagram / system-architecture level) PCB design through libraries of directly reusable subcircuit generators.
78 parts94BSD-3-Clause - 2 layers90 × 90 mm

- 2 layers125 × 100 mm

RTC RELAY
zen451019/EMASA_drivers
Compendium of codes, schematics, and controller boards designed for use by EMASA
56 parts - 2 layers121 × 75.5 mm

Jlctest
cjheath/jlcbasic
JLC Basic parts library for Kicad fetched and converted from EasyEDA
46 parts5 - 4 layers65 × 73.9 mm

Barn blinds controller
irvintim/barn-blinds-controller
Open barn-blinds-controller.kicadpro. Everything the project needs is under this folder: lib/NewLibrary.kicadsym (U1, J4, TMP235), lib/barnshadecontroller.pretty/, and lib/3dmodels/ (referenced as…
118 parts