Firmware

Published on 2024-10-09 in BlueJoy.

With the PCB designed and ordered, it’s time to look at the firmware a bit. Of course with no hardware to test it on, we are going to need to improvise somewhat, and just use some off-the-shelf ESP32 development board, with pull-up resistors added.

../../../_images/IMG_20241004_205425_HDR.jpg

I initially planned to use the Bluepad32-Airlift firmware, only modify it to use I2C instead of SPI. However, after looking a little bit at the source code and realizing I have zero experience with ESP-IDF, I decided to pick the path of the least resistance, and instead use Bluepad32-Arduino together with Arduino’s good old Wire library.

The documentation for Bluepad32-Arduino explains very well how to setup the environment and get the example code compiled and working. One snag that I hit is that by default the example code doesn’t print anything on the serial console when buttons are pressed — it only changes the LEDs on the controller, which incidentally my gamepad didn’t have. So until I actually looked at the code and added some debugging prints, I was convinced it doesn’t work. But I only wasted an hour or two on that, and the rest went smoothly.

The example file actually gets us halfway there: it shows how to initialize newly connected gamepads, and how to run the update loop for them, and how to get their state. Adding the initialization for I2C slave and the onRequest and onReceive callback got the I2C working, and then it’s just a question of a bunch of switch statements to simulate registers.

Because the complete state of the gamepad turned out to be rather large for I2C at 54 bytes, I decided to split it into the basic and advanced parts, the former containing the d-pad, x and y axes, and buttons, and the latter having all the rest, including other axes, gyro, accelerometer, throttle, etc. This way we can keep things fast and snappy for basic use, and still have the advanced stuff if we need it.

I might need to rework some of the details of it further once I have tested it all somewhat. For example, the register that tells us if there has been any change since the last communication right now only returns 0 or 1, but I could make it return a bitmask of which of the gamepads have a change in their status instead, so that we can then only query those.

I will be putting the source code for this firmware, together with an example library for CircuitPython for communicating with it in a repository once I have the hardware tested an working.