Open-source project
dekuNukem/Nintendo_Switch_Reverse_Engineering avatar
dekuNukem/Nintendo_Switch_Reverse_Engineering

Nintendo_Switch_Reverse_Engineering: the Joy-Con, measured on a logic analyzer

A look at inner workings of Joycon and Nintendo Switch

3,784 stars208 forksCLicense varies

At a glance

What is it?
A C repository of Joy-Con findings: the 10-pin connector pinout, SPI traffic to the flash chip and IMU, the keypad button matrix that makes input spoofing hard, and the reader and spoofer tools built on top.
Who is it for?
The value here is measured numbers rather than tooling. Pin assignments, the two SPI clock rates, the IMU configuration and the UART dump command are all specific enough to reproduce, and the raw captures are committed alongside the conclusions.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 46 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A repository of notes first, tools second

The opening line of the README sets the scope honestly: discoveries are dumped here in the hope they are useful to the Switch community. That framing matters, because the repository is mostly markdown notes with three small C directories behind them. The tree shows the split plainly.

text
logic_captures/
datasheets/
joycon_reader/
joycon_spoofer/
packet_parse/
imu_sensor_notes.md
spi_flash_notes.md
rumble_data_table.md

`logic_captures/` holds the `.logicdata` files the conclusions were drawn from, which is unusual and useful: a reader can load the capture rather than trust the interpretation. `packet_parse/` is the packet work, and the topic files split it up, with separate notes for the IMU, SPI flash, rumble data, USB HID and Bluetooth HID subcommands. `joycon_pcb.pdf` is the board layout with pinouts for both the left and right Joy-Con.

The author is explicit that the work belongs to more people than the commit log suggests, and points readers at the contributors graph as well as the issue tracker for questions. With 92 open issues, the tracker is where the conversation happens.

The 10-pin connector and why Jdet decides cable from Bluetooth

When a Joy-Con is docked it stops using Bluetooth and talks over a physical connection, so the first thing the author did was name the pins and work out what each one does. The method is worth noting: the rumble motor was removed, a hole was cut in the back cover, and the wires routed out to a logic analyzer.

code
|            0           |           3          |              Jdet             | HIGH when connected to console via Bluetooth. Joy-Con will not send serial data post-handshake unless pin is pulled LOW by console. |
|            2           |           5          | Serial data console to Joycon |                                             Inverted level (idle at GND)                                                            |
|            3           |           6          |              JRST             |                                      Joy-Con reset signal , high level is reset                                                     |

The table maps logic analyzer channels to connector pins and gives the function and a remark for each. Pin 1, 2 and 7 are ground. Pin 4 is 5V for power and charging. Pins 5 and 8 are the serial data pair, and they are not symmetric: console to Joy-Con is inverted level idling at ground, Joy-Con to console is standard level idling at 1.8V. Pin 9 is power output, which the README says the Joy-Con uses for Ring Fit Adventure and the starlink toy.

Pin 3 is the interesting one. Jdet reads HIGH when the connection is Bluetooth, and the Joy-Con refuses to send serial data after the handshake unless the console pulls that pin LOW. That single line is how the two transports are distinguished, and it is the line a spoofer or a dock emulator has to handle correctly.

The whole board runs at 1.8V, which explains the level choices above and matters for anyone attaching a 3.3V logic analyzer directly.

A keypad matrix instead of the usual button wiring

The most quotable finding in the README is about buttons rather than silicon. Nintendo did not use the traditional arrangement where one side of a switch is pulled up and the other side goes to ground. Instead the buttons sit in a keypad configuration of rows and columns, read by the keypad scanner built into the BCM20734 running at a 128KHz clock.

The consequence, as the author puts it, is that it would be extremely hard to spoof button presses for TAS recordings and Twitch Plays style play. The scanning hardware expects a matrix transition rather than a single line changing state, so a device that fakes one button by pulling a wire low does not look like a button press to the controller.

One exception is documented: the joystick button, which is still activated by pulling it down to ground. The author also notes the absence of silkscreen markings for components and test points, and speculates Nintendo may have been trying to discourage people from poking at the Joy-Con.

Whether the Pro Controller uses the same arrangement is left open in the README, with the reason given plainly: the Pro controller has not been taken apart yet. It is the kind of gap a reader with the hardware can close.

Two SPI devices at two different clock rates

The SPI bus carries exactly two peripherals: a 4Mb MX25U4033E flash memory and an LSM6DS3 six-axis MEMS accelerometer and gyroscope. The author captured the lines from battery connect through dock attach, and read a clock behaviour out of it: SCK runs at 12.5MHz when the flash is being accessed and drops to 6.25MHz for the MEMS chip.

The IMU settings are given as a table, which is the kind of detail that saves someone else a week of work.

code
| Accelerometer               | Gyroscope                      |
|-----------------------------|--------------------------------|
| ODR 1.66KHz, full-scale ±8g | ODR 208Hz, full-scale 2000dps  |

Beyond the output data rates and full-scale ranges, the accelerometer runs an anti-aliasing filter at 100Hz bandwidth with the low-pass filter enabled and a slope filter enabled at a 416Hz cut-off. On connection the microcontroller performs a software reset of the MEMS chip before configuring it.

The polling numbers then get interesting. The Joy-Con polls the LSM6DS3 every 1.35ms, which is 740Hz, for both accelerometer and gyroscope across all axes, twelve bytes in total since each of six axes is two bytes. Controller updates go out only every 15ms. The author flags the mismatch as an open question, wondering whether some internal averaging smooths the data between polls, and says the numbers would need working through to confirm it.

Dumping Joy-Con SPI flash over UART after pairing

The flash chip holds the data you would want when cloning or reconfiguring a controller, and the README documents a way to read it. It can be dumped post-pairing over UART with a fixed command byte sequence, where a 32-bit little-endian address and a length byte are filled in and the response carries the data at offset 0x20.

text
19 01 03 38 00 92 00 31 00 00 d4 e6 01 0c 00 01 40 40 00 01 40 40 10 XX XX XX XX YY 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

The length byte YY caps the dump at 0x1c bytes per read, so reading a whole flash means repeating the command across address ranges rather than one long transfer. The README also carries a capture of the SPI lines during power-up, with all the addresses and data the Joy-Con reads, and the author notes they have not worked through it themselves, inviting others to.

What lives on that flash is documented too: Joy-Con colour, serial and calibration settings are all stored there and reached through the same query. That is the practical reason to care about the command, since it is the path to colour and calibration data rather than just firmware bytes.

What the tooling does and what it leaves undone

Beyond the notes, three C directories carry the working code. `joycon_reader/` is the side that talks to a controller and reads its state, `joycon_spoofer/` is the side that presents itself as one, and `packet_parse/` is the shared packet handling. `push.sh` at the tree root is the build or push helper for that code, and GitHub reports the repository's language as C.

The split between reader and spoofer is worth noting because the README's own findings describe why the second one is hard. A button matrix read by dedicated scanner hardware resists a naive spoofer, and the Jdet handshake has to be reproduced before the console will accept serial traffic. Anyone picking this up is starting from a documented set of obstacles rather than a blank page.

The parts the repository does not cover are the console side. There is nothing here about the Switch's own SoC, its security fuses, or the boot chain, and nothing about custom firmware. This is peripheral-level work, which also means the legal surface is narrower than general console hacking, though that is a question for your own judgement rather than something the repository addresses.

There are no releases and no tags. The last push was on 2026-08-21, so the notes are current, and the loose markdown structure means a new finding is a commit to a file rather than a version bump.

Editorial conclusion

The value here is measured numbers rather than tooling. Pin assignments, the two SPI clock rates, the IMU configuration and the UART dump command are all specific enough to reproduce, and the raw captures are committed alongside the conclusions. What the repository is not is a product: the code lives in `joycon_reader/` and `joycon_spoofer/`, there are no releases, and the last push was on 2026-08-21. If you want to read one thing, read the connector pinout table, because the Jdet and JRST lines explain how the dock handshake works and how a Joy-Con decides whether it is talking over cable or Bluetooth.

Frequently asked questions

What does the joycon_reader and joycon_spoofer code do?

The repository splits its C code three ways: joycon_reader/ talks to a Joy-Con and reads its state, joycon_spoofer/ presents itself as a Joy-Con to a console, and packet_parse/ handles the packets both use. The README documents the protocol details those tools rely on, including the 10-pin connector pinout and the UART command for reading SPI flash after pairing.

Why is spoofing Joy-Con button presses difficult?

Because Nintendo wired the buttons as a keypad matrix of rows and columns, read by the keypad scanner inside the BCM20734 at 128KHz, rather than with the usual pulled-up-to-ground arrangement. A device that fakes a press by pulling a single line low does not look like a matrix transition to the scanner. The joystick button is the one documented exception.

What is stored in the Joy-Con SPI flash?

Joy-Con colour, serial and calibration settings are stored on the MX25U4033E flash and reached through the same UART query used to dump flash contents. The README gives the command bytes for a post-pairing dump, with a 32-bit little-endian address, a length byte capped at 0x1c, and the returned data at offset 0x20 in the response.

Official sources

  1. dekuNukem/Nintendo_Switch_Reverse_Engineering on GitHub
  2. Issues
  3. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/dekunukem-nintendo-switch-reverse-engineering.svg)](https://hysenlabs.com/projects/dekunukem-nintendo-switch-reverse-engineering)