Chapter 2: Memory Architecture

Harvard vs Von Neumann

Before diving into specifics, it helps to understand the two fundamental memory architectures.

Von Neumann architecture uses a single address space for both program code and data. Reading an instruction and reading a variable share the same bus. Most general-purpose computers use this model.

Harvard architecture uses separate buses and address spaces for program memory and data memory. Code and data cannot be mixed without explicit hardware support. AVR microcontrollers are strict Harvard machines. The ESP32 is a modified Harvard architecture — it has separate instruction and data caches, but the underlying SPI Flash is accessible as both code and data through different mechanisms.

This distinction has a direct practical consequence: on AVR, a constant string in your sketch lives in Flash by default only if you place it there explicitly. Otherwise the compiler copies it into SRAM at startup.


Arduino (AVR) Memory Map

A typical ATmega328P (Arduino Uno) has three distinct memory regions:

Flash (Program Memory) — 32 KB

SRAM (Data Memory) — 2 KB

High address  ┌─────────────┐
              │   Stack     │  grows downward
              │      ↓      │
              │  (free RAM) │
              │      ↑      │
              │    Heap     │  grows upward (malloc/new)
              │─────────────│
              │    BSS      │  zero-initialized globals
              │─────────────│
              │    Data     │  initialized globals/statics
Low address   └─────────────┘

EEPROM — 1 KB

ATmega Variants

Board Flash SRAM EEPROM
Uno (ATmega328P) 32 KB 2 KB 1 KB
Nano (ATmega328P) 32 KB 2 KB 1 KB
Mega (ATmega2560) 256 KB 8 KB 4 KB
Leonardo (ATmega32U4) 32 KB 2.5 KB 1 KB

ESP32 Memory Map

The ESP32 has a richer memory landscape. The internal memory is split into several named regions, each with different properties.

Internal SRAM

The ESP32 has approximately 520 KB of internal SRAM divided into three banks:

SRAM0 (192 KB) — IRAM

SRAM1 (128 KB) — DRAM/IRAM shared

SRAM2 (200 KB) — DRAM

In practice, after the system libraries (WiFi stack, BT stack, FreeRTOS), you typically have 200–300 KB of heap available.

RTC Memory — 16 KB

// Variable that survives deep sleep
RTC_DATA_ATTR int bootCount = 0;

External PSRAM (optional)

Some ESP32 modules (e.g., ESP32-WROVER) include 4 or 8 MB of external PSRAM (pseudo-static RAM) connected via SPI. It is slower than internal SRAM (higher latency, lower bandwidth) but dramatically increases available heap for large buffers, image processing, or web serving.

Enable in Arduino-ESP32: Board settings → PSRAM → Enabled.

SPI Flash — 4–16 MB

External Flash chip connected via SPI (or QSPI). Contains:

Flash is not directly addressable as RAM. Code is fetched through a cache (MMU), and data must be explicitly read via APIs.

ESP32 Memory Summary

Region Size Volatile CPU Access Use
IRAM ~192 KB Yes Fast ISR, WiFi stack, time-critical code
DRAM ~160 KB Yes Fast Heap, globals, stack
RTC Fast 8 KB No (deep sleep) Fast Persistent variables
RTC Slow 8 KB No (deep sleep) Slow ULP programs
PSRAM 4–8 MB Yes Medium Large buffers
SPI Flash 4–16 MB No Via cache/API Firmware, filesystem

Checking Memory at Runtime

Arduino (AVR)

extern int __heap_start, *__brkval;

int freeRam() {
    int v;
    return (int)&v - (__brkval == 0
        ? (int)&__heap_start
        : (int)__brkval);
}

ESP32

void printMemInfo() {
    Serial.printf("Free heap: %u bytes\n", ESP.getFreeHeap());
    Serial.printf("Min free heap: %u bytes\n", ESP.getMinFreeHeap());
    Serial.printf("Free PSRAM: %u bytes\n", ESP.getFreePsram());
}

Previous: Introduction Next: RAM Management Home