I recently wrote a couple of programs that connect a PC and a Commodore 64 with an Arduino doing the translation in the middle: The C64 talks to the Arduino with SPI (Serial Peripheral Interface), and the Arduino talks to the PC with its usual serial-over-USB. On the PC, a terminal program can send text to the C64 and receive a response. This may be one of those projects where the first question isn’t so much “how” as it is “why?”. It’s kind of a long story.
I’ve spent the last couple weeks talking about the hardware side of my Project:65 computer, but I’ve also been thinking about software. Not application software, yet, but just programs to test the system and make sure it’s working correctly. One thing’s for sure: while hooking LEDs up to the address lines is a cute trick, I’m going to need a better method of communication.
I decided early on that I’d use a WDC 65c22 VIA for my first attempts at input and output. The VIA – that’s “Versatile Interface Adapter” – is a modern version of the MOS Technology 6522 that was used in the Commodore Vic-20. It features a couple of 8-bit parallel ports, a shift register, and a couple of timers. It’s a predecessor to the 6526 CIA (“Complex Interface Adapter”) that was used in the Commodore 64.
Then I had to decide how I was going to use it. The classic thing to do with this sort of headless machine is to add an RS-232 serial port and hook it up to a dumb terminal. Of course, I don’t actually have any dumb terminals anymore, and my current PC doesn’t even have a serial port, though I do have a USB to serial adapter in a box somewhere. I think.
Poking around online, I decided maybe that wasn’t the best approach anyway. While everyone agrees that you can do serial output with a 6522, nobody seems to recommend it. Especially not anyone with Vic-20 telecommunications experience. It apparently requires pretty good interrupt-based code to get even modest speed out of that interface without dropping characters.
I decided instead to do something quick and dirty, and come up with a better solution using more sophisticated hardware once I knew I had a functioning system. The quickest and dirtiest thing I could come up with was SPI – the synchronous serial interface I’ve used in a variety of previous projects. I’d used SPI on the C64 to talk to an analog to digital converter. I figured I could use the same technique to talk to an Arduino, and then let the Arduino send information back and forth to my PC.
Even so, this was going to involve a lot more code than any of my trivial tests, and I quickly realized that I was going to have to get both the 6522 and the RAM in the Project:65 computer working to pull this off. With two untested hardware elements to worry about, I decided I needed a more stable platform to develop the software on. That led to this week’s project: getting a C64 to work as an SPI master, sending text back and forth to an Arduino SPI slave.
On the C64 side, I needed to keep things simple so that my code would be portable to Project:65. My earlier experiments with SPI used the C64 User Port, which is connected to one of two 6526 CIA chips. The CIA isn’t exactly the same as the VIA, but I was only going to be using one of the parallel ports, and those parts of the two chips are mostly the same. The register layout and the location of the chip in the computer’s memory map is also different. I haven’t even figured out all the details of Project:65’s memory map yet, but as long as I didn’t hardcode any addresses in my software I didn’t figure that would be a problem.
I started with my code for talking to the MCP3008 ADC, and modified it for text and two-way communication. I used a very primitive polling technique, where the C64 sends a character and receives one back simultaneously. Of course, a lot of the time those characters will be ASCII 0’s – the NUL character – which will be ignored on the receiving side. I also fixed up the timing of that code a little bit – in my original version, I was always receiving bits one clock cycle off from when I expected them. This video at Sparkfun.com helped clarify my understanding of the timing situation.
The logic on the C64 side looks something like this:
byte current_character byte character_buffer[40] while true { // send the current character and receive a new one current_character = SendAndReceive (current_character); if current_character is newline or carriage return { current_character = NUL SendString ("\nYou said \"") SendString (character_buffer) SendString ("\"\n") clear character_buffer } else { append current_character to character_buffer } }
So, for sake of testing, it does two things. The first is that it echoes most received characters back to the sender – useful if you expect the sender to be a terminal program. The second is that it stores the received characters in a buffer, and when it receives a newline it sends the whole buffer back with some explanatory text. I figured this would be a good way to both shake out the protocol and, when this eventually runs on Project:65, test if the memory is actually working like it’s supposed to.
The Arduino side was a little tricky. Remember, I was planning this with the C64 as the SPI master and the Arduino as a slave device – but the Arduino SPI library and its documentation is written to expect the Arduino to be the master. Google turned up these posts by Nick Gammon that explained how to set up the Arduino as an SPI slave.
The Arduino side is interrupt based, so that it can respond quickly to the SPI clock which is controlled by the C64. It simply uses a couple one-byte buffers to communicate with the non-interrupt-driven loop() part of the Arduino sketch, which sends and receives information from the PC using the Arduino’s serial library.
The resulting code is a little graceless – the C64 side does a lot of manual bit-banging and is probably terribly slow, while the Arduino code has some hopelessly kludgy buffer code that I got bored with before I got it working correctly – but the important thing is that the communication actually happens, as you can see in the screenshot. There are some occasional glitches when one or the other system is starting up – if I go anywhere with this longer term, I might need to add some more formal handshaking. I think I’ll worry about that when the need arises.
One I got the code running, I decided to have a little fun with it. I changed the C64 side to accept input characters both from the SPI bus and from the C64’s keyboard – so I could type on the C64 and have my characters show up in the terminal window on the PC. That, of course, led me to thinking about PETSCII – Commodore’s slightly weird variation of ASCII. PETSCII dates back to the original Commodore PET, released in 1977. It originally featured capital letters and the special Commodore graphics characters – all those little figures on the sides of they keys on a C64.
The character set was later modified to include special characters that did things like change the text color. In C64 basic, strings can contain all of these special characters that you type with a variety of modifier keys. Of course, nobody but another C64 would understand them. Terminal software like PuTTY uses a different set of control characters – ANSI codes – which were commonly used on BBS systems back in the 80’s.
Just for fun – because I have no intention of doing this for Project:65 – I added some translation code to the Arduino software, to translate some of the PETSCII special characters into their ANSI equivalents. That’s how I got the multicolored text in the screenshot.
switch (newbuf[i]) { case '\n': Serial.println (""); break; case 28: // red Serial.print ("\x1b\x5b""31m"); break; case 5: // white Serial.print ("\x1b\x5b""37m"); break; case 145: // cursor up Serial.print ("\x1b\x5b""1A"); break; case 17: // cursor down Serial.print ("\x1b\x5b""1B"); break; case 157: // cursor left Serial.print ("\x1b\x5b""1D"); break; case 29: // cursor right Serial.print ("\x1b\x5b""1C"); break; default: Serial.print(buf[i]); }
There’s a lot of work to be done before I can run this code on Project:65. I need to get the 6522 hooked up, as well as the RAM. And I need to finalize the memory map and devise the memory decoding logic that will control access to the VIA, RAM, and ROM. I’m just starting that process, and I think it’s going to be the most challenging part of the whole build.
I’ve put up the source code for both the Arduino and Commodore 64 sides of this project for those who are interested. It’s not exactly ready for prime time, but it gives an idea of the experimental process of late-night weekend computing projects like this.
Update: The source code for this project is now available as part of my c64-projects github repository.
Pingback: Communication between Arduino and a Commodore 64 « freetronicsblog
Hi,
This was really useful but I have gone down the rs232 route using this scematic http://ilkerf.tripod.com/chard/rs232c96.txt
It isn’t working… at the moment. I was wondering if you knew how to bypass the CTS handshaking bit that I think my arduino is having trouble with. I may be barking up the wrong tree with that though and it is entirely possible my BASIC code is letting me down (I have not learnt ASM yet). I only want to arduino to recieve and never send.
Thanks for any help with my poorly explain problem.
I’ve only looked at CTS/RTS handshaking a little bit, so I’m not sure I can be much help. I’ve been using a Max3100 to convert SPI to RS-232, but I’ve ignored handshaking so far and only connected Rx, Tx, and ground signals. You could try turning off handshaking and see what happens – you’ll probably drop some characters, but not all of them.
I’d guess BASIC on the C64 might be a bigger problem, though – you just might not be able to get the timing accurate enough for the other side to understand it. That was the main reason I looked at synchronous communication. It freed me from having to worry about any of the timing constraints.
Thanks, I found a solution. First off I had RX and TX wires mixed up in code….. 2 hours to figure that tiny thing out, doh! Still it tuns out handshaking was an issue, the c64 was waiting for the arduino to become ready. I solved this by looping back (Loop back handshaking) the CTS and RTS wires so they connect to each other on the same device. This meant I both are always ready to send if they are not recieving chars and ready to recieve if they are not sending. I am getting a reliable 300 baud, fine for the amount of chars I want to send but it worked fine on 1200. It hasn’t dropped a char yet. I did figure out that the signal needs to be inverted on the arduino end though, weird things happen otherwise.
I really like your blog, I will definately try my hand at ‘bit banging’ but for now I am familiar with rs-232.
My first stop is a c64 twitter client and then is it web feeds.
You should create a YouTube channel, David 😉
Hello
Very nice project. Unfortunately, the Dropbox link isn’t working anymore. If you still have Arduino & Commodore source code around could you sent it to me? I would like to give this a try 🙂
BR
Boris
Still down in 2023. Would you be able to upload to GitHub?
Done! (Finally!)