This is the canonical, cited reference for how this machine's two OPP hardware families address
switches/coils/lights and what rules govern pairing a switch to a coil for a hardware-autofire
device (flippers, slings, pop bumpers). It exists because the two families follow meaningfully
different rules and this project is being rewired from scratch, picking board assignments fresh
component by component — getting this wrong risks a non-working hardware rule at best and a blown
FET/coil/fuse at worst.
tools/hw_console/data/components.yaml stays the live "what's actually wired where" tracker;
this doc is the rulebook it and print/wiring-guide.html both draw on, so
the rules only need to be figured out once. See also docs/wiring-workflow.md for what actually
happens at the bench (name it, wire the coil, identify the switches together, test low-voltage
then high-voltage) and .claude/skills/wire-component/SKILL.md for the bookkeeping steps built
on top of these rules, docs/wiring-guide.md for a single readable table of every component's
current pin assignments and status, and docs/board-silkscreen-reference.md for identifying a
physical pin from a board photo — cross-references every silkscreen label (J1-J12 on
CobraPin, P0.x-P3.x on the red boards) against the MPF number it corresponds to, with real
board photos.
Use CobraPin first wherever possible (chain 0 before chain 1); the red boards (chain 2, boards
0x20-0x23) are the fallback, used only when CobraPin can't fit a component. All LEDs go on
CobraPin, always, regardless of remaining CobraPin coil/switch capacity.
This applies to every component being freshly assigned during the rewire: the VUKs (VUK1-VUK8,
including VUK6, the ball lock that feeds the ball dropper), the ramp diverter, pop bumpers, drop
targets, posts, the third flipper, service-mode nav switches, a future tilt switch, and anything
else not yet wired for real (everything in hardware-draft.yaml).
One physical PCB, two independent STM32 controllers sharing it — chain 0 (COM4, "Board 0") and
chain 1 (COM5, "Board 1"). Switch inputs are 3.3V logic (STM32-based) — keep this in mind
when probing a switch pin with a meter.
J6/J7/J8.J13: HV_A, HV_B,HV_C. A coil's positive lead must come from the HV pin matching its own bank — never aHV_A or HV_C puts current throughA CobraPin board's per-channel behavior isn't fully determined by mpf hardware scan (which only
reports coarse wing-level type — solenoid/input/NeoPixel/etc). A separate, external tool -
CobraPin's own board-config toolchain, on this machine at
C:\Users\dorus\Documents\Pinball-Code\Tools\Boardconfig files\Cobra\ (config scripts) and
...\Tools\OPP - open-pinball-project-code\ (full source) - can set a per-channel config byte
that MPF's hardware scan never surfaces, silently taking an input off the table for plain switch
use without it ever showing as "in use" anywhere in this repo's own config.
Confirmed case (2026-09-06): chain 0 board 0x20's CobraPin_Board0_servos.py config
(vs. the plain CobraPin_Board0.py) sets a special \x96 byte on input indices 8, 9, 10, 11
instead of the normal rs232Intf.CFG_INP_STATE - dedicating those four inputs to servo/PWM use.
A switch wired to one of them reads stuck/garbage regardless of press/release (not a simple NO/NC
reversal, which would just invert). Found after s-start was wired to 0-0-8 and wouldn't work;
moved to 0-0-27 instead.
This is enforced in code, not just documented here: tools/hw_console/registry.py's
RESERVED_NUMBERS dict lists every number known to be off-limits this way, and both
check_collision() (the interactive pre-check in wire-component's step 4) and full_scan()
(run automatically by the PostToolUse hook after any edit to hardware-switches.yaml/
-coils.yaml) check against it. If a board is ever reflashed back to a plain (non-servo) config,
or a new board turns out to have its own repurposed channels, update RESERVED_NUMBERS to match
reality - it's a manually-maintained list, not something derived from a live board query.
For a hardware-autofire device (flippers, slings, pop bumpers — switch and coil linked as a
hardware rule, not software-triggered), the switch and the coil must be addressed by the same
microcontroller: the first digit of both numbers must match. A coil on 0-x-y pairs only with
a switch on 0-a-b; never mixed across 0- and 1-. This is CobraPin's only pairing
constraint — there is no further sub-range requirement (contrast with the red boards, below).
| Coil number(s) | Bank | HV feed pin | Wire color |
|---|---|---|---|
0-0-0, 0-0-8, 0-0-9, 0-0-10, 0-0-11, 0-0-12, 0-0-13, 0-0-14 |
A | HV_A |
brown |
0-0-1, 0-0-2, 0-0-3, 0-0-4, 0-0-5, 0-0-6, 0-0-7, 0-0-15 |
B | HV_B |
teal |
1-0-0, 1-0-1, 1-0-2, 1-0-3, 1-0-4, 1-0-5, 1-0-6, 1-0-7 |
C | HV_C |
purple |
This project's flipper coils (c-flipper-left=0-0-8, c-flipper-right=0-0-9) are both Bank
A, so they draw +50V from the brown HV_A wire. Its flipper switches
(s-flipper-left=0-0-1, s-flipper-right=0-0-2) are on chain 0 too, satisfying the
same-microcontroller pairing rule above; switches don't have a "bank" (that's a coil-only, HV
power concept), so their numbers landing in what the table above calls coil Bank B's range is
irrelevant here.
Other confirmed wire colors: main incoming supply VIN = red, GND = black. The 8-pin
driver-output signal wires observed in photos cycle through blue/yellow/purple/teal, but this
isn't confidently a strict per-pin-number code — don't assert a specific pin always gets a
specific color without checking.
All of this machine's LEDs are on CobraPin (40 GRB pixels today, all on NEO0).
J11 = NEO0, lights numbered 0-0-0 … 0-0-255; J12 = NEO1, lights1-0-0 … 1-0-255. The first LED on a chain is -0. Up to 256 RGB pixels per chain (512J10 is the NeoPixel power input for both chains (5V, or 12V for 12V pixels). It'sF4, and the red D25 LED shows the fuse is good and power is present (no MPF orJ14 is a fused 5V output for extra power taps along a longJ10/J11/J12/J14 are JST VH. Many pixel strips come with JST SMtype: grb (as in hardware-leds.yaml); WS2811-typetype: line.board Overviews.xlsx, sheets Cobrapin - Doc and Cobrapin - Game Funtion (silkscreendocs/references/raw/cobrapin-official-doc/content.md.0x20-0x23)A fundamentally different architecture from CobraPin: each processor board (PSoC4200, this
project's gen2 hardware) can carry up to 4 plug-in "wing" boards, each independently a
solenoid wing, switch wing, or incandescent-lamp wing, mixed freely. Switch inputs are 5V
logic — a different idle voltage than CobraPin's 3.3V.
Format is board-index (two-part) in MPF's generic docs, or chain-board-index (three-part) once
multiple serial chains exist — this project always uses the three-part form (2-0-0, 2-1-16,
etc.), same underlying scheme with the chain prefix added.
0-7, wing 1 → 8-15, wing 2 → 16-23, wing 3 →24-31 (8 per wing).0-3, wing 1 → 4-7, wing 2 → 8-11, wing 3 → 12-15Unlike CobraPin, the red board's silkscreen only prints the raw PSoC4200 pin (P0.0-P3.7 —
see docs/board-silkscreen-reference.md), not the MPF number. The formula above (wing×8/wing×4)
gives the logical wing/position; this table adds the physical-pin side, confirmed against
every row of docs/board-silkscreen-reference.md's per-pin tables for this project's actual
boards:
| Silkscreen port | OPP wing | Function | Pin → position | MPF range (2-<board>-…) |
|---|---|---|---|---|
P0.0-P0.3 |
Wing 0 | Switch (dedicated autofire input) | ascending, pos = pin |
0-3 |
P0.4-P0.7 |
Wing 0 | Coil | ascending, pos = pin - 4 |
0-3 |
P1.0-P1.3 |
Wing 1 | Switch (dedicated autofire input) | ascending, pos = pin |
8-11 |
P1.4-P1.7 |
Wing 1 | Coil | ascending, pos = pin - 4 |
4-7 |
P3.0-P3.7 |
Wing 2 | Switch (pure matrix wing, no coils) | descending, pos = 7 - pin |
16-23 |
P2.0-P2.7 |
Wing 3 | Switch (pure matrix wing, no coils) | descending, pos = 7 - pin |
24-31 |
<board> is 0/1/2/3 for chain2-0x20/0x21/0x22/0x23. The one genuinely non-obvious part:
wings 2-3 count in the opposite direction from wings 0-1 (P3.7/P2.7 is position 0, not
P3.0/P2.0) — confirmed empirically from the sourced tables, not something the generic MPF
docs state, so don't assume it extends to a board family not yet checked this way. The
wing×8/wing×4 formula itself is MPF's own documented OPP convention (mpf-docs-opp-switches/
mpf-docs-opp-drivers in docs/references/), universal across OPP boards; only the
port-to-wing and pin-direction mapping is specific to this board's physical layout.
A solenoid wing's own dedicated direct-switch inputs (for hardware-autofire pairing) are the
first four switch numbers of that same wing position: a coil in wing N (4N..4N+3) pairs only
with a switch in 8N..8N+3 — not just "anywhere on the same board." This is a real, separate
constraint from CobraPin's simpler same-controller-digit rule.
Cross-validated against this project's own already-working hardware (not just theoretical):
0x20, wing 0 (coils 2-0-0..3, dedicated switches 2-0-0..3): c-sling-right/left =2-0-0/2-0-1, paired switches s-sling-right/s-sling-left = 2-0-0/2-0-1 — both insidehardware-coils.yaml/hardware-switches.yaml — this is left as the historical example thatc-plunger/c-trough-eject (2-0-2/2-0-3) were wing 0's remainingball_device), so no paired switch was needed for them. (They're0-0-10/0-0-11.)0x20, wing 1 (coils 2-0-4..7, dedicated switches 2-0-8..11): c-popbumper-1/2/32-0-4/5/6) paired with s-popbumper-1/2/3 (2-0-8/9/10) — the first 3 of wing 1's 42-0-11 unused). c-drop (2-0-7) is wing 1's 4th coil, software-triggered.hardware-draft.yaml with no pin number and 2-0-4..10 are free - kept here as a workedAny future hardware-autofire pairing added to chain 2 must follow this same wing-relative rule.
RSP-320-48 (48V) supply.Format chain-board-index, e.g. 0-0-0 = first RGB LED on chain 0, card 0x20 (card_num is
the board's hex address minus 0x20). Channels use internal_index = 3 * index for 3-channel
RGB/GRB pixels; RGBW doesn't fit this directly (chain LED entries instead and let MPF
auto-calculate channels). Same underlying convention CobraPin's own LED numbering uses — included
here only so the pattern in hardware-leds.yaml makes sense, not because this project uses red
boards for LEDs (it doesn't, per the priority policy above).
mpf hardware scan verifies connected boards (ports, firmware, per-category card counts) — thishardware-basic.yaml.hardware: {platform: opp}, opp: {ports: COM7} (or a list, as this projectCOM4/COM5/COM6). Windows COM ports above 9 need the \\.\COM10 form.debug: true under the opp: config section for verbose diagnostics; poll_hz: 50 (defaultdocs/references/raw/pinballmakers-opp-wiki/content.md.docs/references/raw/mpf-docs-opp-{switches,drivers,leds,lights, connecting,config,troubleshooting}/content.md; full index at docs/references/index.md.