You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/docs/main/docs/user_guide/flash_firmware/use_embassy_boot.mdx
+123Lines changed: 123 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -211,3 +211,126 @@ Additionally the bootymcbootface bootloader has blinking codes using PIN_25 (RP2
211
211
| Successful DFU→ACTIVE copy; about to jump | 5 short blinks (50 ms) |
212
212
| Bootloader itself panicked (e.g. flash read error, invalid state partition) | Morse SOS (... --- ...), repeating |
213
213
214
+
---
215
+
216
+
## Split peripheral updates (dfu_split)
217
+
218
+
When using a split keyboard with separate microcontrollers for each half,
219
+
`dfu_split` lets you update the peripheral's firmware without a debug
220
+
probe — the central acts as a relay.
221
+
222
+
In order for this to work, the peripheral needs to be flashed with an embassy-boot bootloader (e.g. bootymcbootface) and with a peripheral firmware that has `dfu_split` enabled. (See above on how to do that)
223
+
224
+
### Feature flags
225
+
226
+
```toml
227
+
[dependencies]
228
+
rmk = { features = [ "dfu_rp", "split", "dfu_split"] } # or dfu_nrf instead of dfu_rp
229
+
```
230
+
231
+
`dfu_split` requires `dfu` (implied by `dfu_rp` / `dfu_nrf`) and `split`.
232
+
233
+
### Architecture
234
+
235
+
Two complementary paths are provided:
236
+
237
+
| Path | Mechanism | When to use |
238
+
|---|---|---|
239
+
|**Embedded**| The central includes the peripheral binary at compile time via `include_bytes!()` and flashes it automatically when the peripheral connects. | CI/CD, production, "flash-and-forget" |
240
+
|**Passthrough**|`dfu-util -a 1 -D peripheral.bin` sends the firmware through the central's USB DFU interface, which forwards it to the peripheral in real time. | Development, ad-hoc updates without recompiling the central |
241
+
242
+
Both paths split the firmware into 256-byte chunks and send them over the
243
+
split link as `FirmwareChunk` messages. The peripheral writes them to its
244
+
own DFU flash partition, verifies the CRC, and resets into the new image.
245
+
246
+
### Embedded firmware path
247
+
248
+
In order to embed the peripherals firmware into the centrals firmware, we need to tell the central during compilation where the binary of the peripheral is.
249
+
Note that this must be a .bin-file. You can create one using `cargo make bin`
250
+
251
+
import { Tab, Tabs, Rust, Toml } from'@theme'
252
+
253
+
<Tabs>
254
+
<Tablabel={<Toml />}>
255
+
256
+
Add a firmware field with the path to the peripherals firmware binary in the peripheral's section. This is a relative path starting from where the Cargo.toml.
257
+
258
+
```toml title="keyboard.toml"
259
+
[[split.peripheral]]
260
+
rows = 2
261
+
cols = 1
262
+
firmware = "./../peripheral.bin"
263
+
```
264
+
265
+
The `#[rmk_central]` macro then generates the `set_firmware_update_data`
266
+
call automatically. When the field is absent the central relies on
Where the first argument of `set_firmware_update_data` is the index of the peripheral. (The same as the first argument of `run_peripheral_manager`.)
280
+
281
+
</Tab>
282
+
</Tabs>
283
+
284
+
After flashing the central, it will ask the peripheral for its firmware checksum, the peripheral answers and if the checksum does not match with the checksum of the embedded firmware, it will start flashing the embedded peripheral firmware onto the peripheral. The blink codes of the led (see above) are the same like during a normal DFU update.
285
+
286
+
### Passthrough path
287
+
288
+
```shell
289
+
# Flash peripheral 0
290
+
dfu-util -a 1 -D peripheral.bin
291
+
292
+
# Flash peripheral 1 (if you have a second peripheral)
293
+
dfu-util -a 2 -D peripheral2.bin
294
+
295
+
# Flash central
296
+
dfu-util -a 0 -D central.bin -R
297
+
```
298
+
299
+
This works identically to the normal DFU flash — just select a
300
+
different alternate setting (`-a`).
301
+
302
+
::: warning
303
+
Do **not** use `-R` (reset) when flashing a peripheral. The peripheral
304
+
resets itself after the update. `-R` would reset the central and abort
305
+
the transfer.
306
+
:::
307
+
308
+
::: note
309
+
The index of the alternate setting (`-a`) is off by 0 due to technical reasons. So to flash the peripheral with index 0, you have to pass `-a 1`.
310
+
:::
311
+
312
+
### Peripheral firmware requirements
313
+
314
+
The peripheral must call `init_flash()` and `mark_booted()` so that the
315
+
bootloader does not revert the update. With `#[rmk_peripheral(id = …)]`
316
+
(TOML API) this is generated automatically when a `[dfu]` section is
317
+
present in `keyboard.toml`.
318
+
319
+
If you are using the Rust API on the peripheral, ensure you have:
320
+
321
+
```rust
322
+
rmk::dfu::mark_booted();
323
+
```
324
+
325
+
in the main function.
326
+
327
+
Without `mark_booted()` embassy-boot will revert the update (visible as three short blinks of the DFU LED when using bootymcbootface).
328
+
329
+
### Troubleshooting
330
+
331
+
| Symptom | Likely cause |
332
+
|---|---|
333
+
| Peripheral blinks 3 times after update |`mark_booted()` not called in the peripheral. Add `[dfu]` to `keyboard.toml` or call `rmk::dfu::mark_booted()` manually. |
334
+
|`dfu-util -a 1` shows `dfuERROR`| Peripheral not connected or its firmware is built without the `dfu_split` feature. |
335
+
|`dfu-util` hangs on `dfuMANIFEST`| Expected — no USB reset was sent. The peripheral has already been updated. Disconnect / reconnect USB, let the host time out or exit dfu-util |
0 commit comments