EEPROM stands for electricity erasable programmable read only memory and it is a type of non-volatile memory used in different application. It is read only memory whose data can be erase and re-programmed by higher than normal current of electricity. Many microcontrollers have in build EEPROM. In this article we use AT24C512 serial EEPROM. It is a low cost EEPROM with 512K and one million read/write cycle. It can operate from 2.7V to 5.5V, so it can be operate with 3.3V microcontroller.
A1:A0 – Physical Address
Pin WP (write Protection) : The write protection input, when connected to Ground allows normal port operation. When WP is connected to Vcc , all write operation to the memory are inhibited.
Device address
So the write address – 0xA0 and read address – 0xA1. The I2C write protocol-
Here after start condition we have to write the corresponding address than data. Let’s separate the start and write function separately. First send start condition with write operation.
uint8_t I2C_Start(char write_address) -> start with write address
uint8_t I2C_Start( char write_address) { uint8_t status; TWCR=(1<<TWEN)|(1<<TWINT)|(1<<TWSTA); //--- TWI Interrupt desable, TWI enable, TWI Start while (!(TWCR&(1<<TWINT))); //--- Wait untial start condition is executed status=TWSR&0xF8; //--- Read TWI status register if (status!=0x08) //--- Check weather START transmitted or not? return 0; //--- Return 0 to indicate start condition fail TWDR=write_address; //--- Write SLA+W in TWI data register TWCR=(1<<TWEN)|(1<<TWINT); //--- TWI Interrupt desable, TWI enable while (!(TWCR&(1<<TWINT))); //--- Wait untial transmet is complete status=TWSR&0xF8; //--- Read TWI status register if (status==0x18) //--- Check for SLA+W transmitted &ack received return 1; //--- Return 1 to indicate ack received if (status==0x20) //--- Check for SLA+W transmitted &nack received return 2; //--- Return 2 to indicate nack received else return 3; //--- Else return 3 to indicate SLA+W failed } |
uint8_t I2C_Write(char data) -> write address word or data
uint8_t I2C_Write( char data) { uint8_t status; TWDR=data; //--- Data write to transmet TWCR=(1<<TWEN)|(1<<TWINT); //--- TWI Interrupt desable, TWI enable while (!(TWCR&(1<<TWINT))); //--- Wait untial transmet is complete status=TWSR&0xF8; //--- Read TWI status register if (status==0x28) //--- Check for data transmitted &ack received return 0; //--- Return 0 to indicate ack received if (status==0x30) //--- Check for data transmitted &nack received return 1; //--- Return 1 to indicate nack received else return 2; //--- Else return 2 for data transmission failure } |
Now the read operation the I2C protocol is-
Here the first 2 steps are same start and address writes. Now we need new start function with read operation-
uint8_t I2C_Read_Start_Add(char read_address) -> Re-start with read
uint8_t I2C_Read_Start_Add( char read_address) { uint8_t status; TWCR=(1<<TWSTA)|(1<<TWEN)|(1<<TWINT); //--- TWI Interrupt desable, TWI enable, TWI Start while (!(TWCR&(1<<TWINT))); //--- Wait untial start condition is executed status=TWSR&0xF8; //--- Read TWI status register if (status!=0x10) //--- Check for repeated start transmitted return 0; //--- Return 0 for repeated start condition fail TWDR=read_address; //--- Write SLA+R in TWI data register TWCR=(1<<TWEN)|(1<<TWINT); //--- TWI Interrupt desable, TWI enable while (!(TWCR&(1<<TWINT))); //--- Wait untial transmet is complete status=TWSR&0xF8; //--- Read TWI status register if (status==0x40) //--- Check for SLA+R transmitted &ack received return 1; //--- Return 1 to indicate ack received if (status==0x48) //--- Check for SLA+R transmitted &nack received return 2; //--- Return 2 to indicate nack received else return 3; //--- Else return 3 to indicate SLA+W failed } |
In data read operation 8bit data received with acknowledge and if we want to terminate reading we just read with not acknowledge. Let’s look at the read with ack and read with nack function.
char I2C_Read_Ack(void) -> read with acknowledge
char I2C_Read_Ack( void ) //Read data with Acknowladge { TWCR=(1<<TWEN)|(1<<TWINT)|(1<<TWEA); //--- TWI Interrupt desable, TWI enable, TWI Accknowledge while (!(TWCR&(1<<TWINT))); //--- Wait untial transmet is complete return TWDR; //--- Return received data } |
char I2C_Read_Nack(void) -> read with not acknowledge
char I2C_Read_Nack( void ) //Read data without Acknowladge { TWCR=(1<<TWEN)|(1<<TWINT); //--- TWI Interrupt desable, TWI enable while (!(TWCR&(1<<TWINT))); //--- Wait untial transmet is complete return TWDR; //--- Return received data } |
All we are done with necessary function. Now download the EEPROM.c & EEPROM.h file and the main program is to just write some data to EEPROM and read the data from EEPROM. The read EEPROM data will be display into the LCD screen.
#include<avr/io.h> #include<util/delay.h> #include<util/twi.h> #include<string.h> #include"EEPROM.h" #include"LCD.h" char display[20]; int main( void ) { char array[20] = "External I2C EEPROM" ; LCD_INIT(); /* Initialize LCD */ twi_init(); /* Initialize I2C */ I2C_Start(EEPROM_Write_Addess); /* Start I2C with device write address */ /*** since add is 2byte ***/ I2C_Write(0x00); /* Write start 1st byte of memory address for data write */ I2C_Write(0x10); /* Write start 2nd byte of memory address for data write */ for ( int i = 0; i< strlen (array); i++) /* Write array data */ I2C_Write(array[i]); I2C_Stop(); _delay_ms(10); I2C_Start(EEPROM_Write_Addess); /* Start I2C with device write address */ /*** since add is 2byte ***/ I2C_Write(0x00); /* Write start 1st byte of memory address for data write */ I2C_Write(0x10); /* Write start 2nd byte of memory address for data write */ I2C_Read_Start_Add(EEPROM_Read_Addess); /* Repeat start I2C SLA+R */ for ( int i = 0; i< strlen (array); i++) /* Read data with acknowledgment */ display[i]=I2C_Read_Ack(); I2C_Read_Nack(); /* Read flush data with nack */ I2C_Stop(); LCD_write_string(1,1,display); return 0; } |