The NES Advantage shipped in 1987 with a hardwired cable and a nine-pin plug. It is a good stick, and there is nothing modern to plug it into. I wanted mine working on a Switch and on a real NES without giving up anything the original did.
Rules I set before starting:
- No cutting the case and no new holes.
- No added buttons. Everything comes off controls the stick already has.
- Turbo, slow motion, and the player-select slider keep working the way they did in 1987.
- Charge through the hole the cable came out of.
The board
One 2-layer PCB, 78 x 36 mm, replaces the cable and drops into the stock case. A bare ESP32-WROOM-32E reads the stick's original CD4021 shift registers, the same parts the controller has always used to serialize its buttons, and presents the result over Bluetooth. 39 placed parts, all hand-solderable, though the two QFN-style regulators are easier with hot air.
Power is a TP4056 linear charger for the 1S LiPo cell and a TPS63900 buck-boost for the 3.3 V rail, with a load-share path built from a P-channel MOSFET and a Schottky diode so the stick plays while it charges. The TPS63900 idles at 75 nA, which is what makes the standby figure below possible. Battery sense goes through a divider whose ground leg is switched by a small N-FET, so it draws nothing when no one is reading it.
Two transports, one radio
Switch mode (Bluetooth Classic)
A clean-room Switch Pro Controller emulation. It pairs directly from Change Grip/Order on a Switch 1 or a Switch 2 with no adapter in between, and it pairs with an 8BitDo NES Retro Receiver, which is how the stick gets back onto a real NES.
BLE mode
A standard BLE HID gamepad. Windows, Linux, SteamOS, Android, and BlueRetro all take it without drivers. The player-select slider does something new here: the stick shows up as two gamepads, so you flip the slider to hand off and map each gamepad to a player in your emulator. On a Switch the slider still picks which player you report as, since one Pro Controller is one player no matter what.
Hold Select and Start for five seconds to change transports. The RGB status LEDs say which one you are in.
Buttons the NES never had
The Switch expects buttons that 1987 hardware does not have. They live on Select-held chords, which fire instantly instead of needing a long hold, so they work mid-game:
| Hold Select, press | Sends |
| Start | Home |
| Up | ZL + ZR, which opens the menu in NSO retro games |
| Left | ZL |
| Right | ZR |
| Down | Capture, held to record a clip |
The chord has to start inside a short window, 200 ms out of the box. Hold Select past that and it settles into being an ordinary Minus you can keep held, which some games need. The window is adjustable from 100 to 500 ms, or you can set it to Hold for no limit at all, or switch chords off and get a plain Select back. In BLE mode they do not exist: a PC has no use for Home or Capture, and a holdable Select is worth more than either.
Numbers
- Added latency: about 4 ms in Switch mode, about 6 ms in BLE.
- Play time on a full 1800 mAh cell: about 17 hours in Switch mode, about 37 hours in BLE.
- Standby: months. It sleeps at microamps and wakes when you hold Start, so there is no power switch to forget about. Auto-sleep is 90 seconds with no host, or 5 minutes idle while connected.
Configuration in a browser
There is no app to install. Hold A, B, and Select for five seconds to put the stick in config mode, then open the hosted page in Chrome or Edge and connect over Web Bluetooth. Every button, the D-pad, the slider, and both turbo dials light up live as you use them, which turned out to be the fastest way to catch a dirty switch or a wire on the wrong pin while installing the mod. The same page sets transport, button profile, directional mode, and the chord window, and it flashes new firmware over the air. Dropping a firmware.bin on it is the whole update process. It checks the image before sending and writes only the inactive OTA slot, so settings and pairings survive the update.
What the Switch Pro protocol cost me
Reading the stick was the easy half. Convincing a console that the thing asking to pair is a Pro Controller was the rest of it.
- The Class of Device is a discovery gate on the Switch 2. Get it wrong and the inquiry from Change Grip/Order never pages you at all, so the stick is invisible and there is no error anywhere to debug. It also has to be set before the radio comes up. Set it afterwards and the call returns success while the radio keeps answering with the old value.
- Bluedroid fought me on that. ESP-IDF's Classic stack strips bits out of the Class of Device on its own, and its HID device path, sniff handling, and Secure Connections support each needed a build-time patch against its source. Five patches at the worst point. Moving the Classic side to BTstack, which ships a real HID device profile, deleted all five and about 80 KB of flash with them. BLE stayed on Bluedroid, so the firmware carries two host stacks and brings up one per boot.
- Power management belongs to the host. A real Pro Controller never initiates sniff mode, it only accepts what the console asks for. Doing it the other way around gives you dropped links that look exactly like a radio problem.
- A Switch 2 can wedge itself. Mine spent an evening refusing to pair with anything, commercial controllers included, and reported a firmware error while doing it. Power-cycling the console fixed it. I wrote that one down because I had already started rewriting code that was fine.
All of this is in docs/switch_pro_protocol.md in the repo, in more detail and with the register values, on the theory that it saves the next person a week.
Cajun Panda