interfacing of eeprom using the i2c

interfacing EEPROM with 8051 microcontroller using I2C

Introduction

In the article, we see the interfacing  EEPROM with 8051 microcontrollers using the I2C Protocol. In the real world, microcontrollers have a limited amount of memory. Sometimes the limited amount of memory becomes a big issue and creates a roadblock to the development of a project.

Each microcontroller provides flexibility to connect an external memory to store the required data. These data can store in memory by using the I2C, SPI or other communication protocol.

Here, I am explaining an example, where I will store a single byte in an EEPROM and after that, I will read back the written byte from the EEPROM. For verification, I will compare read bytes from the bytes which have been written and toggle a LED if both the bytes are equal.

What is an EEPROM?

An EEPROM is a non-volatile memory that means it can store the data permanently without any power supply. EEPROM stands for Electrically Erasable Programmable Read-Only Memory. We can erase the EEPROM data by the UV eraser.

An EEPROM is slower than the flash memory. In flash memory, we can erase the whole sector at a time but in the case of EEPROM, we can erase a single byte at the time.
Some Microcontroller confines a small amount of EEPROM to store the extra bytes which are required in the program, for example, usernames and password.

There are many vendors who make different kinds of EEPROM but in this article, I will only discuss 24lc64 (manufactured by the microchip). The 24lc64 (EEPROM) is connected to the Microcontroller through the I2C bus protocol.

There some important features of 24lc64 (EEPROM)

  • Organized as 8 blocks of 8kbit (64 Kbit).
  • The interface through two-wire (I2C).
  • Page write buffer up to 32 bytes
  • We can read/ write on it approximately one million times.
  • It can retain the data for more than 200 years.

Here I have found a very useful Embedded Systems Programming courses for beginners, as well as experienced mobile and desktop software developers by Jeremy Willden.

Control bytes of 24lc64 (EEPROM)

Before starting the programming, we have to aware of the addressing of 24lc64 (EEPROM). It contains a control byte which sends by the master in I2C communication followed by a start condition. The control byte confines the control code, chip -select and read/write bits.

The control code for the 24lc64 is “1010” for the read and write operation. The chip select size is 3 bits (A2, A1, A0) it allows the user to connect maximum 8 devices to the I2c bus. The last bit of the control byte is read/write bits, this bit is zero for the write operation and one for the read operation.

Basic Requirements for interfacing EEPROM with 8051

Knowledge of I2C protocol

When you want to interface an EEPROM with microcontroller then you need to have a good knowledge of I2C protocol. If you are not aware of the I2C protocol then don’t need to worry, it is a very simple serial communication protocol.
So it’s my advice to you, before reading the remaining part of this article, read the I2C protocol.

Micro-controller

In our case, Micro-controller works here as master and start the communication to perform the read and write operation on EEPROM.

EEPROM memory

It’s storing device is used to store permanent data like user information (username, password).Here I am using the 24lc64 chip to store the data.
It has 8 blocks of 8kbit (8* 1024 bytes of data storage). The chip has storage location, each location has a unique address ranging from the (0 to 8191) and each location treat as a cell.

For example, after writing the data ‘A’ on the location 0x0001, if you read the location 0x0001 you will get ‘A’.Most important thing is to remember that each cell of 24lc64 can store 8 bits of the data(0 -255). So if you want to store the bigger data then you have to use more than one cells.


Program to interface the 24lc64 with 8051 microcontrollers.

We know that there is no inbuilt chip in 8051 for the I2C communication unlike other microcontrollers like PIC and STM. So here I will implement the I2C communication through the Bit-banging.

In Bit-banging, we need to select two pins of 8051 for the data and clock and treat these pin as like the SDA and SCL lines. Most Important thing is that don’t forget the rule of the I2C communication, like communication is always started and stopped by the master, data lines only change their state when the clock is low, etc.

START CONDITION

It is the first byte which sends by the master to start the communication with EEPROM. Here I am not discussing the I2C protocol, if you want to read about the I2C protocol then please read my previous article which describes the I2C protocol in detail.

 

void StartI2c(void)
{

    SDA_BUS  = 1;
    SCL_BUS  = 1;
    delay(I2C_DELAY);
    SDA_BUS  = 0;
    delay(I2C_DELAY);
}

 

STOP CONDITION

This operation performed by the master to stop the communication. The master releases the bus after asserting the stop condition.

 

void StopI2c(void)
{

    SCL_BUS  = 0;
    delay(I2C_DELAY/2);
    SDA_BUS  = 0;
    delay(I2C_DELAY/2);
    SCL_BUS  = 1;
    delay(I2C_DELAY/2);
    SDA_BUS  = 1;
    delay(I2C_DELAY);

}

 

REPEATED START

During the communication it the master does not want to release the bus then it just asserts a repeated start condition to continue the other communication. In below example controller first write a single byte to the EEPROM after that it just asserts a repeated condition to change the mode from the write to read.

void RepeatedStartI2c()
{

    SCL_BUS  = 0;
    delay(I2C_DELAY/2);
    SDA_BUS  = 1;
    delay(I2C_DELAY/2);
    SCL_BUS  = 1;
    delay(I2C_DELAY/2);
    SDA_BUS  = 0;
    delay(I2C_DELAY);

}

 

WRITE-BYTE TO THE EEPROM

A master first asserts the start bit on I2C bus and after the start bit, send the control byte to the EEPROM followed by the write bit (0) and check the acknowledgment bit.

If the master does not get the acknowledgment from the EEPROM then it will continuously send the control byte to the EEPROM and poll the acknowledgment bit.

When the master gets the acknowledgment then it sends the address of the cell (A15 to A0) where it wants to store the byte. In the last of the communication when the master wants to stop the communication it asserts a stop condition.

void write_byte_to_eeprom(unsigned int addr,unsigned char byte)
{

    StartI2c();

    while(write_i2c(device_addr+0)==1)
    {
        StartI2c();
    }

    write_i2c(addr>>8);
    write_i2c((unsigned char)addr);
    write_i2c(byte);
    StopI2c();

}

 

 

READ BYTES FROM THE EEPROM

A master first asserts the start bit on I2C bus and after the start bit, send the control byte to the EEPROM followed by the read bit (1) and check the acknowledgment bit.

If the master does not get the acknowledgment from the EEPROM then it will continuously send the control byte to the EEPROM and poll the acknowledgment bit.

When the master gets the acknowledgment then it sends the address of the cell (A15 to A0) where it wants to read the byte. After sending the address of cell master sends the repeated start condition on the I2C bus to read the byte from the address which had sent by the master.

unsigned char read_byte_from_eeprom(unsigned int addr)
{

    unsigned char rxdata =0;
    StartI2c();
    while(write_i2c(device_addr+0)==1)
    {
        StartI2c();
    }
    write_i2c(addr>>8);
    write_i2c((unsigned char)addr);
    RepeatedStartI2c();
    write_i2c(device_addr+1);
    rxdata=read_i2c();
    SendNackBit();
    StopI2c() ;

    return rxdata;

}

 

 

PROGRAM TO WRITE AND READ THE BYTE FROM THE EEPROM

The below code explains interfacing EEPROM with 8051 micro-controller using the I2C protocol. In this program, we store a single byte in EEPROM through the I2C protocol and after that read back this written byte from the EEPROM.

In this program for the verification, I will toggle the LED if the read byte is intact.

 

#include <reg51.h>


//Delay for I2c
#define I2C_DELAY    50

//Define Led Toggle Time
#define TOGGLE_LED  20000

//control address of 24lc64
#define device_addr 0xA0

#define ACK_BIT    0


//Define the Pin for the I2c and lec
sbit SDA_BUS = P2^0;
sbit SCL_BUS = P2^1;
sbit Led = P3^0;



/*=========================================
   Prototypes for I2c functions
 ==========================================*/


void InitI2c(void);

void StartI2c(void);

void RepeatedStartI2c(void);

void StopI2c(void);

void SendAckBit(void);

void SendNackBit(void);

void delay(unsigned int);

bit write_i2c(unsigned char);

unsigned char read_i2c(void);

void write_byte_to_eeprom(unsigned int,unsigned char);

unsigned char  read_byte_from_eeprom(unsigned int);



/*=========================================
   Definition of I2c functions
 ==========================================*/


/**
\brief of  delay function.

This function provide the delay which is used in clock generation.
*/
void delay(unsigned int d)
{
    unsigned int i;

    for(i=0; i<d; i++);

}



/**
\brief of InitI2c function.
This function  use to make the data line and clock line idle to put the both line high

*/
void InitI2c(void)
{
    SDA_BUS =1;
    SCL_BUS =1;
}



/**
\brief of StartI2c function.
This function performs the start operation to initiate the communication.

*/
void StartI2c(void)
{
    SDA_BUS  = 1;
    SCL_BUS  = 1;
    delay(I2C_DELAY);
    SDA_BUS  = 0;
    delay(I2C_DELAY);
}



/**
\brief of void RepeatedStartI2c function.

When master does not want to relaese the control from the bus then it assert the repeated
start condition on the i2c bus.
*/
void RepeatedStartI2c()
{
    SCL_BUS  = 0;
    delay(I2C_DELAY/2);
    SDA_BUS  = 1;
    delay(I2C_DELAY/2);
    SCL_BUS  = 1;
    delay(I2C_DELAY/2);
    SDA_BUS  = 0;
    delay(I2C_DELAY);
}



/**
\brief of void StopI2c function.

When master want to stop the communication then it will assert the stop condition to the i2c bus.
*/
void StopI2c(void)
{
    SCL_BUS  = 0;
    delay(I2C_DELAY/2);
    SDA_BUS  = 0;
    delay(I2C_DELAY/2);
    SCL_BUS  = 1;
    delay(I2C_DELAY/2);
    SDA_BUS  = 1;
    delay(I2C_DELAY);
}



/**
\brief of  SendAckBit function.

This function use to send the acknoledgement(ACK) bit the i2c bus.
*/
void SendAckBit()
{
    SCL_BUS  = 0;
    delay(I2C_DELAY/2);
    SDA_BUS  = 0;
    delay(I2C_DELAY/2);
    SCL_BUS  = 1;
    delay(I2C_DELAY);

}



/**
\brief of  SendNackBit function.

This function use to send the Non-acknoledgement(NACK) bit the i2c bus.
*/
void SendNackBit(void)
{
    SCL_BUS  = 0;
    delay(I2C_DELAY/2);
    SDA_BUS  = 1;
    delay(I2C_DELAY/2);
    SCL_BUS  = 1;
    delay(I2C_DELAY);
}



/**
\brief of write_i2c function.

This function use to send signle byte to the I2C Data Bus
*/
bit write_i2c(unsigned char byte)
{
    unsigned char i;
    for(i=0; i<8; i++)
    {
        SCL_BUS  = 0;
        delay(I2C_DELAY);
        if((byte<<i)&0x80)
            SDA_BUS  = 1;
        else
            SDA_BUS  = 0;
        delay(I2C_DELAY/2);

        SCL_BUS  = 1;
        delay(I2C_DELAY);
    }
//ack from slave //
    SCL_BUS  = 0;
    SDA_BUS  = 0;
    delay(I2C_DELAY/2);
    SCL_BUS  = 1;
    delay(I2C_DELAY);
    return SDA_BUS;
}



/**
\brief of write_i2c function.

This function use to read the data from the I2C data bus
*/
unsigned char read_i2c(void)
{
    unsigned char i,d, rxdata=0;
    for(i=0; i<8; i++)
    {

        SCL_BUS  = 0;
        SDA_BUS  = 1;
        delay(I2C_DELAY);
        SCL_BUS  = 1;
        delay(I2C_DELAY/2);
        d=SDA_BUS;
        rxdata=rxdata|(d<<7-i);
        delay(I2C_DELAY);
    }
    return rxdata;

}



/**

\brief of write_byte_to_eeprom function.

This function use to single byte the eeprom at desire address
*///Write Data to eeprom memory
void write_byte_to_eeprom(unsigned int addr,unsigned char byte)
{
    StartI2c();
    while(write_i2c(device_addr|0)==1)
    {
        StartI2c();
    }
    write_i2c(addr>>8);
    write_i2c((unsigned char)addr);
    write_i2c(byte);
    StopI2c();
}



/**
\brief of read_byte_from_eeprom function.

This function use to read the data byte from eeprom at the desire the address
*/
unsigned char read_byte_from_eeprom(unsigned int addr)
{
    unsigned char rxdata =0;
    StartI2c();
    while(write_i2c(device_addr|0)==1)
    {
        StartI2c();
    }
    write_i2c(addr>>8);
    write_i2c((unsigned char)addr);
    RepeatedStartI2c();
    write_i2c(device_addr|1);
    rxdata=read_i2c();
    SendNackBit();
    StopI2c() ;

    return rxdata;
}



// Main function

void main(void)
{
    unsigned char rxbyte=0;
    unsigned char cSendByte = 'a';

    Led  = 0;
    SDA_BUS = 0;
    SCL_BUS = 0;

    InitI2c();
    write_byte_to_eeprom(0x0001,cSendByte);
    rxbyte=read_byte_from_eeprom(0x0001);


    while(1)
    {

        if(rxbyte ==  cSendByte)
        {
            Led =1;		   // Led Off
            delay(TOGGLE_LED);
            Led =0;			  // Led on
            delay(TOGGLE_LED);

        }
    }
}

 

Recommended Post: