Skip to content

Commit 60c5ea6

Browse files
committed
feat(dfu): revisit docs, small corrections
Signed-off-by: Pascal Jäger <pascal.jaeger@leimstift.de>
1 parent 65e0010 commit 60c5ea6

12 files changed

Lines changed: 179 additions & 165 deletions

File tree

docs/docs/main/docs/configuration/bootloader.mdx

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ RMK supports DFU firmware updates via [embassy-boot](https://github.com/embassy-
44

55
A pre-built bootloader called **bootymcbootface** is available for both platforms. The partition formula is identical:
66

7-
```rust
8-
// bootloader+state = 28K (fixed)
9-
// storage = 128K (fixed — 32 sectors × 4K for persistent keymap storage)
10-
// remaining = flash_size - 28K - 128K
11-
// ACTIVE = (remaining - 4K) / 2
12-
// DFU = ACTIVE + 4K
7+
```text
8+
bootloader+state = 28K (fixed)
9+
storage = 128K (fixed — 32 sectors × 4K for persistent keymap storage)
10+
remaining = flash_size - 28K - 128K
11+
ACTIVE = (remaining - 4K) / 2
12+
DFU = ACTIVE + 4K
1313
```
1414

1515
See the [flashing guide](../user_guide/flash_firmware/use_embassy_boot.mdx) for step-by-step instructions.
@@ -40,17 +40,17 @@ led = "PIN_25"
4040
unlock_keys = [[0, 0], [1, 1]]
4141

4242
# ── (Optional) Manual overrides (only if auto-calculation is not suitable) ──
43-
# state_offset = 0x6000
44-
# state_size = 0x1000
45-
# dfu_offset = 0x87000
46-
# dfu_size = 528384
43+
state_offset = 0x6000
44+
state_size = 0x1000
45+
dfu_offset = 0x87000
46+
dfu_size = 528384
4747
```
4848

4949
</Tab>
5050
<Tab label={<Rust />}>
5151

5252
```rust title="main.rs"
53-
/ Flash layout using the bootymcbootface formula:
53+
// Flash layout using the bootymcbootface formula:
5454
// state at 0x6000 (4K), active from 0x7000 (size: (flash_size - 28K (= BOOT2 size + embassy-boot + embassy-boot state) - STORAGE_SIZE (= 128K) - page_size (= 4K)) / 2),
5555
// dfu follows active (active_size + page_size (= 4K))
5656
//
@@ -75,8 +75,7 @@ let active_size: u32 = (remaining - PAGE_SIZE) / 2; // DFU = ACTIVE + 1 page (em
7575
let dfu_size: u32 = active_size + PAGE_SIZE; // embassy-boot needs that extra page for swap info
7676
let dfu_offset: u32 = ACTIVE_OFFSET + active_size; // dfu after active
7777
let storage_offset: u32 = dfu_offset + dfu_size; // storage after active + dfu
78-
let storage_size: u32 = STORAGE_SIZE;
79-
assert!(storage_offset + storage_size == FLASH_SIZE); // sanity check that we fit everything in flash
78+
assert!(storage_offset + STORAGE_SIZE == FLASH_SIZE); // sanity check that we fit everything in flash
8079

8180
info!(
8281
"Flash layout: state @ 0x{:04X} ({}K), active @ 0x{:04X} ({}K), dfu @ 0x{:04X} ({}K), storage @ 0x{:04X} ({}K)",
@@ -87,13 +86,13 @@ info!(
8786
dfu_offset,
8887
dfu_size / 1024,
8988
storage_offset,
90-
storage_size / 1024
89+
STORAGE_SIZE / 1024
9190
);
9291

9392
let flash = async_flash_wrapper(rmk::dfu::init_flash(
9493
p.FLASH,
9594
storage_offset,
96-
storage_size,
95+
STORAGE_SIZE,
9796
STATE_OFFSET,
9897
STATE_SIZE,
9998
dfu_offset,
@@ -144,14 +143,10 @@ led = "P0_15"
144143
unlock_keys = [[0, 0], [1, 1]]
145144

146145
# ── (Optional) Manual overrides (only if auto-calculation is not suitable) ──
147-
# state_offset = 0x6000
148-
# state_size = 0x1000
149-
# dfu_offset = 0x87000
150-
# dfu_size = 528384
151-
152-
# (Optional) BLE + DFU simultaneously
153-
[ble]
154-
enabled = true
146+
state_offset = 0x6000
147+
state_size = 0x1000
148+
dfu_offset = 0x87000
149+
dfu_size = 528384
155150
```
156151

157152
</Tab>
@@ -181,8 +176,7 @@ let active_size: u32 = (remaining - PAGE_SIZE) / 2;
181176
let dfu_size: u32 = active_size + PAGE_SIZE;
182177
let dfu_offset: u32 = ACTIVE_OFFSET + active_size;
183178
let storage_offset: u32 = dfu_offset + dfu_size;
184-
let storage_size: u32 = STORAGE_SIZE;
185-
assert!(storage_offset + storage_size == FLASH_SIZE);
179+
assert!(storage_offset + STORAGE_SIZE == FLASH_SIZE);
186180

187181
info!(
188182
"Flash layout: state @ 0x{:04X} ({}K), active @ 0x{:04X} ({}K), dfu @ 0x{:04X} ({}K), storage @ 0x{:04X} ({}K)",
@@ -193,13 +187,13 @@ info!(
193187
dfu_offset,
194188
dfu_size / 1024,
195189
storage_offset,
196-
storage_size / 1024
190+
STORAGE_SIZE / 1024
197191
);
198192

199193
let flash = async_flash_wrapper(rmk::dfu::init_flash(
200194
p.NVMC,
201195
storage_offset,
202-
storage_size,
196+
STORAGE_SIZE,
203197
STATE_OFFSET,
204198
STATE_SIZE,
205199
dfu_offset,
@@ -233,13 +227,13 @@ run_all!(
233227

234228
The bootloader divides flash into regions. The defaults follow the [bootymcbootface](https://codeberg.org/Schievel/bootymcbootface/) convention and are automatically calculated from `flash_size`:
235229

236-
| Region | Offset | Size |
237-
|-----------------|--------------|------------------------------|
238-
| Bootloader | `0x0000000` | 28 KB |
239-
| Boot state | `0x6000` | 4 KB |
240-
| Active firmware | `0x7000` | `(flash_size - 28K - 128K - 4K) / 2` |
241-
| DFU download | follows active | `active_size + 4K` |
242-
| Storage | follows DFU | 128 KB |
230+
| Region | Offset | Size |
231+
|-----------------|----------------|--------------------------------------|
232+
| Bootloader(s) | `0x0000000` | 28 KB |
233+
| Boot state | `0x6000` | 4 KB |
234+
| Active firmware | `0x7000` | `(flash_size - 28K - 128K - 4K) / 2` |
235+
| DFU download | follows active | `active_size + 4K` |
236+
| Storage | follows DFU | 128 KB |
243237

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

docs/docs/main/docs/user_guide/flash_firmware/use_embassy_boot.mdx

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ RMK supports DFU for **RP2040** (via `dfu_rp`) and **nRF52840** (via `dfu_nrf`).
88

99
RMK and bootymcbootface use an **identical partition formula** so the layout always fits perfectly:
1010

11-
```rust
12-
// bootloader+state = 28K (fixed)
13-
// storage = 128K (fixed — 32 sectors × 4K for persistent keymap storage)
14-
// remaining = flash_size - 28K - 128K
15-
// ACTIVE = (remaining - 4K) / 2
16-
// DFU = ACTIVE + 4K (1 page delta required by embassy-boot swap)
11+
```text
12+
bootloader+state = 28K (fixed)
13+
storage = 128K (fixed — 32 sectors × 4K for persistent keymap storage)
14+
remaining = flash_size - 28K - 128K
15+
ACTIVE = (remaining - 4K) / 2
16+
DFU = ACTIVE + 4K (1 page delta required by embassy-boot swap)
1717
```
1818

1919
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).
@@ -26,8 +26,9 @@ The 4K page delta is an **invariant of embassy-boot's swap algorithm**: the DFU
2626
| Storage | 128K (0x20000) | 128K (0x20000) | 128K (0x20000) | 128K (0x20000) | 128K (0x20000) |
2727

2828
The size of the ACTIVE Region is what you need to plug in as the flash size in `memory.x`.
29+
(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)
2930

30-
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 `dfu_offset` or `dfu_size` when using bootymcbootface.
31+
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.
3132

3233
## Prerequisites
3334

@@ -41,11 +42,13 @@ You need the [bootymcbootface](https://codeberg.org/Schievel/bootymcbootface/) b
4142
- `bootymcbootface-rp204o-8mb.uf2` – for 8 MB flash
4243
- `bootymcbootface-rp204o-16mb.uf2` – for 16 MB flash
4344

45+
::: tip
46+
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.
47+
:::
48+
4449
**nRF52840:**
4550
- `bootymcbootface-nrf52840.uf2` – for 1 MB flash
46-
- or build with `cargo make build-nrf` / `cargo make uf2-nrf`
47-
48-
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, Vial, or many features), pick the matching flash size variant — see the table above for exact slot sizes.
51+
- `bootymcbootface-nrf52840.elf` – for 1 MB flash, for direct flashing via probe-rs
4952

5053
::: warning
5154
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.
@@ -64,10 +67,10 @@ If configuring manually, ensure:
6467
- `keyboard.toml` has `[dfu]` section
6568
- The flash partitioning in `memory.x` matches your bootloader and flash size (see `rmk/examples/use_rust/rp2040_embassy_boot/` for RP2040 or `rmk/examples/use_rust/nrf52840_embassy_boot/` for nRF)
6669

67-
**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.
70+
**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.
6871

6972
::: tip
70-
You can still flash firmware via UF2 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.
73+
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.
7174

7275
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**.
7376
:::
@@ -102,6 +105,8 @@ The first time, you need to flash the bootloader first, then RMK.
102105

103106
**Via debug probe (probe-rs):**
104107
```shell
108+
# in the bootymcbootface directory
109+
cargo build --relese
105110
# RP2040
106111
probe-rs run --chip RP2040 target/thumbv6m-none-eabi/release/bootymcbootface
107112
# nRF52840
@@ -121,18 +126,19 @@ Now flash the actual RMK firmware. The bootloader stays in place.
121126

122127
**Method B – via debug probe (probe-rs):**
123128
```shell
129+
# in your RMK firmware directory
124130
# RP2040
125131
probe-rs run --chip RP2040 target/thumbv6m-none-eabi/release/your-firmware
126132
# nRF52840
127133
probe-rs run --chip nRF52840_xxAA target/thumbv7em-none-eabihf/release/your-firmware
128134

129-
# or for both
135+
# or (for both RP2040 and nRF52840)
130136
cargo run --release
131137
```
132138

133139
### All subsequent updates via DFU
134140

135-
Once bootymcbootface and the RMK firmware have been flashed once, all future updates can be done **easily over USB via DFU**.
141+
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))
136142

137143
#### Generate the .bin file
138144

@@ -150,17 +156,17 @@ rust-objcopy -O binary target/thumbv7em-none-eabihf/release/your-firmware your-f
150156
```shell
151157
cargo make bin --release
152158
```
153-
(Requires a `Makefile.toml` with a `bin` task — the generated template from `rmkit` and the examples already include one.)
159+
(Requires a `Makefile.toml` with a `bin` task — the generated template from `rmkit` and the examples already include one or see embassy-boot examples.)
154160

155161
#### Flash via dfu-util
156162

157163
```shell
158164
dfu-util -D your-firmware.bin -R
159165
```
160166

161-
Or with a device ID if multiple devices are connected:
167+
Or with a device ID if multiple DFU devices are connected:
162168
```shell
163-
dfu-util -d 1209:1234 -D your-firmware.bin
169+
dfu-util -d 4c4b:4643 -D your-firmware.bin
164170
```
165171

166172
Find your device's VID:PID via `lsusb` on Linux or Device Manager (under "Universal Serial Bus devices") on Windows.
@@ -188,10 +194,20 @@ If you don't press the unlock keys within the first 10 seconds, the window close
188194

189195
If an LED pin is configured in `keyboard.toml` (default PIN_25, if not `[dfu] led = "none"`):
190196

191-
| State | LED behavior |
192-
|---|---|---|
193-
| Unlock window open (waiting for keys) | Solid on |
194-
| DFU unlocked (ready for dfu-util) | Blinks Morse "D F U" |
195-
| DFU download started | On |
196-
| Writing data blocks | Toggles on each block (flickers) |
197-
| DFU finished / system reset | Off |
197+
| State | LED behavior |
198+
|---------------------------------------|----------------------------------|
199+
| Unlock window open (waiting for keys) | Solid on |
200+
| DFU unlocked (ready for dfu-util) | Blinks Morse "D F U" |
201+
| DFU download started | On |
202+
| Writing data blocks | Toggles on each block (flickers) |
203+
| DFU finished / system reset | Off |
204+
205+
Additionally the bootymcbootface bootloader has blinking codes using PIN_25 (RP2040) / P0_15 (nRF52840) as well:
206+
| State | LED behavior |
207+
|------------------------------------------------------------------------------------------------------------|------------------------------------|
208+
| Normal boot — bootloader ran and jumped to ACTIVE | 2 short blinks (≈2 Hz) |
209+
| Bootloader detected a pending DFU→ACTIVE swap and is about to copy | 1 s solid on |
210+
| Previous forward swap completed but the new app did not call =mark_booted()= — reverting to the old ACTIVE | 3 short blinks (50 ms) |
211+
| Successful DFU→ACTIVE copy; about to jump | 5 short blinks (50 ms) |
212+
| Bootloader itself panicked (e.g. flash read error, invalid state partition) | Morse SOS (... --- ...), repeating |
213+

examples/use_config/nrf52840_embassy_boot/keyboard.toml

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,28 @@ enabled = true
3636
[ble]
3737
enabled = true
3838

39+
# DFU partition layout — must match your bootloader's memory.x
40+
#
41+
# By default RMK uses the bootymcbootface formula with flash_size from the
42+
# chip default (1 MB for nRF52840).
43+
# Calculation:
44+
# 2 * 1024 * 1024; // 2 MB (default)
45+
# 4 * 1024 * 1024; // 4 MB
46+
# and so on
47+
# the addresses for the state, dfu, active and storage partitions are then automatically calculated.
48+
# Uncomment and adjust to override:
49+
# [dfu]
50+
# flash_size = 2097152 # total flash (default: 1 MB)
51+
#
52+
# To set addresses manually, uncomment and edit the values below.
53+
# Doing so disables the auto-calculation:
54+
# state_offset = 0x6000
55+
# state_size = 0x1000
56+
# dfu_offset = 0x87000
57+
# dfu_size = 528384
58+
3959
[dfu]
40-
led = "P0_15"
60+
led = "P0_15" # default P0_15, to not use set to "none"
4161
# Optional DFU lock — physical keys to press simultaneously to unlock DFU firmware download.
4262
# Requires the `dfu_lock` Cargo feature (not enabled by default).
43-
# unlock_keys = [[0, 0], [1, 1]]
44-
45-
# [storage]
46-
# enabled = false
47-
# start_addr = 0xA0000
48-
# num_sectors = 32
63+
# unlock_keys = [[0, 0], [1, 1]]

examples/use_config/nrf52840_embassy_boot/memory.x

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@ Flash layout matching bootymcbootface nRF layout:
44
ACTIVE (this firmware): 432K at 0x7000
55
DFU: 436K at 0x73000
66
storage: 128K at 0xE0000
7-
8-
ACTIVE size depends on the default [storage] num_sectors (32 = 128K).
9-
If you change num_sectors, adjust LENGTH accordingly.
107
*/
118
MEMORY {
129
FLASH : ORIGIN = 0x00007000, LENGTH = 432K

examples/use_config/rp2040_embassy_boot/keyboard.toml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@ keymap = [
2929
],
3030
]
3131

32-
[storage]
33-
enabled = true
34-
3532
# DFU partition layout — must match your bootloader's memory.x
3633
#
3734
# By default RMK uses the bootymcbootface formula with flash_size from the
@@ -51,15 +48,9 @@ enabled = true
5148
# state_size = 0x1000
5249
# dfu_offset = 0x87000
5350
# dfu_size = 528384
54-
# Optional DFU activity LED (lit during firmware download)
55-
# led = "PIN_25"
5651

5752
[dfu]
5853
led = "PIN_16"
5954
# Optional DFU lock — physical keys to press simultaneously to unlock DFU firmware download.
6055
# Requires the `dfu_lock` Cargo feature (not enabled by default).
6156
unlock_keys = [[0, 0], [1, 1]]
62-
63-
[rmk]
64-
morse_max_num = 8
65-
max_patterns_per_key = 8
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
/*
22
This memory.x is for the RP2040 with 2MB flash.
3-
For different flash sizes see docs.
3+
For different flash sizes uncomment below.
4+
Be aware you need to change [dfu] flash_size in keyboard.toml accordingly
5+
and flash the matching bootloader.
46
*/
57
MEMORY {
68
FLASH : ORIGIN = 0x10007000, LENGTH = 944K
9+
/* 4MB: FLASH : ORIGIN = 0x10007000, LENGTH = 1968K */
10+
/* 8MB: FLASH : ORIGIN = 0x10007000, LENGTH = 4016K */
11+
/* 16MB: FLASH : ORIGIN = 0x10007000, LENGTH = 8112K */
712
RAM : ORIGIN = 0x20000000, LENGTH = 256K
813
}

0 commit comments

Comments
 (0)