Skip to content

nrf52: fix BLE-task stack overflow crashing pairing and wiping LittleFS - #11190

Merged
thebentern merged 1 commit into
developfrom
fix/nrf52-ble-task-stack
Jul 24, 2026
Merged

nrf52: fix BLE-task stack overflow crashing pairing and wiping LittleFS#11190
thebentern merged 1 commit into
developfrom
fix/nrf52-ble-task-stack

Conversation

@thebentern

@thebentern thebentern commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

The bug

On nRF52 targets, BLE pairing/first-sync can crash the device the moment the client writes config — and repeated crashes escalate to a total filesystem wipe: LittleFS metadata gets torn by the mid-write reset, lfs_assert fires on the next boot, the corruption handler formats the FS, and the node loses region, channels, module config, and its keypair (critical fault #13, new identity once region is set again).

Reproduced 100% on a Seeed Wio Tracker L1 on stock develop 6908d27: every iPhone pairing attempt reset the device at Opening /prefs/config.proto, fullAtomic=1, and the wipe cascade followed. This is very likely also #10905 (L1 display-thread crash on full config request) and a match for 2.8 field reports of nodes losing region/keys after a BLE session.

Root cause

Since #10967 made Router::sendLocal() handle self-addressed packets synchronously, the entire phone-API chain runs inline in the Bluefruit characteristic write callback:

toRadioWriteCb -> PhoneAPI::handleToRadio -> MeshService -> Router::sendLocal
  -> handleReceived -> callModules -> AdminModule::handleSetConfig
  -> radio reconfigure -> NodeDB::saveToDisk (LittleFS write)

That callback executes on the Bluefruit BLE FreeRTOS task, whose stock stack is 5 KB (CFG_BLE_TASK_STACKSIZE = 256*5 words). #10944 raised the Arduino loop task to 8 KB for exactly this chain — but after #10967, BLE-originated writes no longer run there, so the fix protects the wrong task. Measured frames (-fstack-usage, seeed_wio_tracker_L1): handleToRadio 520 B + handleReceivedProtobuf 584 B + handleSetConfig 520 B + perhapsDecode 472 B + ~450 B of glue ≈ 2.5 KB of application frames before LittleFS and the SX126x reconfigure even start — a 5 KB task can't carry it.

The fix

-DCFG_BLE_TASK_STACKSIZE=2048 (words = 8 KB) in variants/nrf52840/nrf52.ini, right next to the existing LOOP_STACK_SZ=2048 and for the same reason. bluefruit.cpp guards the define with #ifndef, so it takes effect without a framework patch. Costs 3 KB RAM, nrf52840 targets only.

Validation

A/B on the Wio Tracker L1, same commit, only this flag differing:

5 KB BLE stack 8 KB BLE stack
iPhone pairing + first-sync reset every attempt, then FS wipe pairs cleanly
App config screens (admin gets) n/a (dead before this) load instantly
set_config device + LoRa/region (two config.proto saves over BLE) reset mid-write both saves complete, settings persist

The 8 KB constant was verified in the shipped ELF (mov.w r2, #2048 into xTaskCreate in Bluefruit::begin). rak4631 and seeed_wio_tracker_L1 both build green. Native suites unaffected (build-flag change only).

Credit and relationship to #11155

@Ixitxachitl independently established during #11155 testing that the save-path crash persists after #11185 and that re-queueing sendLocal (which moves this pipeline back to the Router thread, i.e. the 8 KB loop task) makes it disappear — corroborating this diagnosis from the other direction. This PR is the minimal capacity-side guard that stops the crash-and-wipe today; #11155's relocation of the pipeline off the BLE task is the right architectural follow-up, and this guard remains correct after it lands (the BLE task still services SoftDevice events and other callback work, and 5 KB was marginal for that regardless).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved Bluetooth Low Energy pairing and initial synchronization reliability by increasing the task stack allocation.
    • Helps prevent stack overflows during early BLE operations.

Since #10967 made Router::sendLocal handle self-addressed packets
synchronously, the entire phone-API chain for a BLE client runs inline in
the Bluefruit characteristic write callback: toRadioWriteCb ->
PhoneAPI::handleToRadio -> admin set-config -> radio reconfigure ->
NodeDB::saveToDisk. That callback executes on the Bluefruit BLE FreeRTOS
task, whose stock stack is 5 KB (CFG_BLE_TASK_STACKSIZE = 256*5 words) -
not the Arduino loop task that #10944 already raised to 8 KB. The loop-task
fix therefore protects the wrong task for BLE-originated writes.

On a Seeed Wio Tracker L1 the 5 KB stack overflows during pairing
first-sync, resetting the device mid-LittleFS-write, every single time.
Repeated mid-write resets tear the LittleFS metadata, lfs_assert fires on
the next boot, and the corruption handler formats the whole filesystem:
region, channels, module config, and the node's keypair are all lost
(critical fault #13, new node identity on next region set). Reproduced
end-to-end tonight on stock develop 6908d27; with this change the same
device pairs, serves config screens, and survives back-to-back
config.proto saves over BLE.

Raise the BLE task to the same 2048 words (8 KB) as LOOP_STACK_SZ, for the
same reason. bluefruit.cpp's #ifndef guard makes the -D take effect with no
framework patch. Costs 3 KB of RAM on nrf52840 targets only.

Credit where due: Ixitxachitl independently established in #11155 testing
that the save-path crash persists after #11185 and that re-queueing
sendLocal (moving the pipeline back to the Router thread) makes it go away
- which corroborates this diagnosis from the other direction. This commit
is the minimal capacity-side fix; #11155's relocation of the pipeline off
the BLE task remains the right architectural follow-up, and this guard
stays correct even after it lands.

Likely also explains #10905 (L1 display-thread crash when a client
requests full configuration) and the 2.8 field reports of idle nodes
losing region and keys after a BLE session.
@thebentern thebentern added the bugfix Pull request that fixes bugs label Jul 24, 2026
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1367ba5e-60c0-483e-9ce9-e43972965ee8

📥 Commits

Reviewing files that changed from the base of the PR and between 01d1873 and 556931c.

📒 Files selected for processing (1)
  • variants/nrf52840/nrf52.ini

📝 Walkthrough

Walkthrough

The nRF52840 build configuration adds CFG_BLE_TASK_STACKSIZE=2048 to increase the Bluefruit BLE task stack during compilation.

Changes

BLE stack configuration

Layer / File(s) Summary
Configure BLE task stack
variants/nrf52840/nrf52.ini
Adds the CFG_BLE_TASK_STACKSIZE=2048 build flag and documents the pairing/first-sync stack overflow and framework guard.

Estimated code review effort: 1 (Trivial) | ~2 minutes

Possibly related PRs

Suggested reviewers: vidplace7

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: increasing the nRF52 BLE task stack to fix pairing crashes and filesystem wipes.
Description check ✅ Passed The description is detailed and covers the bug, root cause, fix, validation, and impact, matching the template's intent.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/nrf52-ble-task-stack

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.

@thebentern
thebentern merged commit becfb77 into develop Jul 24, 2026
26 checks passed
@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.

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.

1 participant