Skip to content

Memory Configuration

Memory Overview

The N16R8 variant provides substantial memory resources:

MemorySizeInterfaceSpeed
Internal SRAM512 KB-CPU clock
Flash16 MBQuad SPI (QIO)80 MHz
PSRAM8 MBOctal SPI (OPI)80 MHz

Flash Memory

Flash Configuration

ParameterValue
Size16 MB (128 Mbit)
InterfaceQuad SPI (4-bit)
Speed80 MHz
Address Range0x00000000 - 0x00FFFFFF

Default Partition Table

ESP-IDF default for 16MB flash:

PartitionTypeOffsetSizeNotes
nvsdata0x900024 KBNon-volatile storage
phy_initdata0xF0004 KBPHY calibration
factoryapp0x100001 MBMain application
(unused)--~15 MBAvailable for expansion

Custom Partition Table for 16MB

Create partitions.csv:

# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 0x300000,
ota_0, app, ota_0, 0x310000, 0x300000,
ota_1, app, ota_1, 0x610000, 0x300000,
spiffs, data, spiffs, 0x910000, 0x6F0000,

This provides:

  • 3 MB for factory app
  • 3 MB each for 2 OTA slots
  • 7 MB for SPIFFS/LittleFS

Configuration

In menuconfig:

Serial flasher config →
Flash size → 16 MB
Flash SPI speed → 80 MHz
Flash SPI mode → QIO

PSRAM (Octal SPI)

PSRAM Configuration

ParameterValue
Size8 MB (64 Mbit)
InterfaceOctal SPI (8-bit)
Speed80 MHz
TypeESP-PSRAM64H or equivalent

Enabling PSRAM

In menuconfig:

Component config →
ESP PSRAM →
[*] Support for external, SPI-connected RAM
SPI RAM config →
Mode (QUAD/OCT) → Octal Mode
SPI RAM access method → Make RAM allocatable using malloc
SPIRAM size → 8MB

Using PSRAM

#include <Arduino.h>
void setup() {
Serial.begin(115200);
if (psramFound()) {
Serial.printf("PSRAM Size: %d bytes\n", ESP.getPsramSize());
Serial.printf("Free PSRAM: %d bytes\n", ESP.getFreePsram());
}
}
void loop() {
// Allocate in PSRAM
uint8_t* largeBuffer = (uint8_t*)ps_malloc(1024 * 1024); // 1MB
if (largeBuffer) {
Serial.println("Allocated 1MB in PSRAM");
// Use buffer...
free(largeBuffer);
}
// Allocate with preference for PSRAM
uint8_t* buffer = (uint8_t*)heap_caps_malloc(64 * 1024, MALLOC_CAP_SPIRAM);
delay(5000);
}

Internal Memory

SRAM Layout

RegionSizeUse
DRAM320 KBVariables, heap
IRAM128 KBCode execution, ISRs
RTC Fast8 KBFast RTC functions
RTC Slow8 KBULP code/data

Memory Capabilities

CapabilityDescription
MALLOC_CAP_DEFAULTAny memory
MALLOC_CAP_INTERNALInternal SRAM only
MALLOC_CAP_SPIRAMPSRAM only
MALLOC_CAP_DMADMA-capable memory
MALLOC_CAP_EXECExecutable memory

Checking Available Memory

void printMemoryInfo() {
Serial.printf("Total heap: %d\n", ESP.getHeapSize());
Serial.printf("Free heap: %d\n", ESP.getFreeHeap());
Serial.printf("Total PSRAM: %d\n", ESP.getPsramSize());
Serial.printf("Free PSRAM: %d\n", ESP.getFreePsram());
// Detailed breakdown
Serial.printf("Internal free: %d\n",
heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
Serial.printf("DMA-capable free: %d\n",
heap_caps_get_free_size(MALLOC_CAP_DMA));
}

XIP (Execute In Place)

The ESP32-S3 supports executing code directly from flash:

Cache Configuration

ParameterValue
I-Cache16 KB
D-Cache16 KB (configurable)

PSRAM for Code

With XIP enabled, code can run from PSRAM:

Component config →
ESP PSRAM →
SPI RAM config →
[*] Move instructions in flash to PSRAM
[*] Move constant data in flash to PSRAM

Memory Optimization Tips

1. Use PSRAM for Large Buffers

// Good: Large buffers in PSRAM
uint8_t* imageBuffer = (uint8_t*)ps_malloc(320 * 240 * 2);
// Bad: Large buffers in internal RAM
uint8_t imageBuffer[320 * 240 * 2]; // Stack overflow risk

2. DMA Buffers in Internal RAM

// DMA requires internal RAM
uint8_t* dmaBuffer = (uint8_t*)heap_caps_malloc(4096, MALLOC_CAP_DMA);

3. Place Strings in Flash

// Good: String in flash
Serial.println(F("This string stays in flash"));
// Or using PROGMEM
const char message[] PROGMEM = "Flash string";

4. Monitor Heap Fragmentation

void checkFragmentation() {
size_t largest = heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT);
size_t total = heap_caps_get_free_size(MALLOC_CAP_DEFAULT);
Serial.printf("Fragmentation: %.1f%%\n",
100.0 * (1.0 - (float)largest / total));
}

Troubleshooting

PSRAM Not Detected

  1. Verify Octal mode configuration
  2. Check GPIO35-37 are not used elsewhere
  3. Confirm board is N8R8 or N16R8 variant

Out of Memory Errors

  1. Check heap usage with ESP.getFreeHeap()
  2. Move large allocations to PSRAM
  3. Use LittleFS instead of SPIFFS for storage

Stack Overflow

  1. Increase task stack size in FreeRTOS config
  2. Avoid large local arrays
  3. Use heap allocation for big buffers