Custom NES Cartridge – Harambe’s Revenge

As far back as I can remember, I’ve been fascinated with computers. This began with the venerable Nintendo Entertainment System – as a child I often dreamt of making my own NES game. This interest lasted well into my teen years, when I would read programming how-to’s from NesDev and other corners of the internet.

Later in life, I met a fellow named Brad Taylor – he was the author of many programming guides for the NES, and just happened to show up at my local hackerspace one fateful day. I had no idea this guy lived in the same country as me, let alone the same city – small world! With Brad’s NES expertise and my PCB design skills, we joined forces to make a USB reprogrammable NES cartridge. This project would be my first foray into PCBA (Printed Circuit Board Assembly), wherein a vendor does all of the component placement and soldering. This was a big deal for me!

The finished product – Raw PCB (left), mounted in cartridge shell (right)

Hardware Design

Initially, Brad and I wanted to make a PCB that could do some very ambitious things, requiring either a very capable processor, or an FPGA device. We began down this path, but soon realized that we were biting off much more than we could chew for something we had never done before. So, we decided to take a step back, and make a smaller project to verify the foundations of our design. Our final design goals were:

  • Be programmable via USB
  • Be able to play NROM format games
  • Feature nonvolatile storage (no battery required)
  • Be as cheap and easy to manufacture as possible

Component Selection

One of our design goals for this project was to make it cheap and easy to manufacture and prototype. That meant excluding BGA packages, which really limited our options. We also opted for a 2 layer PCB to keep manufacturing costs down, which made the layout more challenging than it would be on a 4 layer board.

For the memory, we used whatever was cheap and available from digikey – and could tolerate the NES’s 5V logic buses. We wound up using a SST39SF010 device (one for the PRG memory, and one for the CHR memory).

For the USB interface, I took a misstep in choosing an FTDI FT232H USB interface – I had selected it solely because I had previous experience using this chip. So, we did save some time on having to learn new tools – but at a unit price over $10 at the time, we likely could have found a cheaper option, and simply spent some time learning a new platform. Lesson learned!

One of the challenges of making an NES cartridge is interacting with the console’s lockout functionality. Luckily, the krikzz forums had a firmware load for an Attiny device, so we simply included this same chip in our design, and flashed the provided firmware onto it.

The rest of the components in this design were fairly standard, and included some generic shift registers and regulator circuitry. We used the shift registers to take serially-loaded memory data, and present it to the flash chips as a 48-bit parallel interface.

Fundraising

PCBA can be a costly service, and I didn’t want to go out-of-pocket on the order of $100’s – $1k for a hobby project. To this end, Brad and I opted to fundraise for a production run by following a crowdfunding model. We didn’t want to go as far as a kickstarter, so we solicited local tech groups (as well as friends and family) to see who would be interested in owning one of the cartridges. We received 13 orders and were able to keep the per-unit cost to around 80 dollars, which was a reasonable amount for all involved.

PCB Design, Iterations, Oversights

This design went through a number of hand-soldered prototype revisions before I placed the final order. We never did get a prototype 100% working due to the difficulty of soldering fine-pitched components, but we were reasonably confident that it would work (this later turned out to be partly incorrect).

One oversight was the control circuitry for the “read only” signal to the memory circuitry – we had assumed that the FTDI device would always provide a logic high on a particular signal, and we were using this signal to determine whether or not the device was plugged in to a USB host. This proved wrong, it only held true for a few units. We had to re-work the PCBs with a hardware patch to correct this:

Hardware patches: not as elegant as software patches

This patch takes one of the clock signals, rectifies it, and low-pass filters it to provide our “read only” signal. So instead of detecting if we are plugged in to a USB host, we now detect if we are connected to a powered-on NES. Luckily this patch saved the batch!

A more serious oversight existed in the design of the USB micro-B connector footprint. When I tested the assembled units back, they didn’t come up in dmesg… and the USB cable was getting hot to the touch. After some debugging, it turned out that the USB connector’s metal casing was shorting out the extra-long USB pads – I had designed them as such to ease manual soldering, but this was problematic for automated assembly. This was fixed by manually removing each USB connector, applying kapton tape to shield the casing from the PCB traces, and re-soldering it in place (yes, this was very tedious).

Kapton tape and tedious soldering saves the day

Software Design

Flashing Software Design

The flashing software for this design – the logic that shuffled a file from my PC to the cartridge – was simple in concept: use libftdi to connect to the USB interface, and bit-bang the memory data out through the shift register chain. I wrote a number of abstracted layers to produce the bit patterns needed for parallel memory programming, you can see a video of me testing the entire SR output chain below.

Unfortunately, I used up all of the FTDI’s I/O, and couldn’t route back a signal for the “Flash is done writing the current byte” signal. This meant I had to wait the maximum write time delay between every byte to ensure that it wrote successfully. I consider this the single largest oversight in the project, as it meant that programming an NES game (order of kB’s) would take 5 minutes or more. I did not realize just how long this would take until I had implemented and tested it. But, after a ton of testing with Brad’s cartridge reader device, we had a working unit!

The first working game on my hardware – exciting!

Game Software Design

Making and selling a cartridge is all well and good, but I can’t go shipping it with material that I had no right to distribute. To that end, I fulfilled a lifelong dream and created an NES game, Harambe’s Revenge:

I could write an entire series of blog posts on how difficult it was to write this game. And for all of my efforts – it is a very basic game. I wrote it entirely in 6502 assembly, and did the graphics myself via GIMP. I used https://github.com/pinobatch/pently for the audio playback library, and started the project with Damien Yarrick’s Project Template. Brad’s knowledge of NES programming was invaluable during my efforts.

A brief playthrough of the latest version of Harambe’s Revenge
An early version of Harambe’s Revenge running on Hardware

Lessons Learned

At the end of the day, we achieved our goals of learning to design for PCBA, and verified some design assumptions for a future board. We even successfully filled all of the orders. The most important outcomes, in my opinion:

  • Validate footprints for automated PCBA – casings can short out large hand-soldering pads
  • Bit-banging is a poor choice for programming a memory device, and while it kept monetary costs down, I wouldn’t opt for this approach again. If I were to redesign this, I would use an MCU with built-in USB functionality.
  • Start small – had we went for our initial design, there’s a large likelihood we would have not been able to complete it before losing steam. All of the work to make this ‘simple’ board took place over the course of a year!
  • Anticipate failure – we made more PCB’s than were required, as we anticipated that there would be some unit failures, and there certainly were.

Most of all – this project really drove home an important notion: projects don’t succeed on technical merit alone. There will always be difficulties – it’s not about how good your PCB layout is, or how elegant your code is. The success of a complex project comes down to perseverance and teamwork in the face of unpredictable problems. Having said that – thank you for all of your help and hard work, Brad!