So I’ve started playing Mech Warrior Online recently and noticed the huge amount of key bindings required to adequately control a mech. That inspired me to design and build a custom controller that would allow me to easily configure and switch between different key layouts on the fly. And so I designed and built a 26 key, touchscreen equipped controller.
There are 22 keys, one push button and three flip switches. Two of those 22 keys are exclusively used to switch between different key layouts (from here on called profiles), that leaves 20 keys, one push button and three flip switches freely programmable via a comfortable touchscreen UI. The touchscreen is a 3.2″ 400×240 pixel widescreen LCD from iteadstudio http://imall.iteadstudio.com/display/im120419006.html . It comes on a breakout board with 2×20 pin 0.1″ header, SD card slot and controller for the touchscreen. The SD card is used to store the graphics for the UI as well as the configured profiles for the keypad.
The UI displays a 5×5 matrix (25 keys – potentially), but since 2 of the buttons on the pad are exclusive for profile switching only 24 buttons of that matrix are really configurable. So the first row configures the flip switches and the push button, leaving the last button in that row unused, while the remaining 5×4 matrix resembles the actual keys on the pad. Next to the 5×5 matrix is a menu that allows to:
- configure the current profile (assign new scan codes to the keys)
- add a new profile (takes you right to the configuration screen)
- save changes to the current profile
- load a profile from disk
On this main screen it is possible to switch the position of keys around. Like if you notice during a game that some key binding is more important than you thought, but is currently inconveniently placed, you can switch its position with that of another key binding that has a more convenient position by simply touching both keys on the screen in order (this is the reason why there is a save-button on the screen, so you can save these on the fly changes).
Conveniently the 5×5 matrix is always displayed throughout all the menus, only the sidebar changes according to required function. For example loading a profile displays the available profiles as a list on the 5×5 matrix, with buttons for flipping pages on the sidebar.
Currently the controller supports almost every key you’d find on a normal keyboard, except for the modifier keys (CONTROL, ALT, SHIFT, etc.)
The 22 keys on the keypad are salvaged from an old keyboard (a mechanical switch type keyboard obviously). Luckily I did the salvaging and soldering of the matrix 10 years ago for another project (building a keyboard that could be used with only one hand), so I only added the push button and the flip switches and was done with the keypad.
In this build I used every feature of the LCD board. With a 16Bit wide data bus for the LCD, SPI lines for SD card and touchscreen controller I used up almost every pin on a Teensy 3.0 board.
I originally planed on using 8Bit latches, to save 8 pins to maybe have a chance to also connect the 5×5 matrix to the same controller as the display. But the setup wasn’t really all that reliable. I don’t know if it were the cables (salvaged from an old IDE cable) or the IC’s, but it didn’t work right. The display crashed at random intervals, and somehow touching the SD SPI pins seemed to solve that problem. But I couldn’t figure out an electronic solution to this EMI problem and started to get frustrated, so I went with the easier solution of using two controllers, one for the display and one for the keypad, connecting them via UART.
Everything is powered via USB, fortunately both the Teensy boards and the LCD board have their own voltage regulators on board.
Wiring of LCD to Teensy 3.0
The Pins labeled with K_Tx and K_Rx are the UART Tx/Rx pins used to connect the two Teensy boards (the one controlling the LCD and the other one controlling the keypad). The K_Tx label means to connect the Keypad controllers UART Tx line and the K_Rx label means to connect the Keypad controllers Rx line to that pin.
The 5V pin on the Teensy is a direct tap to the USB supplied 5V power, so this Pin is directly conected to the LCD boards VDD Pin. The Teensys GND Pin is of course connected to the LCD’s GND Pin. Both lines also connect to the 5V and GND Pins (respectively) on the other Teensy. This way everything is powered from the same USB cable.
I used Teensy 3.0 boards for this task, programming was done with the Arduino IDE.
Now since I resorted to beat my EMI problem to death with the use of two controllers, I had to split up the original keypad-USB code (I’ve actually built just the keypad as an USB keyboard before I added the touchscreen UI part) into the keypad code (reading the 5×5 +1 button matrix and transmitting it over UART) and the USB code (transmitting USB keyboard scan codes for each key based on the current profile). The keypad code remained on the controller already connected to the button matrix. The USB code and of course the touchscreen UI code went on the controller connected to the touchscreen.
The keypad code is rather simple. I used the keypad library I found in the examples for Arduino and initialized it according to my pin configuration for the matrix. I had to desolder two of the rows of the matrix to other pins, since the hardware UART of the Teensy was on the same pins. So moving on to the touchscreen / USB part.
The USB code uses the USB keyboard library included with the Teensy part of the Arduino libraries. The USB keyboard protocol has some peculiarities. One can only send up to six keys at once and modifier keys are a different matter (those are sent with a different function; there can only be three modifier keys sent at once). Since I didn’t need the modifier keys (yet) I conveniently left them out of my programming considerations.
The code for the LCD board consists of multiple parts. There is the LCD driving code, which is mainly handled by the UTFT library which was modified by someone else (credits are in the library headers) to run on the Teensy 3.0 (the library was available from itedstudios, but for 8 Bit Arduinos), I merely adapted it to my pin configuration (that is after rewriting the parallel interface code to work with my 8 Bit latches before I abandoned that idea and started with the library from scratch). I originally intended to use the UTOUCH library for interfacing with the touchscreen controller, but couldn’t get it to work out of the box, so I stuck to the direct touchscreen communication example provided in one of the UTFT demos. I just had to adapt the calibration values (and pin settings of course) to make it work with my display. The calibration was more trial and error and for the purpose of testing I wrote a quick “draw on the touchscreen hello world” program.
The UTFT library hat a bitmap function (write raw bitmaps to the screen), but of course that didn’t have any SD integration. So I wrote my own function to load an image from SD card and directly write it to the display. I had to balance memory usage and performance on that one. So the code loads one line of the image from file and writes it to the display before loading the next line until the entire image has been drawn to the screen. It takes about a second and a half to display the background image (at the full 400×320 resolution), but the sidebar icons load really fast. Fortunately there is an online tool for the task of converting images to the raw image format required by the display (RGB565, 16Bit per pixel): http://www.henningkarlsen.com/electronics/t_imageconverter565.php .
I wrote the UI to be event driven. Touching the screen results in the code checking if the position of the touch intersects with any of the defined touch zones and if so, it triggers a function that processes the event based on the state of the UI. Each menu defines its own UI state in which touching the same area on screen will have a different effect. This method has the potential to work with lots of different screen layouts (just redefine the touch areas and attach different functions to them), but for the sake of UI responsiveness (remember, redrawing the background takes a lot of time) I kept the exact same layout throughout the entire UI. While the SD card holds the images for the UI, it also stores the profiles for the keys. Profiles have numeric names. The code checks how many profiles are in the profile folder and when I add another profile, the UI increments the counter by one and creates a new file in the profile folder with that number as a name. The files themselves contain a dump of all 25 keys (remember the matrix shows 25 keys on screen, while 24 are really on the keypad) for each profile. Each key is represented by a single Byte. The currently selected profile is saved in a special file on the SD card, so the last selected profile can be loaded upon power up of the controller.
This leaves some room for improvement, for example naming of the profiles and grouping them by games. But that’s something for later. For now I’m just happy that it works as intended. The source code can be found here: