Saturday 27 February 2016

Turning the Beaglebone Black into a joystick controller

In my opinion, this is the most interesting part of the project. And the biggest challenge for me.

First of all, have a look at your Beaglebone Black board. So many GPIO ports waiting idlely for some arcade fun! One of the advantages of the Beaglebone Black board over boards like the Raspberry Pi is that lots of GPIO ports are available, more than we need actually if we want to go the simple way: 1 button - 1 GPIO. And as a total beginner in electronics, I wanted to go the simple way!

I wanted to provide a 2-player arcade system (2x 4-way controllers), with enough buttons to emulate up to the Playstation generation (2x 8 action buttons, 2x start buttons), 1 button to "add coins into the slot", and 1 "exit button". 28 "buttons".

Setting up the GPIOs


We have to tell the Beaglebone Black that we will use 28 GPIOs as inputs, activating their internal "pulldown" resistors. This is done by setting a specific device-tree overlay, that tells the system how to configure its ports.
This is explained better than I could by Derek Molloy: http://derekmolloy.ie/gpios-on-the-beaglebone-black-using-device-tree-overlays/. Go check his work, it's great. He doesn't know it, but he deserves a large part of the credit in my Pixbox project! My controller setup is just an application of this tutorial and the related ones.

These documents he made are essential for building your setup: https://github.com/derekmolloy/boneDeviceTree/tree/master/docs
Print them, everything you will ever need is inside.

Anyway, here is the GPIO setup I ended up using:
Button GPIO Key event emitted
Escape (leave game)P8_8Escape
Insert coinP9_155
1P Joystick UpP8_10Up arrow
1P Joystick LeftP8_14Left arrow
1P Joystick RightP9_16Right arrow
1P Joystick DownP8_12Down arrow
1P StartP8_71
1P Action 1P8_9A
1P Action 2P8_13S
1P Action 3P8_17D
1P Action 4P8_26Q
1P Action 5P8_11W
1P Action 6P8_15E
1P Action 7P8_19Z
1P Action 8P9_26X
2P Joystick UpP9_27I
2P Joystick LeftP9_23J
2P Joystick RightP9_27L
2P Joystick DownP9_21K
2P StartP9_112
2P Action 1P9_13F
2P Action 2P9_14G
2P Action 3P9_18H
2P Action 4P9_24B
2P Action 5P9_12T
2P Action 6P9_16Y
2P Action 7P9_22V
2P Action 8P9_30R
The device tree overlay part only activates the GPIOs. The key mapping comes in a later step! Youd can get my device tree overlay definition on the following git repo: https://github.com/alban-rochel/pixbox-controls. Check the "overlay" subfolder. The compilation script also does the installation into the /lib/firmware folder. To activate this overlay definition, you have to tell the system you want to use it:
 export SLOTS=/sys/devices/bone_capemgr.9/slots  
 export PINS=/sys/kernel/debug/pinctrl/44e10800.pinmux/pins  
 echo PixBox > $SLOTS  
Of course, you can (and I believe you should) make this automatic by adding this into an executable script in /etc/profile.d.

Plugging the buttons and testing

Joysticks and buttons are basically the same thing: microswitches. They have two pins each, and the electric current passes when the user presses the button/direction.
If you have a look at my device tree overlay definition, you will notice that I set up my GPIOs with a pull-up resistor. Basically, this means that my GPIOs are, by default, in a "high" state (1). Connecting them to the ground sets them in "low" state (0).
All I had to do was linking one pin of my microswitches to the proper GPIO, the other to the ground, adding a "strong" resistor in-between.
I made my first experiments with a basic switch, a 10k resistor and a breadboard. Just plug one pin of your switch to your GPIO (say P8_8, "escape" button in my setup). The other one to the resistor, and the resistor to the ground of you board (P8_1 or P8_2).

For testing purposes, you will want to expose the GPIO as a special file. Go check the documents from Derek Molly, look for P8_8, and you will see that P8_8 is GPIO #67. Now, on your Beaglebone, write the value "67" to /sys/class/gpio/export and what the magic happen:
 root@beaglebone:~# cd /sys/class/gpio  
 root@beaglebone:/sys/class/gpio# ls  
 export gpiochip0 gpiochip32 gpiochip64 gpiochip96 unexport  
 root@beaglebone:/sys/class/gpio# echo 67 > export  
 root@beaglebone:/sys/class/gpio# ls  
 export gpio67 gpiochip0 gpiochip32 gpiochip64 gpiochip96 unexport  
After you write this value, a gpio67 folder appears. Check its "value" file:
 root@beaglebone:/sys/class/gpio# cat gpio67/value  
 1  
"1" means "high" state.
Toggle your switch, and check the value:
 root@beaglebone:/sys/class/gpio# cat gpio67/value  
 0  
Well done, you are one step closer to having your arcade controller!

From button events to keyboard events

In practice, we do not want to poll the status of the gpio[whatever]/value files. This does work, but is quite slow. We can do better than that! Actually, GPIO values are stored in specific addresses in memory, and we can access them programmatically.

Ethan Hayon (https://github.com/ehayon/BeagleBone-GPIO) did a great job providing C primitives to configure the GPIOs and access their values, and my implementation (https://github.com/alban-rochel/pixbox-controls/tree/master/service) largely relies on his code.

My code is basically polling the proper addresses, and emitting keyboard events when their states changes. To emit keyboard events, I used the uinput Linux subsystem, check it out! Very simple to use.

The only "smart" thing I did was adding a "debounce" period. "Bouncing" is what happens when you toggle the state of a switch: within a very short amount of time, the electric state may be unstable and oscillate between "high" and "low" values. You definitely don't want these to appear as button presses. So, after each state change (button press or depress), I ignore the button for a very short duration.

And that's it! Feel free to use this piece of code, all you have to do for your specific project is to change the "ADD_BUTTON" calls: the first argument is the key emitted, the second the GPIO, and the third one a debug string.

Actual building of the controller

I used the protocape from Adafruit to solder all my resistors and wires: not much to say about this, it is cheap and easy to use: https://www.adafruit.com/products/572

As for the arcade components, I ordered them on http://www.starcab.net/ . Standard 28mm buttons, Sanwa sticks, everything works (and feels) great!

Back to work!

It's been a long time since I have not updated this web page. One of the reasons is that motivation comes and goes. And the other reason is that following a disk crash, I have lost the file in which I had documented all my changes and the interesting links I had found...

I have been contacted recently by a reader of this blog, who made interesting improvements over my own researches - this re-ignited my motivation to continue this blog. I would be happy if he could provide more info through the commentary system.

As for the loss of my documentation on this subject. Well... I'll try and do my best!