Haptic Console · Control Unit · Perfboard Build

Wiring Guide

Every connection, given as the actual perfboard hole (column letter + row number, matching the printed grid on your board) — not an abstract header-pin number. Read a grid ref, find that hole, solder. Click any grid ref to light up every other mention of that same hole.

0/107
Power (+5V / +3V3) — red kit wire Ground — blue kit wire I²C bus (SCL / SDA / IRQ) — yellow kit wire Signal (per-pin GPIO) — white / orange / green kit wire

Using the jumper wire kit

You're wiring this with a pre-formed solid-core jumper kit (the boxed assortment of red/yellow/white/orange/green/blue wires, fixed pre-cut lengths, ends bent square) — the standard kit sold for solderless breadboards. That matters for a few reasons specific to this board:

These wires are made for solderless boards — this perfboard isn't one. The bent tip is shaped to grip a breadboard's spring clip, not to make a reliable joint on its own. It will friction-fit into a perfboard hole and feel "connected," but it isn't electrically sound until soldered. Treat every insertion as a dry-fit, not a finished connection:
  1. Push the wire's tip through the two holes the guide calls out (component-side/top of the board), and check the fit against the grid ref before committing.
  2. Flip the board to the copper/solder side and solder both tips to their pads. A perfboard pad is just a ring of copper around the hole — feed a little solder onto the joint so it wets the ring, not just the wire.
  3. Clip the excess tip flush once the joint has cooled.
The kit's lengths are fixed — the "rail" runs below are not. A shared bus row (GND/+3V3/+5V/SCL/SDA, see Shared bus rails below) usually spans more holes than any single wire in the kit. Two options, both fine:
  • Pick the longest wire that reaches and let it bow slightly between holes — solid core holds its shape, it won't spring back.
  • Daisy-chain shorter wires hole-to-hole along the row: at every intermediate hole, both the incoming and outgoing wire tips land in the same hole and both get soldered there together with the pad. Don't skip soldering an intermediate joint just because the wire "looks continuous" — each hole is a separate solder joint, there's no copper trace linking adjacent holes on bare perfboard.
The solder checklist already lists each rail hop separately, with its length in millimetres, so you can match a hop to a wire in the box before cutting anything.
Colour convention (matches the legend above, the kit's actual colours, and the 3D-modelled wires on the board): red for every +5V/+3V3 connection, blue for every GND connection (the kit has no black — blue is the closest "stay off the power colours" choice and reads unambiguously once you commit to it), yellow for the SCL/SDA/IRQ bus, and white/orange/green for the remaining signal wires. Each signal net gets one fixed colour, so the same wire is the same colour everywhere it appears — on this page, on the diagram, and in the 3D render. The checklist's colour column is the authority.
Test before you solder the far end. The small compartment of premade spade/hook-tipped leads in the kit box is handy for exactly this: clip one onto a wire you've already soldered at one end and touch the other lead to the destination pad with a multimeter in continuity mode, confirming against the grid ref, before soldering the second end permanently.

Back-side wiring diagram

The board seen from the solder side (mirrored), with every jumper drawn where it actually runs on the finished board. Wires that cross are drawn in physical over/under order.

B1B2B3B4B5B6B7B8CB1CB2CB3CB4CB5J1J2NP1R1R12R13R2R3R4R5S1S2S3S4S5S6TP1TP2TP3TP4TP5
power (+5V / +3V3) ground I²C bus (SCL / SDA / IRQ) signal — white signal — orange signal — green

The Teensy header sockets aren't outlined (48 near-parallel verticals would crowd the top of the diagram) — every net still ends at its correct header column. Signal colours are per net, not per connector group, so two adjacent wires can share a colour; cross-check the net name in the tables below.

Shared bus rails

Five nets touch many holes each. Run each as one continuous chain past every hole listed, in the order listed (that's board order, top to bottom), rather than home-running each connector back to the header separately.

GND · 30 taps · blue wire
D11 Y11 T11 O11 J11 E11 A11 D16 Z16 V16 R16 O16 K16 G16 C16 B23 A29 N29 X35 I35 Z44 U44 P44 K44 F44 Z46 U46 P46 K46 F46
+3V3 · 11 taps · red wire
A10 D10 Y10 T10 O10 J10 E10 M13 H13 N23 Z29
+5V · 8 taps · red wire
A09 D09 Y09 T09 O09 J09 E09 B29
SDA · 9 taps · yellow wire
A08 D08 Y08 T08 O08 J08 E08 Q13 T29
SCL · 9 taps · yellow wire
A07 D07 Y07 T07 O07 J07 E07 L13 U29

Test points

Five male 2.54mm header pins in the last column past S6 (column A — the letter sequence wraps back to A at the board's right edge), tapping the same rails S1–S6 share. Clip a jumper or scope hook straight onto a pin instead of back-probing a live JST connector.

TP2 · SCL
A07
TP1 · SDA
A08
TP5 · +5V
A09
TP4 · +3V3
A10
TP3 · GND
A11

Connectors

S1–S6 — haptic drivers (I²C)

Rotated vertical, one per column, centred on the board. GND/+3V3/+5V/SDA/SCL all fall on the same row across all six — a horizontal bus wire along that row reaches every connector. Only pin 6 (IRQ) is unique per connector.

S1JST-XH-6 · col D
1D11GNDGND rail
2D10+3V3+3V3 rail
3D09+5V+5V rail
4D08SDASDA rail
5D07SCLSCL rail
6D06IRQ1D2 → Y23
S2JST-XH-6 · col Y
1Y11GNDGND rail
2Y10+3V3+3V3 rail
3Y09+5V+5V rail
4Y08SDASDA rail
5Y07SCLSCL rail
6Y06IRQ2D3 → X23
S3JST-XH-6 · col T
1T11GNDGND rail
2T10+3V3+3V3 rail
3T09+5V+5V rail
4T08SDASDA rail
5T07SCLSCL rail
6T06IRQ3D7 → T23
S4JST-XH-6 · col O
1O11GNDGND rail
2O10+3V3+3V3 rail
3O09+5V+5V rail
4O08SDASDA rail
5O07SCLSCL rail
6O06IRQ4D12 → O23
S5JST-XH-6 · col J
1J11GNDGND rail
2J10+3V3+3V3 rail
3J09+5V+5V rail
4J08SDASDA rail
5J07SCLSCL rail
6J06IRQ5D27 → J23
S6JST-XH-6 · col E
1E11GNDGND rail
2E10+3V3+3V3 rail
3E09+5V+5V rail
4E08SDASDA rail
5E07SCLSCL rail
6E06IRQ6D31 → F23

R12 / R13 — I²C pull-ups

Sit just below the S-zone, tapping the SDA/SCL/+3V3 rails directly. 4.7 kΩ each.

R124.7 kΩ · row 13
1Q13SDASDA rail
2M13+3V3+3V3 rail
R134.7 kΩ · row 13
1L13SCLSCL rail
2H13+3V3+3V3 rail

B1–B8 — diamond buttons (mirrored)

B1–B4 (left cluster) mirror B5–B8 (right cluster) on the same row band, so left to right the refs read B1 B2 B3 B4 B8 B7 B6 B5 — the cards below are in that physical order, not numeric order. All eight pin-1 (GND) holes share one row: a single wire down that row grounds all eight.

B1JST-XH-2 · col D
1D16GNDGND rail
2D15B1D0 → A23
B2JST-XH-2 · col Z
1Z16GNDGND rail
2Z15B2D1 → Z23
B3JST-XH-2 · col V
1V16GNDGND rail
2V15B3D4 → W23
B4JST-XH-2 · col R
1R16GNDGND rail
2R15B4D8 → S23
B8JST-XH-2 · col O
1O16GNDGND rail
2O15B8D9 → R23
B7JST-XH-2 · col K
1K16GNDGND rail
2K15B7D26 → K23
B6JST-XH-2 · col G
1G16GNDGND rail
2G15B6D30 → G23
B5JST-XH-2 · col C
1C16GNDGND rail
2C15B5D32 → E23

J1 / J2 — joysticks (mirrored)

J1 (left stick) mirrors J2 (right stick); pin 5 (GND) on both lands on the same row.

J1JST-XH-5 · col X
1X39J1.1D22 → X29
2X38J1.2D21 → W29
3X37J1.3D20 → V29
4X36J1.4D16 → R29
5X35GNDGND rail
J2JST-XH-5 · col I
1I39J2.1D37 → I29
2I38J2.2D39 → K29
3I37J2.3D40 → L29
4I36J2.4D41 → M29
5I35GNDGND rail

CB1–CB5 — LED buttons (near-symmetric)

CB3 sits on the centre column; CB2/CB4 and CB1/CB5 mirror around it. Pin 3 is the LED anode and does not go to the Teensy — it goes to that connector's series resistor in the next column across, and the resistor's far end carries the GPIO. Both GND pins (2 and 4) sit on their own rows across all five. CB4's lamp is on D13, the Teensy's onboard-LED pin — safe only because a lamp is a driven output; never move a switch (pulled-up input) onto that pin.

CB1JST-XH-4 · col Z
1Z47CB1D23 → Y29
2Z46GNDGND rail
3Z45LED_ARM→ R1.1 A45
4Z44GNDGND rail
CB2JST-XH-4 · col U
1U47CB2D6 → U23
2U46GNDGND rail
3U45LED_EN→ R2.1 T45
4U44GNDGND rail
CB3JST-XH-4 · col P
1P47CB3D14 → P29
2P46GNDGND rail
3P45LED_SFT→ R3.1 Q45
4P44GNDGND rail
CB4JST-XH-4 · col K
1K47CB4D38 → J29
2K46GNDGND rail
3K45LED_CONF→ R4.1 L45
4K44GNDGND rail
CB5JST-XH-4 · col F
1F47CB5D34 → F29
2F46GNDGND rail
3F45LED_ALT→ R5.1 E45
4F44GNDGND rail

R1–R5 — LED series resistors

Standing upright in the column beside their own connector, pin 1 on row 45 — the same row as that connector's pin 3 — and pin 2 four holes up on row 41, pointing at the Teensy header. R2 and R5 sit one column to the right of their CB; R1, R3 and R4 one column to the left. That puts every LED-cathode jumper at a single 2.6 mm hole-to-hole hop (CB1.3 Z45 → R1.1 A45 and so on) instead of the 25–50 mm runs the old row-48 placement needed.

R1220 Ω · col A
1A45LED_ARM← CB1.3 Z45
2A41LED1D5 → V23
R2220 Ω · col T
1T45LED_EN← CB2.3 U45
2T41LED2D17 → S29
R3220 Ω · col Q
1Q45LED_SFT← CB3.3 P45
2Q41LED3D15 → Q29
R4220 Ω · col L
1L45LED_CONF← CB4.3 K45
2L41LED4D13 → O29
R5220 Ω · col E
1E45LED_ALT← CB5.3 F45
2E41LED5D29 → H23

NP1 — numpad

Pushed to the board's right edge to clear the Teensy header rows it shares rows with. Watch the labels here: the board's 32-column letter sequence reuses each letter at both ends, so NP1's holes can compute to the same letter+row as a header hole at the opposite edge. Use the left/right position, not the label alone. No numpad conductor is on D13 any more — that pin drives CB4's lamp. It stays reserved for driven outputs either way: the Teensy's onboard LED hangs off D13 and would fight a pull-up, so a column line must never be moved onto it.

NP1JST-XH-8 · col B
1B30NP1.1D33 → E29
2B29NP1.2D35 → G29
3B28NP1.3D36 → H29
4B27NP1.4D10 → Q23
5B26NP1.5D28 → I23
6B25NP1.6D25 → L23
7B24NP1.7D24 → M23
8B23NP1.8D11 → P23

Solder checklist

Every wire on the board, once. 107 connections, 3006 mm of wire in total; the longest single run is 109 mm (+5V, S6.3 → J_TEENSY_B.1). Lengths are hole-to-hole Manhattan distance — the routed wire follows the grid, so that is its length, but add a few millimetres for the bend at each tip. Ticks are saved in this browser only.

colournetsignalfromtomm
blueGNDD11 S1.1Y11 S2.112.7
blueGNDY11 S2.1T11 S3.112.7
blueGNDT11 S3.1O11 S4.112.7
blueGNDO11 S4.1J11 S5.112.7
blueGNDJ11 S5.1E11 S6.112.7
blueGNDE11 S6.1A11 TP3.110.2
blueGNDA11 TP3.1D16 B1.186.4
blueGNDD16 B1.1Z16 B2.110.2
blueGNDZ16 B2.1V16 B3.110.2
blueGNDV16 B3.1R16 B4.110.2
blueGNDR16 B4.1O16 B8.17.6
blueGNDO16 B8.1K16 B7.110.2
blueGNDK16 B7.1G16 B6.110.2
blueGNDG16 B6.1C16 B5.110.2
blueGNDC16 B5.1B23 J_TEENSY_A.181.3
blueGNDB23 J_TEENSY_A.1A29 J_TEENSY_B.217.8
blueGNDA29 J_TEENSY_B.2N29 J_TEENSY_B.1533.0
blueGNDN29 J_TEENSY_B.15X35 J1.540.8
blueGNDX35 J1.5I35 J2.538.1
blueGNDI35 J2.5Z44 CB1.466.0
blueGNDZ44 CB1.4U44 CB2.412.7
blueGNDU44 CB2.4P44 CB3.412.7
blueGNDP44 CB3.4K44 CB4.412.7
blueGNDK44 CB4.4F44 CB5.412.7
blueGNDF44 CB5.4Z46 CB1.255.8
blueGNDZ46 CB1.2U46 CB2.212.7
blueGNDU46 CB2.2P46 CB3.212.7
blueGNDP46 CB3.2K46 CB4.212.7
blueGNDK46 CB4.2F46 CB5.212.7
red+3V3A10 TP4.1D10 S1.273.7
red+3V3D10 S1.2Y10 S2.212.7
red+3V3Y10 S2.2T10 S3.212.7
red+3V3T10 S3.2O10 S4.212.7
red+3V3O10 S4.2J10 S5.212.7
red+3V3J10 S5.2E10 S6.212.7
red+3V3E10 S6.2M13 R12.227.9
red+3V3M13 R12.2H13 R13.212.7
red+3V3H13 R13.2N23 J_TEENSY_A.1540.6
red+3V3N23 J_TEENSY_A.15Z29 J_TEENSY_B.345.7
red+5VA09 TP5.1D09 S1.373.7
red+5VD09 S1.3Y09 S2.312.7
red+5VY09 S2.3T09 S3.312.7
red+5VT09 S3.3O09 S4.312.7
red+5VO09 S4.3J09 S5.312.7
red+5VJ09 S5.3E09 S6.312.7
red+5VE09 S6.3B29 J_TEENSY_B.1109.1
yellowSDAA08 TP1.1D08 S1.473.8
yellowSDAD08 S1.4Y08 S2.412.7
yellowSDAY08 S2.4T08 S3.412.7
yellowSDAT08 S3.4O08 S4.412.7
yellowSDAO08 S4.4J08 S5.412.7
yellowSDAJ08 S5.4E08 S6.412.7
yellowSDAE08 S6.4Q13 R12.143.1
yellowSDAQ13 R12.1T29 J_TEENSY_B.948.3
yellowSCLA07 TP2.1D07 S1.573.8
yellowSCLD07 S1.5Y07 S2.512.7
yellowSCLY07 S2.5T07 S3.512.7
yellowSCLT07 S3.5O07 S4.512.7
yellowSCLO07 S4.5J07 S5.512.7
yellowSCLJ07 S5.5E07 S6.512.7
yellowSCLE07 S6.5L13 R13.132.9
yellowSCLL13 R13.1U29 J_TEENSY_B.863.5
orangeD0B1D15 B1.2A23 J_TEENSY_A.227.9
orangeD1B2Z15 B2.2Z23 J_TEENSY_A.320.3
greenD4B3V15 B3.2W23 J_TEENSY_A.622.8
whiteD8B4R15 B4.2S23 J_TEENSY_A.1022.8
orangeD32B5C15 B5.2E23 J_TEENSY_A.2425.4
greenD30B6G15 B6.2G23 J_TEENSY_A.2220.3
greenD26B7K15 B7.2K23 J_TEENSY_A.1820.3
orangeD9B8O15 B8.2R23 J_TEENSY_A.1127.9
whiteD23CB1Z47 CB1.1Y29 J_TEENSY_B.448.3
orangeLED_ARMZ45 CB1.3A45 R1.12.6
orangeD6CB2U47 CB2.1U23 J_TEENSY_A.861.0
whiteLED_ENU45 CB2.3T45 R2.12.6
whiteD14CB3P47 CB3.1P29 J_TEENSY_B.1345.7
orangeLED_SFTP45 CB3.3Q45 R3.12.6
whiteD38CB4K47 CB4.1J29 J_TEENSY_B.1948.3
greenLED_CONFK45 CB4.3L45 R4.12.6
greenD34CB5F47 CB5.1F29 J_TEENSY_B.2345.7
whiteLED_ALTF45 CB5.3E45 R5.12.6
orangeD22J1.1X39 J1.1X29 J_TEENSY_B.525.4
orangeD21J1.2X38 J1.2W29 J_TEENSY_B.625.4
orangeD20J1.3X37 J1.3V29 J_TEENSY_B.725.5
greenD16J1.4X36 J1.4R29 J_TEENSY_B.1133.1
orangeD37J2.1I39 J2.1I29 J_TEENSY_B.2025.4
whiteD39J2.2I38 J2.2K29 J_TEENSY_B.1828.0
orangeD40J2.3I37 J2.3L29 J_TEENSY_B.1728.0
greenD41J2.4I36 J2.4M29 J_TEENSY_B.1628.1
orangeD33NP1.1B30 NP1.1E29 J_TEENSY_B.2410.2
orangeD35NP1.2B29 NP1.2G29 J_TEENSY_B.2212.7
orangeD36NP1.3B28 NP1.3H29 J_TEENSY_B.2117.7
orangeD10NP1.4B27 NP1.4Q23 J_TEENSY_A.1248.4
whiteD28NP1.5B26 NP1.5I23 J_TEENSY_A.2025.6
whiteD25NP1.6B25 NP1.6L23 J_TEENSY_A.1730.7
greenD24NP1.7B24 NP1.7M23 J_TEENSY_A.1630.7
orangeD11NP1.8B23 NP1.8P23 J_TEENSY_A.1335.8
orangeD5LED1A41 R1.2V23 J_TEENSY_A.758.4
orangeD17LED2T41 R2.2S29 J_TEENSY_B.1033.0
whiteD15LED3Q41 R3.2Q29 J_TEENSY_B.1230.5
greenD13LED4L41 R4.2O29 J_TEENSY_B.1438.1
whiteD29LED5E41 R5.2H23 J_TEENSY_A.2153.3
yellowIRQ1D06 S1.6Y23 J_TEENSY_A.455.7
yellowIRQ2Y06 S2.6X23 J_TEENSY_A.545.5
yellowIRQ3T06 S3.6T23 J_TEENSY_A.943.0
yellowIRQ4O06 S4.6O23 J_TEENSY_A.1443.0
yellowIRQ5J06 S5.6J23 J_TEENSY_A.1943.0
yellowIRQ6E06 S6.6F23 J_TEENSY_A.2345.5

107 of 107 shown. On the board these 107 connections become 223 modelled jumper legs, because a run that changes both row and column is drawn as two straight legs meeting at a corner hole, and a run that would lie on top of another wire is detoured around it. Electrically each is still one connection — one length of wire, bent, will do it.

Revision notes

How this layout got here
GPIO assignment (2026-08-26). Connector signals are not in sequential blocks. Each one is wired to a Teensy pin chosen for physical proximity, solved as an assignment problem over the free GPIOs, which is why the numbers look scattered. Eighteen signals override proximity because they are already soldered and stay put: B1–B8 (D0 D1 D4 D8 / D32 D30 D26 D9), J1/J2 (D22 D21 D20 D16 / D37 D39 D40 D41, on the D13–D23 / D33–D41 rail — row 29 here) and LED4/LED5 (D13 / D29, their resistors jumpered L41→O29 and E41→H23). The other 22 — the six IRQs, the five control buttons, three of the five lamps and the eight numpad lines — moved to their nearest free pin. Firmware pin constants must follow this map (scripts/pin_map.json); the tables on this page, the schematic and the manufactured board are all generated from it.
Teensy orientation, verified against the board (2026-08-26). Two earlier revisions of this page had the module in wrong — once with the rows swapped, once with both rows reversed. It plugs in USB toward the B23/B29 end (the left edge of the header strips below), and each socket carries its Teensy row in that row's own order, neither reversed: row 23 runs GND D0 D1 … D12 +3V3 D24 … D32 left to right, row 29 runs +5V GND +3V3 D23 D22 … D13 GND D41 … D33. Three independent readings off the physical board agree: the Vin/GND/3.3V trio sits in B29 A29 Z29, B1's wire is in A23 (D0) and B2's in Z23 (D1) — exactly the firmware's pins. Every already-soldered wire keeps both its GPIO and its hole under this mapping. If this is ever doubted again, settle it by reading a hole off the board, never by checking whether the resulting map looks sensible — every table on this page is generated from the mapping, so a wrong one still looks self-consistent.
R4's jumper was moved off J1's pin (resolved). R4's LED wire had gone into L41→R29, but R29 reads D16J1 pin 4, already soldered. It has been pulled and re-landed five holes along in O29 (D13), so LED4 is now frozen on D13 alongside LED5's E41→H23 (H23 = D29). D13 also drives the Teensy's onboard LED, which is harmless here precisely because LED4 is a driven output — never put a pulled-up input on it.
Connector standard. S1–S6 follow the XH2.54 6-pin Haptic Console Connector Standard v1.1 — pin 1 GND, pin 2 3.3V, pin 3 5V, pin 4 SDA, pin 5 SCL, pin 6 IRQ — matching cables crimped to that spec.
Group layout. Every JST group shares one anchor row, mirrored left/right to match the physical panel (S1–S6 centred; B1–B4 mirrors B5–B8; J1 mirrors J2; CB1–CB5 near-symmetric about the centre column). Because each group shares an anchor row, the same pin number lands on the same row across the group, which is what makes the single-wire bus rails possible. Everything fits inside the physical 32×50 hole grid.
Moves since the first revision. The Teensy sockets moved one column left and two rows up (rows 25→23 and 31→29) and R12/R13 shifted two columns; S1–S6 shifted one column left to clear the TP1–TP5 header at the right edge; R1–R5 went from lying flat across row 48 to standing upright on rows 45/41 in the column beside their own CB, which is what shortened every LED-cathode jumper to one hole.
The KiCad files match this page (2026-08-26). Everything is now generated from the same scripts/pin_map.json: the perfboard has R1–R5 standing on rows 45/41 as rewired by hand (R1 A45/A41, R2 T45/T41, R3 Q45/Q41, R4 L45/L41, R5 E45/E41) with the modelled jumper legs on the back layer, the schematic's net labels carry each signal's GPIO name, and the manufactured board has been re-netted and re-routed from scratch (0 DRC violations, 0 unconnected pads) with fresh gerbers. Change a pin by editing the generator and re-running the pipeline — never by hand-editing this page or a KiCad file.