Friday, July 11, 2014

Tapuino, the $20 C64 Tape Emulator

I’ve been into retro computing for a while now. It all started when I discovered AmiBay and realised that I could finally afford to buy a Commodore Amiga 1200, a machine that I had seen in my youth and lusted after but had no chance of getting hold of. This passion has grown over the years to the point where I own several A500 and A1200 machines in various states (including a mint condition new / old stock A1200 found in a warehouse in India!)

One machine that I haven’t gotten hold of until recently is the venerable C64, the machine that I cut my coding teeth on. I first discovered binary when I needed to learn how to design sprites for C64 games and I can probably attribute some of my success in my career to this incredible device and learning platform. At any rate, a good mate of mine recently emigrated and bequeathed his childhood C64 to me (big up to Mr +Craig Bettridge for that). Along with the C64 came his Datasette, 1541 drive and several boxes of disks. Unfortunately no tapes, and the 1541 drive seems to require significant restoration.

This left me with a C64 and nothing to load! Looking around the ‘net I found various solutions to this problem: The 1541 Ulitimate, SD2IEC etc. for disk emulation and the DC2N and devices similar to the Cassadapt for tape emulation. The 1541 Ultimate is an incredible piece of hardware but very expensive. Implementations of the SD2IEC also seem to be on the expensive side. The same goes for the tape emulators unless you look at the Cassadapt variety and those did not appeal. At this point I had decided to try and build something myself. Inspired by the Uno2Tap firmware, I wondered if I could move the PC part of that solution onto an MCU and create something standalone. My grand goal was to try to build my own fully functional (at least in terms of playback) tape emulator and so the Tapuino was born.

What I wanted to build was a full playback emulator, including motor signal handling, which would allow the user to choose a TAP file from an SD Card via an LCD and then interact with the C64 in a manner indistinguishable from a real Datasette. As I started this project I had the stated aim that I would try to build the device for under $20 and use common components that were easy for anyone to put together. With this in mind I went shopping on eBay and came up with this component list:

  • Arduino Nano Clone $5.87
  • MicroSD breakout board $1.96
  • 16x2 LCD with I2C backpack $5.16

For a total of $12.99, not too shabby! Additionally I obtained the following bits and pieces:
  • Opto-coupler: 4N25
  • 5x 10K resistors
  • 1x 330 Ohm resistor
  • 4x tactile buttons
  • Some jumper wire

I’ve written firmware for various MCUs including the ATMega328 and so had a basis to start from which included having a good idea of the capabilities of the chip and how to interface it with an SD Card and LCD display. For SD Card access I used the amazing PetitFatFs library from Chan, which I modified to support the current directory code from FatFS (PetitFS’ bigger brother).

As the LCD I chose came with an I2C backpack, interfacing to it was relatively easy and reduced the required pin count down to only 4 pins (which came in handy later on). An alternative would be to use a shift register circuit, but at the price, an I2C solution was a no-brainer.

The most expensive part to source was the Datasette connector, which cost over $7 in single quantities from the usual parts suppliers. As I had an existing Datasette at hand I chose to remove the cable and use this. I am still looking for an alternative and inexpensive solution.

The Datasette Victim / Donor

With the connector removed I proceeded to slap together some code from a previous bit of firmware I had written for an ATMega128 based MP3 player and got some filenames displaying on the LCD via the SD Card:

First base firmware actually doing something

Now that I had the basics in place I wired up the sense, read and ground lines from the Datasette connector to the Nano and got the sense line working. From here on out there was a huge amount of firmware hacking and slog to get a game loading. The first success was one of my favourites: Uridium, but while the game loaded flawlessly I couldn’t get anything else to load, specifically any Novaload games.

First bitter / sweet success!
My test games were Monty On The Run and Monty Mole. This failure puzzled me for several days until after walking the code base repeatedly, I realised that I had left the SPI bus at half speed during initialisation! Basically what was happening was that the SD Card read was slow enough to cause a delay in the signal generation for fast loaders, resulting in all kinds of havoc. 

With that problem solved (which incidentally had caused me to rewrite the interrupt handler part of the code three times whilst trying to find the bug!) I was onto a stable base. The firmware still required a serial port to issue commands to the Nano as I hadn’t wired in any buttons yet, but was good enough to demo to a few mates at work. The response was gratifying :)

YEAH! Its finally working!

The next port of call was to get the motor signalling working. I wanted to provide full emulation for fastloaders that stopped the motor during decrunching and for the usual pause when the first part of the tape loaded. This proved (and continues to prove) somewhat tricky. Firstly in terms of wiring details:

I hooked the motor line up to the Nano via a transistor switch. While this worked, current leaked via the transistor into the Nano causing the Nano to become powered via the input pin when the motor was on. This didn’t seem like a great idea so I switched to an opto-coupler which cleanly separated the signal from the Nano. Then came the headaches… The previously mentioned interrupt routine was altered to check the motor signal and exit if the motor was off. This worked… except for Rambo First Blood Part II. This game for some reason seems to switch the motor off before the TAP file is complete which in turn caused the main loading code to loop endlessly waiting for the TAP to complete (you get the picture). The current code has some rather “interesting” ways to mitigate this behaviour and I am not yet satisfied with the result. Unfortunately testing these outcomes is a rather laborious process when you take into consideration the length of a tape load.

Finally I threw together some button reading code, polished up the interface a bit and the standalone unit was finally ready!

The next steps are to build a nice housing using a project box and find an alternative connector for the C64 Datasette port. However, that said, the code is functional if not clean and I’d be interested to see if anyone else would like to give this a go.

Code can be found at on GitHub. Please feel free to send me a pull request if you have some suggestions on how to improve it. I would like to get to the stage where I can provide full instructions and a veroboard schematic so those less comfortable with the technical details can build one. Here is a Fritzing diagram of how I wired things up, I think its correct, but there may be errors :).

Stay tuned for further updates.


  1. Clean this spam...

    BTW. Is there a chance to upgrade TAPUINO firmware, where and how?

    1. You can always get the latest source and compile in the Arduino IDE @

  2. Absolutely amazing project, thanks for sharing & congrats!

  3. Is it possible to use Tapuino on a PET 2001 ?
    What has to be considered?

    1. To be honest, I have no idea if it would work. So far folks have reported success on the C64, Vic20 and C16, so if the pet has similar tap signalling then i dont see why not.

  4. Works nice with C128D. I replaced optocoupler with NPN transistor with success (base via 10k ohm to motor pin, collector and emitter same as in opto-coupler).

  5. Hi Peter ... If you have access to a 3d printer, the files and instructions to make a datasette connector are here, rather than hacking up a real one -

    1. Hi Bill,

      Thanks for this. I've actually tried to print this with limited success, however we've just got a new printer at work so it might be time to try again.

  6. This is great. This could be easily adjusted to work with Amstrad CPC 464 and ZX Spectrums which also use TAP files. Might need to change connector, but everything else would be the same. Amstrad tape files are stored as CDT files, but are essentially the same format as TAP I believe..

    1. Hi,

      The TZXDuino is a piece of hardware inspired by the Tapuino that does exactly this and supports a number of systems that use analogue audio transmission, check it out.

  7. Hi Peter, I am trying to build this project,I have assembled all the hardware, and compiled the software using the Arduino IDE (1.64) and uploade it to a V3 Nano, but the LCD will not initilise. I have tried two different 1602 LCD I2C panels but with no luck! I have run a test sketch for the LCD's and that works, but not the Tapuino Software! any Ideas as to what to try?



  8. Have you checked the config file to see that the i2c address is correct for the display?

  9. Very interesting project. What came up my mind: How do you handle games that require the datasette counter? I remember e.g. Turrican II. You load the game, play it. And to reload the map, the system tells you to reset the counter and rewind to a certain counter mark.

    1. Hi,

      I don't is the short answer :-) I've got code to handle the counter calculations etc but ran out of flash space to implement it. If I ever get the time to revisit this project I'd look at a more capable mcu and implement this.

  10. I want this to replace my old C2N/1530 tape deck, Apart from .tap, can it handle .D64 and PRG files.

    Can you load and save programs written to it from the C64 V2 or Simons Basic.

    Can it use a full size or micro SD card.

    Which mb/gb card would you recommend.

  11. Hi. This is only a C2N replacement so only tap. You can record files. Sd card choice is dependent on what sd card module you use in your build and any size card should work up to 32gb (I think)

  12. Hi, what's C1's capacitor capacity in v1.5? (In Eagle BOM the value is empty!)