Skip to content

Software

joric edited this page Apr 26, 2026 · 837 revisions

This article covers ZMK (recommended), Bluemicro, Bluetosis, RMK and QMK firmwares.

ZMK

ZMK is modern, open source Zephyr-based wireless keyboard firmware.

Duplex serial is supported since #2766, still no dynamic switching at the time: https://zmk.dev/docs/config/split#wired-splits

Also supports ZMK Dongles (USB-powered central), so you can save on battery. There's also ESB support.

Building ZMK

Note that nRFMicro and Jorne are officially supported now. Read official documentation here:

Building jorne for nRFMicro 1.3 locally:

git clone https://github.com/joric/zmk # or https://github.com/zmkfirmware/zmk
cd zmk && git checkout jorne
west build -p -b nrfmicro_13 -- -DSHIELD=jorne_left
west build -p -b nrfmicro_13 -- -DSHIELD=jorne_right

(Before calling west, set up Zephyr environment, as here https://zmk.dev/docs/development/setup)

Issues

  • VCC management seems fine with the latest ZMK, no leak, checked with 26 LEDs per each half, but it needs manual turning off with a shortcut (currently it's tied to RGBTOG). Key matrix still works even with VCC off, it only turns off OLED and RGB.
  • OLED initialization is static in Zephyr so it only works if VCC is enabled on startup. To check if OLEDs work, enable RGB+VCC using RGBTOG key binding, then wait at least a minute. After that, that'd be stored to settings and restored at startup/reset (fixed in #674, #675 so you may want to pull fresh ZMK)

Video

Misc

nRF52833

See Instructions on how to configure ZMK to work with nrf52833.

Displays

See my article about displays: https://github.com/joric/jorne/wiki/Displays

Trackpoint

See my article about trackpoints: https://github.com/joric/jorne/wiki/Trackpoint There are currently 2 problems:

  1. nobody tried trackpoint at 3.3v (edit: tried, it works)
  2. all trackpoints are ps/2 and there's no ps/2 support in ZMK (there's ps/2 driver in zephyr though)

TL;DR: trackpoints work with ps/2 Arduino library at 3.3V just fine. There's no ZMK support just yet.

Update: Keyboard Minimalists ran ZMK touchpad and trackball, links to discord (join at https://discord.gg/zUsWqq9ggb):

HHKB Pro 2

See Adapters.

ZMK Dongles

See Adapters.

Bluemicro

Arduino-based firmware, originally developed for the Bluemicro board, see https://github.com/joric/nrfmicro/wiki/Alternatives#bluemicro

Bluemicro Repository

This is Adafruit nRF52 Arduino package-based firmware. You can build it either with build script or with Arduino IDE.

For split keyboards just use "left" as master and "right" as slave. There are usually three configurations: "master", "left" and "right". For standard keyboards, like a 60%, "master" is just a regular layout, in split configurations it is in fact "standalone", it's a single test layout with no layers or any special keys that's used to test that your hardware works fine (every key does register).

Building Bluemicro

Building from Arduino IDE

Open the BlueMicro_BLE\firmware\firmware.ino file in Arduino IDE, then:

  • copy the following files from your favorite keyboard example in the keyboard folder into the "firmware" folder, same place as the ino file:
    • keyboard_config.h
    • keymap.cpp
    • keymap.h
  • choose the correct board: "Nordic nRF52840DK (PCA10056)". Don't choose nrf52840 feather - they mix GPIO/Pin numbers...
  • compile
  • select your serial port where your board is connected (double press reset to see the port)
  • upload via serial port in Arduino IDE (press "upload" button)

Uploading via serial port is possible for all the boards because Adafruit UF2 bootloader also supports uploading via DFU (when you press reset twice there's an extra virtual COM port that arrives along with the USB drive).

You can also export hex binary in Arduino IDE via Sketch->Export compiled binary, it saves hex file (into the .ino directory) that you may convert to UF2 with uf2conv.py for uploading. You can also modify upload scripts (boards.txt and platform.txt) in %localappdata%\Arduino15\packages\adafruit\hardware\nrf52 (e.g. send "dfu" reset command to the debug port, etc.).

To make firmwares for left and right halves just edit keyboard_config.h and rebild ("master" is for non-split keyboards).

#define KEYBOARD_SIDE LEFT
//#define KEYBOARD_SIDE RIGHT
// CHANGE THIS FOR THE KEYBOARD TO MATCH WHAT IS BEING FLASHED. OPTIONS: LEFT  RIGHT  MASTER

Building from command line

This script is supposed to run from the Bluemicro root. You have to specify keyboard name and role (left/right).

@echo off
set root=%~dp0
cd %root%/build/windows
set keyboard=crkbd
set keymap=jpconstantineau
set role=left
powershell ./build.ps1 %keyboard%:%keymap%:%role% -nrf52840
set path=C:\SDK\gcc-arm-none-eabi-8-2018-q4-major-win32\bin;%path%
cd %root%
set file=%root%/output/crkbd/%keyboard%-%keymap%-%role%.hex
python ./uf2conv.py %file% -c -f 0xADA52840 || exit
echo Waiting for the UF2 drive. Press Reset twice...
echo dfu| plink.exe -serial com9 > nul 2>&1
:loop
if not exist e:\ goto :loop
timeout 1
copy flash.uf2 e:\

Required:

  • Switch to USE_LFRC in %localappdata%\Arduino15\packages\adafruit\hardware\nrf52\0.20.1\variants\pca10056\variant.h:
//#define USE_LFXO      // Board uses 32khz crystal for LF
#define USE_LFRC    // Board uses RC for LF

This firmware uses XTAL (external 32.768 KHz crystal) by default. If you don't have it on the board it can advertise via Bluetooth but would not be able to connect. Since there's no XTAL on some revisions of nRFMicro, you need to edit pca10056\variant.h in the board package and set USE_LFRC as default:

You can't just replace pca10056 with feather52840sense, cplaynrf52840 or cluenrf52840 in the build script, these boards don't use XTAL but they are not supported by this firmware (it uses pca10056 pin definitions).

  • Edit keyboard configuration in keyboard_config.h: #define HARDWARE_MAPPING NRFMICROV0_3 if you use board flipped with solder jumpers, you have to edit pins (see Pinout), there's no flipped nRFMicro yet. The file is breakout_mapping.h.
    #elif HARDWARE_MAPPING == NRFMICROV0_3
        #define BATTERY_TYPE BATT_UNKNOWN
        #define VBAT_PIN  26
    ...
  • To blink with nRFMicro's onboard LED on start put this into firmware_main.cpp:
void setup() {
    ...
    #define LED_PIN (32+10) //1.10  = 32+10
    pinMode(LED_PIN, OUTPUT);
    for (int i=0; i<4; i++) { digitalWrite(LED_PIN, i%2 ? LOW : HIGH ); delay(200); }
    ...
}
  • Use this to enable charger in nRFMicro 1.3+ revisions (put it next to the code above):
    #define PROG_PIN 5 // 0.05
    pinMode(PROG_PIN, OUTPUT);
    digitalWrite(PROG_PIN, 0); // enable charger (set PROG to ground)
  • Use this to enable VCC power mosfet:
    #define POWER_PIN 32+9 // 1.09
    pinMode(POWER_PIN, OUTPUT);
    digitalWrite(POWER_PIN, 0); // enable power (0-enable, 1-disable)

Bluemicro Issues

If the board doesn't connect you probably need to disable external crystal (XTAL, see nRFMicro configuration above).

Building in Arduino IDE is a killer feature no doubt (also built in DFU uploading), but if you're using Arduino IDE, you have to copy keyboard files to the main folder (this the official way for now, so don't blame me on that). Copying doesn't seem too convenient, you also have to compile twice, for left and right halves, use this define in keyboard_config.h:

#define KEYBOARD_SIDE LEFT
//#define KEYBOARD_SIDE RIGHT

Adding includes to firmware.ino probably could be better (could also select hardware configuration there), maybe even use a local config.h so one could contribute keymaps and build things in IDE without altering the repository (not implemented).

Bluemicro Videos

Installing and Testing Arduino IDE for BlueMicro Firmware

More videos: https://www.youtube.com/channel/UCFpGp4hHe03nvF9c8_gF_jA

Bluemicro Mass Storage

It would be cool to read JSON-formatted layouts from MSC (Mass Storage Class, aka USB drive). My take on that (in progress):

I was under impression I could just implement write/read memory location in msc handlers but apparently there's much more than that. It kind of works though (saves and loads data from the internal filesystem) but it doesn't modify FAT entries properly. Still could work with a couple of predefined filenames.

Bluetosis

Originally written for Mitosis, hence the name. It's a nRF51822 firmware that supports both Bluetooth host and RF (Gazell) protocol. True wireless, supports custom RF receiver as well. You can switch between Bluetooth and RF protocol in real time. Left half is RF, right half is BT+RF. Does NOT support 24l01+ (Gazell only supported in nRF5x). Very early, experimental stage. Does not support keyboard matrix, direct pin only.

You can also try to finish my nrf51 QMK fork for nRF51822 MCUs but it never gets into upstream because QMK is shit scared of Nordic licensing terms.

bluetosis

RMK

RMK is a feature-rich keyboard firmware library written in Rust.

QMK

See https://github.com/joric/qmk/wiki

KMK

See Circuitpython.

References

Clone this wiki locally