# Interfacing Arduino to C64's tape port

Update: a practical implementation of this is done in the Tapuino project made by Peter Edwards. Check it out, everything is open sourced: https://github.com/sweetlilmre/tapuino

I'm working on a project where i'm using my Arduino to stream TAP tape data files from my PC to the C64. The software side of the project is going well however i'm still new to electronics and i don't like to fry my Commodore. So i need hardware interfacing help actually.

C64 tapes uses PWM modulation to store program on cassette tape and on reading back the data an opamp + schmitt trigger converts the audio signal into square waves. Every high-low transition triggers an interrupt in the machine and the distance between two interrupts (which is the length of the pulse) represent an atomic part of the stream.

The cassette port's pinout looks like this (the top and the bottom side has the same pins twice):

A-1, GND, Ground

B-2, +5V, 5 Volt DC

C-3, MOTOR, Motor Control, approx. 6 Volt power supply of the motor

E-5, WRITE, Data Output, write data to datasette

F-6, SENSE, Detection, if one of the keys PLAY, RECORD, F.FWD or REW is pressed

My current idea is the following:

Based on the C64 Interfacing Blue Book (starting from page 29) the machine uses TTL level on READ and WRITE port so i guess i can directly connect a PWM pin from the Arduino to the READ pin.

I also need to interface with the SENSE pin. I think i can directly connect that as well to one of the digital PINs and write digital LOW there when i need to signal pressed button state. Is that correct?

Later i wish to detect the presence of +6V signal on the MOTOR pin. Some loaders stop the dataset in the middle of the loading process so i have to detect that as well to emulate the tape correctly. Should i use some kind of resistor to limit the current there or can i just hook up that directly as well? Maybe i should use a relay there?

• The PWM signal from the Arduino goes to the WRITE (not READ) pin. – Telaclavo May 7 '12 at 11:02
• I like to emulate the dataset with the Arduino so i should interface with the READ pin because that's where the C64 accepts input. – NagyI May 7 '12 at 15:22
• From what I understand the format of the data you don't repeat the pulses like a classic PWM signal - but it's the combination of long, medium and long pulses that carry the data. Can the Arduino send PWM signals like that? – Johncl Oct 28 '15 at 10:34

According to the document you provided, the datasette port is looking for a pure digital signal with varying duty cycle (0.75 for H, 0.25 for L).

As long as the Arduino pin can drive sufficient current (it should be able to) and is operating at 5V, a direct connection will work. You may want to investigate using a TTL buffer between the Arduino and the C64 (the buffer would be powered from the +5 supply of the datasette port, and the ground would be common to both the C64 and Arduino).

As for the SENSE, it would be easier to use a digital output to drive a small-signal MOSFET (like a 2N7002) - a logic high turns the MOSFET on, which pulls the SENSE pin (connected to the drain) to ground (connected to the source) without the Arduino having to sink any current at all.

The MOTOR pin could also be used to drive a MOSFET gate. The drain would be pulled up to the Arduino supply voltage with a weak pullup (10k or so), the source connected to ground. The drain would also go to a digital logic pin. When MOTOR is high, the logic input is low, and vice versa, and the Arduino sees a clean logic signal.

For example...

Note using two NAND gates as a buffer of sorts. (Can you tell I used to scrounge for parts?)

TTL is fairly robust. I don't think there's much chance of damaging anything.

• Wow, nice schematics. I think i'll try to connect Arduino's PWM out pin directly to D-4 first because it uses 5V aswell. Anyway thank you! :) – NagyI May 11 '12 at 11:09
• @NagyI It should work. – Adam Lawrence May 11 '12 at 14:43
• Oh my, i haven't accepted this answer? Shame on me. Anyway i just ordered the tape edge connector to try this out and my soldering station arrives next week. So hopefully i can test this soon :) – NagyI Apr 1 '13 at 19:31
• Because i couldn't get a 2N7002 my collegue suggested me the BS170 instead. Sense signaling works perfectly. However motor detection is broken. Arduino always reads logic low. It doesn't matter if i put Gate to Low or High, Arduino always reads logic low. Is this the problem of the BS170 or something different? I've tried it with an another BS170 but the problem remains. It seems to me that BS170 can only switch GND but not voltage. – NagyI Apr 15 '13 at 23:26

Sounds like an interesting project. My recollection is that the VIC-20's hardware fed pulses from the Datasette into an edge-detect circuit (I forget whether it detected rising or falling edges); the C64 tape-load routines were compatible with those of the VIC-20, so I don't think the standard loader could have used any tricks the VIC-20 wouldn't support, though custom loaders might. I never played around with stuff back in the day enough to determine whether the Datasette itself converted both rising and falling edges into pulses (e.g. by feeding a delayed and non-delayed signal into an XOR gate). I came up with a routine to convert data into pulse widths, but never figured out how to use the edge detector at all.

With regard to getting data from the PC to the C64, if you don't want to use a sound card (some sound cards have stereo-image processing and such that could wreak havoc with the phase of outgoing audio) there are two approaches I might suggest: (1) send pulse-interval data from the PC to the Arduino, and simply have the Arduino time individual outgoing pulses. Perhaps encode the data format with two pulses per byte, using something like the following encoding:

0000-1100 -- Output a 20us high followed by 24-60us low (in multiples of 3us)
1101      -- Output 40us low
1110      -- Output 80us low
1111      -- Byte values of \$FF will be ignored
-- Other byes with one nybble equal to 1111 could be used to simulate the
tape motor buttons or indicate an "okay to pause here" indication.


I don't think any loading schemes will try to time pulses with better than 3us precision, and this scheme would allow data to be sent over a UART at 115200. The PC should add 0xFF padding bytes so that rate at which data is sent to the Arduino will reasonably-well match the rate at which the Arduino is clocking it out. Because each nybble will take between 44 and 80 microseconds to process, the Arduino would only have to poll its UART between nybbles and could disable interrupts near the end of each pulse. If the PC pads its data reasonably effectively, one could either (1) have the PC try to send data slightly faster than the Arduino would output it, and use either hardware or software handshaking to slow it down, or (2) have the Arduino shave a microsecond off each pulse when its buffer is nearly full, or add a microsecond to each pulse when its buffer is nearly empty. To avoid having audio glitches result from momentary PC hiccups, one could have the Arduino suspend outputting at an "okay to pause here" byte if its buffer was not nearly full.

• Thank you for the ideas. Actually i'm streaming the TAP file data directly to the Arduino. It specifies each pulse with one byte. (see: c64tapes.org/dokuwiki/doku.php?id=analyzing_loaders) The overcome the glitches of the data transfer i'm using a one kB circular buffer on the Arduino which is being filled in the main loop. The data is consumed by the interrupt function attached to the PWM generator's match event. This gets called twice a pulse. That's where i'm changing the PIN's level and on high-low transition i'm writing the new match register value according to the next byte. – NagyI May 8 '12 at 16:55