Skip to content

Opening soon: browse the range now, orders open at launch

CSE Keyboards

05 / 06 · Wireless and firmware

Bluetooth, nRF52840 and ZMK

What happens between pressing a key and seeing the character on screen in a wireless keyboard: the nRF52840 chip, Bluetooth Low Energy, the ZMK firmware, and how the battery lasts for months.

The nRF52840 chip

The nRF52840, made by Nordic Semiconductor, is not just a microcontroller but a System-on-Chip (SoC): the processor, the 2.4 GHz radio and the peripherals (GPIO, USB) sit on the same piece of silicon.

This integration greatly reduces PCB complexity, part count and possible sources of errors compared with a generic microcontroller plus a separate radio module.

Specifications

Processor
ARM Cortex-M4F, 32-bit
The “F” stands for the floating-point unit (FPU)
Clock speed
64 MHz
Flash memory
1 MB
RAM
256 KB
GPIO pins
48
USB
USB 2.0
Radio
2.4 GHz, Bluetooth 5 / BLE
2 Mbps data rate and Long Range mode
Other protocols
Thread, Zigbee, ANT
Plus proprietary 2.4 GHz protocols

What it means for a keyboard

The processor
Has more than enough power for matrix scanning, debounce, layers, macros and the BLE stack, with a latency the user perceives as zero.
The radio
Bluetooth 5 brings lower latency and a faster first connection, and Long Range mode keeps the link stable even in offices with dozens of Wi-Fi networks.
The memory
1 MB of Flash holds the bootloader, the BLE stack, the Zephyr system, the ZMK application and user settings, and allows firmware updates over Bluetooth (FOTA). 256 KB of RAM gives the BLE stack enough buffers not to drop packets.
Native USB
No separate USB-to-serial converter chip is needed. Over a cable the keyboard works as a standard USB HID device, and the port is also used for charging and debugging.

From the thesis, chapter 2.3

Why nRF52840, not RP2040

Raspberry Pi RP2040

The first option considered: a dual-core ARM Cortex-M0+, well liked in the community.

  • Plenty of GPIO pins, so large layouts (TKL or full-size) without extra components
  • No built-in radio: it relies on an external chip (e.g. Infineon CYW43439) over SPI
  • At the time of the project, ZMK support for this pairing was immature: connection problems, power use that was hard to optimise and complicated debugging

Nordic nRF52840

The final choice, considered the gold standard for ZMK.

  • Processor and radio on one chip, with no MCU–radio interface to manage
  • Zephyr and ZMK were built with first-class support for the nRF series; the BLE stack comes straight from Nordic
  • Fewer GPIO pins available, so compact sizes (60%, 65%, 75%)

A risk-management decision

Because Bluetooth was a must-have, the platform with mature software and a built-in radio was chosen, accepting a more compact layout. As compact sizes are popular, the trade-off was considered acceptable.

From the thesis, chapter 3.4

Bluetooth Low Energy

Bluetooth Low Energy (BLE) has been part of the Bluetooth standard since version 4.0 and was designed for short-range links with very low power use. Unlike Classic Bluetooth, which is optimised for continuous streams (e.g. audio), BLE sends small amounts of data and the radio sleeps most of the time.

That fits a keyboard perfectly, since it only needs to send data when a key is pressed.

GATT roles

GATT server (peripheral)
The device that holds the data: the keyboard. It announces itself by regularly sending small advertising packets, so it can be discovered without a connection.
GATT client (central)
The device that uses the data: the computer, tablet or phone. It actively scans for advertising packets and starts the connection.

Services and characteristics

HID service (UUID 0x1812)
The most important one: it declares the device as a keyboard, mouse and so on.
Battery Service (UUID 0x180F)
Exposes the battery level so the operating system can show it.
Device Information Service (UUID 0x180A)
Details such as the manufacturer, the model or the firmware version.
Report Map
A read-only characteristic: a “map” that tells the operating system how to read the data (e.g. the first byte is for modifiers, the next ones for normal keys). ZMK builds it automatically from the configuration.
Input Report
The characteristic that carries the pressed keys. The computer subscribes to notifications, and the keyboard pushes a packet on every press without being asked. This “push” is key to BLE’s power efficiency.

Security and compatibility

Pairing generates AES-CCM encryption keys, and bonding saves them so the devices reconnect securely without you doing anything. ZMK uses LE Secure Connections, so keystrokes travel encrypted. Thanks to the standard HID over GATT profile, the keyboard works without drivers on Windows, macOS, Linux, Android and iOS.

From the thesis, chapter 2.4

From key to screen

The six stages a key press goes through before it becomes a character on screen.USB: the wired alternative1Switchactuationmechanical →electrical2Matrix scan+ debounce3Keymap &layer lookup4HID report5BLEtransmissionencrypted, atthe connectionevent6Host decodes& shows thecharacter
The six stages a key press goes through before it becomes a character on screen.
  1. The switch actuates

    Your finger compresses the spring. At the actuation point the metal contacts touch and close the circuit: the mechanical action becomes an electrical signal at one point of the matrix.

  2. Scanning and debounce

    The firmware activates each column in turn and reads every row, hundreds or thousands of times a second, and finds the key’s coordinates (e.g. row 2, column 5). Debounce filters out the contact noise.

  3. Interpretation and mapping

    The coordinate is looked up in the keymap, taking modifiers and the active layer into account. The same G key sends “g” on Layer 0 and F5 on Layer 1 (with Fn). This is also where a macro may be triggered.

  4. The HID report

    The resulting codes are packed into an HID Input Report, usually 8 bytes on a standard (6-Key Rollover) keyboard.

  5. BLE transmission

    The BLE stack adds headers, encrypts the packet with the AES keys from pairing and queues it. At the next connection event the radio wakes for a fraction of a second and sends it as a notification on the Input Report.

  6. Reception on the computer

    The computer receives the packet through its Bluetooth adapter, validates and decrypts it, then the generic HID driver reads it using the Report Map and shows the character or runs the command.

The 8-byte HID report: byte 0 for modifiers (bit 0 = left Ctrl, bit 1 = left Shift, etc.), byte 1 reserved, bytes 2–7 for up to 6 keys held at once.Byte 0 · modifier bitmapleftrightCtrlShiftAltGUICtrlShiftAltGUI01234567key codes (up to 6 keys)reservedmodifiers
The 8-byte HID report: byte 0 for modifiers (bit 0 = left Ctrl, bit 1 = left Shift, etc.), byte 1 reserved, bytes 2–7 for up to 6 keys held at once.
Matrix scanning: one column is driven HIGH, and a row that reads HIGH reveals the pressed key at the crossing. The diode beside each switch prevents ghosting.R0R1R2R3rowsreadC0C1C2C3C4column → HIGHdiode prevents ghosting6 rows × 14 columns = 20 pins
Matrix scanning: one column is driven HIGH, and a row that reads HIGH reveals the pressed key at the crossing. The diode beside each switch prevents ghosting.

Why a matrix with diodes

To save microcontroller pins, the switches are laid out in a grid of rows and columns. Each switch has a diode in series, so several presses at once are read correctly (N-Key Rollover) and no “phantom” presses appear (ghosting).

From the thesis, chapter 2.5, 4.3, 1.1

The ZMK firmware

ZMK is an open-source firmware for wireless keyboards. Unlike QMK, the traditional firmware, it is built on Zephyr, a real-time operating system (RTOS) backed by the Linux Foundation. It was designed for wireless from the start, with power management and switching between several Bluetooth connections.

You do not write C code: key behaviour is described in configuration files (.keymap and .conf) using devicetree syntax. The BLE stack comes ready-made and certified from Zephyr.

What it can do

Layers
Several key maps. On a secondary layer, H, J, K and L can become arrows, and the number row can become F1–F12.
Macros
Key sequences fired by a single press, e.g. a code structure such as a for loop.
Combos
An action when two or more keys are pressed together, e.g. J + K sends Escape.
Tap-dance
One key does different things depending on how you tap it: once for “a”, twice for “@”, three times for Caps Lock.
Mouse keys
On a dedicated layer, I, J, K and L move the cursor, and U and O give left and right clicks.
Connection profiles
The keyboard remembers several paired devices. A combination (e.g. Fn + 1/2/3) switches to another one, so you can control a PC, a laptop and a tablet from the same keyboard.

Keymap behaviours

&kp
“Key Press”: sends a standard key code, e.g. &kp Q.
&mo
“Momentary Layer”: turns a layer on only while you hold the key, like the Fn key (e.g. &mo 1).
&bt
Manages Bluetooth profiles: &bt BT_SEL 0 picks the first paired device, &bt BT_CLR clears the saved profiles.
&macro
Defines and fires complex sequences of key presses.

From the thesis, chapter 4.1, 4.4, 2.5, 4.4

Battery and power

How power is saved

Deep sleep
After a configurable idle period, the processor and most peripherals shut down and consumption drops to a few microamps. The first key press wakes the system instantly.
Event-driven design
The firmware does not sit in busy-wait loops; it only wakes on a hardware interrupt (a key press) or a radio event.
Adaptive connection interval
The keyboard negotiates with the computer how often they talk. While you type the interval is short, for low latency; when idle, it grows and the radio transmits less often.
Power gating
Internal peripherals (ADC, SPI, I2C) are powered only when needed. The battery ADC, for instance, takes a single reading and switches off, within a few microseconds.

BLE connection interval

While typing
7.5–15 ms
Minimum latency
Idle but connected
100–200 ms
Fewer radio packets
Deep sleep consumption
µA
A few microamps
The TP4054’s CC/CV charge cycle: trickle charge below ~2.9 V, constant current, constant voltage at 4.2 V, then stop.Pre-charge(trickle)CCconstantcurrentCVconstantvoltageEnd4.2 V~2.9 V~10%timevoltagecurrentTermination: current below ~10% of max
The TP4054’s CC/CV charge cycle: trickle charge below ~2.9 V, constant current, constant voltage at 4.2 V, then stop.

Charging the Li-Po battery

  1. Trickle charge

    If the battery is very low (below ~2.9 V), the chip applies a small current to bring it back to a safe voltage.

  2. Constant current (CC)

    The main phase: the chip supplies a constant maximum current (set by a resistor on the PROG pin) while the battery voltage rises.

  3. Constant voltage (CV)

    At 4.2 V the voltage is held fixed and the current drawn by the battery falls naturally.

  4. Termination

    When the current falls below a threshold (usually 10% of the maximum), charging stops so the battery is not overcharged. An LED shows the charging state.

Power supply and protection

LDO regulator
Whether it comes from USB-C (5 V) or the battery (3.7 V), the voltage is regulated to 3.3 V, which the nRF52840 and especially its radio need. When the cable is unplugged, power switches to the battery without interruption.
Battery level
A voltage divider with high-value resistors brings the battery voltage (3.0–4.2 V) down to the chip’s ADC input. The firmware turns it into a percentage using the Li-Po discharge curve and reports it via the Battery Service. It is less precise than a dedicated fuel gauge, but a good compromise.
ESD protection
The USB-C data and power lines are protected by a suppression circuit, usually a TVS diode array, which diverts electrostatic discharges of thousands of volts to ground.
Hardware switch (shipping mode)
A physical switch in series with the battery disconnects it completely for long storage, cutting self-discharge to almost zero, which software sleep modes cannot do.

From the thesis, chapter 4.5, 3.5

Written from Ștefan-Emanuel Ciupitu’s bachelor thesis “Wireless multifunction keyboard using the nRF52840 module” (Suceava, 2025).