Well it took about two weeks longer than I had planned but I finally have a PS/2 keyboard implementation!
My design places the bulk of the processing on the AVR itself; it decodes the variable-length PS/2 scan codes and translates them into single-byte key codes. The AVR sends all key-down events to the BIOS along with the modifier key state at the time. The key codes it sends are a super set of ASCII; codes with the high bit set are special keys that don’t have an ASCII equivalent (such as the Fn keys). It also maintains the keyboard LEDs when the user presses one of the toggle keys (Caps Lock, Scroll Lock, and Number Lock).
The Bad News
Unfortunately, my design is not very reliable.
The first problem is that I see odd garbage key presses occasionally. The AVR PS/2 receive code does not yet check the parity bit, so it’s quite possible these key presses are due to transmission glitches.
The bigger problem, however, are the hard freezes. After enough typing on the keyboard the system will eventually freeze until I reset the AVR. When this happens the AVR is still working; pressing any of the toggle keys such as Caps Lock will properly update the LEDs. That means the AVR is successfully receiving and decoding keys, and is able to send commands to the keyboard. The breakdown appears to be in the communication link to the rest of the system.
Back to the Drawing Board
My current implementation was an interesting experiment, but I feel like it may just be too fragile to ever be fully reliable. I need something simpler, even if it means making some sacrifices. So I’ve come up with a new design.
My new design is focusing on the keyboard, mouse, and game pads (yes, I’m moving those back to the AVR). Here’s a rough diagram:
The data link to the VIA has been reduced to a unidirectional link driven by a 74HC595 shift register. This frees up six pins and allows me to move the PS/2 clock lines onto the INT0 and INT1 lines (PD2 and PD3). These two lines give me more reliable detection of clock signal transitions. It also means there are enough free lines to move the game pad support back onto the AVR.
In this updated design the AVR will still decode the PS/2 scan codes into key codes, but it will no longer act on any of them; instead they will just be fed directly to the BIOS for further processing. Mouse data will come to the BIOS preceded by a special prefix byte, and the AVR will continuously scan the game pads and present those as key up/down codes as well.
BIOS to AVR Communication
If you’ve been paying attention you may be wondering what happens to the keyboard LEDs now, since all of the key state processing has moved to the BIOS and there’s no reverse comm channel in my diagram. I have two ideas for this; one is to use the VIA’s shift register, and the other is to use the second channel on the system UART.
Using the VIA shift register would give me a moderate-speed channel back to the AVR, over which I could then send commands to either the keyboard or mouse. I have no other plans for the shift register so this could make good use of some otherwise idle hardware. The draw back, however, is that it does not support any sort of framing or error checking so even one missed bit would throw the whole thing permanently of out sync. Since I’d be implementing the AVR side entirely in software I cannot rule out missing a bit here and there.
The UART channel is my preferred choice at the moment. I would be giving up the second serial port, but I would end up with a much more robust link. The framing bits would keep the link in sync, and the AVR has a hardware UART built-in so I wouldn’t even need to implement anything in software other than a handler for the data.
In all of this talk about the new design I’ve neglected to mention the hardware SPI functionality. I was fully prepared to sacrifice this feature in the name of simplification and reliability, but when I started thinking about hooking the AVR up to the UART I realized i can still have my SPI. Indeed this may actually be a better solution than my original design; I already have fully interrupt-driven serial support in the BIOS, and so long SD card block reads and writes can be streamed to and from the AVR entirely in the background. It’s sort of like a poor man’s DMA.
I’ve already implemented most of the hardware changes for this design (everything is done except the serial link). I’m also 75% of the way done with the AVR firmware changes. By this weekend I should be able to type on the keyboard again, hopefully with greater reliability than before.