Interfacing EEPROM AT24C256 with ESP8266 Using I2C

Introduction

In this tutorial, we'll interface two commonly used I2C devices with the ESP8266: the EEPROM AT24C256 and the 12-bit 2-channel ADC MCP3202. The I2C (Inter-Integrated Circuit) protocol, invented by Philips Semiconductor, is widely used for on-board IC-to-IC communication and supports speeds of over 100kbps. We'll write the code from scratch to help you understand the I2C protocol better and make it easier to interface with any I2C device.

Understanding I2C Protocol

I2C uses two lines: Serial Clock Line (SCL) and Serial Data Line (SDA). Both lines are pulled high by external resistors. Data on the SDA line can change only when the SCL line is low. Data changes during high periods of the SCL line indicate start or stop conditions.

Start Condition: A high-to-low transition of SDA with SCL high indicates a start condition.

Stop Condition: A low-to-high transition of SDA with SCL high indicates a stop condition. After a read sequence, the stop command places the EEPROM in standby mode.

Acknowledge: Each byte (8 bits) transmitted is acknowledged by the receiving device during the ninth clock cycle by pulling the SDA line low.

I2C Start and Stop Conditions Sample Code

void i2c_start(void) { RELEASE_I2C_BUS(); delayMicroseconds(I2C_DELAY); SDA_0(); delayMicroseconds(I2C_DELAY); SCL_0(); delayMicroseconds(I2C_DELAY); } void i2c_stop(void) { SDA_0(); SCL_1(); delayMicroseconds(I2C_DELAY); SDA_1(); delayMicroseconds(I2C_DELAY); SCL_0(); delayMicroseconds(I2C_DELAY); }

Interfacing AT24C256 with ESP8266

Before coding, let's understand a few things from the AT24C256 datasheet:

  • Operating Voltage: 1.8V to 5.5V (we use 3.3V)
  • Maximum Clock Frequency: 1 MHz (5V), 400 kHz (2.7V, 2.5V), and 100 kHz (1.8V) compatibility
  • Memory Capacity: 256kbytes

AT24C256 Pin Description

  • SCL (Serial Clock): Used to clock data into and out of the EEPROM.
  • SDA (Serial Data): Bidirectional for serial data transfer.
  • A0, A1: Device address inputs.
  • WP (Write Protect): When connected to GND, allows normal write operations. When connected to VCC, inhibits write operations.

Connections

Connect D6 (GPIO 12) to SDA (pin 5) and D7 (GPIO 13) to SCL (pin 6) of the AT24C256. Also, add pull-up resistors (10KOhm) to SCL and SDA lines. Provide 3.3V power supply and GND.

I2C Communication Header File

The i2c.h file contains basic I2C signaling functions for use in our main program.

i2c.h

#define SDA_PIN 12 /* The SDA port pin */ #define SCL_PIN 13 /* The SCL port pin */ #define I2C_DELAY 5 // 5 microseconds = 200KHz #define I2C_TIMEOUT 1000 #define I2C_READ 1 #define I2C_WRITE 0 #define I2C_NO_ERROR 0 #define I2C_ERROR_DEVICE_BUSY 1 #define I2C_ERROR_DEVICE_NOT_RESPONDING 2 #define I2C_START(ADDRESS) { i2c_start(); i2c_transmit(ADDRESS); } #define SCL_1() { pinMode(SCL_PIN,0); } #define SCL_0() { pinMode(SCL_PIN,1); } #define SDA_1() { pinMode(SDA_PIN,0); } #define SDA_0() { pinMode(SDA_PIN,1); } #define RELEASE_I2C_BUS() { SCL_1(); SDA_1(); } void i2c_start(void); void i2c_init(void); void i2c_stop(void); unsigned char i2c_transmit(unsigned char data); unsigned char i2c_receive(unsigned char ack);

I2C Initialization and Functions

void i2c_init(void) { digitalWrite(SDA_PIN,0); digitalWrite(SCL_PIN,0); RELEASE_I2C_BUS(); delayMicroseconds(I2C_TIMEOUT); i2c_start(); delayMicroseconds(I2C_TIMEOUT); i2c_stop(); delayMicroseconds(I2C_TIMEOUT); } void i2c_start(void) { RELEASE_I2C_BUS(); delayMicroseconds(I2C_DELAY); SDA_0(); delayMicroseconds(I2C_DELAY); SCL_0(); delayMicroseconds(I2C_DELAY); } void i2c_stop(void) { SDA_0(); SCL_1(); delayMicroseconds(I2C_DELAY); SDA_1(); delayMicroseconds(I2C_DELAY); SCL_0(); delayMicroseconds(I2C_DELAY); } unsigned char i2c_transmit(unsigned char data) { for(unsigned char bit = 0; bit <= 7; bit++) { if (data & 0x80) SDA_1(); else SDA_0(); SCL_1(); delayMicroseconds(I2C_DELAY); SCL_0(); delayMicroseconds(I2C_DELAY); data <<= 1; } RELEASE_I2C_BUS(); delayMicroseconds(I2C_DELAY); if (digitalRead(SDA_PIN) == 0) { SCL_0(); delayMicroseconds(I2C_DELAY); } else { delayMicroseconds(I2C_TIMEOUT); if (digitalRead(SDA_PIN) == 0) { SCL_0(); delayMicroseconds(I2C_DELAY); } else { return I2C_ERROR_DEVICE_NOT_RESPONDING; } } if (digitalRead(SDA_PIN) == 0) { delayMicroseconds(I2C_TIMEOUT); if (digitalRead(SDA_PIN) == 0) { return I2C_ERROR_DEVICE_BUSY; } } return I2C_NO_ERROR; } unsigned char i2c_receive(unsigned char ack) { unsigned char data = 0; SDA_1(); for(unsigned char bit = 0; bit <= 7; bit++) { SCL_1(); delayMicroseconds(I2C_DELAY); data = (data << 1) | digitalRead(SDA_PIN); SCL_0(); delayMicroseconds(I2C_DELAY); } if (ack == I2C_CONTINUE) SDA_0(); else SDA_1(); SCL_1(); delayMicroseconds(I2C_DELAY); SCL_0(); delayMicroseconds(I2C_DELAY); return data; }

Program for EEPROM 24C256 Interface

This program writes one byte at the beginning (setup) and continuously reads it in the loop.


#include "i2c.h" void setup() { delay(1); Serial.begin(115200); Serial.println(""); i2c_init(); // Initialize I2C Serial.println("I2C Initialized"); Serial.println("Writing Data: 123"); Write_EEPROM(0, 123); // Data to write } void loop() { Serial.print("Reading Data: "); Serial.println(Read_EEPROM(0)); delay(1000); } void Write_EEPROM(int add, char data) { int addH = (add & 0xFF00) >> 8; int addL = add & 0x00FF; I2C_START_TX(0b10100000); // Device address with write command i2c_transmit(addH); // Send Word Address i2c_transmit(addL); i2c_transmit(data); // Send data to write i2c_stop(); delay(20); // Wait for EEPROM to write data } int Read_EEPROM(int add) { int addH = (add & 0xFF00) >> 8; int addL = add & 0x00FF; I2C_START_TX(0b10100000); // Device address with write command i2c_transmit(addH); // Send Word Address i2c_transmit(addL); I2C_START_TX(0b10100001); // Device address with read command int data = i2c_receive(0); i2c_stop(); return data; }

Upload the sketch and open the serial monitor to see the results.

Results

You should see the data "123" written and read successfully from the EEPROM in the serial monitor.

By following this tutorial, you have successfully interfaced the EEPROM AT24C256 with the ESP8266 using I2C without any external libraries, giving you a clear understanding of the I2C protocol and how to implement it from scratch.

No comments

Theme images by Dizzo. Powered by Blogger.