Storage Technologies

On this page

Saving a configuration value may require only a few bytes, but the underlying operation might need to erase several KiB. During programming, instruction fetches may be blocked, and a power loss could leave a half-written record. Choosing storage media should not rely solely on comparing capacity and read/write speeds; first ask: what are the read, program, and erase granularities? When is a write considered persistently successful? And who manages the worst-case write latency and endurance limits?

Data Use CasePrimary ConsiderationConditions Not to Omit
Runtime BufferSRAM, External RAMDMA accessibility, timing, volatility
Code & ResourcesInternal or External FlashXIP support, access during erase/program, boot path
Small ConfigurationsEEPROM, Log-style Flash, Key-Value StoreChecksums, versioning, update atomicity
High-Frequency Small RecordsF-RAM or suitable logging schemeBus throughput, limited endurance, multi-byte consistency
Large Records / ExportSD, eMMC, etc. (Managed Storage)Tail latency, controller behavior, file system sync

View Media, Bus, Controller, and File System in Layers

SRAM/DRAM describe storage cell types, SPI/QSPI describe interfaces, SD/eMMC are storage form factors that include protocols and management functions, and FAT/littlefs organize data. Names from different layers cannot be directly placed in the same "who is faster" ranking; read latency, sustained bandwidth, programming time, and erase time are not the same speed metrics.

Media or Form FactorTypical OrganizationWhat the Host Needs to Care About
SRAM / DRAMVolatile random access; DRAM requires refreshPower supply, controller, timing, and bus access
NOR FlashRandom read, programmed in specified units, erased in blocks1→0 programming, erase/rewrite limits, XIP support
Raw NANDPage read/write, block eraseECC, bad blocks, read disturbance, wear management
EEPROMByte/page write, internal erase/program completionPage boundaries, busy time, endurance and retention conditions
F-RAMNon-volatile read/write without Flash-style block eraseInterface speed, endurance, power-loss write window
SD / eMMCController presents a logical block interfaceCache/sync, tail latency, and power-loss recovery capability

XIP also requires the processor's memory mapping interface, boot configuration, and possibly cache support; it is not as simple as connecting any SPI Flash and executing code directly. Some platforms also copy code to RAM first. Whether internal Flash can read another region while erasing/programming depends on banks, buses, and chip limitations.

Why NOR Programming and Erase Are Separate

Typical NOR Flash is all 1s after erasure; programming changes selected bits to 0; restoring 0s to 1s requires erasing the containing block. Therefore, appending new data to a blank record area can be done by programming without immediate erasure; changing arbitrary bytes in place may trigger an erase and data migration. Specific devices have minimum programming units, page boundaries, alignment requirements, internal ECC, and repeated programming limits; allowed operations cannot be inferred solely from bitwise logic.

Example 4 KiB erase block: 16 x 256 B programming pagesPage 0256 BPage 1256 BPage 2256 BPage 3256 BPage 4256 BPage 5256 BPage 6256 BPage 7256 BSubsequent pages 8 … 15; specific dimensions depend on device specificationsNOR: Programming pages and erasing blocks are two different granularitiesErased 1111 → Programmed 1010; to restore to 1111, the containing block must be erasedUpdating a single byte does not equate to an immediate block erase; page boundaries, minimum programming units, and repeated programming limits cannot be ignored.

Assuming a device programming page size of 256 B, writing 20 bytes starting at offset 250 within a page should be split according to driver requirements into 6 bytes for the current page and 14 bytes for the next page. Writing beyond the boundary may cause page-internal wrapping on some devices; do not assume automatic continuation. Typical command flows also include write enable, issuing program/erase commands, polling for busy status, and error handling; the end of an SPI transmission does not mean the internal operation is complete.

AT25SF041 is a 4 Mbit SPI Flash. Distinguish between "bit" and "Byte" in device names. Renesas AT25SF041 Datasheet

EEPROM and F-RAM: Fast Write Does Not Mean Automatic Transaction Atomicity

Taking the 24LC256 as an example, it is a 256 Kbit, i.e., 32 KiB EEPROM, with a 64 B page write buffer. Page writes must respect boundaries; ready detection and ACK semantics during the internal write cycle are implemented according to the datasheet; bus ACK cannot be treated as data being permanently written. Microchip 24LC256

F-RAM does not require NOR-style block erasure and is suitable for certain frequent small-write tasks, but endurance is still a limited and conditional specification. Fast internal chip writes do not mean I²C/SPI serial transfers complete instantly; a business record composed of multiple bytes may still only be partially updated if power is lost mid-transfer. FM25V02A is 256 Kbit, 32 KiB, not 2 Mbit. Infineon FM25V02A

Endurance Calculated Based on Actual Erase/Write Amplification

If the same erase block is erased every 10 seconds, a rated 100,000 erase cycles correspond to a count budget of approximately 11.57 days. The key condition is "erasing the same block every time a save occurs," not "one business write every 10 seconds." If multiple records are appended to a blank area before erasing, the erase frequency can be significantly reduced.

Assuming 4096 B per block and 64 B per complete record, one block ideally holds 64 records; with 16 blocks rotating evenly, each block experiences one erase only after every 1024 records are written. At 100,000 cycles, this yields an ideal throughput budget of approximately 102.4 million records, but metadata, garbage collection, reserved space, bad blocks, and specific programming limits will reduce this. This is not a guarantee of product service life; retention time, temperature, and other device endurance limits may be reached first.

Dynamic wear leveling disperses wear across participating blocks, and static wear leveling may migrate long-inactive data to utilize more blocks. Algorithms also generate write amplification; measure actual physical operation counts rather than assuming all addresses endure the same wear just because the file system claims "wear leveling."

Dual-Bank Record Selection After Power Loss

PrepareA: Old record, validB: Blank / Safe to eraseWriteA: Still retainedB: Body + checksum, not committedCommitA: Can be reclaimed laterB: Committed; new sequenceDual-bank recovery: Before the new record is fully committed, the old record remains the basis for recoveryOn startup, scan both areas: only compare sequence numbers after format, length, commit marker, and checksum are all validAtomicity depends on media write/power-loss behavior and driver order; placing two data sets in the same erase block does not constitute independent dual-banks.

The two areas should be independently erasable. When preparing a new record, retain the old one; first write the format version, sequence number, length, body, and checksum. After confirming the order and completion conditions, write the commit marker according to the media's allowed independent programming granularity. On startup, reject uncommitted, out-of-bounds length, malformed, or checksum-failed records; select the newer sequence number among valid records; reclaim the old area only after the new record is reliably committed.

Power Loss PointRecovery ViewAction to Take
During new block erase or body writeOld area valid, new area incompleteRetain old version
Checksum written but not committedNew area is not yet a committed recordRetain old version
Commit complete, old area not erasedBoth areas validSelect new sequence number
During old area reclamationNew area validUse new version

The commit write itself may also be interrupted; its valid encoding and checksum rules must be defined; CRC can detect many common errors, but it is not an absolute guarantee against arbitrary corruption mathematically, nor does it provide authentication against malicious tampering. Sequence number rollover, format upgrades, and whether power loss might affect data outside the target area must also be handled. The simple dual-bank model cannot directly cover all failure modes within an SD controller.

Below enumerates each breakpoint of writing the new record byte-by-byte to verify that a half-written new record is never selected. The model assumes the old area is independent and undamaged, writes only form specified prefixes, and sequence numbers do not rollover; actual Flash minimum programming units and tearing write behavior still require separate verification.

import struct
import zlib

def encode(seq, payload):
    body = struct.pack('<IH', seq, len(payload)) + payload
    return body + struct.pack('<I', zlib.crc32(body)) + b'DONE'

def decode(blob):
    if len(blob) < 14:
        return None
    seq, size = struct.unpack('<IH', blob[:6])
    end = 6 + size
    if end+8 > len(blob) or blob[end+4:end+8] != b'DONE':
        return None
    if zlib.crc32(blob[:end]) != struct.unpack('<I', blob[end:end+4])[0]:
        return None
    return seq, blob[6:end]

old = encode(7, b'old configuration')
new = encode(8, b'new configuration')
for cut in range(len(new)+1):
    target = new[:cut] + bytes([255])*(len(new)-cut)
    valid = [x for x in (decode(old), decode(target)) if x is not None]
    recovered = max(valid, key=lambda x: x[0])
    assert recovered[0] == (8 if cut == len(new) else 7)
assert decode(b'bad') is None
assert decode(old)[1] == b'old configuration'
print('All prefix power-loss points: recover old record before commit, select new record after commit')

Which version survives a cut at each byte?

Moving the cut from 11 to 12 writes only the commit byte but changes recovery. Corrupting payload rejects the new record even with a commit. Removing the old region exposes premature reclamation: an uncommitted new record cannot replace a deleted old one.

Preparing the visual
Which version survives a cut at each byte?

A completed checksum is not a commit. Keeping an independent old region enables recovery from uncommitted or corrupt records.

SD / eMMC: Behind Logical Blocks Lies the Controller

Managed storage encapsulates many NAND details; the host faces logical block read/write, but internally there are still caches, mapping, garbage collection, and wear management. Writes of the same size may result in different busy times; buffers for continuous acquisition must cover the longest acceptable pause and define timeout and drop-sample policies.

For example, a 160 kB/s data stream encountering a 200 ms write pause requires at least 32,000 B of additional buffer, not accounting for scheduling and other margins. Looking only at the card's peak MB/s does not guarantee zero sample drops. SD storage buses and SDIO extension functions should not be conflated into the same term; whether to use SPI or native bus depends on card and host controller support and initialization requirements, not relying on fixed "send a few more clocks" patches.

Block devices can store custom raw formats; using a file system is not mandatory. If file exchange with a PC is needed, choose an implementation supporting the target format; voltage, pull-ups, and decoupling should be designed according to the respective interface and hardware documentation; do not uniformly add pull-ups to all signal lines.

File System Consistency Does Not Equal Business Commit Completion

FAT provides broad file exchange capabilities, but multiple metadata updates and power-loss semantics require careful application handling. littlefs is designed for constrained devices and Flash power-loss recovery, using corresponding metadata and copy-on-write designs; it still requires correct underlying read, program, erase, and sync contracts. littlefs Design

For example, after writing a new configuration file, sync/close according to the API and use a suitable atomic replacement process; separate successful updates of two files do not automatically constitute a cross-file transaction. littlefs documentation explicitly requires cached storage drivers to implement sync during sync, otherwise data integrity cannot be guaranteed. Successful mounting does not mean the last unsynced record is definitely retained. littlefs Interface and Sync Notes

Power-hold capacitors can be part of the design, but first detect voltage drop, stop new transactions, and reserve energy for the worst-case pending operation. Under constant current simplification, C ≥ I·Δt/ΔV; for example, 50 mA, 10 ms, allowing a 0.3 V drop yields approximately 1667 μF; ESR, tolerance, conversion efficiency, and minimum write voltage must also be considered. Unknown long-tail write times cannot be guaranteed by arbitrarily adding a capacitor.

Recalculating Granularity and Budgets

from math import isclose
assert 256*1024//8 == 32768
page, offset, count = 256, 250, 20
first = min(count, page-offset%page)
assert (first, count-first) == (6, 14)
assert isclose(100000*10/86400, 11.574074074074074)
records = (4096//64)*16*100000
assert records == 102400000
assert 160000*0.2 == 32000
assert isclose(0.05*0.010/0.3*1e6, 1666.6666666666667)
print('Capacity units, cross-page splitting, erase budget, buffer, and hold capacitor calculations passed')

This article verifies the model and breakpoint recovery logic; it did not erase/write actual storage media, nor perform real power-loss tests.

Continue Reading