I2C EEPROMs are very popular in embedded system as they provides very good solution for storing data on a non-volatile storage device. AT24xxx series serial eeprom works on I2C protocol. This tutorial will help you understand in depth detail of i2c EEPROMs so you can easily use EEPROMs in your projects.

I2C EEPROM Basics and Bus Addressing

These i2c memories comes in many variants, like:

  • 24C01 - 1Kbits (128 bytes)
  • 24C02 - 2Kbits (256 bytes)
  • 24C04 - 4Kbits (512 bytes)
  • 24C08 - 8Kbits (1KB)
  • 24C16 - 16Kbits (2KB)
  • 24C32 - 32Kbits (4KB)
  • 24C64 - 64Kbits (8KB)
  • 24C128 - 128Kbits (16KB)
  • 24C256 - 256Kbits (32KB)
  • 24C512 - 512Kbits (64KB)
  • 24C1024 - 1Mbits (128KB)

The memories behave as slave devices in the i2c protocol with all memory operations synchronized by the serial clock. The I2C EEPROM carry a built-in 4-bit unique identification code (0b1010) corresponding to the I2C Bus definition followed by 3 bits of device or block select bits.

Eeprom xx.jpg Eeprom.jpg

Most of the EEPROMs have 3 configurable address bits some have only two e.g. with 256 or 512Kbit EEPROMs. This lets you to cascade multiple I2C EEPROMs on same I2C Bus. As you can see in the figure above A0, A1 and A2 are the address select bits. The final address of EEPROM always depends on configuration of address select pins.

7-Bit EEPROM Address: 1010 A2 A1 A0
Lets say If you connect A0, A1 and A2 to GND in your circuit then, addresses will be as follows:

7-Bit EEPROM Address: 1010 0 0 0 = 0x50
I2C address for Write: 1010 0 0 0 0 = 0xA0
I2C address for Read: 1010 0 0 0 1 = 0xA1

AT24C1024 (1MBit EEPROM Addressing)

For 24C1024 (1Mbit EEPROM) addresses are little different. There is an internal block select bit to select between upper and lower 64KB of EEPROM memory as shown below.

I2c eeprom 1024.jpg

So with block select use can select to read/write the upper and lower 64KB area of EEPROM memory, So Single 1Mbit eeprom has two internal addresses of its own.

Lower 64KB address (A0, A1 to GND): 7-Bit Address: 1010 0 00 = 0x50
I2C address for Write: 1010 0 00 0 = 0xA0
I2C address for Read: 1010 0 00 1 = 0xA1

Upper 64KB address (A0, A1 to GND): 7-Bit Address: 1010 1 00 = 0x54
I2C address for Write: 1010 1 00 0 = 0xA8
I2C address for Read: 1010 1 00 1 = 0xA9

Internal Sub-Address for EEPROMs

The sub address (also called word address) is used to point to the internal address of EEPROM. After sending slave address of the EEPROM master must send the sub-address to set the internal address pointer to memory location where read/write should take place. Once the address pointer is set, it auto interment for every sequential read/write operation. However in-case of write operation sub address is bound to page boundary limits. For EEPROM with less than 256bytes of memory area subaddress size is 1 byte, whereas for others its 2 bytes.

So I2C transaction looks like this:
[Start] [Slave Address | R/W] [A] [Sub Address] [A] [Data] [A] ... [Data] [NAK] [Stop]

Write Operations

There are two types of write operations possible on I2C EEPROMs

  1. Byte Write
  2. Page Write

As soon as a I2C write finishes EEPROM enters into an internal self timed write cycle to finish the write opeartion on a memory location. This time is typically not more than 5ms. All inputs are disabled during this write cycle and EEPROM will not respond to any I2C operation until write cycle is finished.

Byte Write

This mode is a very similar to normal I2C write operation with only 1 byte of data written to EEPROM at a time. Following the start condition master sends the slave address and sub address after reeving acknowledge from slave (memory). The sub address sets the internal address pointer to memory location on EEPROM. Master device will then sends the data to be written to addressed memory location followed by a stop condition on by Master.

I2c eeprom byte write.png

Page Write

A Page write is initiated the same was as byte write operation but master device does not send stop condition after the first data byte, Instead after the first data is acknowledged by EEPROM master can send data continuously upto the page boundary. e.g. if EEPROM has page size of 64 bytes then master device can send 64 bytes before sending a stop condition. This increases the write efficiency of EEPROM as the write cycle take same amount of time for both byte and page write.

I2c eeprom page write.png

To know about the page size of any I2C EEPROM memory, download datasheet of that EEPROM and look into first page under "Features".

Acknowledgement Polling

As explained in the Write operation section, the EEPROM will not acknowledge during a write cycle. This can be used to determine when the write cycle is completed. This will help increase the bus throughput. So instead of giving delay, you can poll EEPROM to know when it is ready to accept further commands.

Once the Stop condition for a Write command has been issued from the master, the device initiates the internally timed write cycle. polling can be initiated immediately. This involves the master sending a Start condition, followed by the slave address with R/W bit as 0. If the device is still busy with the write cycle, then no ACK will be returned. If no ACK is returned, then the Start bit and slave address must be resent. If the cycle is complete, then the device will return the ACK and the master can then proceed with the next Read or Write command. This is explained by a simple flow chart here:

I2c eeprom ack polling.png

Programing For EEPROM

Follow example is based on the I2C Implementation on 8051, so subroutine calls will have same name as mentioned in that tutorial. I am assuming that AT24C512 (512Kbit) eeprom is connected to 8051 microcontroller.

Assembly Sample

Following Assembly code example shows all the EEPROM operations:

;*****************************************
; I2C EEPROM (AT24C512) Byte Write
;*****************************************
	acall startc
	;Slave address
	mov a,#0A0H
	acall send
	;2-Byte Sub Address
	mov a,#00H
	acall send
	mov a,#00H
	acall send
	;Data
	mov a,#55H
	acall send
	acall stop

;*****************************************
; I2C EEPROM (AT24C512) 64-Byte Page Write
;*****************************************
	acall startc
	;Slave address
	mov a,#0A0H
	acall send
	;2-Byte Sub Address
	mov a,#00H
	acall send
	mov a,#00H
	acall send
	;Data
	mov r0,#64
again:
	mov a,r0
	acall send
	DJNZ r0, again
	acall stop

;*****************************************
; I2C EEPROM (AT24C512) Read Data
;*****************************************
	acall startc
	;Slave address
	mov a,#0A0H
	acall send
	;2-Byte Sub Address
	mov a,#00H
	acall send
	mov a,#00H
	acall send
	;Data
	acall rstart
	;Slave address writh Read bit
	mov a,#0A1H
	acall send
	;Read 10 Bytes
	mov r0, #9
	;Load read location (50H) in R1
	mov r1, #50H
read_more:
	acall read
	acall ack
	mov @r1, a
	inc r1
	djnz r0, read_more
	acall read
	acall nak
	mov @r1, a
	acall stop
	
;*****************************************
; I2C EEPROM (AT24C512) ACK Polling
;*****************************************
eeprom_not_ready:
	acall startc
	;Slave address
	mov a,#0A0H
	acall send
	acall stop
	jc eeprom_not_ready
	;When carry (ACK bit) is 0 it means EEPROM
	;Has acknowledged and its ready for next operation

C Sample Source

Following C code example shows all the EEPROM operations:

/******************************************
 * I2C EEPROM (AT24C512) Byte Write
 *****************************************/
	I2CStart();
	/* Slave address */
	I2CSend(0xA0);
	/* 2-Byte Sub Address */
	I2CSend(0x00);
	I2CSend(0x00);
	/* Data */
	I2CSend(0x55);
	I2CStop();

/******************************************
 * I2C EEPROM (AT24C512) 64-Byte Page Write
 *****************************************/
	I2CStart();
	/* Slave address */
	I2CSend(0xA0);
	/* 2-Byte Sub Address */
	I2CSend(0x00);
	I2CSend(0x00);
	/* Data 64 bytes */
	for (i = 0; i < 64; i++)
		I2CSend(i);
	I2CStop();

/******************************************
 * I2C EEPROM (AT24C512) Read Data
 *****************************************/
	I2CStart();
	/* Slave address */
	I2CSend(0xA0);
	/* 2-Byte Sub Address */
	I2CSend(0x00);
	I2CSend(0x00);
	I2CRestart();
	/* Slave address writh Read bit */
	I2CSend(0xA1);
	/* Read 10 Byte from EEPROM */
	for (i = 0; i < 9; i++) {
		array[i] = I2CRead();
		I2CAck();
	}
	array[i] = I2CRead();
	I2CNak();
	I2CStop();
	
/*****************************************
 * I2C EEPROM (AT24C512) ACK Polling
 *****************************************/
unsigned char eeprom_not_ready()
{
	unsigned char ack;
	
	I2CStart();
	/* Slave address */
	ack = I2CSend(0xA0);
	I2CStop();
	
	return ack;
}

/*
 * Example usage of eeprom_not_ready()
 *
 * while (eeprom_not_ready());
 * ... rest of code
 *
 */

See Also

Read more Tutorials on I2C based devices

Help & Queries

If you have any queries, doubts or feedback on this tutorial please share in our discussion forum.

Powered by MediaWiki
This page was last modified on 6 March 2015, at 13:58.
ArrayContent is available under Creative Commons Attribution Non-Commercial Share Alike unless otherwise noted.