On [Arduino](https://www.ampheo.com/c/development-board-arduino), EEPROM.put() / EEPROM.get() are designed for the internal EEPROM (on AVR boards like [Arduino Uno](https://www.ampheo.com/product/a000046-25542493)/Nano/Mega). For an external EEPROM (typically I²C parts like [24LC256](https://www.onzuu.com/search/24LC256)/[24LC512](https://www.onzuu.com/search/24LC512)/[AT24Cxx](https://www.onzuu.com/search/AT24C)), you have two good options: 1. Use an external-EEPROM library that already provides get/put-like helpers, or 2. Write your own “put/get” wrappers that read/write arbitrary types over I²C. Below is a practical, copy-paste friendly approach (option 2), plus notes to avoid the classic EEPROM pitfalls. ![_GlVxsZ0wTh](https://hackmd.io/_uploads/SyxpL6z-4bl.jpg) **Typical external EEPROM wiring (I²C)** * EEPROM SDA → Arduino SDA * EEPROM SCL → Arduino SCL * Pull-ups on SDA/SCL (often 4.7k to 10k to VCC) * EEPROM A0/A1/A2 set device address (commonly all GND → base address) * EEPROM WP (write protect) to GND to allow writes (or VCC to lock) Most 24xx EEPROMs show up at I²C address 0x50–0x57 depending on A0–A2. **“put/get” for external I²C EEPROM (works with structs, floats, etc.)** Example assumes a 16-bit address EEPROM like 24LC256 / 24LC512 (most common). **Core byte read/write + ACK polling (recommended)** ``` #include <Wire.h> static const uint8_t EEPROM_I2C_ADDR = 0x50; // 0x50 + (A2 A1 A0) static const uint16_t EEPROM_PAGE_SIZE = 64; // 24LC256 often 64-byte pages // Wait until EEPROM finishes its internal write cycle (ACK polling). void eepromWaitReady() { while (true) { Wire.beginTransmission(EEPROM_I2C_ADDR); uint8_t err = Wire.endTransmission(); if (err == 0) break; // device ACKed delay(1); } } void eepromWriteByte(uint16_t memAddr, uint8_t data) { Wire.beginTransmission(EEPROM_I2C_ADDR); Wire.write((uint8_t)(memAddr >> 8)); // high byte Wire.write((uint8_t)(memAddr & 0xFF)); // low byte Wire.write(data); Wire.endTransmission(); eepromWaitReady(); } uint8_t eepromReadByte(uint16_t memAddr) { Wire.beginTransmission(EEPROM_I2C_ADDR); Wire.write((uint8_t)(memAddr >> 8)); Wire.write((uint8_t)(memAddr & 0xFF)); Wire.endTransmission(false); // repeated start Wire.requestFrom(EEPROM_I2C_ADDR, (uint8_t)1); return Wire.available() ? Wire.read() : 0xFF; } ``` **Page-safe block write + sequential read** External EEPROMs write in pages. If you cross a page boundary in a single write, data can wrap and corrupt. ``` void eepromWriteBlock(uint16_t memAddr, const uint8_t* data, size_t len) { while (len > 0) { uint16_t pageOffset = memAddr % EEPROM_PAGE_SIZE; uint16_t spaceInPage = EEPROM_PAGE_SIZE - pageOffset; uint16_t chunk = (len < spaceInPage) ? len : spaceInPage; Wire.beginTransmission(EEPROM_I2C_ADDR); Wire.write((uint8_t)(memAddr >> 8)); Wire.write((uint8_t)(memAddr & 0xFF)); for (uint16_t i = 0; i < chunk; i++) { Wire.write(data[i]); } Wire.endTransmission(); eepromWaitReady(); memAddr += chunk; data += chunk; len -= chunk; } } void eepromReadBlock(uint16_t memAddr, uint8_t* out, size_t len) { Wire.beginTransmission(EEPROM_I2C_ADDR); Wire.write((uint8_t)(memAddr >> 8)); Wire.write((uint8_t)(memAddr & 0xFF)); Wire.endTransmission(false); size_t idx = 0; while (idx < len) { uint8_t chunk = (len - idx > 32) ? 32 : (uint8_t)(len - idx); // Wire buffer Wire.requestFrom(EEPROM_I2C_ADDR, chunk); while (Wire.available() && idx < len) { out[idx++] = Wire.read(); } } } ``` **Now the “put/get” templates (drop-in replacements)** ``` template <typename T> void eepromPut(uint16_t addr, const T& value) { const uint8_t* p = (const uint8_t*)&value; eepromWriteBlock(addr, p, sizeof(T)); } template <typename T> void eepromGet(uint16_t addr, T& value) { uint8_t* p = (uint8_t*)&value; eepromReadBlock(addr, p, sizeof(T)); } ``` **Example: store and load a struct** ``` struct Calibration { float offset; float scale; uint32_t magic; }; static const uint16_t CAL_ADDR = 0x0000; void setup() { Serial.begin(115200); Wire.begin(); // Write Calibration calWrite { 1.25f, 0.98f, 0xC0A1B123 }; eepromPut(CAL_ADDR, calWrite); // Read back Calibration calRead; eepromGet(CAL_ADDR, calRead); Serial.println(calRead.offset, 6); Serial.println(calRead.scale, 6); Serial.println(calRead.magic, HEX); } void loop() {} ``` **Important notes (so it works every time)** * Write cycle time: external EEPROM needs a few ms to internally commit data. That’s why ACK polling (eepromWaitReady()) matters. * Page boundaries: always write in page-safe chunks (done above). * Wire buffer: many Arduino cores limit I²C TX/RX to ~32 bytes at a time. * Wear: EEPROM has limited write endurance. Avoid writing the same address constantly; consider writing only when values change, or implement simple wear-leveling. **If you prefer a library** Search [Arduino](https://www.ampheoelec.de/c/development-board-arduino) Library Manager for: * extEEPROM (popular for 24xx I²C EEPROM) * I2C_eeprom Many of these libraries provide .read()/.write() and sometimes .get()/.put() style helpers.