Embedded

Flash vs EEPROM vs RAM in MCUs

By CourseTron Team ·  8 min read ·  Updated Oct 2026 💬 𝕏 in f
Table of Contents
    ? Print / Save as PDF

    In short: RAM holds your running variables and is volatile and infinitely rewritable; Flash stores your program and constants with huge capacity but coarse block erases and ~10k–100k write cycles; EEPROM is the small, byte-addressable store for settings that must survive power loss with the highest endurance of the three.

    Every microcontroller (MCU) ships with three memory technologies working together, and confusing them is one of the fastest ways to corrupt data, brick a bootloader, or watch a variable mysteriously reset. If you have ever asked "why does my calibration value vanish on reboot?" or "why can't I just write one byte to Flash like I do to RAM?", the answer lives in the physics and architecture of these three stores. Let us walk through endurance, access granularity, wear leveling, and the single most practical question for a firmware engineer: where do my variables actually live?

    The three memories at a glance

    On a typical Arm Cortex-M part such as an STM32F4 or an NXP Kinetis device, the address map carves out distinct regions. Flash is mapped at 0x08000000, SRAM at 0x20000000, and emulated or dedicated EEPROM sits in its own window. They differ not just in size but in how you are physically allowed to touch them.

    PropertyRAM (SRAM)Flash (NOR)EEPROM
    VolatilityVolatile (lost on power-off)Non-volatileNon-volatile
    Typical size4 KB – 512 KB32 KB – 2 MB128 B – 16 KB
    Write granularityByte / wordWord to program, block/page to eraseByte
    Endurance (write cycles)Effectively unlimited~10,000 – 100,000 per page~100,000 – 1,000,000 per byte
    Access speedFastest (single cycle)Fast read, slow erase (ms)Slow write (ms)
    HoldsStack, heap, globals, buffersCode, const tables, firmwareSettings, counters, calibration

    The defining asymmetry of Flash: you can program individual words (flip 1→0), but you can only erase in large pages (flip 0→1), often 2 KB, 4 KB, or 128 KB at a time. That one rule drives nearly every design decision around non-volatile storage.

    Why Flash cannot behave like RAM

    A NOR Flash cell stores charge on a floating gate. Programming injects electrons to represent a 0; erasing tunnels them off to restore a 1. Because erase is a high-voltage, whole-block operation, you cannot change a single byte from 0x3F to 0x40 in place. To "update" one byte you must erase the entire surrounding page and rewrite it. This is why embedded logging, firmware updates, and settings storage all revolve around page management rather than simple pointer writes.

    MCU address map: three memories, three jobs RAM / SRAM volatile, fastest Stack ↓ Heap ↑ .data .bss 0x20000000 Flash (NOR) non-volatile, page erase Vector table .text (code) .rodata 0x08000000 EEPROM non-volatile, byte write Settings Calibration Counters byte-addressable Runtime state in RAM, firmware in Flash, persistent settings in EEPROM CourseTron · coursetron.com
    The MCU address map: fast volatile RAM for runtime state, large Flash for code, and byte-addressable EEPROM for persistent settings.

    Where do my variables live?

    This is the question every embedded C newcomer gets wrong once. The linker, not you, decides placement based on how a symbol is declared:

    • Local variables (int x; inside a function) live on the stack in RAM. They vanish when the function returns.
    • Initialized globals (int gCount = 5;) live in .data: the initial value is stored in Flash and copied to RAM by the startup code before main().
    • Zero-initialized globals (static int buf[256];) go to .bss in RAM and are cleared at boot.
    • Constants (const uint8_t lut[] = {...};) stay in .rodata in Flash and are read in place, never copied.
    • Dynamic allocations (malloc) come from the heap in RAM.

    A 10 KB const lookup table costs you 10 KB of Flash and zero RAM. The same table without const is copied into RAM at startup, costing you 10 KB of both. On a 32 KB-RAM part, that single keyword is the difference between fitting and overflowing.

    Where the linker places each C symbol const lut[] → .rodata (Flash) int gCount = 5; → .data (Flash init, RAM copy) static int buf[256]; → .bss (RAM, cleared) int x; (local) → stack (RAM) malloc() → heap (RAM) Flash .rodata (const lut) .data initial value RAM .data (copied at boot) .bss (cleared at boot) stack (locals) heap (malloc) CourseTron · coursetron.com
    Placement by declaration: const data stays in Flash, initialized globals are copied to RAM at startup, and locals and heap live in RAM.

    Endurance and wear leveling

    Because Flash and EEPROM cells degrade with every erase/program cycle, a naive design that rewrites the same page on every update will wear it out. At 10,000 cycles, a datalogger writing once per second kills a page in under three hours. Wear leveling spreads writes across many physical locations so no single cell is hammered.

    The classic MCU technique is EEPROM emulation: dedicate two Flash pages and, instead of overwriting a value, append a new (virtual-address, value) record to the active page. When the page fills, valid records are migrated to the second page and the first is erased. ST's X-CUBE EEPROM library and NXP's FTFx drivers both implement exactly this. The effective endurance multiplies by the number of records a page can hold.

    Wear leveling: append-only write pointer One Flash page = 9 record slots Orange slot = next free slot; each update is appended, never rewritten When the page is full, valid records move to page 2 and page 1 is erased CourseTron · coursetron.com
    Rather than rewriting one cell, each new value is appended to the next free slot — spreading erase cycles evenly across the page.

    Access speed and the execution picture

    RAM reads and writes complete in a single clock cycle; that is why the CPU executes from it fastest and why time-critical routines are sometimes copied into RAM (__attribute__((section(".ramfunc")))). Flash reads are nearly as fast at low clock speeds but need wait states above ~30 MHz, which is why vendors add prefetch buffers and caches (ST's ART Accelerator, for example). Flash and EEPROM writes, however, take milliseconds and typically stall the Flash interface — on many parts you cannot fetch code from Flash while erasing it, so the write routine itself must run from RAM. EEPROM hides this behind its controller but is still orders of magnitude slower than RAM.

    Practical rules for firmware engineers

    • Never store a frequently-changing counter directly in a fixed Flash location without wear leveling.
    • Mark large constant tables const so they stay in Flash and spare your RAM.
    • Validate persisted data with a CRC; a power loss mid-write leaves EEPROM/Flash in an indeterminate state.
    • Prefer true EEPROM (or FRAM) for data updated thousands of times a day; its endurance dwarfs Flash.
    • Remember that understanding the address map is the foundation for memory-mapped I/O and peripheral programming.

    Teams doing serious embedded and silicon work verify these behaviors in simulation and on-target; for RTL and verification training that complements firmware skills, our sister brand ChipXpert VLSI training covers the hardware side in depth. If you are building the design itself, interrupt latency fundamentals is a natural next read.

    Want to master memory architecture, bare-metal C, and the Cortex-M toolchain hands-on? Explore our Embedded Systems track on CourseTron Courses and build real firmware from the first lesson.

    Frequently Asked Questions

    Can I use Flash as extra RAM?

    Not for read/write data. Flash is read-in-place for code and constants, but it cannot be written byte-by-byte or erased quickly. Use it only for values that change rarely. For scratch data you always need genuine RAM.

    Why does my global variable keep its value but a local one does not?

    Globals live in .data or .bss in RAM for the whole program lifetime, so they persist across function calls (but still reset on power-off). Locals live on the stack and are reclaimed the moment the function returns.

    Is EEPROM always a separate chip?

    No. Some MCUs have dedicated on-die EEPROM; many modern parts have none and instead emulate EEPROM inside Flash using wear-leveling libraries. External I2C/SPI EEPROMs and FRAM are also common when you need high endurance.

    What happens if power is lost during a Flash write?

    The cell can be left half-programmed, so the stored value is unreliable. Robust designs use a two-copy scheme with a CRC or a valid-flag written last, so the firmware can detect and discard a torn write on the next boot.

    Advertisement