Skip to main content

Module mem

Module mem 

Source
Expand description

Global heap ownership + external PSRAM integration.

The BSP owns the global heap so a binary never spells out esp_alloc::heap_allocator! or the per-board region sizes itself: init_heap declares the esp-alloc DRAM regions for a HeapProfile and, optionally, registers external PSRAM. esp-alloc’s global heap holds at most three regions, so each profile registers the reclaimed-ROM region, the plain-DRAM region, and (when PSRAM is supplied) the external region — never a fourth (a 4th add_region panics silently). The sizes are the HIL-proven per-board values previously copied into every binary.

use m5stack_core::mem::{self, HeapProfile};

// After board init, before the first allocation:
mem::init_heap(HeapProfile::Default); // DRAM regions only — never touches PSRAM
mem::init_heap(HeapProfile::Lvgl);

init_heap never touches PSRAM — it owns only the DRAM region sizes for a HeapProfile. PSRAM is a separate, deliberate decision: see psram_map / psram_split below. The PSRAM-specific surface (those two, the checked psram_box / psram_vec, PsramSafe) needs the psram feature; the heap regions and dma_buffer need only heap.

Both boards carry SPI PSRAM (Fire27: ~4 MB, CoreS3: ~8 MB). esp-alloc exposes a single global heap that can be backed by several regions. Getting PSRAM into one of those regions is opt-in and explicit — there is no function that puts PSRAM behind the global allocator as a side effect of anything else, because once a region carries external capability, every plain alloc::vec! / Box / String in the whole crate graph — not just your own code — becomes eligible to silently spill into it once internal DRAM is exhausted (esp-alloc has no “external, but not for capability-less requests” region flag).

  1. psram_map — the default. Maps PSRAM and hands back the whole region as a private slice. Nothing is registered with the global heap; nothing here is ever reachable by a plain allocation. Hand the slice to a foreign allocator (e.g. LVGL’s TLSF) or use it directly.
  2. psram_split — deliberate global exposure. Carves a private region off the base (as above) and registers the remainder with the global heap, for the checked psram_box / psram_vec helpers (which reject atomic-bearing types at compile time — see PsramSafe). Reach for this only when you’ve decided part (or with reserve: 0, all) of PSRAM should be globally exposed, and accept what that costs.
use m5stack_core::mem;

// Never touches the global allocator:
let psram = mem::psram_map(peripherals.PSRAM);

// Deliberately expose part of PSRAM globally:
let split = mem::psram_split(peripherals.PSRAM, 2 * 1024 * 1024)?;
let mut big = mem::psram_vec::<u8>(512 * 1024);   // in PSRAM, atomics rejected
let scratch = mem::psram_box([0u32; 1024]);       // in PSRAM
let dma = mem::dma_buffer(4 * 1024);              // in internal DRAM, DMA-safe

The raw marker allocators (ExternalMemory / InternalMemory) are also re-exported as an escape hatch for allocator_api2 containers, but they do not perform the atomic check — reach for them only when you know what you are placing in PSRAM.

§Enforced vs. documented caveats

  • Atomics must not live in PSRAM. Enforced on the checked path: psram_box / psram_vec bound T: PsramSafe, so anything holding an Atomic* (directly or transitively) fails to compile.
  • DMA from PSRAM: the original ESP32 (Fire27) cannot DMA out of PSRAM. Guarded by assert_dma_capable (a debug_assert on Fire27, a no-op on CoreS3, which can DMA from PSRAM); use dma_buffer to get an internal-DRAM buffer in the first place.
  • opt-level > 0: Enforced at build time — enabling the psram feature with opt-level = 0 fails the build (see build.rs). PSRAM timing calibration is unreliable unoptimized.

Structs§

AnyMemory
An allocator that uses all configured, available memory.
ExternalMemory
An allocator that uses external (PSRAM) memory only.
InternalMemory
An allocator that uses internal memory only.
PsramSplit
A private PSRAM region carved off the global heap, plus the external bytes registered with the global heap. Returned by psram_split.

Enums§

HeapProfile
Heap size profile — selects the HIL-proven per-board DRAM region sizes for a workload. The BSP owns the sizes so every binary gets the validated values; pass the matching profile to init_heap.
PsramSplitError
Why psram_split could not satisfy the request.

Traits§

PsramSafe
Marker for types safe to store in PSRAM: nothing holding an inline atomic.

Functions§

assert_dma_capable
Debug-assert that buf is DMA-reachable on this chip.
dma_buffer
A zeroed byte buffer in internal DRAM, suitable as a DMA buffer.
external_free
Free bytes in the global heap’s external (PSRAM) region, right now — 0 unless psram_split registered a non-empty remainder globally (a private psram_map / psram_split region is not counted here).
init_heap
Register the global heap’s DRAM regions for profile, using the HIL-proven per-board sizes. Call once, right after crate::board::init / Board::split and before any allocation.
internal_free
Free bytes in the global heap’s internal DRAM regions (reclaimed-ROM + plain-DRAM), right now. The tight resource on both boards; use it to measure headroom (e.g. before/after moving a subsystem’s heap to PSRAM).
psram_box
Allocate value in external PSRAM. Atomic-bearing T is rejected at compile time via PsramSafe.
psram_map
Map the board’s external PSRAM and return the whole region as a private slice. Nothing is registered with the global heap — nothing returned here is ever reachable by a plain alloc::vec! / Box / String.
psram_split
Map the board’s external PSRAM, carve a private region off the base, and register the remainder with the global heap.
psram_vec
A Vec<T> with room for capacity elements reserved in external PSRAM. Atomic-bearing T is rejected at compile time via PsramSafe.