← Back to Academy

Lesson 181: External Data Storage with the AT24C256 I2C EEPROM

We optimized our SRAM. But what if you need to store data—like high scores or settings—and make sure it survives when the Arduino is unplugged? The Uno has 1KB of internal EEPROM, which is practically nothing. Enter the AT24C256 I2C EEPROM Module. It gives you a massive 32 Kilobytes of non-volatile storage. Finally, your Arduino can have long-term memories.

The Hardware: AT24C256 Module

The AT24C256 EEPROM Module is cheap, reliable, and incredibly easy to use.

Why Use External EEPROM?

  1. Persistence: Data stays saved even when power is disconnected.
  2. Endurance: It can handle up to 1,000,000 write cycles (much more than typical flash memory).
  3. Expandability: Since it uses I2C, you can daisy-chain multiple EEPROM chips on the exact same two pins by changing their physical addresses!

Wiring It Up

Connecting the AT24C256 to your Arduino Uno is simple thanks to the I2C bus.

AT24C256 PinArduino Uno PinDescription
VCC5VPower supply
GNDGNDGround
SCLA5 (or SCL)I2C Clock Line
SDAA4 (or SDA)I2C Data Line
WPGNDWrite Protect (Tie to GND to enable writing)

(Note: If your module has address pins like A0, A1, A2, leave them unconnected or tie them to GND. This sets the default I2C address, usually 0x50.)

The Code: Writing and Reading Data

To communicate with the EEPROM, we will use the built-in Wire.h library. We don’t even need a special EEPROM library for basic operations!

Here is a simple sketch that writes a number to memory, and then reads it back:

#include <Wire.h>

// Default I2C address for the AT24C256
#define EEPROM_ADDR 0x50 

void setup() {
  Serial.begin(9600);
  Wire.begin();
  
  Serial.println("EEPROM Write and Read Test");
  
  // 1. Write Data
  unsigned int memoryAddress = 0x0000;
  byte dataToWrite = 42; // The meaning of life, or just a test number
  
  writeEEPROM(EEPROM_ADDR, memoryAddress, dataToWrite);
  Serial.print("Wrote: ");
  Serial.println(dataToWrite);
  
  // Give the EEPROM a few milliseconds to complete the write cycle
  delay(10);
  
  // 2. Read Data
  byte readData = readEEPROM(EEPROM_ADDR, memoryAddress);
  Serial.print("Read back: ");
  Serial.println(readData);
}

void loop() {
  // Nothing to do in the loop for this test
}

// Function to write a byte of data to a specific memory address
void writeEEPROM(int deviceAddress, unsigned int memAddress, byte data) {
  Wire.beginTransmission(deviceAddress);
  Wire.write((int)(memAddress >> 8));   // MSB of the memory address
  Wire.write((int)(memAddress & 0xFF)); // LSB of the memory address
  Wire.write(data);                     // The data byte
  Wire.endTransmission();
}

// Function to read a byte of data from a specific memory address
byte readEEPROM(int deviceAddress, unsigned int memAddress) {
  byte data = 0xFF;
  
  Wire.beginTransmission(deviceAddress);
  Wire.write((int)(memAddress >> 8));   // MSB
  Wire.write((int)(memAddress & 0xFF)); // LSB
  Wire.endTransmission();
  
  Wire.requestFrom(deviceAddress, 1);
  if (Wire.available()) {
    data = Wire.read();
  }
  
  return data;
}

Understanding the Code

What’s Next?

Now that you have 32KB of permanent storage, you can build weather stations that log temperatures over weeks, or a custom combination lock that remembers passcodes even if the battery dies.

Happy tinkering!