Skip to content

Added MCUboot support for RAK4631 module - #9

Merged
srcnert merged 11 commits into
rak-mainfrom
dev/mcuboot
Sep 28, 2026
Merged

srcnert merged 11 commits into
rak-mainfrom
dev/mcuboot

Conversation

@srcnert

@srcnert srcnert commented Sep 24, 2026 •

Copy link
Copy Markdown
Owner

Adds MCUboot as the first-stage bootloader for the RAK4631 (nRF52840), so the
loader and the sketch can both be updated over USB CDC-ACM without a J-Link.

Flash layout

The RAK4631 flash map moves into a shared rak4631_nrf52840_partitions.dtsi,
included by both the loader overlay and the MCUboot image overlay so the two
can never drift:

Partition Address Size Role
boot_partition 0x00000 64 KB MCUboot
slot0_partition / code_partition 0x10000 448 KB loader
slot1_partition / user_sketch 0x80000 480 KB sketch
storage_partition 0xf8000 32 KB NVS/LittleFS

Entering serial recovery

Two ways in, both routed through a boot-mode retention area in the last 1 KB of
SRAM (rak4631_nrf52840_bootmode.dtsi, also shared between the two images):

  • Double-tap reset — new modules/rak_double_tap module, built into the
    MCUboot image. The first pin reset arms a magic value and busy-waits
    CONFIG_RAK_DOUBLE_TAP_WINDOW_MS (default 500 ms) with the LED lit; a second
    reset inside that window sets BOOT_MODE_TYPE_BOOTLOADER.
  • 1200-bps touch — new variants/rak4631_nrf52840/variant.cpp implements
    _on_1200_bps(), setting the same boot mode and resetting, so arduino-cli upload works without touching the reset button. bootmode_set is added to
    loader/llext_exports.c so the sketch can reach it.

Build and upload

  • extra/build.sh gains --mcuboot, which switches the loader build to
    west build --sysbuild and picks up loader/sysbuild.conf,
    loader/overlay_mcuboot.conf and loader/sysbuild/mcuboot/. Artifact paths
    move under build/<variant>/loader, and firmwares/mcuboot-<variant>.hex is
    produced alongside the signed loader.
  • New mcumgr tool and programmer in platform.txt / programmers.txt /
    boards.txt: upload writes the sketch to slot 1, burn-bootloader sends
    the 1200-bps touch itself (arduino-cli does not) and then writes the loader
    to slot 0.
  • CI (extra/rak/checkall.py) now builds the loader with --mcuboot.

Other changes

  • loader/rak4630_regout0.c moves to modules/rak_regout0_fix/, becoming a
    Kconfig-selectable module (CONFIG_RAK_REGOUT0_FIX) so the MCUboot image and
    the samples can enable it too — the REGOUT0 fix has to run before the 3.3 V
    rail is needed, including in the bootloader. A new top-level modules/
    directory is wired into CMakeLists.txt and Kconfig.rak.
  • The three USB CDC-ACM ports are reordered so the sketch's Serial enumerates
    first, which is what the 1200-bps touch needs to land on; the console/logging
    port moves to third. This is user-visible: the console is no longer the
    first port.
  • Images are signed with a new committed ECDSA-P256 development key
    (key/arduino_key_ecdsa-p256.pem). As loader/sysbuild.conf notes, this key
    is for development only and must be replaced for production.
  • loader/mcuboot.md documents installing mcumgr/scripting-tools and the
    manual upload commands.

Signed-off-by: Sercan Erat <sercan.erat@rakwireless.com>
Signed-off-by: Sercan Erat <sercan.erat@rakwireless.com>
Signed-off-by: Sercan Erat <sercan.erat@rakwireless.com>
Signed-off-by: Sercan Erat <sercan.erat@rakwireless.com>
Signed-off-by: Sercan Erat <sercan.erat@rakwireless.com>
Signed-off-by: Sercan Erat <sercan.erat@rakwireless.com>
Signed-off-by: Sercan Erat <sercan.erat@rakwireless.com>
Signed-off-by: Sercan Erat <sercan.erat@rakwireless.com>
Signed-off-by: Sercan Erat <sercan.erat@rakwireless.com>
Signed-off-by: Sercan Erat <sercan.erat@rakwireless.com>
@claude

claude Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Claude finished @srcnert's task in 5m 44s —— View job


Review of the latest push

  • Read the diff against origin/rak-main
  • Check which previous findings were addressed
  • Review new/changed code (build.sh, CI, loader, modules, platform/boards)
  • Post inline comments + summary

This push mostly lands review feedback, and the substantive parts look right to me:

  • extra/build.sh — the signed-image guard now runs before the copy loop, so a --mcuboot build that produced no zephyr.signed.{bin,hex} aborts without leaving a mixed fresh/stale firmwares/. Correct.
  • .github/workflows/rak-build.yml:94 — lint path is now build/rak4631_nrf52840/loader, matching what extra/build.sh actually creates.
  • loader/overlay_mcuboot.conf — trimmed to IMG_MANAGER / STREAM_FLASH / BOOTLOADER_MCUBOOT; the dead mcumgr stack (several KB of flash in a 0x70000 slot0 with no transport) is gone. The loader already has CONFIG_FLASH/CONFIG_FLASH_MAP, so IMG_MANAGER resolves.
  • boards.txt — both 0x5300 and 0x5301 are declared as upload_port.*, so the running board is still identifiable.
  • loader/main.c — the 1200-bps touch now also lives in the loader, closing the "no sketch yet / crashed sketch" gap; ZARD_FIRST_SERIAL_IS_SERIALUSB holds for this variant (cdc-acm-serial = <&board_cdc_acm_sketch>, no arduino-router-serial), so the handler is really compiled in. The sketch_valid && guard on SKETCH_FLAG_LINKED is a good independent fix — an erased sketch area reads 0xff flags.
  • variant.cpp now uses sys_reboot() (exported in llext_exports.c under CONFIG_REBOOT) instead of NVIC_SystemReset, and builtin-led-gpios was dropped.
  • boards.txt:785 adding rak4631.build.zephyr_toolchain=arm-zephyr-eabi is right — extra/bootstrap.sh:49 reads that property, and every other board sets it.
  • .vscode/flash_sketch.jlink offset moved to 0x80000, matching the new slot1_partition. Consistent.

Three things still open, all posted inline:

  1. extra/rak/checkall.py:65 — --mcuboot is applied to every board, but the workflow you changed in this same push only passes it for rak4631; west rak-checkall -b nrf52840dk now runs a build that cannot succeed, and the build/{variant}/loader lint path doesn't exist for it either.
  2. programmers.txt:31 — the mcumgr programmer declares program.tool but platform.txt has no tools.mcumgr.program.pattern, so -P mcumgr (used by the new .vscode task) has no recipe.
  3. tools/mcumgr/go.mod:1 — .github/dependabot.yml wasn't regenerated; package_tool.yml's "Verify dependabot config" step compares it byte-for-byte and will fail.

Still open from earlier rounds, not re-posted inline to avoid repetition:

  • modules/rak_regout0_fix/Kconfig:7 — depends on BOARD_RAK4631_NRF52840 drops the nRF52840 DK, which the pre-move loader/rak4630_regout0.c covered via #if defined(CONFIG_BOARD_NRF52840DK). The DK can be jumpered into VDDH mode, so this is a behavioural regression, not a refactor. depends on BOARD_RAK4631_NRF52840 || BOARD_NRF52840DK plus CONFIG_RAK_REGOUT0_FIX=y in variants/nrf52840dk_nrf52840/nrf52840dk_nrf52840.conf restores it — or a line in the PR description if it's deliberate.
  • loader/mcuboot.md:41 — image confirm <hash of slot-1 image> marks the sketch slot as a pending upgrade for image 0; with SB_CONFIG_MCUBOOT_MODE_OVERWRITE_ONLY=y that can overwrite the loader. image list on the line above is the verification step you want.
  • loader/main.c:28,68 — the block is guarded on CONFIG_RETENTION_BOOT_MODE alone but also uses uart_line_ctrl_get() (CONFIG_UART_LINE_CTRL) and sys_reboot() (CONFIG_REBOOT). Only rak4631_nrf52840.conf sets CONFIG_REBOOT today, and this is a file shared by every board, so widening the guard the way llext_exports.c:552-558 already does would keep it safe.
  • README.rak.md:190 — "the four recipes" is five now, and since the mcumgr package-index entry is deferred to another PR, {runtime.tools.mcumgr.path} resolves to nothing for everyone while boards.txt:799 makes mcumgr the default upload.tool. A note that platform.local.txt must override tools.mcumgr.path={runtime.platform.path}/tools/mcumgr would keep the source-checkout path working in the meantime.

One withdrawal: I flagged the .gitignore __pycache__/ removal as a regression last round. That was wrong — .gitignore:10 already carries the same entry, so the deleted line at the bottom was a duplicate. Nothing lost.

I also re-checked the -DEXTRA_CONF_FILE question from an earlier round and it's fine: zephyr_get(EXTRA_CONF_FILE SYSBUILD LOCAL ...) falls back to the un-prefixed sysbuild cache variable for the main application image, and the loader is the main app. No -Dloader_ prefix needed.
· branch dev/mcuboot

Comment thread extra/build.sh
Comment thread platform.txt Outdated
Comment thread boards.txt Outdated
Comment thread loader/overlay_mcuboot.conf Outdated
Comment thread variants/rak4631_nrf52840/rak4631_nrf52840_partitions.dtsi
Comment thread modules/rak_double_tap/double_tap.c Outdated
Comment thread loader/sysbuild/mcuboot/boards/rak4631_nrf52840.overlay
Comment thread variants/rak4631_nrf52840/rak4631_nrf52840.overlay Outdated
Comment thread .gitignore
Comment thread platform.txt Outdated
Comment thread modules/rak_double_tap/double_tap.c
Comment thread platform.txt
Comment thread loader/mcuboot.md
Comment thread boards.txt
Comment thread modules/rak_regout0_fix/Kconfig
Comment thread variants/rak4631_nrf52840/variant.cpp
Comment thread extra/build.sh
Comment thread loader/mcuboot.md
Comment thread README.rak.md
Comment thread platform.txt
Comment thread extra/build.sh Outdated
Comment thread modules/rak_regout0_fix/Kconfig
Comment thread README.rak.md
Comment thread extra/rak/checkall.py
Comment thread extra/rak/checkall.py
Comment thread .github/workflows/rak-build.yml
Comment thread extra/rak/checkall.py
Comment thread loader/main.c
Comment thread .github/workflows/rak-build.yml Outdated
Comment thread programmers.txt
Comment thread tools/mcumgr/go.mod
Signed-off-by: Sercan Erat <sercan.erat@rakwireless.com>
Comment thread extra/rak/checkall.py
Comment thread programmers.txt
Comment thread tools/mcumgr/go.mod
@srcnert
srcnert merged commit 5179845 into rak-main Sep 28, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant