Bootloader Configuration (embassy-boot)

embassy-boot is a libary of the embassy framework that is used to build bootloaders. RMK supports DFU firmware updates via embassy-boot for RP2040 and nRF52840. An embassy-boot based bootloader splits flash into ACTIVE and DFU slots, providing safe updates with automatic rollback on failure. This is an optional feature of RMK, the default bootloaders of the devices can still be used as usual without runtime updates via USB DFU.

A pre-built embassy-boot based bootloader called bootymcbootface is available for both platforms. The partition formula is identical:

bootloader+state = 28K (fixed)
storage = 128K (fixed — 32 sectors × 4K for persistent keymap storage)
remaining = flash_size - 28K - 128K
ACTIVE    = (remaining - 4K) / 2
DFU       = ACTIVE + 4K

See the flashing guide for step-by-step instructions on how to get the bootloader and RMK flashed.

RP2040

Add a [dfu] section to your keyboard.toml or use the Rust API directly.

Toml
Rust
keyboard.toml
[dfu]
# (Optional) Total flash size in bytes. Used to auto-calculate partition addresses.
# Defaults to 2 MB (2097152) when omitted.
# ⚠ You can define your own FLASH_SIZE and offset addresses, but then you must build and
# flash a custom embassy-boot bootloader with a matching memory.x!
flash_size = 2097152

# (Optional) Flash page size in bytes (4096 for RP2040).
page_size = 4096

# (Optional) DFU activity LED pin, default "PIN_25".
led = "PIN_25"
# led = "none" to omit DFU LED

# (Optional) Unlock keys for dfu_lock (physical matrix positions). Only works with dfu_lock feature enabled in Cargo.toml.
unlock_keys = [[0, 0], [1, 1]]

# ── (Optional) Manual overrides (only if auto-calculation is not suitable) ──
state_offset = 0x6000
state_size   = 0x1000
dfu_offset   = 0x87000
dfu_size     = 528384

nRF52840

Add a [dfu] section to your keyboard.toml or use the Rust API directly.

Toml
Rust
keyboard.toml
[dfu]
# (Optional) Total flash size in bytes. Used to auto-calculate partition addresses.
# 1 MB flash — auto-calculates ACTIVE (432K) and DFU (436K)
# ⚠ You can define your own FLASH_SIZE and offset addresses, but then you must build and
# flash a custom embassy-boot bootloader with a matching memory.x!
flash_size = 1048576

# (Optional) Flash page size in bytes (4096 for RP2040).
page_size = 4096

# (Optional) DFU activity LED pin, default "P0_15".
led = "P0_15"
# led = "none" to omit DFU LED

# (Optional) Unlock keys for dfu_lock (physical matrix positions). Only works with dfu_lock feature enabled in Cargo.toml.
unlock_keys = [[0, 0], [1, 1]]

# ── (Optional) Manual overrides (only if auto-calculation is not suitable) ──
state_offset = 0x6000
state_size   = 0x1000
dfu_offset   = 0x87000
dfu_size     = 528384

Partition layout

The bootloader divides flash into regions. The defaults follow the bootymcbootface convention and are automatically calculated from flash_size:

RegionOffsetSize
Bootloader(s)0x000000028 KB
Boot state0x60004 KB
Active firmware0x7000(flash_size - 28K - 128K - 4K) / 2
DFU downloadfollows activeactive_size + 4K
Storagefollows DFU128 KB

The DFU partition size follows embassy-boot guidelines, the additional page is used for status information during flashing.

All [dfu] fields are optional. The partition values are auto-calculated from flash_size and page_size using the bootymcbootface formula. If you supply any of state_offset, state_size, dfu_offset, or dfu_size directly, auto-calculation is disabled and your values are used as-is.

Your memory.x must match this partition layout — see the flashing guide for details.

DFU LED (optional)

A GPIO pin for the DFU LED.

PlatformDefault LED pinExample configuration
RP2040PIN_25led = "PIN_25"
nRF52840P0_15led = "P0_15"

See the LED behavior table for the full state machine.

DFU lock (optional, feature dfu_lock)

Physical key positions that unlock DFU firmware downloads. Requires the dfu_lock Cargo feature. Keys are identified by matrix position (row, col), not by keycode.

See the DFU lock section for the unlock workflow.

Tip

Choose keys that are easy to press simultaneously but not commonly pressed together accidentally.