These are the results of my attempt to reverse-engineer the Gamecube controller protocol.
Gamecube Controller Reversing Data
You can also download CSVs of the scope captures:
The Gamecube controller protocol is most famously explored here. The info there is useful, but not useful enough to build and test custom Gamecube hardware without doing some reversing of my own. All the scope captures I took are availabe for testing your own hardware; simply load the CSVs into an arbitrary waveform generator to produce your own Gamecube signals, no Gamecube required!
A recap of what we already know:
Some info on the scope captures:
Initial Polling: This is the sequence sent by the Gamecube when no controller is connected. You can see from the first image that The Gamecube polls for the controller every 16.7ms The second image is zoomed in on the polling sequence. The signal represents a byte of all 0s. Notice that the gamecube terminates the byte with a stop-bit (1), much like many other serial protocols. At each bit, you can see that we have a falling edge followed by 75% low and 25% high, indicating a 0. You can also see that the period for each bit is 5us. The controller uses a slightly faster 4us period instead of the 5us period sent by the Gamecube, as we'll see later.
Negotiation: This is the sequence of bits exchanged when the controller is first plugged in, before a game has been started. In the macro view, the first two thin lines are the polling sequence we discussed earlier, the first thick line constitutes the negotiation beween the controller and Gamecube, and the following thick lines are normal Gamecube request/controller response packets. The gamecube requests the controller state in two-packet bursts, but this pattern changes when a game is running. You can tell when the Gamecube is transmitting, becuase its open-drain circuit pulls the line all the way down to 0v, while the controller's open drain only pulls down to 1v or so. This might be a function of my breakout circuit that I used to capture these signals.
Not much else is known about this part of the controller. It doesn't seem to contain calibration information, and I only have 1 official Gamecube/controller pair to test with, so there's no way for me to check if different hardware presents different data. The negotiation while game running tab shows what the negatiation looks like when we plug in a controller while Super Smash Brothers Melee is running.
Packets: This is the packet where the Gamecube requests data from the controller, and has already been documented at the link I provided above. In both cases, the Gamecube sends a 24-bit command: 01000...1. When the game is running, two extra bits are sent high which you can see in the packet while game running tab. Following the command word, the controller responds with 64 bits of controller data, who's format is also documented at the link above. The image labeled "With Infinite Persist" shows all the bits that I can flip by manipulating the controller. As you can see, the first couple bits of the controller response don't seem to contain button data.
With the game running, I measured a period of 8.36ms between command words sent from the Gamecube. This is pretty different from the two-packet bursts from when the game is not running, so the game might have some control over when it polls for controller information. All in all, when designing 3rd-party Gamecube hardware, be tolerant of many different polling intervals.
Individual Bits: This is a zoom on the individual bits driven from the Gamecube and controller. You can see that the Gamecube bit is 5us, while the controller's reponse bit is 4us. Again, tolerance of a variety of timings is important for interoperability here. This image also shows the Gamecube line-code well: the 1 bit is mostly high while the 0 bit is mostly low, and both are initiated by a falling edge.
When Super Smash Brothers Melee is running, the last 16 bits of the controller response contain the L and R button positions, each as an 8-bit number from 20-ish to near 240-ish. However, when a game is not running, both buttons are 4-bit numbers in the penultimate byte, while the last byte of the response is all 0s (excluding the final stop bit). This is another area where it seems that the game can dictate the data format used by the controller.
The command word sent to the controller to request data doesn't seem to do much, with the exception of the last bit which will trigger the rumble motor when set high. I can't find an explanation for the two-bit difference between the in-game and non-game command words.