ZMK and custom firmware¶
The Create's stock keyboard firmware is Naya's own fork of ZMK: the vendor said so from the campaign on, and the host software, the keymap records and the Bluetooth descriptors all agree. This page gathers that evidence, shows where the fork goes beyond upstream ZMK, lists the hardware facts a porter would start from, and states the one hard gate: the signed bootloader. The thing to know first: nobody has ported open firmware to the Create, and erasing a half over SWD to try would destroy the only key that can decrypt the stock images, so there would be no way back to stock.
This page stays at the level of consequences. It does not describe, and this site does not publish, any method to read, bypass or extract keys or to defeat a debug lock.
At a glance
- The stock firmware is a ZMK derivative on Zephyr, according to the vendor and to host-side evidence.
- The halves are nRF52840 (1 MB flash, 256 KB RAM, native USB, QSPI), not nRF52811.
- The bootloader accepts only images signed with Naya's key; a USB update path exists for those.
- An SWD mass erase removes the only key that unwraps the stock images: no way back to stock.
- Known for a porter: the SoC, the split-link parameters, the key positions, the LED map. Unknown: the matrix pins, the LED driver, the dock protocol, the split-link payload.
Status¶
As of 2026-09-23 nobody we know of has ported ZMK, or any other open firmware, to the
Create: a GitHub search that day found no keyboard firmware port (createflow-dongle replaces only the
dongle's firmware) INFERRED. The firmware update path is SMP image upload over serial recovery, not the configuration
protocol MEASURED (Flashing). This differs from naya-create-kb, which places it on the
configuration protocol REPORTED20. For a porter, the rest of the stock firmware's behavior is on
our wire protocol pages.
Evidence the stock firmware is a ZMK fork¶
The vendor said so. The Kickstarter campaign page says remapping is done "between our custom ZMK firmware and Naya Flow"; update 9 (2023-12-07) describes the Create firmware as based on a customized ZMK base that adds features ZMK lacks; the campaign FAQ says building and flashing your own layout with ZMK is "not available for now" DOC132. A staff comment on Reddit (2023-05-18) adds that it is a custom fork of ZMK, made to allow external modules and other custom features, and closed source DOC5. Earlier and later vendor comments on Reddit say the firmware is being heavily modified (2023-01-06, the same staff account) and that the vendor builds on ZMK's MIT license and hoped to offer an open SDK later (2024-04-17, the brand account) DOC6. The Reddit comments are quoted from archived copies; we could not open them live. The Kickstarter pages are the live sources.
NayaCore logs ZMK behavior names: "ZMK Behaviour: (0x%1) %2", "Unimplemented ZMK behaviour: %1" and "Unknown ZMK behaviour: (%1) %2" STATIC7.
The keymap record's type byte is a ZMK behavior index. Types 00 to 0f index
NayaCore's behavior table; 10 sits outside it STATIC MEASURED7:
| Type | Behavior | Type | Behavior |
|---|---|---|---|
00 |
&bt (Bluetooth) |
09 |
&rgb_ug |
01 |
&kp (key press) |
0a |
sticky key |
02 |
macro | 0b |
&sl (sticky layer) |
03 |
&mt (mod-tap, the hold-tap form) |
0c |
&to |
04 |
grave escape | 0d |
&tog |
05 |
&mo |
0e |
&trans |
06 |
Naya system action | 0f |
mouse |
07 |
&none |
10 |
hold-tap record (what OpenFlow calls OneKey) |
08 |
&out |
The indices were matched against records captured from the owner's board between 2026-09-03 and 2026-09-22. The full record format is on Keymap.
Hold-tap flavors are ZMK's four (balanced, tap-preferred, hold-preferred,
tap-unless-interrupted), stored per record next to the tapping term (default 200 ms) STATIC7.
Valid values are 0 to 3. A value of 4 was accepted and stopped every key until the board was
unplugged (a power cycle); 02 was measured as tap-preferred MEASURED (owner's board, 3.41.0,
2026-09-03 and 2026-09-17). A home-row typing test fits ZMK's order for 00 and 01: with 00 holds
fired on fast rolls (hold-preferred), with 01 fast rolls typed cleanly (balanced)
MEASURED (owner's board, 3.41.0, 2026-09-25). What 03 does is open
OPEN. See Settings and timing.
Key names follow ZMK's keys.h, aliases included (for example K_LOCK,
K_SCREENSAVER and K_COFFEE all map to usage 0xF9, and the LANG and INT aliases), and the 4-byte
key-press parameter is ZMK's 32-bit keycode, little-endian: usage low, usage high, usage page,
modifiers STATIC INFERRED7.
&bt (0 clear, 1 next, 2 previous, 3 select), &out (1 USB, 2 Bluetooth) and the LED
color packing (RGB_COLOR_HSB) match ZMK STATIC INFERRED (checked against captures, owner's board,
2026-09-08 and 2026-09-10).
The Bluetooth HID report map is ZMK's, with a vendor mouse. The 212-byte report map that
createflow-dongle reads over Bluetooth, byte-identical to the left half's USB HID report descriptor in
our own capture, contains ZMK's keyboard input items and a consumer collection identical to ZMK's, and
its HID service attribute list is ZMK's hog.c. The mouse collection is vendor-modified: 8-bit X, Y,
wheel and pan plus AC Zoom, where upstream ZMK uses 16-bit fields and no zoom. There is no boot
protocol over Bluetooth. The Bluetooth read is createflow-dongle's REPORTED; the USB
descriptor is ours MEASURED (owner's board, 3.41.0, 2026-09-11); the comparison with
current ZMK is ours, made on those bytes INFERRED89.
The Bluetooth qualification points to Zephyr. The Bluetooth SIG listing 311198 declares Zephyr's host subsystem (QDID 151074) and Zephyr's own nRF52 controller (QDID 150092), not Nordic's SoftDevice. Those are reusable Zephyr 2.2-era designs, so they fit a ZMK-on-Zephyr stack without dating it DOC INFERRED11.
The bootloader was built from an upstream Zephyr tree. The bootloader banner's Zephyr
build v3.7.0-5411-g31fea97e05fd is an upstream Zephyr main commit of 2024-10-25, after v3.7.0,
not an nRF Connect SDK tag, and the MCUboot build is vendor-local DOC INFERRED12
(Bootloader).
Where the fork goes beyond upstream ZMK¶
In ZMK the hold-tap flavor and tapping term are compile-time devicetree properties; this firmware stores both in every hold-tap record and changes them at runtime. The whole keymap (156 records per layer, in two banks), per-layer LED maps, the layer list and the module configurations are all writable at runtime over USB. There is no macro table: macro records are stubs DOC MEASURED INFERRED10. Details: Keymap, Layers, LEDs.
The gate: the signed bootloader¶
The gate is the bootloader, not an "encrypted bootloader". MCUboot verifies each image's RSA-2048-PSS signature against Naya's key and decrypts the AES-128 image body with a key it holds. A firmware update path does exist, MCUboot serial recovery over USB, but it accepts only Naya-signed images STATIC MEASURED13 (Images, Flashing).
Custom firmware therefore needs either Naya's signing key or a replaced bootloader, written over SWD, and the SWD route is only open if the debug port is not locked STATIC INFERRED.
What an SWD mass erase costs
The carved stock images are encrypted, and the key that unwraps them exists only
inside the stock bootloader. A mass erase (the only SWD action available if the debug port is
locked, APPROTECT) destroys that key. After it, no bootloader you build can decrypt the stock
images, so there is no way back to stock from the archive. This differs from naya-create-kb,
which counts the carved stock images as a way back over SWD20. A real way back would need a
complete dump of the internal flash (and ideally the QSPI) taken before any erase, which is only
possible if the debug port is not locked. Whether shipped halves have it locked is open: the
build code D0 suggests revision 2 silicon, but the silicon revision and its APPROTECT default
are unconfirmed INFERRED OPEN17.
The hardware a port targets¶
The halves are Nordic nRF52840 (package CKAA, WLCSP; marking N528… / CKAAD0 /
2301ME, the end of the first line partly hidden by the potting edge; build code D0): 1 MB flash,
256 KB RAM, native USB and a QSPI host DOC1516. Photos and part details are on
The keyboard half.
No stock keyboard image would fit an nRF52811's 192 KB of flash: the 26 stock images of the 25 stable releases run from 218 064 to 361 632 bytes, each in a 663 552-byte slot. Each half also carries an external QSPI NOR flash (Winbond wordmark; part and capacity unreadable in the filed photos) STATIC DOC1417.
There is no second MCU-class part on the half's mainboard; a few small power parts are unidentified. The nRF52840's native USB makes a separate USB MCU unnecessary, and each half enumerates directly as a USB device DOC INFERRED17 (USB).
Debug pads are labeled: on the halves SWDIO and SWDCLK (plus test pads) at the USB-C
corner; on the dongle SWDIO, TP1, TP2, 5V and GND; on the module boards SWDIO, SWCLK,
BOOT0, BOOT1 and RST DOC17. Read the erase cost above before touching them.
Split link. The halves are Bluetooth-bonded to each other: each half's pair address
(be/1002) is the other's own address (be/1008). The left half is the central and holds the whole
keymap; the right half reports key positions over the link. The link parameters in the be/100c
status are a 7.5 ms interval, latency 0 and a 4 000 ms supervision timeout. The payload protocol on
the link is open MEASURED OPEN (owner's boards, 2026-09-08 and 2026-09-20). See
Split link.
Wired mode, as the vendor described it. Update 10 (2024-01-06) reports full-duplex communication over the wired USB-C connection at "10 mb/s", chained right module, right half, left half, left module, with the left half talking to the computer. The campaign page (2023) said the opposite for USB mode: the halves stay on radio and only the left half sends data over USB DOC41. Shipped halves fit the campaign page: on 3.41.0 with both halves on USB the right half exposes no HID interface and its keys reach the host through the left, and every measurement fits a radio link between the halves MEASURED (USB, Split link). So update 10 most likely describes a prototype or a design that changed INFERRED. Whether any shipped unit has a wired path between the halves, and the rate of the dock link to a module, are open OPEN.
Key matrix. fe/1008 TOGGLE_KEYSCAN_MODE makes a half stream raw key events
(fe/1009 [row][col][state]) straight off its matrix, bypassing the split link: a right half that
could not type through the link sent 143 events this way (owner's board, 2026-09-20) MEASURED. A porter
can map positions to rows and columns without opening the case; the pin assignment stays open,
and the press polarity is inferred OPEN INFERRED.
LEDs. Each layer has a 136-entry LED map: 0 to 73 the keys, 74 to 87 the two side bars, 88 to 111 the left module bay, 112 to 135 the right bay MEASURED (owner's board, 2026-09-08 and 2026-09-10). The LED driver chain and its pins are open OPEN. See LEDs.
Modules. Each module has its own STM32F411CEU6 running its own firmware, which is not
an MCUboot image, so modules are not part of a keyboard port. They have no radio and no FCC ID of their own. The dock has 8
contacts carrying UART, boot and power, no USB data. The dock address encodes type and side (Touch
0x10 and 0x11, Track 0x20 and 0x21, Tune 0x40 and 0x41; 0xF0 and 0xF1 mean nothing has
booted). Power flows both ways: a charged docked module can power the keyboard, and the keyboard
charges a docked module. The data protocol on the dock is open DOC MEASURED OPEN1817
(Module dock, Module firmware).
Battery gauge. fe/1006 returns the half's own cell voltage in millivolts (take the
median of five samples) and de/100b the module cell in millivolts; percentages are computed on the
host MEASURED. NayaFlow's module percentage is
(clamp(mV, 3300, 4200) - 3300) * 100 / 900, truncated, then clamped to 1-100 %, from the de/100b
millivolts STATIC (NayaCore 6.11.0)7: 9 mV per point. nayactl uses
the same range for halves and modules STATIC19, and NayaFlow showed a Tune at 4228 mV as
100 % MEASURED. A half's own cell stops charging at a firmware-dependent voltage: flat on USB,
3.41.0 halves held about 4.07 to 4.09 V and 3.28.7 halves about 4.19 to 4.21 V
MEASURED (owner's boards, 2026-09-26), so the same linear scale shows a full 3.41.0 half at
about 85 to 88 % INFERRED. OpenFlow keeps NayaCore's formula for modules and maps a half's
voltage with a curve whose full point follows the firmware STATIC21
(Power and batteries).
Known and unknown for a porter¶
| Subsystem | Known | Unknown |
|---|---|---|
| SoC | nRF52840, 1 MB / 256 KB, native USB, QSPI host | silicon revision |
| External flash | QSPI NOR (Winbond wordmark), holds the secondary slot and data | part number and capacity |
| USB | native, one CDC data port on 3.41.0 | |
| Split link | Bluetooth bond, central left, 7.5 ms interval, latency 0, 4 s timeout | payload protocol |
| Key matrix | positions mapped via keyscan events | pin assignment, polarity (inferred) |
| LEDs | 136-entry map per layer, index ranges | driver chain and pins |
| Modules | separate STM32F411, 8 dock contacts, address scheme | dock data protocol, module bootloader |
| Battery | millivolt reads, host-side curves | |
| Bootloader | MCUboot, Naya-signed images only, USB serial recovery | |
| Debug port | pads labeled | lock state (APPROTECT) |
Verdict¶
The SoC is not a blocker: the nRF52840 has room for the stock images and native USB, with no separate USB MCU (above). The signing gate and the erase cost are the blockers. A port means rebuilding a ZMK fork for the nRF52840 with QSPI and a Bluetooth split, with the LED engine, the dock protocol and the module side as the undocumented parts. Nobody has published one INFERRED.
Open questions¶
- OPEN The debug-lock (APPROTECT) state and silicon revision of shipped halves (details).
- OPEN What a port would still need: the split-link payload protocol, the matrix pinout, the LED driver chain, the dock data protocol (details).
- OPEN What flavor value 3 does (details).
- OPEN Whether any shipped unit uses the wired link between the halves that update 10 describes.
Sources¶
-
Kickstarter campaign page, naya-create (story and Connectivity sections; read 2026-09-23). ↩↩
-
Kickstarter update 9, 2023-12-07. ↩
-
Kickstarter update 10, 2024-01-06. ↩
-
Reddit, r/ErgoMechKeyboards, comment
jklwnhzin thread13jydnp(2023-05-18), vendor staff account; quoted from archived copies, not verified live. ↩ -
Reddit comments
j34yvw9(thread101pr7o, 2023-01-06) andl001rpv(thread1bqumqm, 2024-04-17); quoted from archived copies, not verified live. ↩ -
NayaFlow 1.25.1, NayaCore 6.11.0 strings (behavior names and table, key vocabulary, flavor names) and macOS symbols (
Naya_Device::getModuleBatteryPercentage). ↩↩↩↩↩ -
createflow-dongle,
firmware/src/usb_hid.c(the stock report map, read from a Create over Bluetooth). ↩ -
ZMK,
app/include/zmk/hid.handapp/src/hog.c. ↩ -
ZMK documentation, hold-tap behavior. ↩
-
Bluetooth SIG listing 311198 (Naya B.V., model
NAYA-800-1(NAYA-CREATE)), read through the SIG's public listing search on 2026-09-23. Details on Regulatory records. ↩ -
Zephyr, commit
31fea97e05fd. ↩ -
create-legacy-firmware,
FLASHING-PROCEDURE.md, "Bottom line". ↩ -
create-legacy-firmware,
FIRMWARE-HISTORY.md. ↩ -
FCC ID 2BQ4V0825CRL and 2BQ4V0825CRR, internal photos exhibits; see Regulatory records. ↩
-
Nordic Semiconductor, nRF52840 Product Specification. ↩
-
Parts list (FCC internal photos of the halves, dongle and modules). ↩↩↩↩↩
-
naya-create-kb, firmware/zmk. ↩↩
-
OpenFlow: its battery percentages (NayaCore's linear formula for modules; for the halves, a curve whose full point follows the keyboard firmware). ↩