Wednesday, November 21, 2012

Arduino Controlled NES (2A03) Synth - PART I

image credit: the internet

I've wanted to build an NES synth for some time. I knew there were a few options for writing sequenced tracks for the Nintendo, but nothing that would be as satisfying as hitting a key on a keyboard and hearing a sweet arpeggiated square wave spill out. Rather than try to interface with the entire system via the cartridge slot, I felt the easiest way was to just rip out the CPU and control it with an arduino Uno/Duemilanove.

I was lucky to find a very similar Arduino Mega controlled 2A03 project by Jaroslaw Lupinski (he's the guy behind the Chip Maestro NES MIDI Synth Cart).  Using this as a starting point got me 90% of the way there, hardware-wise. The only issue when porting this design to the Uno is the number of pins available for port manipulation. As we'll see, while this does prevent us from using the design outright, we can at least rough out a proof of concept and get the 2A03 to chirp out some notes.

the OG schematic

I'm going into this assuming he knew what he was doing when he laid this out and that everything would work as advertised. Given that, we'll treat the majority of the circuit as a black box and just focus on how our arduino will interface to it.

According to the schematic, we have a few points we will tie into the arduino:
  • JP4 (Power): Digital Output to power the 2A03 on and off
  • JP5 (Reset): Digital Output tied directly to the 2A03 reset pin
  • JP7 (Interrupt): Interrupt pin used to alert the arduino when the 2A03 is ready to receive commands
  • JP1 (Address): 8  Digital Output pins to populate the address bus
  • JP2 (Data): 8 Digital Output pins to populate the data bus
The power and reset pins can be any digital pin, and the interrupt must be either digital pin 2 or 3. Its the  address and data bus pins that will be the problem here.

The example design uses the Mega's PORTF (digital pins 54-61) and PORTK (digital pins 62-69) to connect to the address and data busses. The direct port manipulation is necessary since we have to flip the bits relatively simultaneously. While the Uno has 3 ports, only one (PORTD, digital pins 0-7) has the 8 pins we'd need for either the data or address bus, but that is off limits since all of the interrupt pins fall in that range. The remaining 2 ports (B and C) have only 6 pins each, which means we'll have to get a little creative.

Luckily, a closer look at the example sketch shows none of the addresses used and only one data message (aside from note data) contain a value greater than 0x3F (00111111 in binary). Essentially, we are only using the 6 least significant bits. So, assuming that particular byte can be changed to something meaningful less than 0x3F, we should just be able to tie the 2 most significant pins of each bus to ground and carry on our merry way..

Here is the line in the example sketch we'll need to change:
sendAddrData(0x00, 0xBF);//Turn square wave to max volume, 50% duty, etc
This is loading a value of 0xBF (b10111111) in register 0x00, which apparently sets the volume and duty cycle of one of the square wave generators. According to Brad Taylor's unofficial 2A03 technical reference, register $4000 ($4000 = 0x00, don't ask me why) breaks down like this:
bits   descrtiption
0-3 volume / envelope decay rate
4 envelope decay disable
5 length counter clock disable / envelope decay looping enable
6-7 duty cycle type (unused on noise channel)
With our hardware limitation, we'll only be able to send 0's in bits 6-7 (duty cycle type). Reading further, we see the table for decoding bits 6-7 shows that 00 is, in fact, a valid option:
val   duty (positive/negitive) in clock cycles
00     2/14
01     4/12 
10     8/8
11     12/4
So, the only difference in sending 0x3F (b00111111) rather than 0xBF (b10111111) is the duty cycle of the square wave will change from 8/8 to 2/14. I have no idea what that will sound like, but it should sound like SOMETHING, and that's good enough for me at this point.

Keeping everything else the same, we move interrupt, power, and reset to digital pins 2, 3, and 4, respectively. We then move the address and data buses to PORTB (digital pins 8-13) and PORTC (analog pins 0-5), respectively, tying the remaining 2 pins of both to ground.

Altered Schematic

Before we can actually test any of this out, we'll have to gut the NES and remove the 2A03 chip. Unfortunately, Nintendo didn't believe in IC sockets at the time; the (40 pin!) chip is soldered directly to the board. Desoldering this with a soldering iron and some solder wick is possible, but not recommended. A hot air rework station with plenty of flux is definitely the way to go. Although, you could also use a heat gun or maybe even a blow dryer or toaster oven if you are careful.  Look at the internets, there's about 100 different ways to do it. Which ever way you choose, do this at your own risk in a well ventilated area. Burnt PCB smells like cancer. (UPDATE: looks like you can just buy them here)

I am too lazy to go downstairs and take a picture of my NES, so look at this one.

Once I got the whole mess breadboarded, it was time to load the modified test sketch and let her rip!

Ok, so its not pretty and we have a way to go, but still, its exciting. I tried to relay this excitement to some friends, but it didn't quite translate. My girlfriend just thinks I'm weird.

The code is trying to play a few octaves of ascending notes, but since we are basically chopping off the two most significant bits of the note data, the result is a bit random. Still, we know our circuit is correct and we feel damn good about ourselves!

fun times.
Here are the parts I used (bought from mouser, total: $8):

In case you missed them, here are some useful downloads:

Next Step (Part II):
We'll expand the Uno's i/o with some shift registers and set up a proper interface to the 2A03.

1 comment:

  1. "Ok, so its not pretty and we have a way to go, but still, its exciting. I tried to relay this excitement to some friends, but it didn't quite translate. My girlfriend just thinks I'm weird."

    Story of my life sadly...

    I am excited!