NES Controller over serial: (USB)


Dealing with data:
In my adventures for making new electronic devices, I always pondered what kind of projects I could make if I could ever deal with digital data: an idea which has kept me dumbfounded for the last few years. It wasn't until I got a better understanding of how memory works that I began exploring reading and writing data for myself.

In CSE115 class, we focus a lot on the memory map of what's going on at a lower level when we write programs. This has helped a lot when figuring out just exactly what's stored in these sources. However, one idea which I never understood was, how serial and parallel data sources were read. For this example, I thought of learning to program EPROM and make my own NES carts, but I don't have a burner. I also thought of making my own LED matrix or POV device, but I didn't have any shift registers, or for that matter, that many LED's. Instead, I looked through some old junk, and found a half ripped apart NES controller, and took a look at the chip inside.

The IC in the NES controller is a 4021 Parallel In, Serial Out, what I'll call a “Data Controller”. In this case, the parallel inputs coming into the IC are each of the buttons, and the serial 8 bit data coming into the system. 8 bit data had me confused for a while, but once I thought about it, there are really 8 buttons on the controller, which would either be triggered as HIGH or LOW to show if the button was unpressed or pressed. But what confused me a lot was, how exactly can we just look at a pulse coming in and say that “This pulse means the A button is pressed, and this one says that B is pressed”. In order for this to occur, we need to divide the incoming data pulse into 8 units. This is simple, but how can a computer recognize that one high pulse isn't the first button or the 27th button? For this to occur, we need a way of telling the computer “This pulse is the first of the 8 bits, and the next 7 will be coming” And, the way this is done, is by utilizing the “LATCH” line, along with the “CLOCK” line. In this case, the LATCH line would represent the first bit, and then the next 7 pulses would occur on the CLOCK line, producing an output on the DATA line. In the case of the NES, a LOW pulse on the DATA actually indicates that a button had been pressed.Moo2

(Above: Logic inverter placed on the DATA line makes a button press create a logic HIGH.)

So, what all of this means is that if I send a clock pulse to the NES controller, I can get serial data out from it which can then be used to show which button is pressed. In practicality, First, I assigned an LED to each button, to make sure that it worked. But this idea didn't sit well with me. After all, with just this setup alone, all I'd be doing was splitting the incoming serial button pulses back out in parallel data, thus basically making the NES controller convert to serial and then back to parallel for no reason whatsoever. So, we need a new way of reporting the results of the data.

Another idea was to make an 8 segment LED display show letters representing the buttons of the controller that were being pressed, but I decided not to do this. This setup was very similar to the 1 LED per button situation. But the whole idea was to interface the NES controller to something practical, so I decided that I would rather just send data over USB to the computer, and then maybe write a program to state what buttons were being pressed.LED

(Above: Wiring diagram I made for the segmented display.)


(Above: Segmented display wired in.)


(Above: 8 Segment display setup. This was made prior to implementing the Inverter. In the picture, the A button was being pressed.)

In order to start sending data over USB, I needed to first get data into the computer. We know that every 12us, the data line will either by HIGH or LOW. This is convienient when determining the Baudrate of the system, or “Data pulses per second” on the USB line. In this case, a pulse of HIGH or LOW every 12us would mean a 83_333 baudrate. This seems way too high for me. So, I decided that I needed to send data in packets, once every 96us, which gives us a much better baudrate of 10_417.

Now I needed a way to start sending data in 'packets', rather than at each 12us interval. First, I wrote a small program that checked if the DATA line went high at a certain point, and then turned on a specific LED if that were the case. This showed that I can at least get something to occur at each button press without effecting the functionality of the controller. Now, instead of toggling LED's to go HIGH when the DATA pulses were read, I decided to create an array that would hold a 1 or 0 for the 8 buttons, indicating if the button were pressed or not. Then, at the end of the loop, I checked if that element in the array was 1 or 0, and reported the results by displaying a character on a TV, using Parallax's TV documentation.


(Above: The TV displays a character update once every 96 microseconds. This is why when you press a button for what seems to be a very short time, the TV still prints out several of that character. This also shows that the array checking method works without interrupting the normal cycle of the controller.)

Next up was implementing a serial port transfer of data to the PC, rather than to a tv. So, I used the "Simple_Serial" object provided on the Parallax website, and I wrote the spin document to transmit a character (a,b,s,t,u,d,l,r) over serial to the PC, by using the serialport.tx("a") and so on. Using a serial debug terminal on the PC, I was albe to watch it work, just as it did on the TV earlier, only this time, the characters displayed would allow me to do something with them.

After that, I decided that I needed to write some sort of program to handle the Serial data. I was told that C# already makes it very simple for me to access the serial port (and boy, it does), so I went with that. Basically, what I did, was add an actionlistener to the serial port to tell me when a new character was found. Then, I simulated a keyboard key press by saying something like "SendKeys.Send(serialPort1.ReadExisting());" Which in my case, since all the data inputs were characters recognized by the keyboard, the serialKeys doesn't need any extra coding to decode what the serialport is reading in.

So, after all this work, I made a small circuit that sent pulses to an NES controller. I tested it in several ways, and got the buttons to do different actions. Eventually, I harnessed the data being sent out of the NES controller and routed it into the PC, and in turn, represented button presses on the controller as key presses on a windows keyboard. 

It's not great for gaming (because of Sendkeys), but we can write programs to make it do just about anything!