DeterministicESPAsyncWebServer v6.28.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
psram_pool.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file psram_pool.h
6 * @brief Buffer placement policy (DRAM vs PSRAM) + SPI DMA ping-pong index manager
7 * (DETWS_ENABLE_PSRAM_POOL).
8 *
9 * An ESP32 with PSRAM has two heaps: fast internal DRAM (scarce, DMA-capable) and large external PSRAM
10 * (roomy, but not DMA-capable for most peripherals and slower). Serving big web assets / net buffers well
11 * means putting the large, cold buffers in PSRAM and keeping the small, hot, DMA buffers in DRAM, while
12 * always leaving an internal-DRAM reserve so the stack does not starve. That placement choice is a pure
13 * policy; the actual `heap_caps_calloc(..., MALLOC_CAP_SPIRAM / MALLOC_CAP_DMA)` is the app's.
14 *
15 * This module is that policy (`detws_psram_place`) plus the classic SPI DMA **ping-pong** double-buffer
16 * bookkeeping (`detws_pingpong_*`): while DMA drains one buffer, the CPU fills the other, and a swap
17 * exchanges their roles. Pure, no heap, no stdlib, host-testable.
18 */
19
20#ifndef DETERMINISTICESPASYNCWEBSERVER_PSRAM_POOL_H
21#define DETERMINISTICESPASYNCWEBSERVER_PSRAM_POOL_H
22
23#include "ServerConfig.h"
24#include <stddef.h>
25#include <stdint.h>
26
27#if DETWS_ENABLE_PSRAM_POOL
28
29/** @brief Placement verdict (the sole return of detws_psram_place). */
30enum class DetwsPlace : uint8_t
31{
32 PLACE_DRAM = 0, ///< allocate in internal DRAM.
33 PLACE_PSRAM = 1, ///< allocate in external PSRAM.
34 PLACE_FAIL = 2 ///< neither heap can satisfy the request.
35};
36
37/**
38 * @brief Decide where a buffer should live.
39 *
40 * Rules: a zero-size request fails; a DMA-required buffer must go in DRAM (or fail); a buffer at or above
41 * @p psram_threshold prefers PSRAM (falling back to DRAM); a smaller buffer prefers DRAM (falling back to
42 * PSRAM). A DRAM placement must still leave @p dram_reserve bytes free in DRAM.
43 *
44 * @param size requested bytes.
45 * @param dma_required true if the buffer must be DMA-capable (DRAM only).
46 * @param free_dram currently free internal DRAM.
47 * @param free_psram currently free PSRAM (0 if no PSRAM).
48 * @param psram_threshold size at/above which PSRAM is preferred.
49 * @param dram_reserve internal DRAM to keep free after a DRAM placement.
50 * @return PLACE_DRAM / PLACE_PSRAM / PLACE_FAIL.
51 */
52DetwsPlace detws_psram_place(size_t size, bool dma_required, size_t free_dram, size_t free_psram,
53 size_t psram_threshold, size_t dram_reserve);
54
55/** @brief SPI DMA ping-pong double-buffer state. */
56struct PingPong
57{
58 uint8_t fill_idx; ///< buffer the CPU is filling (DMA drains the other).
59};
60
61/** @brief Initialize: CPU fills buffer 0, DMA drains buffer 1. */
62void detws_pingpong_init(PingPong *pp);
63
64/** @brief The buffer index the CPU should fill. */
65uint8_t detws_pingpong_fill_index(const PingPong *pp);
66
67/** @brief The buffer index DMA should drain (the other one). */
68uint8_t detws_pingpong_drain_index(const PingPong *pp);
69
70/** @brief Swap roles (a filled buffer is handed to DMA; the drained one is now filled). @return new fill index. */
71uint8_t detws_pingpong_swap(PingPong *pp);
72
73#endif // DETWS_ENABLE_PSRAM_POOL
74#endif // DETERMINISTICESPASYNCWEBSERVER_PSRAM_POOL_H
User-facing configuration for DeterministicESPAsyncWebServer.