Wednesday, July 16, 2014

Tapuino Part 2: Building the $20 C64 Tape Emulator


Having detailed the Tapuino in my last post, its now time to get down to the specifics of how to build one. In keeping with the low-cost requirement I developed the initial prototype on a breadboard and then moved that design onto strip or vero board. The vero board based construction will eventually live in a nice neat project box (when I finally get there).

DISCLAIMER: If you build this and it blows up your C64, sets your house on fire, kidnaps your dog or any other negative occurrence, I take no responsibility or liability whatsoever. That said I will do my best to help troubleshoot any builds.

So lets get started. Firstly a bill of materials:

Major components:
  • Arduino Nano V3
  • 16x2 LCD Display with I2C backpack
  • SD Card module with built-in level conversion
  • 40 wire Dupont female-female 'ribbon'
I got all of this from TxHang Electronics on eBay. They are cheap and ship relatively quickly, so are worth it in my book. Here is an example shopping list:

Addition components:
  • Piece of vero board. The one I got was 100mm wide x 200mm long. This is also known as strip board and must be the kind with strips of copper (as opposed to individual 'cells')
  • 32 pin (16x2) WIDE dip socket (this is what the Nano will plug into)
  • 6 pin (3x2) dip socket (for the opto-coupler)
  • A strip of male pin headers
  • A strip of male right-angle pin headers
  • A strip of female pin headers (sockets)
  • 5x 10K Ohm resistors
  • 1x 430 Ohm resistor
  • 4x Tactile switches (6x6)
  • 1x 4N25 Opto-coupler
  • Some jumper wire (I use single core wire from a piece of telephone cable)
Here are examples of the headers:

So lets build the main board first. You'll want to put it together like this:

Top view of the main board

Note the minimum dimensions of the board: 26x15. You may wish to make the board larger to allow for mounting holes.

R1 = 10K Ohm
R2 = 430 Ohm
Green blocks = straight header pins.

Break the header pins into appropriate size groups:
3x3 pins
1x1 pin
1x6 pins
and cut the female pin headers to size (mine were 40 pin, so cut down to 19 pins)

Bottom view of the main board
The lighter yellow bits are where the vero board has been cut. It is essential that you check that these tracks are cut properly. Use a multimeter to test for continuity between the tracks once cut. To cut the tracks on my prototype I used a small sharp drill bit that was luckily a perfect fit.
Please take note of the cut track between the two pins of R2.

I would suggest that you solder in this order:
  1. 32 pin wide dip
  2. 6 pin dip
  3. 2x3 pin header group next to the 6 pin dip
  4. Remaining pin headers
  5. Jumper wires

Feel free to extend the pin headers to access additional pins on the Nano if you like, I just wanted to keep it simple for wire-up later and expose only the pins necessary.

Next up is the button board:

Top view of the button board

Note the minimum dimensions of the board: 22 x 21. You may wish to make the board larger to allow for mounting holes.

R1, R2, R3, R4 are all 10K Ohm
Green pin headers are right angle.
The pinouts of the green pin headers, left to right are as follows: GND, PWR, BTN1, BTN2, BTN3, BTN4

Bottom view of the button board

Take careful note of the tracks to cut:
  • There is a cut between each end of each resistor
  • Between the poles of the switches
  • On the 6th track (from the left) to isolate button 3 from button 1
Also note that the jumper wires for the power and ground lines are soldered through to multiple points. I achieved this by cutting the wires into individual sections:
  • power line (top most line) there are 4 jumper wires of 3, 6, 6, 6 tracks in length.
  • ground line (under the switches) there are 4 jumper wires of 4, 6, 6, 6 tracks in length.

Now lets install the components and connect it all up.
Firstly install the 4N25 opto-coupler into the 6 pin socket:

Installing the 4N25 opto-coupler

Note the small dot on the chip, this indicates pin 1. The chip should be oriented such that pin 1 connects through to the 440 Ohm resistor (R2).

Next the Nano:

Installing the Nano

As the Nano has 2x15 pins and the socket 2x16 pins, care must be taken to place the Nano correctly. The Nano must be aligned so that the empty socket pins are on the right most pins of the socket as per the image above i.e. the Nano is mounted as close as possible to the opto-coupler.

If you trace out the circuit you will observe that the 2x3 pin headers between the opto and the Nano expose a ground and power rail (left is GND, right is PWR). You will use these rails to provide power to the LCD, SD Card and Button breakout boards.

Connect in the following manner:

  • Power and Ground go to the rails described above
  • Nano A5 goes to SCL
  • Nano A4 goes to SDA
SD Card:
  • Power and Ground go to the rails described above
  • Nano D13 goes to SCK
  • Nano D12 goes to MISO
  • Nano D11 goes to MOSI
  • Nano D10 goes to SS
Button Board:
  • Power and Ground go to the rails described above
  • Nano A3 goes to BTN1
  • Nano A2 goes to BTN2
  • Nano A1 goes to BTN3
  • Nano A0 goes to BTN4
Finally the pinout for the C2N connector to the board:

You will need to break out 15 pins from a pin header i.e. have 15 continous pins.
Solder the C2N connector to the pins in the follow manner:

  • MOTOR to PIN 1
  • GND to PIN 4
  • PWR to PIN 5
  • WRITE to PIN 12
  • READ to PIN 13
  • SENSE to PIN 15

Remove all other non-connected pins: e,g, pins 2, 3 6-11 and 14. I recommend you heat-shrink the pins as above.

Your connector should look like the one above, the colour to pin map in my case is:
  • Red (MOTOR) to PIN 1
  • Black (GND) to PIN 4
  • Green (PWR) to PIN 5
  • Brown (WRITE) to PIN 12
  • White (READ) to PIN 13
  • Blue (SENSE) to PIN 15
Final assembly should look something like this:
Final Assembly! YES! :)


PIN 1 (RED/MOTOR) is connected to the left-most pin of the female pin header.

Now all that is left to do is flash the sketch to the Nano, disconnect it from USB, insert an SD Card with TAP files, connect the Tapuino to the C64 and enjoy!

The UI is controlled as follows:

BTN 2 is ABORT (during a load) or BACK one directory if browsing

If you have directories on your SD card they will be indicated by an arrow in the right-most column of the LCD where the filename is displayed. Currently only 8.3 format names are supported. I will look into LFN names at a later date.

Caution: Do not connect the Nano to both the C64 and PC. Also check all soldering very carefully for shorts before wiring up to your beloved machine!

Hope you enjoyed this, it was a helluva post to write!


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.

Thursday, June 20, 2013

Hacking (fixing) Toki Tori for ICS+ Devices

A while back I picked up one of the excellent +Humble Bundle collections for Android (actually I think I've bought them all!) and included in the bundle was an interesting little platformer called Toki Tori.

I'd actually forgotten about this game completely until the latest +Humble Bundle Android release. I was browsing the new games using the app they provide when I saw it and thought it would be a great game for the kids. Unfortunately after installing it I found that it wouldn't work! A Google search revealed:

Which was a bit disappointing, especially considering these articles mention ICS and JellyBean has already been out for ages...

So, what to do? Well I assumed that there must be some Android platform related change that was causing the issue. Maybe this could be patched or worked around? First thing then is to have a look the logcat output when the game crashed:

E/AndroidRuntime(24470): FATAL EXCEPTION: main
E/AndroidRuntime(24470): java.lang.NoClassDefFoundError: android/view/ViewRoot
E/AndroidRuntime(24470):        at com.polarbit.fuse.MainTask.processTouchpadAsPointer(Native Method)
E/AndroidRuntime(24470):        at com.polarbit.fuse.MainTask.access$200(
E/AndroidRuntime(24470):        at com.polarbit.fuse.MainTask$RenderSurface.surfaceCreated(

A bit of searching revealed this:

It seems that the Toki Tori developers (or porters or whatever) might have been a bit naughty and referred to an internal framework class that changed between GB and ICS as per this quote from the ViewRoot 2.2 source:

The top of a view hierarchy, implementing the needed protocol between View and the WindowManager. This is for the most part an internal implementation detail of WindowManagerImpl

At this point I had two choices:
  • try and reverse engineer the native method processTouchpadAsPointer() and attempt to patch it
  • see what would happen if I simply didn't call it.
I opted for the easier route :) This wasn't an entirely sloth based decision: several obscure searches pointed in the direction of this function being linked to the Xperia Play, which in my case (I have a Samsung S3) wasn't a relevant platform.

When reverse engineering Android code I usually just use the excellent command line utilities: APKTool and Dex2Jar and then run the resulting jar through JD-GUI to have a look.

However on this occasion I stumbled upon the most excellent Virtuous Ten Studio which automates most of the drudgery out of the process. I'd really recommend it and suggest you go and buy a licence to support the devs if you can afford it! So following the stack trace we get to the surfaceCreated method of the RenderSurface class which looks like this in smali:

.method public surfaceCreated(Landroid/view/SurfaceHolder;)V
    .locals 4
    .parameter "holder"

    const/4 v3, 0x1

    .line 332
    iget-object v2, p0, Lcom/polarbit/fuse/MainTask$RenderSurface;->this$0:Lcom/polarbit/fuse/MainTask;

    iput-boolean v3, v2, Lcom/polarbit/fuse/MainTask;->mHasSurface:Z

    .line 334
    iget-object v2, p0, Lcom/polarbit/fuse/MainTask$RenderSurface;->this$0:Lcom/polarbit/fuse/MainTask;

    iget-object v2, v2, Lcom/polarbit/fuse/MainTask;->mContext:Landroid/app/Activity;

    invoke-virtual {v2}, Landroid/app/Activity;->getWindow()Landroid/view/Window;

    move-result-object v2

    invoke-virtual {v2}, Landroid/view/Window;->getDecorView()Landroid/view/View;

    move-result-object v2

    invoke-virtual {v2}, Landroid/view/View;->getRootView()Landroid/view/View;

    move-result-object v0

    .line 335
    .local v0, root:Landroid/view/View;
    if-eqz v0, :cond_0

    .line 336
    invoke-virtual {v0}, Landroid/view/View;->getParent()Landroid/view/ViewParent;

    move-result-object v1

    .line 337
    .local v1, viewRoot:Landroid/view/ViewParent;
    if-eqz v1, :cond_0

    .line 338
    iget-object v2, p0, Lcom/polarbit/fuse/MainTask$RenderSurface;->this$0:Lcom/polarbit/fuse/MainTask;

    iget v2, v2, Lcom/polarbit/fuse/MainTask;->mInstance:I

    #calls: Lcom/polarbit/fuse/MainTask;->processTouchpadAsPointer(ILandroid/view/ViewParent;Z)Z
    invoke-static {v2, v1, v3}, Lcom/polarbit/fuse/MainTask;->access$200(ILandroid/view/ViewParent;Z)Z

    move-result v2

    if-ne v2, v3, :cond_0

    .line 350
    .end local v1           #viewRoot:Landroid/view/ViewParent;
.end method

The interesting bit being this line of code:

if-eqz v0, :cond_0

Which is a basic null check before calling some additional code and finally the nasty method we want to get rid of. Hmmm looks like an interesting candidate and an elegant patch point. If we change the code to this:

if-nez v0, :cond_0

Then the condition is inverted and the relevant code skipped....
Making the change and using Virtuous Ten Studio to rebuild the APK was a 30 second operation, and guess what... it WORKS!

That is to say: I've played several levels and not only does the game now start, but it appears to work flawlessly.

Obviously I can't share the APK, but if the +Humble Bundle guys / gals want to get hold of me, I'd be happy to help them through this process. Alternatively, you could give it a go yourself.

Until next time, happy hacking!

Monday, May 6, 2013

Make: Poor man's Minimig ARM Controller

In the last post I presented my findings on using a cheap ARM dev board as a replacement for a MiniMig ARM Controller. I've done some fairly extensive testing and it seems to work passably, so here are some instructions on how to build your own.

Firstly you are going need a board that hosts a AT91SAM7S256 chip and exposes the GPIO in a direct manner i.e. does not have any peripherals attached etc.

Specifically you need to make sure that:
  • PA4 - PA10
  • PA12 - PA15
  • PA24 - PA28
  • PA20
  • GND
  • 3.3V
  • nRST
Are available. If this is not the case, you could possibly alter the code to change pin mappings, but that is beyond the scope of this post.

Next you'll need to get hold of a 28 pin DIP socket, preferably the "tulip" kind:

In my case the dev board headers were available as headers with 2 rows of 10 pins:

So I used some crimp connectors and 20 way ribbon cable to connect these up.
Next you'll need to figure out the pin mappings between your dev. board and the pic socket.
To start you need the schematic for your dev board, mine had this for the pinout info:

Then this must be mapped to the relevant pins on the PIC socket. I used the ARM controller schematics as a guide:

and the PIC mapping:

This should get you to something like this:

From there its just a matter of carefully mapping pin to pin with some wire.
I stripped and tinned the relevant wires in the ribbon cable, pushed them into the mapped holes in the DIP socket and then soldered them in.

The observant reader will notice that GND, 3.3V and nRST are not mapped to the dev board header.
There is another header on my board that provides GND and 3.3V and the JTAG header exposes nRST.

And that is all there is to it :)


Friday, May 3, 2013

Prelude: Poor man's Minimig ARM Controller

I have 2 Minimigs both fitted with the replacement ARM Controller boards.
In a recent cock-up I nearly managed to destroy one of the ARM boards by breaking a pin off whilst hastily pulling it out of the Minimig.

Thanks to a $1 DIP socket I managed to save the controller by soldering the pin back onto the board.... and gently plugging the controller into the new socket:

Which thankfully worked pretty well. During this whole debacle I happened to have a proper look at the mcu on the board and saw that it was an AT91SAM7S256. I remembered that I had a cheap dev board with the same chip on it. The dev board cost me $25 when I bought it, as opposed to the near $100 price tag of the ARM Controller, so I began to wonder if it might serve as a cheap replacement.

After some very careful pin mapping and buzzing the dev board out, I came up with this:

And it works 100% (or seems to so far). Whilst the board I used does not seem to be for sale any more, there are alternatives available and even this board ($27 on eBay as of this post) :

(the bigger brother AT91SAM7S512) should be simple enough to wire up and port the code to (if even necessary).

All in all a fairly cost effective hack that also has the benefit of providing JTAG access for devs that wish to extend the ARM Controller firmware.


Tuesday, February 12, 2013

Amiga A500 addon card "fixed"

Well it seems that I've managed to fix the card mentioned in my previous post.
The battery arrived from eBay, I cleaned up the traces (and repaired where necessary) and the miggy now boots with the card in place. I think its looking pretty darn good:

With some identification help from the friendly folk at AmiBay this seems to be an RTC and 1/2 or 1MB RAM upgrade board (seems that the RAM chips are 256KB, so possibly 1MB). Now I need a new FDD or equivalent to test this baby out as I can't get disks to load properly. No one ever said a retro-computing hobby was going to be cheap...

Wednesday, January 23, 2013

Resurrecting an Amiga 500

 A buddy of mine is emigrating and while going through all of his stuff came across his old Amiga 500 and Commodore 64 which he very graciously has donated to me! SCORE!

I love old computing hardware, already owning an Amiga A1200, Atari, ZX80 and various other bits and pieces so these two machines were a welcome addition to the fold.

The first thing to do was obviously to boot the machines up, so I started with the A500 and was greeted with the 10-short 1-long Blink Code of Death. A little Goolge-fu revealed that this indicates various severe issues, one pointing at a leaked battery and another at a chip RAM issue.

So I did the next logical thing and opened the miggy up. What I found was that (thankfully!) the main board was clean as new but an expansion card had a battery that had leaked (the miggy boots without this card, so another win):

It seems this might be an ActionReplay of some variety. Having a closer look at the problem revelead this:

Traces looking a bit dodgy and battery acid has leaked along the traces into the chip (RAM) socket.... oh dear... so I guess its time to clean it all up, but first a closer look at the damage:

Time to whip out the iron and get to work. After a fair bit of struggle (the battery contacts were well corroded and needed to be cleaned before I could de-solder them), the board now looks like this:

Looking not too bad in fact! The traces are intact, its just the lacquer on top that has gone. A really good clean with some isopropyl alcohol and a pretty thorough test with the multimeter indicates that all is OK. Unfortunately the other battery contact point was not so good:

Bit of missing trace there, but easily repairable. So off to eBay to get another battery and to the local electronic supplier to get another socket (why is it that you always have every other chip socket but the one you need!!!).

The battery is in transit and should arrive in a week or two (the joy of living at the bottom of Africa) and the socket I'll pick up this weekend. Hopefully the actual RAM chip is okay and once I've sorted out these two issues the card will work again.

I'll update with info as it goes. Now I have to find a suitable video-out option for the A500 as B&W composite is just not doing it for me, the best looking option is a bit expensive though...