Skip to content

Reset into BLE OTA DFU instead of jumping from the DFU callback - #12220

Merged
thebentern merged 1 commit into
developfrom
fix-nrf52-ble-dfu-reset
Oct 23, 2026
Merged

thebentern merged 1 commit into
developfrom
fix-nrf52-ble-dfu-reset

Conversation

@jamesarich

@jamesarich jamesarich commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

BLE OTA started from the apps fails on nRF52 builds since #12027 moved the toolchain to GCC 12.3.1. The node shows the bootloader's BLE OTA screen and is back in its old firmware about 10 s later; no update can start. USB/UF2 updates are unaffected.

The Adafruit BLEDfu handler switches to the main stack (__set_CONTROL(0)) and then calls bootloader_util_app_start(). GCC 9 emits a plain bl; GCC 12 makes it a tail call whose epilogue (add sp, #108; ldmia sp!, {r4-r7, lr}) pops the task frame from the main stack, past the end of RAM, and the CPU locks up. The bootloader then starts with GPREGRET 0xB1 but no SoftDevice, faults on its first SoftDevice call, and resets into the app.

QuiescingBLEDfu now handles START_DFU itself: same CCCD check and reply, same peer data at 0x20007F80 (layout asserted, same CRC), then enterOTADfu(), a reset with the 0xA8 magic, instead of the jump. The bootloader inits the SoftDevice itself and still reconnects to the peer.

The same root cause is fixed library-side by blin00 in meshtastic/Adafruit_nRF52_Arduino#8; this change does not depend on it. The bootloader is hardened separately in meshtastic/nRF52_Bootloader#69.

🤝 Attestations

  • I have tested that my proposed changes behave as described.
  • I have tested that my proposed changes do not cause any obvious regressions on the following devices:
    • Other: Seeed Wio Tracker L1 Pro (two units)

Bisected to #12027 on both units (parent good, #12027 bad on each). With this change, a full BLE update (713 KB, legacy DFU from bleak) completed and booted on an OTAFIX master bootloader without the #69 fix, and the bootloader came up in 1.5 s on the second unit's OTAFIX 2.2-BP1.3 bootloader. Not tested on other boards, on a stock vendor bootloader, or with the Meshtastic Android DFU client.

Summary by CodeRabbit

  • Bug Fixes
    • Improved Bluetooth OTA firmware update handling. Update requests are now rejected when they use unsupported write operations or notifications are disabled.
    • Accepted update requests preserve the connection and bonding information needed by the bootloader before disconnecting and entering update mode. Other control requests continue through the existing handling path.

fixes #12196

The Adafruit BLEDfu handler switches to the main stack and jumps to the
bootloader. Since the nRF52 toolchain moved to GCC 12.3.1 (#12027) that
call is compiled as a tail call whose epilogue pops the task frame from the
main stack, past the end of RAM, and the CPU locks up; the bootloader then
starts with GPREGRET 0xB1 and no SoftDevice, faults, and resets into the
app. Handle START_DFU here instead: write the same peer data and leave
through enterOTADfu(), a reset with the 0xA8 magic that every bootloader
handles.
@jamesarich jamesarich added the bugfix Pull request that fixes bugs label Oct 22, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚡ Try this PR in the Web Flasher

Note

Building this pull request… the flash button, badges and supported-board
list will appear here automatically once CI finishes.

@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
📥 Commits

Reviewing files that changed from the base of the PR and between 0d3da2d and 1511b14.

📒 Files selected for processing: 1
  • src/platform/nrf52/NRF52Bluetooth.cpp

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.

📝 Walkthrough

The nRF52 BLE DFU path now handles START_DFU directly. It validates the write, stores peer and bond data for the bootloader, disconnects, and enters OTA DFU.

Changes: nRF52 BLE OTA DFU

Layer / File(s) Summary
Direct START_DFU handoff
src/platform/nrf52/NRF52Bluetooth.cpp
onControlWrite calls the direct handler for START_DFU and retains library handling for other values. The handler validates the write, saves peer and bond data with a CRC, disables advertising restart, disconnects, and enters OTA DFU.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Possibly related issues

  • meshtastic/firmware#12196 — The issue reports BLE OTA entering a boot loop after a GCC toolchain update. This change uses a direct DFU path instead of jumping from the DFU callback, which targets that failure.

Suggested reviewers: thebentern

Merge Risk: ⚪ Minimal · up to 1511b

No actionable merge-blocking issue was established. Compatibility with other bootloaders remains untested, but the available evidence does not show a failure.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 1 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the primary change: resetting into BLE OTA DFU instead of jumping from the DFU callback.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description check Passed The description follows the repository template closely. It explains the problem (BLE OTA failing on nRF52 since #12027 moved to GCC 12.3.1), the root cause (tail-call epilogue pops the task frame fro…
Full details: Description check

Explanation

The description follows the repository template closely. It explains the problem (BLE OTA failing on nRF52 since #12027 moved to GCC 12.3.1), the root cause (tail-call epilogue pops the task frame from the main stack), and the fix (handle START_DFU in QuiescingBLEDfu and reset via enterOTADfu() instead of jumping). It links the issue with 'fixes #12196', lists related PRs in other repos, and gives test details on two Seeed Wio Tracker L1 Pro units. The Attestations section is filled in. Only the device checkboxes for the template's standard boards are unchecked; the author explicitly says those boards were not tested. The template's tip block was removed, as required.

✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

MemBrowse Memory Report · Explore what changed →

heltec-mesh-node-t114

  • FLASH: .text +336 B (+0.0%, 722,776 B / 802,816 B, total: 90% used)

nodara

  • FLASH: .text +336 B (+0.0%, 730,056 B / 802,816 B, total: 91% used)

rak4631

  • FLASH: .text +336 B (+0.0%, 716,296 B / 802,816 B, total: 89% used)

seeed_wio_tracker_L1

  • FLASH: .text +336 B (+0.0%, 712,936 B / 798,720 B, total: 89% used)

t-echo-plus

  • FLASH: .text +352 B (+0.0%, 723,984 B / 802,816 B, total: 90% used)

tracker-t1000-e

  • FLASH: .text +336 B (+0.1%, 507,128 B / 798,720 B, total: 63% used)

xiao_nrf54l15_lr2021

  • FLASH: .text +352 B (+0.1%, 582,040 B / 1,306,624 B, total: 45% used)

No memory changes detected for:


Catch memory regressions in CI with MemBrowse. Free for open source.

@jp-bennett jp-bennett added this to the 2.8.2 milestone Oct 23, 2026
@thebentern

Copy link
Copy Markdown
Contributor

LGTM. We should probably test on both SD versions.

@thebentern
thebentern added this pull request to the merge queue Oct 23, 2026
Merged via the queue into develop with commit e039e34 Oct 23, 2026
101 of 102 checks passed
@caveman99
caveman99 deleted the fix-nrf52-ble-dfu-reset branch October 26, 2026 08:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix Pull request that fixes bugs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: entering nrf52 BLE OTA from software broken after gcc toolchain update

3 participants