What do we have on our plate?
We can access the internal EEPROM using
1. EEPROM library functions available in AVR-GCC.
2. EEPROM access registers available in ATmega328P
The first method is simple and straight forward by just calling the library functions available in eeprom.h. Whereas, the second method is slightly complicated by directly accessing the EEPROM's address/data/control registers and is preferred for time critical applications. I will explain both briefly.
1. Using EEPROM library functions availabe in AVR-GCC
AVR-GCC library provides set of library functions to access EEPROM. All interface functions are declared in avr/eeprom.h, and thus, we have to include this header in our code.
AVR-GCC library provides set of library functions to access EEPROM. All interface functions are declared in avr/eeprom.h, and thus, we have to include this header in our code.
Lets look at couple of functions which read and write a byte on EEPROM. Their prototype is as below.
uint8_t eeprom_read_byte(const uint8_t * pAddress)
Returns a byte of data read from address pAddress.
void eeprom_write_byte(uint8_t *pAddress, uint8_t value)
Write a byte of data, value, at address pAddress.
The documentation of full list of EEPROM access functions are listed here.
The below example code demonstrates the use of few functions.
The below example code demonstrates the use of few functions.
/*
* 328_eeprom.c
* ATMega328P Internal EEPROM read/write
* Created on: 20-Mar-2011
* Author: samy
*/
#define F_CPU 16000000UL
#define BAUD 9600
#define MYUBRR F_CPU/16/BAUD-1
#include <stdio.h>
#include <avr/io.h>
#include <avr/eeprom.h>
#include "delay_x.h"
#include "USART328.c" /* Shared by Abhishek for USART interface */
//#include <avr/sfr_defs.h>
int main (void)
{
char buf[20];
unsigned int addr;
uint8_t rb8, wb8 = 'a';
uint16_t rw16, ww16 = 12345;
uint32_t rdw32, wdw32 = 1234567;
float rfloat, wfloat = 123.45f;
char rblk[5], wblk[5] = "abcd";
USART_init(MYUBRR);
for(;;) // Loop Forever
{
addr = 0;
/* Read and Write a word */
eeprom_write_word( (uint16_t*)addr, ww16 );
rw16 = eeprom_read_word((uint16_t*)addr);
sprintf( buf, "R/W %d @ %d\r\n", rw16, addr);
USART_String(buf);
/* Read and Write a double word */
eeprom_write_dword( (uint32_t*)addr, wdw32 );
rdw32 = eeprom_read_dword((uint32_t*)addr);
sprintf( buf, "R/W %ld @ %d\r\n", rdw32, addr);
USART_String(buf);
/* Read and Write a float */
eeprom_write_float( (float*)addr, wfloat );
rfloat = eeprom_read_float((float*)addr);
sprintf( buf, "R/W %d.%d @ %d\r\n", (int)rfloat, ((int)(rfloat*100))%100, addr);
USART_String(buf);
/* Read and Write a block */
eeprom_write_block(wblk, (void*)addr, sizeof(wblk) );
eeprom_read_block (rblk, (void*)addr, sizeof(wblk) );
sprintf( buf, "R/W %s @ %d\r\n", rblk, addr);
USART_String(buf);
_delay_s(3);
while( addr <= E2END ) /* E2END : last valid address in Internal EEPROM */
{
/* Read and Write a byte */
eeprom_write_byte( (uint8_t*)addr, wb8 );
rb8 = eeprom_read_byte((uint8_t*)addr);
sprintf( buf, "R/W %c @ %d\r\n", rb8, addr);
USART_String(buf);
++addr;
}
_delay_s(3);
}
}
ATMega328P provides 3 registers to control the operation of EEPROM.
1. Address Register (EEAR)
2. Data Register (EEDR)
3. Control Register (EECR)
The below table explains the purpose and function of each register/bit.
Name
Length/Bit#
Purpose/Function
EEAR
10(remaining 6bits unused)
Address register. Contains EEPROM address to which data is read/written
EEARH
2 (Bits 0 to 1)
Address high order bits
EEARL
8
Address low order byte
EEDR
8
Data register. Contains data to be read/written
EECR
6 (Bits 0 to 5)
Control register.
EEPM1
EEPM0
Bit 5
Bit 4
Together controls the programming mode.
0 – Erase and write, 1 – Erase only, 2 – Write only, 3 - unused
EERIE
Bit 3
Ready Interrupt Enable
1 – Enable Ready interrupt, 0 – Disables
EEMPE
Bit 2
Master Write Enable. Must be set to one to write and will be reset after 4 clock cycles.
EEPE
Bit 1
Write Enable. When set to one, writes the content of EEDR at EEPROM address EEAR. EEMPE must be set to one.
EERE
Bit 0
Read Enable. When set to one, trigger the Read operation. Reads the data at address EEAR and store to EEDR.
More detailed information such as number of clock cycles for each operation, interrupt controlled EEPROM access, etc are explained in the datasheet.
Below is the implementation of simple read/write operation for a byte and string. These functions can be interfaced with above code. Also, please note that these functions assume interrupts are disabled, if not, you have to call cli() function (clear global interrupt mask in avr/interrupt.h) first before invoking any one of the below functions.
void eeprom_write_byte1(uint16_t addr, uint8_t data)References:
{
while(EECR & (1<<EEPE)) /*wait until previous write any*/
;
EEAR = addr;
EEDR = data;
EECR |= (1<<EEMPE);
EECR |= (1<<EEPE);
}
uint8_t eeprom_read_byte1(uint16_t addr)
{
while(EECR & (1<<EEPE))/*wait until previous write any*/
;
EEAR = addr;
EECR |= (1<<EERE);
return EEDR;
}
/*assumes s is a proper null terminated string*/
void eeprom_write_string(uint16_t addr, char *s)
{
while(*s)
{
eeprom_write_byte1(addr, *s );
++s;
++addr;
}
}
/* read a string of len characters maximum starting at addr.
* modify according to your need!
*/
void eeprom_read_string(uint16_t addr, char *s, int len)
{
while(len)
{
*s = eeprom_read_byte1(addr);
if( *s == '\0' )
return;
--len;
++s;
}
*s = '\0';
return;
}
Thanks for the information, it was useful for me.
ReplyDeletein eeprom_read_string function I think it is missing address increment statement.
ie there should be addr++; statement after ++s;
char eep[10] = {"HELLO"};
ReplyDeleteeeprom_write_block(eep,(void*)0x00,10);
char eepdata[12];
eeprom_read_block(eepdata,(void*)0x00,10);
i'am getting perfect data from eeprom.
but when m trying to fetch data later.
char eepdata[12];
eeprom_read_block(eepdata,(void*)0x00,10);
m getting garbage. what are the possible problems?
then again m doing this
char eep[10] = {"HELLO"};
eeprom_write_block(eep,(void*)0x00,10);
char eepdata[12];
eeprom_read_block(eepdata,(void*)0x00,10);
and getting the perfect value.
cn you help?