Saturday, October 11, 2014

Go for....C64

My first computer was a TRS-80 Model I. I still have fond memories of this black and grey box with it's black and white screen, 128x48 monochrome graphics, 12" monitor and tape drive for data storage. Unfortunately we sold it when we got the twice as fast and portable Aster CT-80 (4 Mhz clock, two floppy drives!). Only for sentimental reasons I'd love to own one now., but  they are quite rare and therefore relatively expensive on eBay...
Anyway, I always kept a weak spot for these all-in one keyboard computers like the TSR-80, Atari 2600, VIC-20 and of course the Commodore C64. According to Wikipedia 12 to 17 million of these units were sold at the time making this a lot less rare.
 (An uncertainty of 5 Million ? That's so weird there are even special pages dedicated to this mystery..)

Anyway, 12 million or more seems to be enough to saturate the demand even 30 years later and complete systems can be bought for 50 to 100 Euro's. Actually I own a complete system myself. It's a complete, working set including an original tape recorder and diskette drive. I might have to wipe the dust off and find a suitable TV-set to check if it's still 100%. In the meantime I thought it was a nice idea to have just an empty C64 housing with keyboard and use that as a keyboard for my PC. Or maybe mount a Raspberry Pi inside to turn it into a working Linux computer. Or connect it to a tablet running a C64 emulator like C64.EMU .

[ As usual, I'm not the first to think about this and there is even a complete interface for sale: the Keyrah V2. Better (or worse..) there is even an Etsy shop that has Commodore and many other computers converted to USB keyboards. But that's what I consider cheating. At least some hacking has to be done or it would be too easy ! My first thought was to use the Arduino Micro. While building my MAME cabinet I already discovered that this would have been the easiest way to implement a virtual USB keyboard.  On the biosrythm blog there is already a complete description on how to use Arduino to get the C64 keyboard to USB, but he is using the Duemilanove . ]

I picked up an empty C64 from ebay.de for €30 and bought a Arduino Pro Micro for only €7,- (who said hobbies have to be expensive?)

 The cable that sticks out on the right is the keyboard connector that used to be connected to the C64 motherboard.
First we obviously have to find out how the keyboard is actually wired. I found a neat diagram on the 'WaitingForFriday' blog:

Corrected C64 Keyboard matrix and keyboard connector diagrams  
Great, but it presents and unexpected surprise: we will need 16 Input / Outputs for reading this matrix. And the Micro Pro only has 9 digital I/O pins. My first idea was to expand the number of I/O pins by using some shift registers but then I remembered I also had some PICAXE chips in my toolbox. The PICAXE is a standard PIC micro-controller, pre-programmed with a Basic interpreter which makes programming real simple.And the PICAXE 28X2 has 16 freely configurable I/O pins so that should work fine.

This chip even has all the I/O pins nicely laid out,making it easy to route the connector to the chip.
Some soldering will be necessary though to split out the connector in sections that will go to B0..B7
C0...C3 and C4...C7.
 Unfortunately this does not work. The PICAXE does not have any pull up or down resistors on its pins, so when no key is pressed they are all floating which results in random values.Adding a 10K pull up resistor to each input solves this problem immediately.
It's still a lot of puzzling to detect the right keys, certainly in combination with the  left-shift, right-shift or Commodore key but you can find a complete working version of the PICAXE software at the end of this page.
But since the PICAXE lacks an USB output we still need the  Arduino Pro Micro to create a keyboard compatible output.
So the whole exercise has been a fun and useful learning experience, but in hindsight it would have been easier to use the Arduino Leonardo... After all, this is a Pro Micro, but with plenty I/O to implement everything on a single board.


 
'Commodore 64 Keyboard Decoder. Columns (A..H) connected to Port B. Rows (1..8) to port C
'Both ports have 10K Pull up resistor on each pin


main:
symbol ROWS = b1
symbol COLUMNS = b2
symbol ROW = b4
symbol COLUMN = b5
symbol KEY =b6
symbol CHECK_ROW = b11
symbol CHECK_COL = b12
symbol TEMP_SUB = b13
symbol TEMP_SUB1= b14
symbol SPECIAL_KEY_PRESSED = b15
symbol RIGHT_SHIFT = b16
symbol LEFT_SHIFT = b17
symbol CTRL =b18
symbol PREVIOUS_KEY =b19
symbol KEY_COUNT=b20
symbol KEY_DELAY = b21

PREVIOUS_KEY = 0
KEY_DELAY = 100
do            ; Endless loop
 let dirsC = %11111111 ' switch all pins to outputs
 let dirsB = %00000000 ' switch all pins to inputs
 let pinsC = %00000000 ' switch all outputs low 
 b1 = pinsB 
 let dirsC = %00000000 ' switch all pins to inputs
 let dirsB = %11111111 ' switch all pins to outputs
 let pinsB = %00000000 ' switch all outputs low 
 b2 = pinsC
 
 b3 = NOT b1
 ROWS = NOT b2
 COLUMNS=b3

 'sertxd("B1,B2: ",#b1," ",#b2,13,10)
'Check if Left Shift is pressed 
 CHECK_ROW = %00001000
 CHECK_COL = %00000010 
 gosub CheckRowCol
LEFT_SHIFT = SPECIAL_KEY_PRESSED 
'Check if Right Shift is pressed
 CHECK_ROW = %00010000
 CHECK_COL = %01000000 
 gosub CheckRowCol
RIGHT_SHIFT = SPECIAL_KEY_PRESSED 
'Check if Right Shift is pressed
 CHECK_ROW = %00000100
 CHECK_COL = %00000001 
 gosub CheckRowCol
CTRL = SPECIAL_KEY_PRESSED   


 ROW = ncd ROWS
 COLUMN = ncd COLUMNS
 'sertxd("B1,B2,ROW,COL: ",#b1," ",#b2," ",#ROW," ",#COLUMN,13,10)
if ROW=0 or  COLUMN=0 then goto reset_keycount
 ROW = ROW-1
 COLUMN = COLUMN -1
 b0 = 8*COLUMN + ROW
 if LEFT_SHIFT =1 OR RIGHT_SHIFT=1 then goto Shift_pressed
 
  lookup b0,("1",8,"cr cq23wa~zse45rdxcft67ygvbhu89ijnmko0+pl,.:@-$*;/~=???",13,"?ffff"),KEY
 goto Key_Pressed
 Shift_pressed: 
       lookup b0,("!",8,"cr CQ",34,"#WA~ZSE$%RDXCFT&'YGVBHU()IJNMKO0+PL<>[@-$*]?~=???",13,"?ffff"),KEY
 Key_Pressed:
 'sertxd("KEY PRESSED!",#ROW," ",#COLUMN," ",#b0,":",b1,13,10)
 if KEY = "~" then goto continue     '~ marks an unprintable character (Only Shift is pressed)
 if KEY = PREVIOUS_KEY AND KEY_COUNT < KEY_DELAY then goto count_keys
 if KEY_COUNT <> KEY_DELAY then goto normal_delay
  KEY_DELAY = 3
      normal_delay:
 KEY_COUNT =0
 sertxd(KEY)
 serout A.0,T9600_8,(KEY)
 PREVIOUS_KEY = KEY
 goto continue


count_keys:
 KEY_COUNT = KEY_COUNT+1
 goto continue
reset_keycount:
 KEY_COUNT=0
 KEY=0
 PREVIOUS_KEY =0
 KEY_DELAY = 30
  
continue: 

loop   ; next loop

CheckRowCol:
SPECIAL_KEY_PRESSED = 0
 TEMP_SUB = ROWS and CHECK_ROW       'Check if a specific bit in ROWS is set
 if  TEMP_SUB = 0 then goto NotPressed
 TEMP_SUB = COLUMNS and CHECK_COL    'Check if a specific bit in COLUMNS is set
 if TEMP_SUB = 0 then goto NotPressed
 TEMP_SUB = NOB ROWS                    'Bit in ROWS and in COLUMNS found. Check how many bits in ROWS are set
 if TEMP_SUB = 1 then goto no_bit_reset 'If it is just one bit, do not reset it
 TEMP_SUB = NOT CHECK_ROW          'Invert all bits in the CHECK_ROW
 ROWS = ROWS and TEMP_SUB               'AND it with the ROWS to reset the bit we just found 
 no_bit_reset:
 TEMP_SUB = NOB b2
 if TEMP_SUB = 1 then goto no_bit_reset_2 
 TEMP_SUB= NOT CHECK_COL  
 COLUMNS = COLUMNS and TEMP_SUB 
 no_bit_reset_2:  
 SPECIAL_KEY_PRESSED = 1
NotPressed:
 
return