megi's PinePhone Development Log RSS

Genocide is bad

2021–08–10: Wrapping up Pinephone keyboard firmware development

The keyboard production seems to start soon.

I'm ending the firmware development for now. The final code is here:

https://xff.cz/git/pinephone-keyboard/

Samuel Holland helped with the final testing, and this code will be flashed in factory. You can read about the design of the code here:

https://xff.cz/git/pinephone-keyboard/tree/README

and in other readme files in that repository.

What I've achieved since June

Initially I received the vendor's flashing tool, vendor's proprietary firmware code for the keyboard and some schematics for the keyboard.

And this was just the keyboard MCU part. The second part of the problem is the charging chip.

All in all this project required a lot of bootstrapping, reverse engineering, and custom tooling support. That's why you'll find many tools in my code repository, each can still be used for one of the purposes I used them for originally.

I don't measure time spent on my hobbies, but this easily took ~100h of time over the last ~2.5 months and I quite like the result and all the new stuff that I've learned. That's also why I haven't done much on Pinephone kernel last few months. ;)

Lessons learned

I didn't know much about using USB from Linux and writing USB code for microcontrollers. Nor did I use USB in any of my hobby HW projects in the past, and that changed after this project. I thought USB is complicated. I found that using USB as a dumb transport is quite comparable to using a serial port. It needs more code, but USB solves issues that you have to solve by hand in some upper protocol layer you layer on top of serial port communication, so the complexity is comparable.

On Linux side you can access USB devices with about 4–5 ioctl calls, and in most microcontrollers that I have access to, you can write basic USB device code in about 200 lines (no need for large USB stacks supplied by the vendor when you're just using USB as a dumb transport instead of trying to implement some of the standard USB device classes).

In fact I wrote 2 USB device implementations during the development of the keyboard. One for the controller inside the keyboard, and one for FX2 board I used to simplify testing. And it was not that hard. FX2 is especially easy and well documented, with hardware helping the firmware writer quite a bit at each step.

It was a fun ride, mostly, except for some stressful frustrations towards the end. I don't mind frustration with trying to fix a broken HW, reverse engineer stuff, etc. There was a lot of that in this project after all. Interrupt driven MCU code is especially tedious to write, since you have to re-read the code several times, searching for potential cirical sections, etc. Compiler does not help at all here.

What I do mind is being put under time pressure on a project where I'm just volunteering my free time. That's very easy way to get bitter feelings, which I'd like to avoid.

I've damaged the last prototype trying to figure out some way to connect I2C of the keyboard MCU to the charger I2C so that phone can monitor the keyboard battery charge and control the charger.

At the moment I have no way to do anything with the keyboard, until I fix my prototype to revert the various HW modifications I attempted, or get the final keyboard, so the feeling of accomplishment is a bit bittersweet. Oh well. :)

Some random photos from my efforts

First effort to give access to charger I2C to the phone (using TXS0108 level converter):

Second attempt to give access to charger I2C to the phone (via direct connection of I2C A MCU interface to the charger chip). A plan:

Execution:

And giving up after weird voltages on I2C pins and no more time to try things: :(

Final untested suggested changes for having I2C access to the charger proxied by the keyboard, that will be present in the final keyboard design, to have a chance to figure out the charger I2C communication later on (as a firmware update):

My new favorite USB dev board (Cypress FX2), that I used to test I2C interface of the keyboard:

FX2 controlling the keyboard over I2C from the PC: