This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Sending data to NES through controller port

Sending data to NES through controller port
by on (#132356)
Hey guys

Just wondering what you think of this. I haven't been able to find anything similar so let me know if someone has tried this before!

I've rigged up an arduino to send data to my NES through the controller port. So far I'm able to able to:

- send text from computer and have it display on screen like a text console
- send bytes representing frequencies to play simple melodies
- drag&drop an image into a program to make nes-friendly tiles then send them to the NES, overwriting the pattern table (CHR RAM), and then writing to the nametable to show the tiles on the screen as they were displayed in the computer program (*not perfect)


How it works:

I soldered a little port in the bottom of an nes controller with 1 wire for each button, plus 1 ground (9 pins) so that if you connect a wire from one of the 8 button wires to the 9th (ground), it is equivalent to what happens when you press a button.

I connected the controller to an arduino using darlington transistors which work sort of like relays so that when I change the state of a pin on the arduino I can open and close a circuit. You can't just hook the buttons up to an arduino output pin directly, you only want to allow electricity to go through (button pressed) or not (button not pressed) rather than sending electricity to the controller from the arduino. You want it so that you can tell the arduino to set an output pin to 1 (electricity going out the pin) and that is the signal for the darlington transistor to close the gap as if you had pressed a button. The darlington transistors were pretty cheap and easy to order.

I open and close a circuit for each button in the controller. Because there are 8 buttons which can be in a state of 0 (not pressed) and 1 (pressed), I can take an 8-bit value (0 to 255) and break it down into 8 bits and then "press" the controller buttons accordingly. The wiring does not interfere with pressing buttons on the actual controller - if the arduino is not manipulating the state of the buttons, the extra wires stay open, so the controller can be used normally when the arduino is not plugged in to it.

In the case of the text console, I have an nes program where the background tileset contains all the basic ASCII characters. Their index in the pattern table is their ascii code.

So say I have a tile at position 65 in the pattern table that looks like the letter A, and 65 is the ascii code for A. I send an "A" (65) to the arduino from a computer, it turns the 65 into 01000001. If you don't know how binary works you could say that each bit in that sequence is "worth" a certain amount. The amount each bit is worth goes in this order: 128,64,16,8,4,2,1. So we have one bit worth 64 and one bit worth 1 in the example of the letter A (65).

The button order is A, B, Select, Start, Up, Down, Left, Right.
So in this case the arduino will press/not press the buttons as follows:

A = not pressed (128)
B = PRESSED (64)
Select = not pressed (32)
Start = not pressed (16)
Up = not pressed (8)
Down = not pressed (4)
Left = not pressed (2)
Right = PRESSED (1)
....... and 64+1 = 65 = A

On the nes I have a program that reads the state of all the buttons and recreates the byte. In the case above, it would start out with a value of 0. Since B is pressed it would add 64, and since Right is pressed it would add 1. So it would end up with the value 65. It puts this value in the nametable and since position 65 in the pattern table contains a pattern that looks like the letter A, the letter A gets displayed on screen!


Parts

Arduino + 8 darlington transistors + 8 resistors + wires + soldering 8 points in controller
python program to communicate with arduino. python program sends text, music, or chr tile data.
processing (.org) program for drag&drop conversion of image to nes-friendly format, creates tile data that python script can send to arduino
nes program to interpret controller presses as bytes (on flash cart)


Problems

- A few bytes are reserved for control codes so when you send new CHR data for displaying images, there are certain values you can't send because they're reserved.

- The arduino and NES are not exactly in sync so sometimes the nes gets the wrong value if the arduino was in the middle of switching to a new byte when the NES read the state of the buttons. Probably about 1 out of every 300 bytes comes out wrong but I'm hoping to add a couple more wires so that the arduino can tell when the NES strobes the controller and switch to the next value perfectly between reads.

- This is the second thing I've ever tried to program on the NES and the first didn't come out too good. I could work around the control code problem with some better code but I'm completely new to 6502 asm and the nes.

- Trying to think of a way to send data out of the nes to the arduino for two-way communication


The Rest

Let me know if you've seen/done something like this before, I'd love some tips. I really don't know if this will even interest anyone. I'll post some pictures/videos/code if it does.

If you're familiar with the arduino, you can solder the wires in the controller, and you can pick up some darlington transistors you could probably have this up and running in about an hour. I'm not sure what you could use it for but if it was a bit more solid you could send pretty much anything you want from a computer to an NES.
Re: Sending data to NES through controller port
by on (#132357)
Does your microcontroller have an SPI slave port? The NES controller protocol is really just a variant of SPI. The console can send bits by putting a voltage on the strobe wire (STA $4016) and sending clock pulses to one of the devices (LDA $4017). The Super NES Mouse, for example, uses this to send commands to change the sensitivity.

What tool are you using to convert graphics to NES format?
Re: Sending data to NES through controller port
by on (#132365)
Hmm I think the arduino can work with SPI though I haven't done anything with it before. I'll have to look into that.

The tool I'm using is just something I wrote. It doesn't use any standard formats it just generates data that I can dump directly into the pattern table. Saves it in a text file for the python program to read and send it to the arduino, which sends it to the nes.
Re: Sending data to NES through controller port
by on (#132366)
Hi kids! Do you like Python?
I made a PNG to NES converter so you can get your draw on.
Wanna copy me and be a pixel artist?
Try your hardest to make the NES show all this?
Re: Sending data to NES through controller port
by on (#132369)
I've not made an interface exactly like that, but others, and myself, have built communication adapters using RS232 (w/ MAX232/MAX202) and USB (PL2303 or FT232) through the controller port. I've built a batch of these recently that will be used for an upcoming project. It's just bog-standard, old-as-the-hills RS232, and common USB adapters work in a compatible way by creating a "virtual COM port". With that interface, you only need 1 input and 1 output. The input to the NES is usually D0 (though D3,D4 are available if you have the right cable), and output from the NES the only option is OUT0 (AKA 'strobe').

So, to receive data you would read the input bit at D0 of $4017, if you use the 2nd port. And to write data, write to D0 of $4016 (doesn't matter which port you're using).

There are quite a bit of other threads on the forum, here's one:
http://forums.nesdev.com/viewtopic.php?t=7032&view=next

I remember another project that was kinda similar, in that it was synchronous:
http://nesdev.com/lptnes_v130.zip

Quote:
- A few bytes are reserved for control codes so when you send new CHR data for displaying images, there are certain values you can't send because they're reserved.

Yes, a common problem. The usual solution is to use "escape codes", say $FE is the escape code. To send command 0, send $FE $00 and so on. Send $FE $FE to send just plain old byte $FE. It's much like run-length-encoding, which has a lot of examples on NES.
Re: Sending data to NES through controller port
by on (#132374)
Ah so this has been done before. Sounds like a much better way of doing it too.

What kind of speed can you get with your method?

I've read through the link you posted, thanks. I'm not sure I could build such a thing from that information though.

Would you happen to have instructions on how to build the cable you're using?
Re: Sending data to NES through controller port
by on (#132377)
There's also this, which I built a cable for and it works great. (The Youtube video is missing however, sorry about that -- I merged my old Youtube and Gmail accounts and as such it didn't move a lot of my videos, so I had to reupload ones I had archived, which were only a few):

viewtopic.php?f=9&t=7520

I'm sure thefox will chime in here if/when he sees your thread. :-)
Re: Sending data to NES through controller port
by on (#132386)
Blargg has done some awesome work when it comes to sending data through the controller port. The software koitsu linked is my software called pc2nes which takes an iNES ROM and transfers it over the controller port to PowerPak. pc2nes uses blargg's nrpc library. nrpc is a C/C++ library that takes a set of commands as function calls (such as write to CPU memory, write to PPU memory, etc) and produces a file that can be transferred to a NES that is running a bootloader software. Bootloader is simply a tiny software that waits for a transfer from outside, then executes the transferred block. nrpc was never officially released though.

Upcoming is also nrpc 2, which adds synchronous serial so it can get transfer speeds upto 25 KB/sec. The asynchronous serial was limited to about 10 KB/sec. I have been testing nrpc 2 a little bit earlier this year.
Re: Sending data to NES through controller port
by on (#132402)
The darlington transistors are not really necessary. It is easier to just set the pin to output a logic 0 and then change its mode to OUTPUT to pull the line low, and change it to INPUT to put it in a high-z state (no button pressed). However, the transistors make the design a little easier to adapt.
Re: Sending data to NES through controller port
by on (#132407)
Ah, interesting.

I'm not a pro when it comes to the electronics side of things. A friend picked up some darlington transistors and when I saw how they work I thought of this project. Didn't realize it could be done without them or some form of relay. Though I see now there's definitely better ways to do it with ftdi/rs232/spi/whatnot. Must have been using the wrong search terms when I set out to find if anybody had done this before. A few of you, at least, have this all figured out.

I'm still not sure what the concensus is on the best way to do it, though.

Is there any thread that sort of sums up the various approaches and singles one out as the winner? Or is there a most-popular method that is the best supported by all the tools people have made? Seems like all the information on this is scattered between many threads.

I'm still reading through the threads and I'm at work at the moment so maybe there's a nice summary I haven't run into yet. I've already got an FTDI cable and a RS232-USB cable so hopefully when I get home I can get to the bottom of this.

Thanks for all the replies, by the way!
Re: Sending data to NES through controller port
by on (#132425)
I believe Blargg's bootloader is the best solution for compatibility:
http://slack.net/~ant/old/nes-code/bootloader/
http://slack.net/~ant/old/nes-code/serial/spec.html
http://slack.net/~ant/old/nes-code/serial/cable.html

What I like about it, is that it's basically a bootloader's bootloader. It could be compatible with any type of comms adapter, all it has to do is support 57600 baud async for the initial load. So for the end user, they would select a driver for the device they have. The bootloader then loads that driver into the NES's RAM, from there it could begin using SPI, parallel, other async options, anything.

It doesn't address compatibility between programs, that's something that remains to be worked out as more of these types of programs are developed. I'd say on the PC side that using a serial port (COM port in Windows, TTY in Linux) is pretty much universal. The end user just needs to select which port to use, the OS handles the rest. On the NES side, it pretty much comes down to having 2 subroutines, one to send a byte, and one to receive a byte. Receiving is the only place where differences could occur, I think it's best to return from it with (for example) a pass/fail condition in the carry flag, as opposed to polling forever. But maybe that would be a candidate for a third subroutine, I don't know. The bootloader pretty much makes it easy for the end user, since it's typically easier to load new software onto the PC compared to an NES cart.
Re: Sending data to NES through controller port
by on (#132660)
Woo, got it working! Both the bootloader thing and pc2nes.

pc2nes worked right away on my PC but the computer closest to my NES is a mac and under wine pc2nes bugged out so I had to compile pc2nes from source.

Initially it didn't work but I noticed it would do the first transfer properly and then bug out on the second, regardless of whether the second part was configured to go at 57600 or 115200 bps. I went back to the source and changed the delay between the two transfers to 500ms instead of 100ms, which is probably overkill, but now it works. Though only at 57600bps for some reason on the mac. On my pc 115200bps works no problem.

Instructions for anyone trying to get pc2nes-v01 working on osx (tested on mavericks) so you can drag&drop to send files to the NES through the second controller port:

1. Get a USB-RS232 cable, I used this one. This one uses a "Prolific PL-2303" chip, I'm not sure what everybody else is using but add this to the list of chips that work.

2. Build the RS232-TTL circuit from here. So far I have only built the one-way cable, the diagram on the left. Credit goes to Blargg for this one.

3. Download pc2nes-v01 from here. Credit to thefox for pc2nes-v01.

4. Extact the zip and follow the instructions in the readme file, put your mappers in the mappers folder and get it on your powerpak. Then go to the source folder. Open up Main.cpp. Change #define SEND_115200 from 1 to 0. Look for delay(100) and change it to delay(500). Save.

5. Download the boost library source from here.

6. Build the boost libs for your system. In a terminal, cd /path/to/boost_1_56_0/ and then run ./bootstrap.sh and then ./b2

7. Compile the pc2nes source. The first time you run this command you might get an error saying you don't have the developers tools and it will prompt you to install the command line developers tools. Go along with it. And then cd to the pc2nes-source directory and run this command, with paths changed so it can find the boost include and lib files on your system (credit goes to Bananmos from this thread):

g++ -o pc2nes_osx_57600 -I./nrpc-1.2a1 -I/wherever/you/put/boost_1_56_0 -L/wherever/you/put/boost_1_56_0/stage/lib Main.cpp nrpc-1.2a1/nrpc/*.c* -pthread -lboost_system
mv pc2nes_osx_57600 ../

8. Use automator to make a shortcut you can drag .nes files on to send them to the NES similar to the SendTo trick posted by thefox here.

Open automator from the Applications folder, pick "Application" as the type and click the choose button.
Type shell in the search box and drag a "Run Shell Script" action over to the right side.
On the "Run Shell Script" action you just added, where it says "Pass input: to stdin" change it to "Pass input: as arguments".
Replace the default script with:

export DYLD_LIBRARY_PATH=.:/wherever/you/put/boost_1_56_0/stage/lib
cd /wherever/you/put/pc2nes-v01/
./pc2nes_osx_57600 -ntsc -port=/dev/tty.usbserial $1

Of course, replace the paths to the boost libs and pc2nes-v01 folder with your own, and replace /dev/tty.usbserial with the name of the device your USB-RS232 cable is showing up as.
Now click Save and call the .app file whatever you want. For me I called it SendToNES.app. I dragged it on to my dock and now when I want to send something to the NES I just drag it on to the icon and off it goes. My next step will be moving the pc2nes and boost libs into the SendToNES.app package so that everything is completely self contained. But this example doesn't get to that point.

9. Drag and drop something to the NES, you're done.


Serious thanks to everyone that has been working on this. thefox, pc2nes is amazing. I'm SO new to nes development. I have to try things over and over to get them working. This really saves time.
Re: Sending data to NES through controller port
by on (#133294)
Memblers wrote:

Does anyone know what happened to this website? Been down for a few weeks.
Re: Sending data to NES through controller port
by on (#133301)
nestendo wrote:
Does anyone know what happened to this website? Been down for a few weeks.

Using redirections described in this thread, the new locations are:

http://blargg.8bitalley.com/parodius/nes-code/bootloader/
http://blargg.8bitalley.com/parodius/nes-code/serial/spec.html
http://blargg.8bitalley.com/parodius/nes-code/serial/cable.html

Although I think the boot loader specs on the wiki is more up to date and simpler.
Re: Sending data to NES through controller port
by on (#133307)
Awesome, thank you.

I'm hoping I can use this to make a set of general send/receive functions I can use inside a game to stream in small amounts of data between frames or larger amounts if the screen is turned off. Not a bootloader just some way to signal the PC and then pick up a stream of bytes of whatever length, so that the NES doesn't have to keep polling the data line to wait for the PC to send something.

If anybody has anything like that, let me know!

I've got a vertical scrolling ski-free sort of game started, I'm thinking of trying to stream in the level from a PC.
Re: Sending data to NES through controller port
by on (#133363)
nestendo wrote:
Awesome, thank you.

I'm hoping I can use this to make a set of general send/receive functions I can use inside a game to stream in small amounts of data between frames or larger amounts if the screen is turned off. Not a bootloader just some way to signal the PC and then pick up a stream of bytes of whatever length, so that the NES doesn't have to keep polling the data line to wait for the PC to send something.

If anybody has anything like that, let me know!

I've got a vertical scrolling ski-free sort of game started, I'm thinking of trying to stream in the level from a PC.


You'll need a hardware UART, the NES polling is really a software implementation of the same thing. The old Squeedo board had one, as did MIDINES. The Everdrive seems to have USB (so inevitably a UART of some type), but I don't know how it's set up. The next NES board I make will have one.

Depending on your CPU requirements, I think streaming may still work even with a soft UART though. You lose the CPU time for the transfer, but you should nearly double that because you'll have to wait for the start of the data (and triple it if you want extra data to buffer). What I imagine is like a simple packet, that would be the start byte (not used in the data) followed by the data. The PC would just send those bytes repeatedly, until it received an acknowledgement from the NES. In a safer setup, you would include a packet number, and checksum or CRC (and then it's basically XMODEM format). Ideally, you'd want enough time to receive 2 packets per frame so you could start buffering them in RAM.

So the setup I imagine with that is, game runs in NMI, soft UART runs in main loop running forever, and it disables NMIs after detecting the start of a byte (so to avoid data corruption). If that byte happens to be the 'start byte', then it keeps NMIs disabled and receives the packet, then acknowledges (send PC an incrementing packet number).
Re: Sending data to NES through controller port
by on (#133364)
I'm not sure async serial is necessarily the most efficient protocol for this, at least after the bootloader has finished. I'd prefer the SPI-like protocol of the OP, with some sort of MCU in the middle to act as a FIFO because both the NES and the PC want to be a master: the NES with modified SPI and the PC with USB. You'd need an MCU anyway to run async serial.
Re: Sending data to NES through controller port
by on (#133365)
Unless you're going to run it over the controller port, IMSNHO you should use something that appears to the NES as a parallel interface. Deserializing something is a large amount of overhead for no obvious benefit.
Re: Sending data to NES through controller port
by on (#133404)
Memblers wrote:
So the setup I imagine with that is, game runs in NMI, soft UART runs in main loop running forever, and it disables NMIs after detecting the start of a byte (so to avoid data corruption). If that byte happens to be the 'start byte', then it keeps NMIs disabled and receives the packet, then acknowledges (send PC an incrementing packet number).

That's what I'd like to do. The controller port is still pretty fast at 115200 or 57600bps. If you have to turn the screen off to get any real amount of data through I think it would still be useful. You could stream in different rooms with a little fade to black, load whole levels with a slightly longer one.

For smaller bits of data I was hoping there might be a way to squeeze a byte or two though without disabling NMI. Would it be possible to get enough time per frame to grab a few packets in NMI after screen updates? and still finish in time for the next NMI?

If I could get two bytes through that would be enough for a PC to signal my vertical skiing game to drop a specific object at a specific x coordinate (at the bottom of the screen).

I'll see what I can come up with but it'll probably take me a while.
Re: Sending data to NES through controller port
by on (#155010)
Might also want to look into these for file transfers over a serial bus:
https://en.wikipedia.org/wiki/List_of_f ... onnections XMODEM is a very simple protocol but good as historic example to compare to. DON'T implement this for reasons mentioned in the article on it. :P BLAST is neat... but proprietary.

https://en.wikipedia.org/wiki/Category:Link_protocols PPP is overkill, hehe. But these protocols might give you some good ideas.