Subscribe via RSS
19Jun/1611

Commodore 64: Serial Interface to Arduino

So, in my previous post, I was heading towards building an archaic circuit to control trains with the User Port. This would've worked, had I spent a lot more time and built a very complex circuit. Instead I've now chosen a new path... let's hook the C64 up to an Arduino and do most of the work there. The C64 can be the display and input/output for controlling the trains.

Interfacing both components

The C64 User Port has both a 'parallel port' with 8 i/o pins and a serial port. I initially wanted to use the parallel pins, but came to the conclusion that I'd have to write my own language on both sides and deal with the data transfer timings and clock synchronisation. Instead, it'll be easier to use industry-standard RS-232!

I suppose this is a bit of a cop-out. I wanted to build something that was dated to the level of technology that existed back when these machines were in their prime... unfortunately my electronic knowledge isn't up to scratch... so getting to a variable 12v output wasn't overly easy. It also would not have been PWM. Due to all this, including the Arduino into the mix isn't such a bad idea. Plus, everyone I'd asked for help told me to do this... even sending me links to my own blog posts :)

DTE vs. DCE

Serial plugs have a single channel, with each end having one transmit (TX) and one receive (RX) pin. Each end will send data down the cable via the TX pin and expect to receive data on the RX pin. Standard serial cables are 'straight through', meaning that the TX pin is connected to the TX pin and likewise with RX. Doesn't quite make sense, does it? How are two separate devices meant to eachother if they are both transmitting down the same singular TX wire and hearing silence on the RX?

This all becomes clear once you realise that devices fit into two categories: DTE (data terminal equipment) and DCE (data circuit-terminating equipment, also known as data communication equipment.) In the end, these two devices boil down to one being the master (the DTE) and one being the slave (the DCE.)

Of course, you can purchase 'cross-over' cables for serial connections. These are known as null-modem cables and allow you to hook two DTEs together. Say, for example, you want to transfer a file from your PC to your Amiga, or somesuch!

In my previous serial project, when I connected the IBM receipt printer to the Arduino, I needed the Arduino to be the master, and so I hacked around until I had correctly configured it as a DTE. This time around we want the Arduino to be the DCE. Due to this, be careful to follow the pinouts and wiring from the serial port to the MAX232 in the circuits below!

Note: For further reading/wiring on RS-232, there's a good article at avr Programmers and another at Advantech.

C64 Serial Port

The User Port on the C64 also has serial connections. These are TTL and so need to be brought up to the RS-232 5v standard. The MAX232 IC will do this for us quite easily. We'll also use one at the other end for the Arduino.

C64-RS232

The circuit is derived from 8bitfiles.net. This circuit was also correct in that the pins are wired up as DTE. This means that you could use it, as-is, to also hook to a modem or any other DCE device.

The MAX232 needs few extra components. Fortunately, these extra components are identical on both ends, so buy everything in duplicate! The capacitors are all 1.0uf electrolytic. I used 1k resisters on the LEDs so as not to draw too much current from the User Port.

Arduino Serial Port

This is nearly the same circuit as the C64 end. The funniest thing happened here... if you google enough 'arduino max232' you'll just loop back around to my post, from ages ago on interfacing an IBM printer to the Arduino. Just make sure you don't use that circuit! It's DTE, we need DCE as per below! I've left out the RTS/CTS as I don't intend on using any form of handshaking in this project. It's still in the circuit above for the C64 so that you can use the port for other purposes.

ARDUINO-RS232

As per usual, make sure you DO NOT apply 5v in the wrong direction... I did and it ruined a few caps and possibly the IC. Garbage then came through the serial port. If this ever happens, then throw out the components and start again; you'll never be able to trust them.

Also make sure that you use the 5v pin on the Arduino. AREF is NOT a valid voltage source.

Hooking it all together

Build both circuits above and give one a male and the other a female db-9 connector. The DCE device usually gets the female, so put this on the Arduino-side!

DSC03947 DSC03956 DSC03954

DSC03955 DSC03950

If you want to roll your own cable, then grab some grey IDC and two crimp-style plugs. Just make sure that you have pin 1 matched to pin 1. If you're splitting the cable, then paint a wire (or use a marker) to ensure that you get the orientation correct. It's really easy to confuse pin 1.

DSC03998 DSC04000 DSC04002

From above, you can see the pin numbering. I slid the second port all the way to the end, prior to crimping, to ensure that the numbers matched up. Using the red '#1 wire' on the cable worked wonders too.

Testing with Strike Terminal 2013 Final

Download Strike Term 2013 Final from here and then get it to your C64. I copied the D64 to my SD2IEC and loaded it up. Hit M and select User port. Hit b and switch it to 1200 Baud (or other baud, depending on what you've configured in the Arduino.)

DSC03976 DSC03978 DSC03957

DSC03958 DSC03964 DSC03965

Once ready, hit f5 and then hit enter on the default server. This'll start sending modem AT commands down the serial and they should start showing up at the other end. Either open the Arduino Serial Monitor... or edit the code to display it. I bought some 8x8 LED Matrices to render the data coming in.

DSC03963 DSC03971

There were no real caveats here... everything just worked! Press f3 to get to the terminal. Hit commodore+e for local echo and then commodore+i to 'send id'. You should now be able to type freely... everything will be sent down the wire.

DSC03983 DSC03984 DSC03985

DSC03986 DSC03987 DSC03988

At that point I only had one matrix... so the last char typed was displayed.

Writing C code to use the Serial Port

Nanoflite has written a 2400 baud User Port Serial Driver for cc65. I originally tried to use this at 1200 baud, as that's what I'd been using everywhere and heard it was the max the User Port was capable of. It turns out that this driver only supports 2400 baud! Download it and put the source somewhere.

Switch to the driver directory and compile it:

cl65 -t c64 --module -o c64-up2400.ser c64-up2400.s

Copy this to the folder that has your source file it. I slightly modified the example.

#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <serial.h>
#define DRIVERNAME  "c64-up2400.ser"

static const struct ser_params serialParams = {
    SER_BAUD_2400,      /* Baudrate */
    SER_BITS_8,         /* Number of data bits */
    SER_STOP_1,         /* Number of stop bits */
    SER_PAR_NONE,       /* Parity setting */
    SER_HS_NONE         /* Type of handshake to use */
};

int main (void)
{
  int xx;
  
  clrscr();
  puts("C64 serial ...");

  // Load driver
  ser_load_driver(DRIVERNAME);

  // Open port
  ser_open(&serialParams);

  // Enable serial
  ser_ioctl(1, NULL);

  for (xx = 0; xx < 10; xx++) {
	ser_put('C'); 
	ser_put('6'); 
	ser_put('4');
	ser_put('.');
	ser_put('.');
	ser_put('.');
  }
 
  return EXIT_SUCCESS;
}

Compile this:

cl65 -t c64 -O -o trainctl2 trainctl2.c

I then put it on the SD2IEC and loaded it via LOAD "0:TRAINCTL2",8 followed by a RUN.

DSC03993 DSC03989 DSC03991

DSC03992 DSC03994 DSC04003

Shit... worked... this is great! Next it's time to put a PWM throttle onto the Arduino and control it from the Commodore... I'll tinker with graphical programming in C also.

Comments (11) Trackbacks (2)
  1. Hello,

    Why it is necessary to invert CTS ad RTS ?

    Thanks in advance for your help !

    Regards

    • Hello Yoruk,
      The circuits were taken from the link provided directly under the images.
      Unfortunately, it’s been such a long time that I don’t remember the exact reasons for the inversion.
      I’d go with just trusting them ;)
      Steven.

  2. Hi,

    The DB9 in the C64 serial diagram (the 1st diagram), is that a FEMALE DB9 or MALE DB9? I am building one.

    • Hi AL,

      That’s entirely up to you. It depends what you want to connect to. If you have long enough IDC cable, then you can make it female to plug straight into a PC.
      If you want to use a standard modem serial cable, then, actually, it should also be a female.

      Steven.

      • Thanks, Steven! Female it is! I just downloaded the CC65 compiler. Will try things out.

        Sorry to have forgotten to ask this previously, but I made the board exactly based on the schematic (the first diagram). You mentioned that this schematic is derived off the one from the one at ftp://8bitfiles.net/archives/genie-commodore-file-library/CompSysCBM/070596H.TXT. I see that your diagram has pins 9 & 12 of the MAX232 swapped, respectively, to the 74LS00 and to the user port. Just wanted to confirm that is your intention.

        Thanks again!

        • AL,

          Good pick up. I don’t have a C64 anymore, but it would seem that I’ve mixed up 9 and 12. There’s no reason for the CTS to be mixed with RX.

          Please use the original. I’ll try and find time to fix the diagram above.

          (As per the comment further below, the diagram above is perfectly OK! Turns out that I just aligned the R1/T1 and R2/T2 on the MAX232.)

          Steven.

  3. Steven, actually maybe your diagram is OK?

    Please read https://www.engineersgarage.com/knowledge_share/max232-pin-out-and-description/. It says the MAX232 pins 9 (R2OUT) and pin 12 (R1OUT) act the same.

    Your diagram currently says:

    1) pin 9 of the MAX232 is R2OUT, and is connected to pins 4 and 5 of the 74LC00, which inverts the signal and is connected to the K pin on the C64 port.

    2) The MAX232’s pin 12 is connected to the RX (pins 7+B+C of the C64’s user port), and the TX connection is for pins 11 of the MAX232 and pins 5+6+L+M of the user port.

    So, I am not sure I understand that you mentioned you mixed the CTS with RX.

    If there is no problem, then I won’t have to cut the traces and patching wires.

    Thanks.

    • AL,

      Apologies, it was late last night when I was trying to review this issue for you. I’d written this article over 4 years ago!

      So, if you look at the source document, you can see they’ve used T1 and R2, which I must’ve seen as messy and re-aligned. Therefore my circuit uses T1/R1 and T2/R2.

      If you’ve modified your boards already, then you’ll also just need to swap the output wires. In the end the MAX232 is just a voltage converter, so just make sure the outputs are correct for the pins on the serial port.

      Steven.


Re: AL 's comment

( Cancel )

*