Experience Writing Firmware with the CH582 Port of QMK
As noted previously, WeAct Studio have a BLE devboard that costs about $2 (which is MUCH cheaper than the BLE devboards popular in custom mechanical keyboard designs), but there isn’t much community attention for this board; there aren’t many (any?) keyboards designed to use this devboard, and there aren’t many people using firmware for it. There is a port of QMK to use the CH582.
And it’s been announced that FAK support for the CH58x/CH59x is planned.
I designed a keyboard to use WeAct Studio’s BLE devboard.
In a sense, this somewhat puts the cart before the horse, since I hadn’t tried proper keyboard firmware with the devboard before designing the keyboard.
The good news is, I was able to get working keyboard firmware for my keyboard using the QMK port for CH582.
Unfortunately, this wasn’t without frustration.
Initial Impression
I have experience writing keyboard firmware, by way of making use of what others have written. e.g. I’ve written keyboard definitions for QMK (including before the move to data-driven configuration), implemented the game Snake using QMK’s RGB Matrix effects system; I’ve written keyboard firmware in Rust; I’ve implemented CapsWord functionality for FAK.
My initial impression of the CH582 port of QMK is it feels fragile and finicky.
The structure of the repo wraps CMake lists around the QMK codebase. – To me, this seems like additional effort, for marginal benefit. It’s not clear to me that it’s necessary, either. – This leads to (as noted below) requiring additional effort to use features which QMK implements, & it took significant additional effort to figure out how to re-use the keymap code I had written in QMK.
In terms of QMK, it felt like writing qmk before the data driven configuration. (In order to make use of QMK’s data driven configuration, more CMake code would need to be added to support using the autogenerated keymap code).
Obstacles
Didn’t Produce Working Firmware with the Open-Source Risc-V Toolchain
When I build the EVT examples for the CH592, I was able to build and run the examples with either the ‘public’ risc-v gcc distributed by xpack, or the toolchain distributed by MounRiver Studio.
Although I noticed I had to make changes to the CMake lists in order to build the QMK fork for CH582 with the ‘public’ xpack toolchain, I had been able to build the firmware.
Unfortunately, when I was finally able to try running this firmware on a CH582 devboard, only the firmware built by the MounRiver toolchain worked when I ran it.
I don’t know why.
BLE is Still WIP
The README currently has the line: “Support wired, Bluetooth, and triple mode 2.4G (WIP)”. I understood this to mean “Supports wired, Bluetooth” and “triple mode 2.4G” is WIP.
But, as others have observed, e.g. the TychePad keyboard (which uses BLE) doesn’t build.
Enabling BLE requires the wireless lib, but in order to build the wireless lib, the required files aren’t provided in the repo.
Hence, BLE isn’t available with the publicly provided code.
I don’t mind the work being WIP; but I assess it as sloppy to have WIP code that doesn’t build on a release branch.
And $2 for a risc-v devboard is pretty neat, even if for keyboard firmware it’s USB only at the moment.
Getting My Keymap to Build
The CMake Files Don’t Support Community Layouts
The qmk_firmware
repository supports putting keymap definitions in layouts/community
. This allows you to define the keymap for some layout (such as ortho_4x12
or split_3x5_3
), rather than only defining a keymap specific to a keyboard.
At the time of writing, the CMake lists in the CH582 port don’t support using this feature.
Perhaps it could, but it doesn’t at the time of writing.
False Friends: config.h
This confused me for some time:
Both sdk/HAL/include
and QMK use header files called config.h
.
So, by adding a CMake statement include_directories(...)
pointing to a QMK keyboard or keymap directory (which has config.h
), this breaks the build since then the CH582 HAL doesn’t correctly include its config.h
.
This is more of a -1 to C than to anything else.
I worked around this by using more of the path when including; e.g. rather than #include "rgoulter.h"
, I use #include "users/rgoulter/rgoulter.h"
.
Some QMK Features Not Implemented
The CH582 port of QMK uses CMake to manage its build.
So, QMK features are enabled by checking CMake variables.
Turns out, some of the features I use weren’t described there. I was able to add them.
While for other QMK features (such as the haptic feedback feature) which depend on driving hardware peripherals, it makes more sense that the CH582 platform for QMK lacks the implementation.. for stuff like the leader key or combos, I felt “not implemented” was more due to it needing to be declared in CMake.
Custom Keycodes: Safe Range
I also ran into problems where my keymap defined new keycodes.
Again, this is more of a -1 to C, and that it doesn’t necessarily compose things like this well.
The QMK interface for defining new keycodes is to use NEW_SAFE_RANGE
.
This port declares its own NEW_SAFE_RANGE
.
So, my code needed to untangle a bit from that; and it’d take some care to be aware of whether the codebase I’m building against defines its own NEW_SAFE_RANGE
or not.
Mirroring my Community Layout
Initially I’d tried copying the C files across in order to get my layout on the keyboard. This works, but isn’t the most maintenance friendly approach. (I’d need to re-copy each time I changed my layout).
Once I figured the stuff above out (about config.h
, etc.), I was able to come up with a way of using my community layout without too much fuss: https://github.com/O-H-M2/qmk_port_ch582/commit/67795a2beb647276d30bdf3da771584e6465465f
The keymap.c
just includes the keymap.c
from the community layout:
#include "layouts/community/ortho_5x12/rgoulter/keymap.c"
The qmk_config.h
includes the config.h
from the community layout dir, and the user dir:
#pragma once
#include "users/rgoulter/config.h"
#include "layouts/community/ortho_5x12/rgoulter/config.h"
and the rules.cmake
ports the rules.mk
functionality over:
set(COMBO_ENABLE ON CACHE BOOL "KB" FORCE)
set(LEADER_ENABLE ON CACHE BOOL "KB" FORCE)
set(DYNAMIC_MACRO_ENABLE ON CACHE BOOL "KB" FORCE)
list(APPEND QMK_PORTING_SOURCES
"${QMK_BASE_DIR}/users/rgoulter/rgoulter.c"
)
Conclusion
I feel more sour about the above than I should, because it took a bunch of effort to figure this stuff out.
I don’t love the use of CMake. (e.g. my re-implementing stuff from rules.mk
, it feels like there are multiple sources of truth for describing the same thing).
I wish it implemented support for QMK’s community layouts, or for QMK’s data driven configuration.
I was disappointed to realise the BLE code wasn’t publicly available, and that the code somehow relies on the proprietary MounRiver distribution of the risc-v toolchain.
But, for the moment, I don’t think there’s any other publicly available keyboard firmware for CH582.