To get my feet wet with AVRs, LUFA, and USB HIDs, I decided to throw together a little, plastic piano keyboard that acts as a USB keyboard.
It isn't going to be fancy, for a number of reasons:
1. The keys are from a Casio SA-38 (no big loss, believe me).
2. It only has the one, fixed keymap (currently targeting the OpenMPT* default keys).
3. It only supports the standard USB 6-key roll-over.
LUFA-compatible AVR board
(I'm using a "PS3opendous 1.3" I built from a kit sold by eBay user "nooelec").
The keyboard I'm using is arranged in an 8x4 matrix, with "anti-ghosting" diodes.
Well, if this project wasn't in "hack territory" before – despite an actual hacksaw already having been part of the process ;) – it's definitely there now!
Yesterday, I removed all 32 "anti-ghosting" diodes, and reinstalled them the other way round (except for the one I broke, which I replaced with one from the ol' junk bin). I did this for a couple of reasons:
Due to the AVR only having pull-up resistors available on the inputs, the diodes forced me to scan the eight columns, and read the four row inputs, meaning each complete scan took eight iterations of a for loop. Now that the columns are connected to inputs, I can scan the rows, which results in a loop with only four iterations – a 50% speed-up!
Using the simplest wiring layout, the keyboard is logically laid out as rows of columns. By scanning the columns and reading the rows, I received every eighth key, compressed into a nybble. I didn't technically have to, but to make the key-code map easier to edit, I was unpacking these nybbles to represent consecutive keys as consecutive bits. I suspected that this was the source of my "shifted-columns" problem (although I still have no idea what, exactly, was causing it).
With the above changes to the hard- and firmware complete, it works great! As for the source, I think I'll skip github and just share an archive of the four files that differ from the LUFA keyboard demo (Demos/Device/ClassDriver/Keyboard in the LUFA package, at time of writing) and the .hex file (although, according to various web searches, I appear to be the only person on the planet still using an AT90USB162 at all, much less this particular carrier board :P).
Since I can't attach (non-image) files to the Hackaday.io project, and I don't want to maintain the file on an external hosting service, and the file is so small, I'm going to include a Base64 encoded version of "usbiano.zip" at the end of this post.
To use it:
Build the hardware
Download and install WinAVR
Unzip it into a folder called "LUFA"
Copy the keyboard demo folder mentioned above into the folder containing the above "LUFA" folder
I know… Thurs was quite a few days ago. I did get the headers then, and I even used them to rig up the new cables the same day. As you can see in the spiffy new photo, I decided to use separate cables for the columns and rows; one 8-pin, and one 4-pin, respectively. This was useful when I moved the rows to port C as a test (which, unfortunately, didn't solve any of my problems). Since this isn't the final resting-place of either the keyboard or the dev. board, it'll also make the reuse of either one much easier.
On the software side, I flipped the keymap the right way round, so that part's working better. I also solved a problem I was having which I didn't mention in the last log entry. Every key was sending a keystroke, but the entire right half of the keyboard was sending the same keystroke. I thought this was just a couple of row lines not making connection, and it would be fixed when I added the new cables/plugs. When I tried it out after the hardware update, it was still happening. I eventually tracked it down to the compiler defaulting to a 16-bit data type, when I need a 32-bit. So, that's fixed, and I get a different keystroke for every key, but the "rotated one column to the left" problem is still there.
Here are some things I've checked:
The pins on the board are indeed the pins they claim to be on the actual AVR chip.
The pins on my added connectors correspond with the switches according to the PCB traces.
This leads me to the inevitable conclusion that there is something amiss in the software, but I cannot figure out what it could be. If I'm shifting the wrong number of places, it seems like the "upper" column bit would be lost, not magically wrapped around to the "lower" column! If it was an "off by one" error in the switch-to-keycode map, the whole keyboard would be shifted, not each individual row! It's maddening! (And it's even more maddening knowing that it's something extremely simple that someone with more experience will spot immediately…)
Anyway, that's where I am now. I could start using it now, if I readjusted the key map to compensate for the key rotation, but I really want to know why it's doing that, rather than just cludge a work-around. I'll work on getting the code up on github, ASAP.
Well, I loaded the "alpha" firmware, temporarily connected the keyboard, and fired it up. No magic smoke was lost (not that I was expecting any, since the board worked fine with the LUFA joystick demo), and it enumerated as a keyboard.
I pressed the low "F" key, and… I GOT A KEYSTROKE! Of course, it was the wrong one… but, hey, at least it's something, right?
It turns out I
got the key-map "end-for-end", despite drawing a really nice diagram of the rows and columns. Something slightly more odd is the fact that each "row" is rotated one "column" to the… left, I think… yeah, left. I'm assuming this is a software problem, since the matrix is very straight-forward, but I can't figure out why it's happening. Once I get the source posted, I'd appreciate some more eyeballs seeing what I'm missing and letting me know about it.
First, though, I have to get the keys properly connected to the board. I've ordered some single-row, male headers from fleaBay. I'm going to replace the tiny piece of ribbon-cable on the keyboard with a longer one from an old floppy cable, and put some pins on the other end. I'm going to put another set of pins on the AVR board. Then, I'm going to plug both sets of pins into a breadboard socket. Easy-peasy. They're estimating Thurs. for delivery of the headers, so I guess I'm on-hold until then (which will give me time to github-ify my code, and maybe post some pictures).