We’ve seen NES, SNES, Sega, and just about every weird controller Atari put out connected to microcontrollers, but connecting the N64 controller to a project has remained one of those seldom-seen, rarely copied endeavors, not often tackled by makers around the globe. [Pieter-Jan] decided to throw his hat in the ring and give reading an N64 controller with a PIC a try, and we’re pleased to report he’s been completely successful.
One of the difficulties of reading an N64 controller is simply the speeds involved; with only three pins on the controller port, the N64 controller uses a serial protocol to send 32 bits of controller data at a fairly fast rate. Armed with a PIC18F ‘micro, [Pieter] realized that programming in C would be too slow, he needed to go all the way down to the bare metal and program his micro in assembly.
Every time the N64 controller data needs to be read, the console sends out a 9-bit polling request. The controller responds in turn with a 32-bit sequence informing the console of the status of all the buttons and joysticks. Once [Pieter] got his micro sending the correct polling response, it was only an issue of parsing the data returned from the controller.
Right now, [Pieter] has a small demo board rigged up that flashes a LED whenever the A, B, or Z buttons are pressed. This can be expanded to the remaining buttons and joystick, but for now we’ll just enjoy [Pieter]’s demo after the break.
29 thoughts on “Reading An N64 Controller With A Microcontroller”
I wonder if this is the reason that Killer Instinct Gold has always felt like the most responsive fighting game to me…
I always thought it was the KI software, but it may just have been the N64 hardware all along!
Why do you say that? Are some video game console controllers laggy or what? Why would they be?
Current generation wireless ones are actually pretty horrible. Bluetooth as a standard even has some serious overheads with latency.
PIC? seriously? Why would anyone want to deal with that movlw – movwf craf in 2012?
I have seen this done elsewhere on the web with a pic, the pic then connected via USB to a computer exposing itself as a HID.
Very interesting regardless
Why limit yourself as far as clock speed to the point where you can’t write in C anymore? Just put in a faster crystal. There are 48mhz versions of those USB 18f chips. There are also C routines for fast interrupts and stuff like that. It’s not like you have to deal with an undeterministic scheduler or something. If you are just spinning in a loop somewhere it’s not wasting many cycles having been written in C.
Or just get a faster chip. There are enough hard things you don’t’ have control over. Use the best tools for the job.
I worked out at one point that to do the n64 controller side without assembly would require a 200MHz micro. For the host side I think you’d possibly be able to do it with 48MHz but that would require turning a host of space optimisations off. Assembly isn’t that hard, it’s better for high speed bit banging and writing the routines in c would require examination of the disassembly.
This is perhaps one of the two applications you’ll ever want to use assembly.
Scratch that, you can definitely do the host with a 48MHz in c. It’s still more accurate timing wise to do assembler but c would obviously be easier to program.
no. You dont need to sample at crazy speeds, just setup some counters, calculate time spend hi and low and compare do get bit values.
Damn.. Didn’t mean to send that yet… I meant to add…
Other than that… Good job!
“Armed with a PIC18F ‘micro, [Pieter] realized that programming in C would be too slow, he needed to go all the way down to the bare metal and program his micro in assembly.”
That’s simply not true.
As I explained in the article I wanted to limit myself to a clock speed of 20Mhz so that I could maintain compability with my other projects. The resolution of the signal to be read is 1 uS. With a PIC this means that there are only 5 instruction cycles. (On an ATmega this is a whole other story – you have 20 instruction cycles there) so that is not enough to use C.
Switching to other architectures and other clock speeds would make C possible but that was not the challenge I put out for myself.
jajajaja just a few months ago I was looking for this same topic XD
Excellent write-up on the project. I actually did this using a PIC24 and C/assembly. It was quite a challenge since I didn’t have access to an oscilloscope and was relying on MPlab simulator for the timing information. It would be very difficult to do anything like this only using C
We’re pleased to report he’s been completely successful.
This can be expanded to the remaining buttons and joystick…. but hasn’t been done yet?
As in, he hasn’t made a demonstration showing all the buttons hooked to LEDs. He’s getting the whole protocol.
Seriously?! A simple, humble ATmega 8 can handle parsing the protocol and emulating a hid device and a pic cant even handle parsing the protocol in c? wow! Link to project –>
There is a guy that’s done this already on an atmega, that translates to a gamecube output. He also has one that goes to USB, here’s the link to the GameCube open source solution. (I’ve built a couple, they work great)
I’ve been trying this on the Raspberry Pi without any supporting circuitry and can’t get a reliable input. I can send poll requests to the controller just fine, but it takes about 2 seconds to get a response that I’m confident in (32 bits) which just won’t do. Of course this is because I’m running Raspbian and coding it in C, but I’m much too busy to get it down further.
I think there is code out there to do this with the parallax propeller. Kudos non the less :]
I think a cooler solution would repurpose an existing shifter in the MCU to do the work for you. For example you could use an MSP430 USI in SPI mode for the output quite trivially (4 bits per bit in fixed patterns). For the receive you could do clock syncronisation and just sample at the mid-point of each period giving you 1 bit per bit input.
If you used the G2121 for example and connected P1.6+P1.7 together to the data line you would output on 1.7 and then swap it to a timer input to track the clock synchronisation.
If you ran TimerA in up mode with TimerA0 set to half the expected period and the output set to toggle on reset you could use it to clock USI. If TimerA1 is set to capture mode (falling edge) then the value captured in A1 is twice synchronisation error of TimerA0 allowing you to track the clock of the controller.
This only requires you to run at 1Mhz for transmit and maybe for receive (the timers can run at double the clock rate, giving 4 counts per half period) if you don’t need correction. Running the receive with correction you’d need at least 4+2+4+1+4=15 CPU cycles per half period so 8Mhz to correct every cycle.
+1. Had just finished reading the linked article and was getting ready to post the same output technique, but you beat me to it. :)
There’s probably several ways input could be managed. SPI might be able to do it, if after sending the poll request you immediately drop the clock rate by a factor of four so it samples in the middle of each period, then send 4x bytes containing zero. Or use the Input Capture peripheral to measure the time of each on/off interval.
At any rate, bitbanging is not the only way to accomplish this, nor is assembly required.
I don’t have any familiarity with PIC but reading an app note on the Input Capture the FIFO in particular makes it attractive (I love getting peripherals to do as much work without MCU intervention as possible). You could capture just the rising edges and toggle high on a short interval and low on a long interval and preserve the existing value otherwise. You’d just need to measure the first low interval to get the starting value.
Honestly can’t understand why anyone would willingly choose to use an N64 pad…
It might be worth noting that GameCube pads use pretty much the same communication methods with like one extra byte for the C stick’s analog data IIRC.
It’s my favorite controller to use. If you are a N64 controller fan there’s just something about the feel of the controller and the familiar feel is important.
The gamecube controller is one of the worst controllers ever made.
I’ve never used an n64 (honest) but gamecube controllers were shockingly bad. I don’t think ot was the controller itself so much but the quality of them, the thumb sticks almost seemed digital, buttons were noisey and rattled in their places and it wasn’t the most comfortable. Although I still have my gamecube and controllers I instead use a wired Xbox 360 pad on the dolphin emulator, much better experience. Build quality has room for improvement but is far superior to that of the GC pad and its analogue sticks are analogue… My games have been improved substantially…
Now, if someone built a good controller for the GC in the first place….
@Pieter Thank you! for tackling this! I will be using your data on a project I have been wanting to start for a while now!
Dont. He used suboptimal method. If you really really want n64 controller look at Atmega V-usb adapters.
Please be kind and respectful to help make the comments section excellent. (Comment Policy)