Copyright © 2007 Mark Feldman. All Rights Reserved.
GameCube Controller Protocol
The gamecube controller pinout is as follows (courtesy of the Nintendo Gamecube Controller Protocol page):
|1||Yellow||2||5V power supply (used by rumble motor).|
|2||Red||3||DATA line: bi-directional data to/from console, pull-up to 3.43V|
|4||White||5||Ground (Skillz interface has pins 3+4 wired as common ground).|
|5||-||-||Unknown: not connected by official controller, or Skillz interface.|
|6||Blue||1||3.43V logic supply.|
|7||Black||6||Cable shielding / ground. Usually common ground with pin 3.|
The +5V line is ordinarily used for rumble motors; as it turns out, the wireless receiver chip used in this project also requires +5V in order to operate reliably.
The data line is a bidirectional line used to both send and receive commands to and from the console. The line is normally held high by a pull-up resistor inside the console; open-collector outputs are used to pull the line low when either the console or controller sent a bit. A "bit" lasts exactly 4uS. To transmit a 0, the line is pulled low for 1uS and then allowed to go high again for 3uS. To transmit a 1 the line is pulled low for 3uS and allowed to go high for 1uS.
When the console sends a command it starts by pulling the data line low, this generates an interrupt and control is transferred to address 0004h. The interrupt handler at that address then sits in a loop polling the incoming bits. If a given low pulse doesn't arrive on time then a time-out is assumed and the routine examines the packet it received and responds accordingly.
A 00h command from the console is used to initiate communication with a controller and request its ID and status word. The receiver responds to this with the sequence 090000. The first two bytes are the ID for a standard GameCube controller. I haven't been able to find much information about the status word, other than it appears to indicate whether or not rumble is supported. The following image shows how the 00h command appears on a scope:
A 41h command is used to request the origin points of each buttons and joystick axis on the controller. Calibration is easy with this device, since everything is digital. The receiver responds with the fixed sequence 00h 80h 80h 80h 80h 80h 00h 00h 02h 02h. The Gamecube to N64 converter project contains information on the individual fields inside this packet.
A 4003XXh command is used to request button and joystick data (the XX is normally 0, but can be different when rumble commands are being sent). A fixed packet is maintained in memory containing the data to be sent to the console which the main loop is continuously updating (remember that communication with the console is done entirely inside the interrupt handler). This packet is sent to the console in response to this command. The Gamecube to N64 converter project page again contains information on the individual fields, alternatively you can check the receiver source code. The following (rather poor) image shows the data pin during a 4003XX command as it appears on a scope. There is a short pause immediately after the command followed by the 10-byte response sent by the receiver containing the button states:
The receiver circuit is quite straightforward and is powered directly by the console. The PIC is responsible for receiving and interpreting wireless packets, responding to commands sent by the console and setting the LED to reflect wireless connection state.
The 3.43V power line on the controller plug powers the PIC while the 5V line powers the receiver (the receiver doesn't work very reliably at 3.43V). The resistors form a voltage divider that lowers the data output from the receiver chip from 5V to just under 3.4V. The two LEDs shown are in fact a single bicolor red/green LED; the PIC sets the appropriate color to indicate whether or not a valid wireless signal is currently being received. RB0 and open-collector RA4 are both connected to the data line; the former reads incoming packets from the console while the latter sends data back.
The receiver circuit firmware is somewhat more complex than the transmitter firmware. While the transmitter is in complete control of the timing of its operations, the receiver is continuously responding to two separate events, neither of which it can accurately predict: the receipt of button state packets from the wireless receiver and the receipt of command packets from the console.
Button state packets from the receiver are a relatively low-frequency event. Each packet lasts exactly 3.5mS and is broken down into 14 bits, each of which lasts 250uS. Packets from the console, on the other hand, are sent at a much faster rate of 4uS per bit. The instruction execution rate of a microcontroller is a quarter of the clock rate, so a 20MHz PIC can execute 5 million instructions a second, or 20 instructions in the 4uS it takes to receive a bit from the console. These 20 cycles must maintain perfect synchronization with the bit stream while also storing the data received and checking for time-outs and overflows.
The PIC I've chosen to use in the receiver is the same as that used in the transmitter, i.e. the Microchip 16F84A, although in this circuit the chip is run at 20MHz. As with the transmitter, there are several smaller PICs that would do the job just as well, but the 16F84A's wide availability and popularity among hobbyists should make this project accessible to more people.
The A4 and B0 pins are used to communicate with the console and connected directly to the data pin of the GameCube controller port; A4 is open collector output and can thus be used to safely send data while B0 supports interrupt-on-falling-edge for detecting when packets arrive.
The following image is a very slow scope trace of the data port during game play for a particular GameCube title. Each "blip" on the upper trace represents a pair of commands sent by the console (namely 4003XXh and 41h) along with the appropriate response from the receiver; these are sent approximately 50 times a second. The lower trace is a test signal generated by the microcontroller on PORT B pin 4, it is made to go high whenever the receiver is reading a packet from the wireless chip. Wireless packets last 3.5mS and are separated by 3.5mS of 0s, hence the 50% duty cycle observed in the lower pulse. As mentioned in the transmitter article, packets are sent at rate of roughly 142 per second, or almost 3 times faster than this particular title polls the controller. The console has CPU priority when it sends a command, so any wireless packets that clash with a console command are ignored. What isn't as obvious in the image below is that the test signal cuts out immediately after a console packet is received, as the CPU knows to ignore the rest of the packet. Since packets are being sent at a rate of 142 times a second, losing every second or third packet doesn't noticeably affect the response time of the controller.
Back to the main page...