Step 36 of 56
Off-chip memory: NOR flash, EEPROM and FRAM
Three non-volatile technologies with three different bargains — and a family catalogue that turns a whole product line into one shared driver plus a geometry.
W25Q: SPI NOR flash
Winbond W25Q-series, targeting the W25Q256FV (32 MB, JEDEC ID
EF 40 19), on a general-purpose SPI host
with an application-driven chip select through the CS callback
— so it shares a bus with other devices.
procedure Initialize (Dev : Flash; OK : out Boolean);
procedure Read_Identification (Dev : Flash; ID : out JEDEC_ID);
function Capacity_Bytes (ID : JEDEC_ID) return Address;
procedure Read (Dev : Flash; Addr : Address; Data : out Byte_Array);
procedure Erase_Sector (Dev : Flash; Addr : Address);
procedure Program_Page (Dev : Flash; Addr : Address; Data : Byte_Array);
Over 16 MB means 4-byte addressing.
Initialize puts the chip into 4-byte address mode (opcode
0xB7) once at startup, after which the standard opcodes
— Read 0x03, Page-Program 0x02, Sector-Erase
0x20 — each take four address bytes, which is what the FV
datasheet prescribes. The FV has no dedicated 4-byte
program/erase opcodes; the 0x12/0x21/0xDC
set is a later W25Q256JV addition, and issuing them here is silently
ignored — a failure that leaves your data unwritten with no error.
Flash is erase-before-write: sectors erase to all-ones, and a page program can
only clear bits. That asymmetry is why the API has both
Erase_Sector and Program_Page rather than a
Write.
The 24C EEPROM catalogue
Every part in the family — ST M24Cxx, Microchip 24AAxx/24LCxx, Atmel
AT24Cxx, onsemi CAT24Cxx — speaks the same protocol: device-type code
1010, a big-endian word address, page writes that wrap
inside the page rather than advancing, a ~5 ms program cycle that NACKs
everything until it finishes, and a random read that turns the bus around on a
repeated START.
So a part is nothing but a geometry.
ESP32S3.EEPROM_24C.Driver implements the protocol once, and each
part is a child instantiation —
with ESP32S3.EEPROM_24C.M24C64; costs you one part, not the whole
catalogue.
Two traps the catalogue exists to encode:
Page size varies by vendor at the low end. ST's M24C01/M24C02 have a 16-byte page; Atmel's and Microchip's 1K/2K parts have 8. Guessing wrong does not fail loudly — the write wraps inside the page and silently overwrites what you just wrote. Hence separate AT24C01 and AT24C02 entries.
High address bits eat chip-enable pins. A part whose array outruns its word address folds the surplus bits into the low bits of its own device-select byte, costing a strap each: E0, then E1, then E2. A 24C16 folds three and has no strap left — only one can sit on a bus. The driver derives this from capacity and address width rather than taking it as a parameter. Microchip's 24LC1025 is the one part that breaks the rule, putting its block bit in the high position instead.
Only parts marked Verified have been run
against real silicon. The rest are transcribed from datasheets —
the protocol is shared so they are very likely right, but nobody has watched them
on a scope. Each instance re-exports its status as
Hardware_Verified and says so in its spec banner.
FRAM: non-volatile RAM
Fujitsu MB85RS and Cypress/Infineon FM25 over SPI (and MB85RC/FM24 over I2C). The distinction from EEPROM is the interesting part:
FRAM is byte-writable, has no page boundary, and has no program cycle at all — a write is committed as it is clocked in. None of the EEPROM ceremony applies: no page-wrap trap, no ~5 ms NACK-until- done wait, no erase. If you are logging frequently, that difference is the whole reason to pay for FRAM.
Because the read/write protocol is identical across manufacturers, parts are
keyed by density rather than part number:
with ESP32S3.FRAM_SPI.Kbit_256;. Only the identity command differs
by vendor, so Read_Device_ID returns the raw bytes rather than
pretending to decode them.
Address width follows density: 16 Kbit .. 512 Kbit use two address bytes, 1 Mbit uses three, and the 4 Kbit parts use one, with the ninth address bit carried in bit 3 of the opcode — the legacy 25040 convention.
Status: no FRAM part has been run against real silicon yet. These are datasheet-derived.