36. EEPROM Memory-Map Viewer

The task is to read and display all EEPROM (Electrically Erasable Programmable Read-Only Memory) data on a serial terminal (e.g., PuTTY, Arduino IDE) in a structured HEX format.

EEPROM is a non-volatile memory used to store small amounts of data that must be preserved even after power loss.

Requirements:

  • Print 16 bytes per row with the corresponding memory address.
  • Show both address and data in HEX.

Example Output:

0000: 3A 6F 9C 00 14 FF 23 7E 11 0A 55 42 80 91 00 3C
0010: 12 00 34 FF 89 21 7A 5E 09 7F 66 88 44 00 00 10

Concept
The program reads EEPROM sequentially, groups data in 16-byte blocks, and prints address–data pairs for easy analysis, debugging, or memory verification.

Below are the solutions to the given task using the following microcontrollers

  1. ESP32
  2. Arduino UNO

We are using the ESP32 DevKitC v4 development board and programming it using the Arduino IDE.

  • Before uploading, make sure to select “ESP32 Dev Module” as the board to ensure correct settings and compatibility.

ESP32 does not have a real EEPROM chip inside. Instead, part of its Flash memory is used to simulate EEPROM behaviour.

Hardware Connection

Connect the ESP32  development board to your computer using a USB cable.

Code

#include <EEPROM.h>

// Configuration
#define EEPROM_SIZE 512   // Flash-backed EEPROM emulation size (max ~4096 on ESP32)
#define BYTES_PER_ROW 16  // Hex bytes per printed row
#define START_ADDR 0x0000
#define END_ADDR 0x01FF

// Compile-time guards
#if (END_ADDR >= EEPROM_SIZE)
#error "END_ADDR must be <= EEPROM_SIZE - 1"
#endif

#if (START_ADDR > END_ADDR)
#error "START_ADDR must be <= END_ADDR"
#endif

void printEEPROMMap();

void setup() {
  Serial.begin(115200);

  // Initialize EEPROM emulation; required before read/write ops.
  EEPROM.begin(EEPROM_SIZE);

  // display the contents of memory(Hex + ASCII with address window).
  printEEPROMMap();

  // Free EEPROM internal buffers
  EEPROM.end();
}

void loop() {
  // No operations in the loop.
}

// Prints a hex table of EEPROM bytes from START_ADDR to END_ADDR.
// Format:
//   Address | 16 bytes in hex | ASCII

void printEEPROMMap() {
  Serial.println(F("\nESP32 EEPROM Memory Map"));
  Serial.println(F("---------------------------------------------------------------------"));
  Serial.println(F("Address | 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F | ASCII"));
  Serial.println(F("---------------------------------------------------------------------"));

  char ascii[BYTES_PER_ROW + 1];  // Holds printable ASCII for each row
  ascii[BYTES_PER_ROW] = '\0';

  for (uint16_t base = START_ADDR; base <= END_ADDR; base += BYTES_PER_ROW) {
    // Row prefix: 16-bit hex address, zero-padded.
    Serial.printf("0x%04X  | ", base);

    // Print hex bytes and build ASCII column.
    for (uint8_t offset = 0; offset < BYTES_PER_ROW; offset++) {
      uint16_t addr = base + offset;

      if (addr <= END_ADDR) {
        uint8_t data = EEPROM.read(addr);
        Serial.printf("%02X ", data);

        // Printable ASCII range 0x20..0x7E; use '.' otherwise.
        ascii[offset] = (data >= 0x20 && data <= 0x7E) ? static_cast<char>(data) : '.';
      } else {
        // Pad hex area for incomplete final row.
        Serial.print("   ");
        ascii[offset] = ' ';
      }
    }

    // ASCII column
    Serial.print("| ");
    Serial.println(ascii);
  }
}

Code Explanation

  • setup();
     Runs once at startup; initialises Serial communication, begins EEPROM emulation, calls printEEPROMMap(), and then ends EEPROM access.
  • loop();
     The main program loop; left empty.
  • printEEPROMMap();
     Custom user-defined function that reads EEPROM data from the defined address range and prints it as a formatted Hex + ASCII memory map.
  • EEPROM.begin(512);
     The ESP32 internally reserves 512 bytes from its Flash (NVS partition) as an emulated EEPROM area. This space behaves like a normal EEPROM.
  • EEPROM.read(address);
     Reads one byte of data from the specified EEPROM address within the emulated memory region.
  • EEPROM.end();
     Frees the internal EEPROM buffer and ends access to the emulated EEPROM area

Precautions when Allocating Flash to EEPROM

  1. Don’t exceed Flash partition size
    • The emulated EEPROM uses the “app data” area of Flash and is safe up to about 4096 bytes. Allocating more (e.g., EEPROM.begin(8000)) can corrupt other Flash data or cause runtime errors.
  2. Write infrequently
    • Each Flash cell supports a limited number of writes (~100k).
      • Avoid continuous writing in loop().
      • Use EEPROM.commit() only when values actually change.
  3. Call EEPROM.commit() after writing
    • Without this, your changes stay only in RAM and disappear after a restart.
  4. Avoid overlapping with other Flash uses

We are using the Arduino UNO development board and programming it using the Arduino IDE.

  • Before uploading, make sure to select “Arduino UNO” as the board to ensure correct settings and compatibility.

Hardware Connection

Connect the Arduino UNO  development board to your computer using a USB cable.

Firmware Implementation

We are going to use EEPROM.h library to implement this task. In Arduino UNO, there is a separate EEPROM chip available of 1KB.

Code

#include <EEPROM.h>

// Define the size of EEPROM (varies depending on microcontroller)
const int EEPROM_SIZE = 512; // For Arduino Uno, update based on your board's EEPROM size.
const int BYTES_PER_ROW = 16; // Bytes to display per row

void setup() {
  Serial.begin(9600);
  while (!Serial);

  Serial.println("EEPROM Memory Map:");
  Serial.println("Address   | Data (in Hex)");
  Serial.println("-------------------------");
  printEEPROMMap();
}

void loop() {
  // No operations in the loop.
}

void printEEPROMMap() {
  for (int i = 0; i < EEPROM_SIZE; i += BYTES_PER_ROW) {
    // Print starting address of the row
    Serial.print("0x");
    if (i < 16) Serial.print("0"); // Formatting for single-digit addresses
    Serial.print(i, HEX);
    Serial.print("       | ");

    // Print the data in hexadecimal format
    for (int j = 0; j < BYTES_PER_ROW; j++) {
      if (i + j < EEPROM_SIZE) {
        byte data = EEPROM.read(i + j);
        if (data < 16) Serial.print("0"); // Ensure two digits
        Serial.print(data, HEX);
        Serial.print(" ");
      } else {
        // If out of bounds, print placeholder
        Serial.print("-- ");
      }
    }
    Serial.println();
  }
}

Code Explanation

  • setup()
    • Runs once at boot; starts the serial port at 9600 bps, waits for the port to be ready, prints table headers, then calls printEEPROMMap().
  • loop()
    • Main program loop; empty here.
  • printEEPROMMap()
    • Walks EEPROM in steps of BYTES_PER_ROW (16), prints the row’s starting address and the next 16 bytes in hexadecimal, padding with -- if past the end.
  • EEPROM.length()
    •  Returns the EEPROM size (bytes). On AVR, it’s fixed; on ESP32, it reflects the size configured with EEPROM.begin(size).
  • EEPROM.read(address)
    • Reads a single byte from the given EEPROM address and returns it for printing.

Precautions

  • Be careful while writing to the EEPROM, as it has limited write cycles.
  • Writing time is 3.3ms per byte; consider this while writing your code.

Output

The below output is of the EEPROM (after writing random values)

 

The below output is of the Formatted EEPROM. (Writing 0xFF to all EEPROM locations)

 

You can also try the following

  • You can write the code to randomly add values to the EEPROM, and then see how the memory is printed.
  • You can also try resetting the EEPROM by setting each address to 0xFF and watching the memory map.

Precautions:

  • Be careful while writing to EEPROM as it has limited write cycles.
  • Writing time is 3.3ms per byte, consider this while writing your code.