nrf52840: right-size the SoftDevice RAM reservation (+8 KB heap arena) - #10903
Conversation
The app RAM ORIGIN in both nrf52840 linker scripts has been a hard-coded
0x20006000 (24 KB reserved for S140) since they were introduced, but
sd_ble_enable() with our fixed Bluefruit configuration (one peripheral
link, BANDWIDTH_MAX / ATT MTU 247, 0x1000 attribute table) requires
substantially less. The SoftDevice cannot use the gap and the app image
is linked above it, so every byte between the true requirement and the
ORIGIN is simply unusable RAM - on a part where 2.8.0 field reports
showed the heap arena at 99% use.
Lower the ORIGIN to 0x20004000 in both s140 v6 and v7 scripts. The heap
arena is the linker gap on this platform, so the change is worth exactly
+8,192 B of free heap on every nRF52840 board (verified: rak4631 .heap
section 124,572 -> 132,764 B; both v6- and v7-script boards link with
.data at 0x20004000).
Safety net: Bluefruit.begin()'s return value - previously discarded -
is now checked. If a future SoftDevice or Bluefruit config change raises
the requirement past the reservation, the node logs a critical error
instead of silently running without BLE, with instructions to re-measure
via CFG_DEBUG=1 ("SoftDevice's RAM requires: 0x...").
📝 WalkthroughWalkthroughAdds a failure check for Bluefruit.begin() in NRF52Bluetooth::setup(), logging a critical error and returning early on failure. Updates SRAM region origin addresses in the S140 v6 and v7 linker scripts from 0x20006000 to 0x20004000, with updated comments describing RAM requirement handling. ChangesNRF52 BLE Initialization and RAM Configuration
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Setup as NRF52Bluetooth::setup
participant Bluefruit
participant ErrorLog as LOG_ERROR/RECORD_CRITICALERROR
Setup->>Bluefruit: begin()
Bluefruit-->>Setup: success/failure
alt failure
Setup->>ErrorLog: log critical error
Setup-->>Setup: return early
else success
Setup->>Setup: continue BLE setup
end
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Warning Review ran into problems🔥 ProblemsGit: Failed to clone repository. Please run the Comment |
⚡ Try this PR in the Web FlasherWarning This is an automated, unreviewed CI test build. Back up your device configuration Supported boards built by this PR (26)
Build artifacts expire on 2026-08-05. Updated for |
Firmware Size Report22 targets | vs
Show 17 more target(s)
Updated for 8facda9 |
|
Hardware validation (rak4631, S140 6.1.1, v6 linker script):
Remaining before undraft: phone pairing smoke (FIXED_PIN/RANDOM_PIN + config download) and one v7-board boot. |
|
Measured on hardware — the outstanding item is closed. rak4631 (S140 6.1.1, v6 linker script), Why it wasn't showing up before: on nRF52 this firmware overrides The number validates the choice and corrects the draft's speculative target:
So BLE bring-up on the 0x20004000 build: |
|
Caution Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted. Error details |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/platform/nrf52/NRF52Bluetooth.cpp (1)
280-284: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueTrim the multi-line comment to comply with guidelines.
This 5-line explanatory comment exceeds the "one or two lines maximum" limit for comments in
.cpp/.hfiles. Consider condensing the rationale into 1-2 lines and moving the detailed re-measurement instructions into the linker script comment (already present there) rather than duplicating them here.✏️ Suggested trim
- // sd_ble_enable() rejected our RAM base: the linker RAM ORIGIN - // (src/platform/nrf52/nrf52840_s140_v*.ld) is below what the SoftDevice needs for the - // current Bluefruit config. Without this check the node would silently run without BLE. - // Rebuild with -DCFG_DEBUG=1 to get "SoftDevice's RAM requires: 0x..." in the log, then - // raise the ORIGIN accordingly. + // sd_ble_enable() rejected our RAM base; see nrf52840_s140_v*.ld comment for details. LOG_ERROR("Bluefruit.begin failed - SoftDevice RAM reservation too small for this config");As per coding guidelines, "Keep code comments minimal: one or two lines maximum, only when the reason is not obvious, and do not restate the next line."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/platform/nrf52/NRF52Bluetooth.cpp` around lines 280 - 284, The comment in NRF52Bluetooth.cpp is too long for the `.cpp`/`.h` guideline and should be shortened to 1-2 lines. Trim the explanatory block near the `sd_ble_enable()` RAM-base check so it only states the essential rationale, and remove the duplicated re-measurement/build instructions since those belong in the linker script comment already. Keep the updated comment concise while preserving the key context around the RAM ORIGIN mismatch and the BLE failure.Source: Coding guidelines
src/platform/nrf52/nrf52840_s140_v6.ld (1)
24-34: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winComment overstates the safety margin.
The comment claims a "
~2+ KB margin" over the reported SoftDevice requirement, but per the PR's own hardware validation the measured requirement was0x200038A0, leaving only 1,888 bytes (< 2 KB) of margin against the new0x20004000origin. Update the comment to reflect the actual measured margin to avoid misleading future readers who might push the ORIGIN further down based on this comment.✏️ Suggested fix
- * 0x1000 attr table) sd_ble_enable() reports a requirement well below the old - * 0x20006000 ORIGIN; every byte of gap is unusable RAM. 0x20004000 keeps a - * ~2+ KB margin over the reported base. NRF52Bluetooth::setup() now checks + * 0x1000 attr table) sd_ble_enable() reports a requirement well below the old + * 0x20006000 ORIGIN; every byte of gap is unusable RAM. 0x20004000 keeps a + * ~1.9 KB margin over the reported base. NRF52Bluetooth::setup() now checks🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/platform/nrf52/nrf52840_s140_v6.ld` around lines 24 - 34, The RAM layout comment overstates the SoftDevice safety margin; the measured requirement against the new origin is under 2 KB, not “~2+ KB.” Update the explanatory comment in nrf52840_s140_v6.ld near the RAM ORIGIN to reflect the actual validated margin (based on the 0x200038A0 measurement) so future readers don’t infer extra headroom. Keep the note about NRF52Bluetooth::setup() and Bluefruit.begin() fallback, but make the margin wording precise and conservative.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/platform/nrf52/nrf52840_s140_v6.ld`:
- Around line 24-34: The RAM layout comment overstates the SoftDevice safety
margin; the measured requirement against the new origin is under 2 KB, not “~2+
KB.” Update the explanatory comment in nrf52840_s140_v6.ld near the RAM ORIGIN
to reflect the actual validated margin (based on the 0x200038A0 measurement) so
future readers don’t infer extra headroom. Keep the note about
NRF52Bluetooth::setup() and Bluefruit.begin() fallback, but make the margin
wording precise and conservative.
In `@src/platform/nrf52/NRF52Bluetooth.cpp`:
- Around line 280-284: The comment in NRF52Bluetooth.cpp is too long for the
`.cpp`/`.h` guideline and should be shortened to 1-2 lines. Trim the explanatory
block near the `sd_ble_enable()` RAM-base check so it only states the essential
rationale, and remove the duplicated re-measurement/build instructions since
those belong in the linker script comment already. Keep the updated comment
concise while preserving the key context around the RAM ORIGIN mismatch and the
BLE failure.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 28de4bb5-2bfe-4e93-913f-a3457c5fc3d1
📒 Files selected for processing (3)
src/platform/nrf52/NRF52Bluetooth.cppsrc/platform/nrf52/nrf52840_s140_v6.ldsrc/platform/nrf52/nrf52840_s140_v7.ld
meshtastic#10903) The app RAM ORIGIN in both nrf52840 linker scripts has been a hard-coded 0x20006000 (24 KB reserved for S140) since they were introduced, but sd_ble_enable() with our fixed Bluefruit configuration (one peripheral link, BANDWIDTH_MAX / ATT MTU 247, 0x1000 attribute table) requires substantially less. The SoftDevice cannot use the gap and the app image is linked above it, so every byte between the true requirement and the ORIGIN is simply unusable RAM - on a part where 2.8.0 field reports showed the heap arena at 99% use. Lower the ORIGIN to 0x20004000 in both s140 v6 and v7 scripts. The heap arena is the linker gap on this platform, so the change is worth exactly +8,192 B of free heap on every nRF52840 board (verified: rak4631 .heap section 124,572 -> 132,764 B; both v6- and v7-script boards link with .data at 0x20004000). Safety net: Bluefruit.begin()'s return value - previously discarded - is now checked. If a future SoftDevice or Bluefruit config change raises the requirement past the reservation, the node logs a critical error instead of silently running without BLE, with instructions to re-measure via CFG_DEBUG=1 ("SoftDevice's RAM requires: 0x...").
Part of the heap-recovery series (#10898, #10901, #10900, #10899, #10902).
Problem
Both nrf52840 linker scripts hard-code the app RAM ORIGIN at
0x20006000— a 24 KB SoftDevice reservation dating to their introduction.sd_ble_enable()computes the actual requirement from the Bluefruit configuration (one peripheral link,BANDWIDTH_MAX/MTU 247,0x1000attribute table) and it is substantially below that. The SoftDevice can't use the gap and the app is linked above it, so the difference is pure waste — on the platform where 2.8.0 field reports show the heap arena (which on this BSP is exactly the linker gap) at 99% use.Change
RAM ORIGIN 0x20006000 → 0x20004000in bothnrf52840_s140_v6.ldandnrf52840_s140_v7.ld.Bluefruit.begin()'s return value — previously discarded — is now checked: if a future SoftDevice/Bluefruit config bump raises the requirement past the reservation, the node records a critical error with instructions instead of silently running without BLE.Measured effect
+8,192 B of heap arena on every nRF52840 board, BT on or off:
.heapsection.dataaddrHardware validation (rak4631, S140 6.1.1)
Measured the actual SoftDevice requirement via
CFG_DEBUG=1:0x200038A00x200060000x200040000x20004000reclaims the full +8 KB while keeping a ~1.8 KB margin for SD-version/config variance across the v6/v7 fleet. (Measurement also ruled out tightening to0x20003800, which would sit below the 0x200038A0 floor.) BLE bring-up confirmed on the new base:Init Bluefruit → services (DIS/BAS/Mesh) → Advertise,Bluefruit.begin()returns success (the new critical-error guard never fires), client reconnects over serial; a v7-script board links at the new base too.Summary by CodeRabbit