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):

C64's tape port

A-1, GND, Ground

B-2, +5V, 5 Volt DC

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

D-4, READ, Data Input, read data from datasette

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?

  • \$\begingroup\$ The PWM signal from the Arduino goes to the WRITE (not READ) pin. \$\endgroup\$
    – Telaclavo
    May 7, 2012 at 11:02
  • \$\begingroup\$ 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. \$\endgroup\$
    – NagyI
    May 7, 2012 at 15:22
  • \$\begingroup\$ 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? \$\endgroup\$
    – Johncl
    Oct 28, 2015 at 10:34

2 Answers 2


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...

Arduino to C64 V1

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.

  • \$\begingroup\$ 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! :) \$\endgroup\$
    – NagyI
    May 11, 2012 at 11:09
  • \$\begingroup\$ @NagyI It should work. \$\endgroup\$ May 11, 2012 at 14:43
  • \$\begingroup\$ 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 :) \$\endgroup\$
    – NagyI
    Apr 1, 2013 at 19:31
  • \$\begingroup\$ 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. \$\endgroup\$
    – NagyI
    Apr 15, 2013 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.

  • \$\begingroup\$ 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. \$\endgroup\$
    – NagyI
    May 8, 2012 at 16:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.