0
0
Power-electronicsHow-ToBeginner · 4 min read

How to Interface EEPROM Using I2C in Embedded C

To interface EEPROM using I2C in Embedded C, initialize the I2C peripheral, then use start, send device address, write/read data, and stop commands to communicate. Use the EEPROM's I2C address and handle memory addressing properly in your code.
📐

Syntax

Basic steps to communicate with EEPROM over I2C:

  • Initialize I2C: Set up clock speed and pins.
  • Start Condition: Begin communication.
  • Send Device Address: EEPROM I2C address with read/write bit.
  • Send Memory Address: Specify EEPROM memory location.
  • Write or Read Data: Send or receive bytes.
  • Stop Condition: End communication.
c
void I2C_Start();
void I2C_Stop();
bool I2C_WriteByte(uint8_t data);
uint8_t I2C_ReadByte(bool ack);
void EEPROM_WriteByte(uint16_t memAddress, uint8_t data);
uint8_t EEPROM_ReadByte(uint16_t memAddress);
💻

Example

This example shows how to write a byte to EEPROM and then read it back using I2C in Embedded C.

c
#include <stdint.h>
#include <stdbool.h>

#define EEPROM_I2C_ADDRESS 0x50 // 7-bit address

// Mock functions for I2C operations
void I2C_Init() {
    // Initialize I2C peripheral (clock, pins)
}

void I2C_Start() {
    // Send start condition
}

void I2C_Stop() {
    // Send stop condition
}

bool I2C_WriteByte(uint8_t data) {
    // Write byte and return ACK status
    return true; // Assume ACK received
}

uint8_t I2C_ReadByte(bool ack) {
    // Read byte and send ACK/NACK
    return 0xFF; // Dummy data
}

void EEPROM_WriteByte(uint16_t memAddress, uint8_t data) {
    I2C_Start();
    I2C_WriteByte((EEPROM_I2C_ADDRESS << 1) | 0); // Write mode
    I2C_WriteByte((uint8_t)(memAddress >> 8));    // High byte of memory address
    I2C_WriteByte((uint8_t)(memAddress & 0xFF));  // Low byte of memory address
    I2C_WriteByte(data);                           // Data byte
    I2C_Stop();
}

uint8_t EEPROM_ReadByte(uint16_t memAddress) {
    uint8_t data;
    I2C_Start();
    I2C_WriteByte((EEPROM_I2C_ADDRESS << 1) | 0); // Write mode
    I2C_WriteByte((uint8_t)(memAddress >> 8));    // High byte
    I2C_WriteByte((uint8_t)(memAddress & 0xFF));  // Low byte
    I2C_Start();
    I2C_WriteByte((EEPROM_I2C_ADDRESS << 1) | 1); // Read mode
    data = I2C_ReadByte(false);                    // Read byte with NACK
    I2C_Stop();
    return data;
}

int main() {
    uint16_t address = 0x0010;
    uint8_t writeData = 0xAB;
    uint8_t readData;

    I2C_Init();
    EEPROM_WriteByte(address, writeData);
    readData = EEPROM_ReadByte(address);

    // Here you would normally check if readData == writeData
    while(1) {}
    return 0;
}
⚠️

Common Pitfalls

  • Wrong I2C Address: EEPROM devices have 7-bit addresses; shifting or wrong bits cause failure.
  • Missing Start/Stop: Forgetting start or stop conditions breaks communication.
  • Incorrect Memory Addressing: EEPROMs often use 16-bit addresses; sending only 8 bits causes wrong data access.
  • No ACK Handling: Not checking for ACK can hide communication errors.
  • Timing Issues: EEPROM write cycles need delay before next operation.
c
/* Wrong way: Missing stop condition */
void EEPROM_WriteByte_Wrong(uint16_t memAddress, uint8_t data) {
    I2C_Start();
    I2C_WriteByte((EEPROM_I2C_ADDRESS << 1) | 0);
    I2C_WriteByte((uint8_t)(memAddress >> 8));
    I2C_WriteByte((uint8_t)(memAddress & 0xFF));
    I2C_WriteByte(data);
    // Missing I2C_Stop(); causes bus hang
}

/* Right way: Include stop condition */
void EEPROM_WriteByte_Right(uint16_t memAddress, uint8_t data) {
    I2C_Start();
    I2C_WriteByte((EEPROM_I2C_ADDRESS << 1) | 0);
    I2C_WriteByte((uint8_t)(memAddress >> 8));
    I2C_WriteByte((uint8_t)(memAddress & 0xFF));
    I2C_WriteByte(data);
    I2C_Stop();
}
📊

Quick Reference

  • EEPROM I2C Address: Usually 0x50 (7-bit), shift left by 1 for R/W bit.
  • Memory Address: Send high byte then low byte for 16-bit addressing.
  • Start/Stop: Always use start before and stop after communication.
  • Write Cycle Delay: Wait ~5ms after write before next operation.
  • Check ACK: Confirm device acknowledges each byte sent.

Key Takeaways

Initialize I2C and use start, address, data, and stop commands to communicate with EEPROM.
Send the correct 7-bit EEPROM address shifted left with R/W bit appended.
Use 16-bit memory addressing by sending high and low bytes separately.
Always include start and stop conditions to avoid bus errors.
Allow write cycle delay and check for ACK to ensure reliable communication.