Use embassy-boot bootloader
embassy-boot is a bootloader framework from the Embassy project. It splits the flash into two firmware slots (active and DFU download), so updating is safe even if power is lost or the transfer fails — the old firmware remains intact and the bootloader can roll back automatically. You can build your own bootloader, or use a pre-built one like bootymcbootface.
RMK supports DFU for RP2040 (via dfu_rp) and nRF52840 (via dfu_nrf).
bootymcbootface is a pre-built embassy-boot bootloader for both platforms. It sits at the beginning of flash and handles the dual-slot firmware switching and rollback on boot. RMK itself provides the DFU USB interface (via embassy-usb-dfu) for subsequent updates, so once bootymcbootface and RMK are flashed, you never need to press BOOTSEL again.
RMK and bootymcbootface use an identical partition formula so the layout always fits perfectly:
The 4K page delta is an invariant of embassy-boot's swap algorithm: the DFU slot must always be exactly one erase page larger than the ACTIVE slot. Storage is reserved at the end of flash and cannot be reconfigured when using bootymcbootface — it is always 128K (32 sectors × 4K).
The size of the ACTIVE Region is what you need to plug in as the flash size in memory.x.
(see also the examples memory.x in rmk/examples/use_rust/rp2040_embassy_boot/ for RP2040 or rmk/examples/use_rust/nrf52840_embassy_boot/ for nRF)
If you override flash_size in your keyboard.toml's [dfu] section, RMK's auto-calc recomputes the layout on the fly. You never need to manually set the addresses like dfu_offset or dfu_size when using bootymcbootface.
Prerequisites
bootymcbootface
You need the bootymcbootface bootloader in the correct flash size for your board. The available versions are named by flash size, e.g.:
RP2040:
bootymcbootface-rp2040-2mb.uf2– for 2 MB flashbootymcbootface-rp204o-4mb.uf2– for 4 MB flashbootymcbootface-rp204o-8mb.uf2– for 8 MB flashbootymcbootface-rp204o-16mb.uf2– for 16 MB flash
The 2 MB version works with larger flash chips too (e.g. 4 MB or 8 MB), using only the first 2 MB. On 2 MB you get 944K of ACTIVE space, which is ample for most RMK firmwares. If you need more room (e.g. with large keymaps, displays, RGB, or many features), pick the matching flash size variant — see the table above for exact slot sizes.
nRF52840:
bootymcbootface-nrf52840.uf2– for 1 MB flashbootymcbootface-nrf52840.elf– for 1 MB flash, for direct flashing via probe-rs
When using the nRF52840 with the Adafruit UF2 bootloader, flashing bootymcbootface overwrites the Adafruit bootloader (even when flashing via UF2). Subsequent UF2 uploads won't work.
Compile RMK with DFU support
RMK must be compiled with the dfu feature and the platform-specific feature:
- RP2040:
dfu_rp - nRF52840:
dfu_nrf— optionally withnrf52840_blefor simultaneous BLE support
If configuring manually, ensure:
Cargo.tomluses thedfu_rp(RP2040) ordfu_nrf(nRF52840) featurekeyboard.tomlhas[dfu]section- The flash partitioning in
memory.xmatches your bootloader and flash size (seermk/examples/use_rust/rp2040_embassy_boot/for RP2040 orrmk/examples/use_rust/nrf52840_embassy_boot/for nRF)
Important: For RP2040 the bootymcbootface version (2MB, 4MB, ...) and the RMK settings must use the same flash size. Example: bootymcbootface 2 MB → RMK with 2 MB flash configuration. So that means, if you have a RP2040 with bigger flash, you can always use a bootymcbootface and a memory.x in your firmware for a smaller flash size, but the both must be for the same flash size.
You can still flash firmware via UF2 (when using RP2040, on nRF52840 the UF2 bootloader was overwritten by bootymcbootface) or probe-rs — as long as it was built with the correct memory.x for the embassy-boot partition layout (i.e. with dfu_rp or dfu_nrf feature), it will land in the active firmware slot and leave bootymcbootface untouched.
If you flash a RMK firmware built with a normal memory.x (without embassy-boot), it will start at flash address 0x0 and overwrite bootymcbootface.
On RP2040 the UF2 bootloader lives in ROM and can't be overwritten. On nRF52840 with the Adafruit UF2 bootloader, flashing bootymcbootface via UF2 overwrites it — use DFU or probe-rs for subsequent uploads.
On nRF52840, DFU and BLE can be used simultaneously. Enable both dfu_nrf and nrf52840_ble features in RMK, set [ble] enabled = true in keyboard.toml, and your keyboard works over USB + BLE with DFU updates (over USB).
Step-by-step guide
First-time flashing
The first time, you need to flash the bootloader first, then RMK.
1. Flash bootymcbootface
RP2040 – via UF2:
- Put your RP2040 into bootloader mode (hold BOOTSEL button, plug in USB, release)
- A USB drive named
RPI-RP2should appear - Copy the matching
bootymcbootface-rp2040-<size>mb.uf2to the drive - The RP2040 reboots – the bootloader is now active
nRF52840 – via UF2:
- Double-tap the reset pin (connect to GND twice within 500 ms) — the LED pulses and a
NICENANOdrive appears - Copy
bootymcbootface-nrf52840.uf2to the drive - The board reboots — the bootloader is now active ⚠️ This overwrites the Adafruit UF2 bootloader on the nRF52840.
Via debug probe (probe-rs):
2. Flash RMK firmware
Now flash the actual RMK firmware. The bootloader stays in place.
Method A – via UF2:
- RP2040: Put the board into bootloader mode (hold BOOTSEL button, plug in USB, release), then copy the RMK firmware
.uf2file to the appearingRPI-RP2drive. - nRF52840: Since the Adafruit bootloader was overwritten when flashing the bootymcbootface bootloader, this method does not work for nRF52840 anymore.
Method B – via debug probe (probe-rs):
All subsequent updates via DFU
Once bootymcbootface and the RMK firmware have been flashed once, all future updates can be done easily over USB via DFU. (but as stated above, as long as the memory.x of your firmware fits, you can still use probe-rs (RP2040 and nRF52840) or the UF2 bootloader (RP2040))
Generate the .bin file
DFU flashing requires a .bin file (not .elf or .uf2). You have two options:
Option 1 – using rust-objcopy (or arm-none-eabi-objcopy):
Option 2 – using cargo make bin:
(Requires a Makefile.toml with a bin task — the generated template from rmkit and the examples already include one or see embassy-boot examples.)
Flash via dfu-util
Or with a device ID if multiple DFU devices are connected:
Find your device's VID:PID via lsusb on Linux or Device Manager (under "Universal Serial Bus devices") on Windows.
Installing dfu-util:
- Linux:
sudo apt install dfu-util(Debian/Ubuntu) orsudo pacman -S dfu-util(Arch) - macOS:
brew install dfu-util - Windows: Download from dfu-util.sourceforge.net
dfu-util will automatically detect the board — the RMK firmware exposes a DFU USB interface at runtime. No need to press BOOTSEL or trigger a special mode. (With the optional dfu_lock feature, DFU downloads require a physical key press to unlock — see below.)
Unlocking DFU (optional, dfu_lock)
If your RMK was compiled with the dfu_lock feature, DFU starts in a locked state. To unlock:
- Run
dfu-util -D your-firmware.bin— the download will be rejected, but this signals the keyboard to open the unlock window - The DFU LED turns solid on — you have 10 seconds to press the
unlock_keyscombination configured inkeyboard.toml(e.g.[[0, 0], [1, 1]]) - Once the keys are pressed, the LED blinks "D F U" in Morse code (
-.. ..-. ..-) — the DFU lock is released for another 10 seconds - Re-run
dfu-util -D your-firmware.bin— this time the download proceeds, the LED flickers, and the firmware is updated - After the update completes, the LED turns off and the board reboots
If you don't press the unlock keys within the first 10 seconds, the window closes and the LED turns off. If no DFU download starts within the unlocked 10 seconds, the lock re-engages automatically. In both cases just repeat from step 1.
LED behavior during DFU transfer (optional)
If an LED pin is configured in keyboard.toml (default PIN_25, if not [dfu] led = "none"):
Additionally the bootymcbootface bootloader has blinking codes using PIN_25 (RP2040) / P0_15 (nRF52840) as well: