Bare-Metal Ada on the ESP32-S3 A step-by-step guide to running Ada on the ESP32-S3 with no ESP-IDF, no FreeRTOS, and no Python.

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.

Off-chip memory: NOR flash, EEPROM and FRAM · Bare-Metal Ada on the ESP32-S3
Bare-Metal Ada on the ESP32-S3 A step-by-step guide to running Ada on the ESP32-S3 with no ESP-IDF, no FreeRTOS, and no Python.

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.

Off-chip memory: NOR flash, EEPROM and FRAM · Bare-Metal Ada on the ESP32-S3
Bare-Metal Ada on the ESP32-S3 A step-by-step guide to running Ada on the ESP32-S3 with no ESP-IDF, no FreeRTOS, and no Python.

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.

Off-chip memory: NOR flash, EEPROM and FRAM · Bare-Metal Ada on the ESP32-S3
Bare-Metal Ada on the ESP32-S3 A step-by-step guide to running Ada on the ESP32-S3 with no ESP-IDF, no FreeRTOS, and no Python.

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.

Off-chip memory: NOR flash, EEPROM and FRAM · Bare-Metal Ada on the ESP32-S3
Bare-Metal Ada on the ESP32-S3 A step-by-step guide to running Ada on the ESP32-S3 with no ESP-IDF, no FreeRTOS, and no Python.

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.

Off-chip memory: NOR flash, EEPROM and FRAM · Bare-Metal Ada on the ESP32-S3
Bare-Metal Ada on the ESP32-S3 A step-by-step guide to running Ada on the ESP32-S3 with no ESP-IDF, no FreeRTOS, and no Python.

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.