First I want to start by saying this. The harder the challenge, the greater the reward. I also want to take this time to apologize to Ladyada, the staff at Adafruit and the creators of the PS/2 Arduino library. I thoroughly hacked away at your code and made one hell of a mess of it. Thank you for your hard work.
Now that, that’s over, I want to reflect on my first statement which I said, “The harder the challenge, the greater the reward.” What I’m referring to is the small memory size that the Trinket (ATtiny85), has to offer. After the code for the boot loader, the amount of room available on the chip is only 5,310 bytes, which, although sounds like a lot, is not. This made for a great challenge, as I had never programmed for such tight memory constraints. Before this project, I had only programmed for devices with large amounts of resources (Like my Mega or a PC), and I was never faced with the challenge of fitting a lot into a small space. Completing (getting it to work) this project is my great reward.
The Back Story:
After receiving my first order from Adafruit, I was sitting at my desk staring at my three new Trinkets and wondering what kind of cool project I could build with them. I had a lot of idea’s but I wasn’t sure what I really wanted to do, so I went over to Adafruit’s learning system, and looked up the different Trinket projects they had. I thought that I might be able to draw inspiration from something they had done. That’s when I found the USB Keyboard project, a writeup on using the Trinket as a USB Keyboard. I thought that would be a cool project, though I didn’t want just two buttons as shown in the project. That is the point when I looked at my old PS/2 keyboard which I loved but couldn’t use with my laptop, and that’s when it hit me, I wonder if I could get the Trinket to bridge my Keyboard to USB?
To start, I downloaded and installed the PS/2 library for the Arduino. I then created a PS/2 cable bread board break out (see picture below), and wired it to my Mega, which I loaded with the Serial example. I wired everything up according to the directions in the library and I was able to get it to work.
The next thing I did, was setup my computer to use the Trinket. After which I loaded the TrinketKeyboard library and tested that out. This also worked. Now that I knew I was able to read the keyboard and that I was able to use the Trinket, I thought I was set.
What I did next was simple, I created a new sketch with both library’s in place, along with the bare minimum amount of code needed to use each function. I knew that there was not a lot of memory available to me so I wanted to know if the code would fit. Little to my surprise, it didn’t and the compiler throw all kinds of errors.
The size of the code was too large to fit so I needed to find a way to cut down the code size as much as I could. I started with the PS/2 library. I just went to town, anything I thought I wouldn’t need got cut. I figured out which were the important functions that made everything work and all the extra functionally stuff was removed. I then repeated the process for the USB Keyboard library. Any code that was there that I felt didn’t need to be for my project was cut.
I ended up with code that resembled Swiss cheese in comparison to what I started with, but I did end up with something that was small enough to fit in the Trinket’s limited memory.
When I started out with this project, my thought was, that I could take the output of the Keyboard.read() function and feed it right into the TrinketKeyboard.pressKey(0,0) function. In my mind, I would be able to use the (remaining) power of both library’s to convert the PS/2 Keyboard scan codes to USB Keyboard scan codes. My thought was wrong.
After I wired up my breakout board to the Trinket (see wiring below), and uploaded my code, and I tried to type something. I did get an output, but it was random characters. To understand why this was I delve into the library’s to get a better understanding of how they worked. After reading thought all the lines of code, and cross checking PS/2 scan codes, it hits me, maybe usb keyboards have different codes.
I did a quick Google search and I found this to be the case. This meant that the codes I was feeding into the Trinket’s USB keyboard function were the wrong codes and the reason I was getting the wrong output. I now had to think about how I could easily go from one scan code to the other with minimum memory usage. If there was enough memory, I could have just used the unmodified keyboard.read() function and pipe that into TrinketKeyboard.print() as the output of read was just a character, and the print function was able to output characters. Unfortunately, after looking over the code required to use print (I had cut it out before to save space) there was just no way.
What I ended up doing was changing the read function to output the raw scan codes from its look up table and inputting that into the presskey function. I then changed the scan codes in the table to match the ones for a USB keyboard. I uploaded this code and it worked!
Right now, not all of the keys work, as I didn’t map all the keys out, and it only works for lowercase numbers as I didn’t created a way for key modifiers to get past to the Trinket library, but even with all these short comings it still worked. This is why I’m calling it a hacked converter, being that its just hacked together and doesn’t work fully. Still, I wanted to use my PS/2 keyboard with my laptop and now I can!
Here is a short video showing off the results:
No GitHub this time around, the code it just too all over for me to upload it there and I’m not sure what I’m going to do next with it, if anything at all. So for now here is a Zip with the ino file and the library’s I hacked away at. Simply load the library’s the same way you would any other Arduino library.