EEPROM stands for electrically erasable programmable read-only memory. EEPROM can be erased and reprogrammed by the user by applying electrical voltages. Its life is limited that it can be reprogrammed only tens, hundreds or thousands of times. Life of EEPROM is a major concern in the design of systems in which memory contents are altered frequently. The interfacing of EEPROM with microcontrollers is mostly done with serial interface protocols like I2C, SPI, and UART. Here we are going to interface AT24C16A, 16kilobyte EEPROM from ATMEL.


AT24C16A is an I2C compatible EEPROM IC manufactured by ATMEL. AT24C16A is a 16K serial EEPROM internally organized with 128 pages of 16 bytes each (total 128×16=2048 bytes), the 16K requires an 11(2^11=2048) bit data word address for random word addressing. Each byte location in the EEPROM can be accessed with an 11-bit address for a read or write operation.


A0-A2 : Address inputs
SDA : Serial Data
SCL : Serial clock input pin
WP : Write Protect
GND : Ground
VCC : Supply

A0-A2 pins are address pins. But they are not used in AT24C16A and can be connected to ground. These bits can be used to address same chips if more than one of the other ICs in the same family like AT24C02 is connected to the bus. As many as 8 AT24C02 devices (2^3) can be connected.

Every EEPROM requires an 8-bit device address following a start condition to enable the chip for read or write operation. The address word will consist of a mandatory “1”, “0” sequence for the first for most significant bits as shown. This is common to all the serial EEPROM devices. The next 3 bits A2, A1, A0 are device address bits. The 16K does not use any device address bits, instead, they are used for memory page addressing. A2, A1, and A0 are used in AT24C16A as the most significant bits of the data word address.


The eighth bit of the device address is a read/write operation select bit.

I2C Protocol

I2C protocol is developed by Philips. The number of devices which can be connected to the common data and clock lines is more than that of SPI and other commonly used serial communication protocols. I2C can have multiple masters and multiple slaves connected to the same network. However, at a time, only one master device can have the control of the I2C bus. In most embedded systems, the master device will be a microcontroller with an integrated I2C module.

There are two signal lines in I2C, SDA, and SCL. SDA line is used for the data transfer with the controller and the device. I2C is a master-slave protocol in which one of the devices will act as the master and generates the clock pulse for communication.The SDA and SCL lines connected between the master and the bus is open drain.These lines need to be pulled up to VCC through pull-up resistors.

When a microcontroller is connected to an I2C bus, the bus needs to communicate with any one of the slaves connected to it. The microcontroller generates a start condition which signals all the slave devices that a communication is going to begin. The start condition is pulling the SDA line low when SCL is held high. After the start condition is generated, the microcontroller will send the 7-bit address of the desired slave along with its eighth bit indicating the operation to be performed. If the eighth bit sent is a 0, the microcontroller will write into the slave device and if it is 1, the master will receive data from the addressed slave. All of the slave devices connected with the I2C bus will receive the address and compares with its stored address. The device which matches the address will respond to the master with an acknowledgment bit. Now communication will be established between the master and the slave which responded earlier. Master device initiates the desired operation whether to read or write data.


A write operation involves the transmission of data from the master to the slave in bytes and slave acknowledges after each byte is received. A read operation involves reception of data at the master side (transmission at slave) and master acknowledges after each byte.When a read operation is being done the microcontroller should send a non-acknowledgment signal for the last data byte instead of an acknowledgment. Once the communication is established between a master and slave, the I2C bus will be free and accessible to another master only if a stop condition is generated in the bus. If a stop condition is issued by the master which currently uses the I2C bus, it will be available for other devices.

If the existing master needs to communicate with a different slave or need to perform a different operation(read/write), it should stop and then start again. But there is a chance of losing the control over the bus after the stop condition. Then it would have to wait until the bus is free again. To avoid this, the master generates a restart signal instead of generating a stop followed by a start. A repeated start is a start condition not following a stop.

Write Operation

A write operation requires an 8-bit data word address following the device address word and acknowledgment. After receiving the data word address, the device will respond with an acknowledgment. Then 8-bit data word is sent. Upon receiving the data word the device will acknowledge and microcontroller should send a stop condition to terminate the byte write operation.


Similar to byte write, page write can also be done. In this case, the microcontroller will not send the stop bit followed by the acknowledgment. Instead, it will clock in the next byte of data after each byte is acknowledged. The controller must terminate the process after the full page is written.


Read Operation

Read operations are initiated in the same way the write operation is initiated with the exception that the read/write bit in the device address is set to 1. Read operations can be performed in 3 different ways.

Current address read is in which the internal data word address counter maintains the last read address or last write address incremented by one. Once the device address with the last bit set is sent, the device will clock out the data in the current data word address. The microcontroller generates a non-acknowledgment followed by a stop.


In random read, a dummy write cycle is done first to load in the data word address. Once the device address is sent and the data word address is clocked in, the acknowledge is sent by EEPROM. The microcontroller must generate another start condition. The microcontroller now initiates a current address word read by sending the device address word with a read bit as LSB. The EEPROM will now clock out the data in the current word address.


Sequential reads are initiated either by a current address read or random address read. After the microcontroller receives a data word, it responds with an acknowledge bit. Upon receiving the acknowledge by EEPROM, it will sequentially clock out data by incrementing the data word address. The sequential data read will continue until the microcontroller initiates a non-acknowledgment along with a stop condition instead of an acknowledgment. If the data word address reaches its limit, the data word address will roll over and sequential read will continue.


Example Firmware

Since EEPROM is interfaced with the controller using the I2C interface, the header files should include relevant headers for I2C. In this example, we are interfacing EEPROM with PIC18F4550.

PIC18F4550 has an I2C module. There is a detailed tutorial on how to use I2C module in PIC18F4550 

Writing the EEPROM requires addressing the device in write mode with the device address and LSB bit 0. The device address sent after the start condition will have the 4 MSB bits which are same for all the EEPROMs. The next 3 bits will be the most significant bits of the data word address(11 bit) following the LSB bit 0 or 1 according to which read or write operation is performed. After the device address word is sent, the LSB (8 bits) of the data word address is transmitted.

void EE_byte_write(unsigned int page,unsigned char byte,unsigned char data )
unsigned int byte_adress;                            // byte address   
byte_adress=(page*16)+byte;                          // generates  16 bit byte address from page num and byte number
I2C_Start();                                         // start I2C
I2C_Write(0xA0|((byte_adress>>7)&0x0E));             // MSB of the address
I2C_Write(byte_adress);                              // LSB of byte address(data word address)

I2C_Write(data);                                     // input character to eeprom
I2C_Stop();                                          // stops I2C

_delay_ms(100);                                      // delay for internal write cycle of EEPROM

Reading a byte from EEPROM involves the same strategy, except that the device should be accessed in read mode and after writing byte address, I2C needs to be restarted.

unsigned char EE_byte_read(unsigned int page,unsigned char byte)
unsigned int byte_adress;                           // byte address 
unsigned char data;
byte_adress=(page*16)+byte;                         // generates  16 bit byte address from page num and byte number
I2C_Write(0xA0|((byte_adress>>7)&0x0E));            // access in write mode

I2C_Write(byte_adress);                             // LSB of byte address(data word address)
I2C_Restart();                                      // restart I2C
I2C_Write(0xA1|((byte_adress>>7)&0x0E));            // access in read mode
data = I2C_Read(0);                                 // read with NACK
I2C_Stop();                                         // stops I2C
// write_uart(data);                                // writes the data to uart - for debugging
return data;

The above two functions are for reading and writing single bytes from EEPROM. For reading and writing pages of data, the above functions can be extended to accommodate more bytes.

Circuit diagram – Interfacing EEPROM with PIC18F4550

AT24C16 is a 16KB EEPROM is arranged as 128 pages of 16 bytes. It uses I2C protocol for communication. SDA and SCL pins of EEPROM is connected to the corresponding pins of PIC18F4550 (RB0 and RB1).


WP is the write protect pin. If connected to Vcc it will disable all the write operation to the EEPROM. For enabling both write and read operations, connect it to the ground. A2-A0 pins are not shown here since we have used SO8 package. If you are using DIP package, they should be connected to the ground.

Spread the love, share this