Enforce classic ESP32 memory budgets and safe image merging
This commit is contained in:
1 parent
51ce1f8f0d
commit
f8dfcaa240
13 files changed
+516
-9
No files matched your search
@@ -1916,7 +1916,7 @@ removed. The fixed-size STM32WL FPF6 build cannot match authenticated channels.
|
||||
|
||||
**Parameters:**
|
||||
- `n`: Slot number within the table compiled for the target. Roomy ESP32 builds
|
||||
provide `1-255`; DRAM-tight classic ESP32 LoRa-OTA repeaters and nRF52/other
|
||||
provide `1-255`; classic ESP32 repeaters and nRF52/other
|
||||
normal constrained builds provide `1-31`; very-tight STM32WL repeaters provide
|
||||
`1-15`; the no-PSRAM LilyGo T-LoRa V2.1 repeater/observer provides `1-4`.
|
||||
- `channel`: `public`, a public `#channel`, or a 128/256-bit channel key in hex.
|
||||
@@ -3391,6 +3391,11 @@ set direct.retry.cr 20.0,12.0,6.0,2.0
|
||||
|
||||
**Note:** These commands are repeater-only.
|
||||
|
||||
The default capacity is 256 entries on classic ESP32, 2,048 on other ESP32
|
||||
chips, 512 on nRF52, and 64 on other platforms. Builds can override it with
|
||||
`MAX_RECENT_REPEATERS`. Classic ESP32's history uses 3,072 bytes of startup
|
||||
heap instead of 24,576 bytes, leaving more memory for the packet pool and Wi-Fi.
|
||||
|
||||
**Output order:**
|
||||
- `get recent.repeater` lists 3-byte prefixes first, then 2-byte prefixes, then 1-byte prefixes.
|
||||
- Within each prefix length, entries are sorted from highest SNR to lowest SNR.
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
# Classic ESP32 image memory budget
|
||||
|
||||
Classic ESP32 has 320 KiB of internal DRAM, but at most 160 KiB can hold
|
||||
statically allocated data. The remaining DRAM is available only through the
|
||||
runtime heap. Bluetooth, tracing, and SDK reservations further constrain the
|
||||
usable region. See Espressif's [memory types documentation](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/memory-types.html#dram-data-ram).
|
||||
|
||||
An image can therefore approach its static limit while PlatformIO reports
|
||||
less than 40% of the 320 KiB total in use. PSRAM does not expand the region used
|
||||
by ordinary internal `.data` and `.bss` allocations.
|
||||
|
||||
## Build enforcement
|
||||
|
||||
Every classic ESP32 environment inheriting `esp32_base` runs
|
||||
`scripts/check_esp32_dram.py`. The release builder also adds the script when
|
||||
an ESP32 profile replaces the inherited extra scripts. The check runs before
|
||||
image generation, merging, and uploading, including cached `nobuild` uploads.
|
||||
It requires the ELF and linker map to be present for those cached operations.
|
||||
The check script must load after `merge-bin.py` so the merge target retains its
|
||||
pre-action. A merge also requires the bootloader/partition flash layout;
|
||||
`nobuild` cannot create a bootable merged image when that layout is absent.
|
||||
|
||||
The check reads `dram0_0_seg` from the final linker map. SDK reservations are
|
||||
already reflected in that region; Bluetooth's reservation is not subtracted
|
||||
a second time. The occupied span runs from the region origin to `_heap_start`,
|
||||
including `.data`, `.bss`, `.noinit`, and alignment gaps. The allowed region is
|
||||
the smaller of the linker's region and 160 KiB.
|
||||
|
||||
Builds must leave at least **8 KiB free within that static region**. This is
|
||||
an additional project margin against near-full images, not an Espressif
|
||||
hardware limit or a prediction of free heap. A profile may require a larger
|
||||
margin with `custom_esp32_static_dram_reserve` in bytes; values below 8192 are
|
||||
rejected. Missing or unrecognized map boundaries also fail the check.
|
||||
|
||||
For the Heltec V2 build used to investigate the repeater report:
|
||||
|
||||
| Shared repeater defaults | Static span | Static region | Remaining | Result |
|
||||
| --- | ---: | ---: | ---: | --- |
|
||||
| Previous 255 scope slots | 124,020 B | 124,580 B | 560 B | Rejected |
|
||||
| Tuned 31 scope slots | 108,308 B | 124,580 B | 16,272 B | Passed |
|
||||
|
||||
These measurements remove the board's existing scope-capacity override to
|
||||
exercise the shared defaults. The normal Heltec V2 profile already used 31
|
||||
scope slots. Exact sizes vary with build flags and SDK versions.
|
||||
|
||||
To inspect an existing classic ESP32 build:
|
||||
|
||||
```sh
|
||||
python3 scripts/check_esp32_dram.py .pio/build/Heltec_v2_repeater/firmware.map
|
||||
python3 test/test_esp32_dram.py
|
||||
```
|
||||
|
||||
ESP32-S2, S3, and C-series chips have different memory maps and do not inherit
|
||||
this classic ESP32 check.
|
||||
|
||||
## Boot versus running memory
|
||||
|
||||
The build gate checks static placement needed to load and start the image.
|
||||
It never counts heap-only RAM toward that static budget. Allocations made with
|
||||
`new` or `malloc` in global constructors consume heap and are not included in
|
||||
the static span. Moving a table there changes its placement, not total RAM
|
||||
consumption.
|
||||
|
||||
Successful build checks do not prove that every runtime configuration will
|
||||
boot. Hardware validation must still cover startup allocations and the enabled
|
||||
Wi-Fi/Bluetooth services, recording minimum free internal heap and the largest
|
||||
free internal block. Available heap changes during initialization; for example,
|
||||
the Arduino 2.x repeater releases unused Bluetooth controller RAM in
|
||||
`initArduino()`, after global constructors have run.
|
||||
@@ -182,7 +182,7 @@ Capacity is selected at build time:
|
||||
|
||||
- Roomy ESP32 builds: 255 rewrite slots and 32 regionless-target slots, 10,204
|
||||
bytes RAM.
|
||||
- DRAM-tight classic ESP32 LoRa-OTA repeaters, nRF52, and other normal
|
||||
- Classic ESP32 repeaters, nRF52, and other normal
|
||||
constrained builds: 31 rewrite and regionless-target slots, 2,108 bytes RAM.
|
||||
- Very-tight STM32WL builds: 15 rewrite slots and one reusable regionless-target
|
||||
slot, 572 bytes RAM.
|
||||
@@ -190,6 +190,13 @@ Capacity is selected at build time:
|
||||
regionless-target slots, 272 bytes RAM. This minimum holds the
|
||||
three wildcard classes and one exact channel mapping.
|
||||
|
||||
Classic ESP32 uses the 31-slot default even on boards with PSRAM because these
|
||||
tables live in internal static DRAM. The separate channel-requirement table
|
||||
defaults to the same capacity and uses another 34 bytes per slot. Together,
|
||||
the 31-slot defaults save 15,712 bytes of static RAM compared with 255 slots.
|
||||
Custom builds can override `FLOOD_CHANNEL_SCOPE_SLOTS` and
|
||||
`FLOOD_CHANNEL_SCOPE_REQUIRE_SLOTS` with build flags.
|
||||
|
||||
Each rule retains its 36-byte record. A separate table holds 32-byte normalized
|
||||
names for up to the smaller of the rule count or 32 distinct regionless
|
||||
targets, except that very-tight STM32WL builds retain one reusable direct
|
||||
|
||||
@@ -11,6 +11,7 @@ Below are a few quick start guides.
|
||||
- [Filter Policy Playground](./filter_tool.md)
|
||||
- [Telemetry Decoder](./telemetry_decoder.md)
|
||||
- [CLI Availability by Firmware Build](./cli_build_matrix.md)
|
||||
- [Classic ESP32 image memory budget](./esp32_memory_budget.md)
|
||||
- [Easy LoRa OTA: ESP32 and nRF52 firmware updates](./ota_easy.md)
|
||||
- [Scripted LoRa OTA: Bash and PowerShell](./lora_ota_automation.md)
|
||||
- [nRF52 repeater OTA with external QSPI](./ota_nrf52_qspi.md)
|
||||
|
||||
Reference in new issue
Block a user