Skip to content

PCEngine Input Interface

Reads native PCEngine / TurboGrafx-16 controllers by bit-banging the controller's multiplexer directly. PCE pads are a 74157-style 2:1 mux with no clock to track, so no PIO is required -- the driver drives the SEL/CLR lines and samples the four data lines from a ~60Hz polling task.

Protocol

  • Bus: 4-bit multiplexed parallel (SEL + CLR control, D0-D3 data)
  • Method: GPIO bit-bang, ~60Hz timestamp-throttled from pce_host_task()
  • Location: src/native/host/pcengine/

A standard pad multiplexes two nibbles onto the four data lines, selected by SEL (all signals active-LOW, 0 = pressed):

SEL D0 D1 D2 D3
HIGH Up Right Down Left
LOW I II Select Run

CLR is held low for an active read; pulsing it advances the pad's internal bank (used for the 6-button extended read and multitap addressing). The ~60Hz poll interval also provides the idle gap the 6-button bank counter needs to reset between frames.

Supported Controllers

Device Notes
Standard 2-button pad I, II, Select, Run, D-pad
6-button Avenue Pad 6 Adds III, IV, V, VI (best-effort -- see below)

Button Mapping

PCE Button JP_BUTTON_*
I B2
II B1
III B3
IV B4
V L1
VI R1
Select S1
Run S2
D-pad Up/Down/Left/Right DU/DD/DL/DR

I/II mapping

PCE button I maps to B2 and II to B1, matching the PCEngine output interface (pcengine_device.c) so a pad read here and sent back out to a real PCEngine round-trips identically.

6-Button Support

The 6-button Avenue Pad 6 exposes III-VI in an extended bank read after a CLR pulse. The driver reads it best-effort, gated by an all-zero signature nibble so a 2-button pad can never be misread (PCE_ENABLE_6BUTTON, default on). The CLR-pulse bank-advance model is derived from the PCEngine device emulation and has not yet been validated against real 6-button hardware.

Analog Axes

PCEngine controllers are purely digital. All analog axes remain at center (128).

Connection Detection

The data lines use internal pull-downs. A connected pad's 74157 mux actively drives released buttons HIGH (push-pull), while an empty port floats to all-zero -- so any high bit means a pad is present (you cannot hold all four directions plus all four buttons at once). This is what makes presence detection possible; with pull-ups, an idle pad and an empty port are indistinguishable (both read all-high).

  • Connect / Disconnect: 300ms debounced (PCE_DEBOUNCE_US)
  • On disconnect, the player slot is released so the status LED returns to idle
  • Input is only submitted while a pad is present (an empty pull-down read of all-zero must not be treated as "all buttons pressed")

Push-pull assumption

Presence detection assumes the pad's data outputs are push-pull (the standard 74HC157 is). A hypothetical open-drain pad would read as never-connected.

Feedback

No rumble or LED feedback (PCEngine controllers have none).

Configuration

Default GPIO pins (overridable per-app in app.h):

Pin Default GPIO Function
PCE_PIN_SEL 5 SEL output to controller
PCE_PIN_CLR 6 CLR output to controller
PCE_PIN_D0 8 D0-D3 inputs (8, 9, 10, 11; pull-downs enabled)

PCEngine Controller Port (8-pin mini-DIN)

Pin Signal Description
1 VCC Power (use 3.3V -- see warning)
2 D0 Up / I
3 D1 Right / II
4 D2 Down / Select
5 D3 Left / Run
6 SEL Select line (input to controller)
7 CLR Clear/enable line (input to controller)
8 GND Ground

Power at 3.3V, not 5V

RP2040 GPIOs are not 5V-tolerant. Power the pad from the board's 3.3V output so the data lines idle at 3.3V. Powering at 5V requires level-shifting D0-D3.

Verify connector numbering

Mini-DIN pin numbering varies between sources. Buzz out pin 1 (VCC) and pin 8 (GND) with a multimeter before powering on. SEL/CLR and D0-D3 ordering are also remappable in app.h if they come up swapped or scrambled.

Pico / Pico W Wiring

GPIO numbers are identical on both boards (same physical layout).

PCE Pin Signal GPIO Physical Pin
1 VCC -- 36 (3V3 OUT)
2 D0 (Up / I) GP8 11
3 D1 (Right / II) GP9 12
4 D2 (Down / Select) GP10 14
5 D3 (Left / Run) GP11 15
6 SEL GP5 7
7 CLR GP6 9
8 GND -- 8 (or any GND pin)

KB2040 Wiring

PCE Pin Signal KB2040 GPIO
1 VCC (3.3V) 3V3
2 D0 (Up / I) GP8
3 D1 (Right / II) GP9
4 D2 (Down / Select) GP10
5 D3 (Left / Run) GP11
6 SEL GP5
7 CLR GP6
8 GND GND

D0-D3 have internal pull-downs enabled in firmware. No external resistors are required.

  • Device address range: 0xF0+ (port 0 = 0xF0)
  • Max ports: 1
  • Transport type: INPUT_TRANSPORT_NATIVE
  • Input source: INPUT_SOURCE_NATIVE_PCE
  • Layout: LAYOUT_UNKNOWN

Apps Using This Input

  • pce2usb -- PCEngine controller to USB HID