I'm heading to the
Midwest Vintage Computer Festival and
Fall Commodore Expo this weekend and wanted to bring something down to show-off. I grew up with an Apple ][, but today I still enjoy retro computing - I particularly enjoy finding new ways of interfacing new technology to these old computers. In college I saved a Commodore 64 out of the garbage bin, and the first time I ever used a soldering iron was to make a serial cable between my PC so I could get the Commodore 64 on the internet. I lost that Commodore 64 a few years ago, but recently I've upgraded to it's big brother the Commodore 128.
One piece of software on the Commodore 64 that I always liked was GEOS. However, I never really had a mouse to go with it, in particular the Commodore 1351 mouse. You could use a joystick to control the cursor, but I want the real thing. A while ago I was looking at the specifications of the mouse and how it worked, and I thought I could make a USB to 1351 converter. Lots of people have made a PS2 mouse to Commodore 1351 mouse converter, but I hadn't seen a USB one.
To summarize how the 1351 mouse works, it sends X and Y location to the computer by varying the duration of a pulse on the X and Y line. The computer starts grounding the X and Y line for 256us to discharge any holding capacitors on the line, and then the computer floats the line for 256us. At the period where the computer floats the line it starts looking for the mouse to pull the line up, the duration between the time the computer floated the line and the mouse pulled the line up is the new position location. The computer then performs math on the previous position and the new position and determines the delta of movement. If one of those 512us cycles is missed by the mouse, then the mouse position will be calculated incorrectly and the mouse cursor will jump - meaning there are some strict timing rules.
To create this USB to 1351 converter, I started with a PIC24USB Development kit from
CCS. This development kit has everything you need for developing USB host applications, like a 5V 1A regulator for powering USB devices. I replaced the PIC24 that was on the board with a Microchip dsPIC33EP256MU806. It's pin compatible with the existing board, and the EP family can run at 70MIPS while handling USB (the PIC24 is limited to 16MIPS when handling USB). For software development I used the CCS C Compiler - I've been using it for years and have gotten addicted to all the libraries it provides, and the IDE runs well on my low performance netbook.
The 1351 Mouse connects to the Joystick port of computer, which runs at 5V. The dsPIC runs at 3.3V. So I created a small daughter board that plugs into the development kit that has two 4 channel buffers and a DB9 port for the joystick port of the computer. I probably didn't need two 4 channel buffers, the up/down/left/right/fire controls on the port I could have connected to a 5V tolerant pin on the PIC and just floated/grounded the pin for control. The X and Y lines are the only ones that really need the buffering as they require 5V output from the PIC.
I did make a mistake in the design, hence the jumpers above. I originally tied output re-programmable pins to the latch pins of the buffer - but then I realized I want to use the output compare pin to control enable pin of the buffer (to toggle between floating and 5V). The pins I had tied to the enable pins of the buffer were not re-programmable to the output compare peripheral, so I had to swap some. The schematic above is correct.
To recreate the 1351 Mouse on the PIC, EXT1 interrupt pin and two output compare (OC) pins were used. OC peripheral pins were tied to the X and Y enable pins of the buffer. The EXT1 interrupt pin was tied to the X line directly on the DB9 connector of the joystick - that means this pin has to be 5V tolerant. EXT1 interrupt was used to detect when the computer pulled the line low, at which point the X and Y OC pins were primed to create a rising pulse at the desired position. The X and Y lines are floating during the time between the computer floating the line and the OC fired to bring the line high. While it's floating the voltage was hovering around 1-2V, kind of an intermediate state for the input buffers for the PIC so this was causing spurious EXT1 interrupts. So after the OC is primed, I had to turn off the EXT1 interrupt and then turn on the OC1 interrupt. Once the OC1 interrupt fired, then the OC1 interrput got turned off and the EXT1 interrupt turned back on.
To handle the USB and controlling the mouse I used Microchip's USB stack. Reading through the code in the stack, it was pretty smartly written in how it can determine from the HID descriptor which bytes in the HID report are the cursor position and which bytes are the button press indicators. They also provided a demo mouse program, of which I used and added a few key calls to my new 1351 library. It worked pretty much right away but there was occasional glitches - I am guessing it's because the USB stack used interrupts and that was interfering with the interrupts in the 1351 library (and it's strict 512us timing). I was about to turn on nested interrupts and make the 1351 interrupts a higher priority, but then I realized it's probably easier to just poll the USB in the main loop instead of using USB interrupts. Microchip didn't provide this feature, so I made some modifications to their Stack to support polling instead of interrupts. USB interrupts out of the way, mouse movement and cursor position was glitch free!
Happy computing!