Sei sulla pagina 1di 9

Skip to content

Home
ARM Cortex Tutorials
AVR Tutorials
MSP430 Tutorials
Contact
Forum
Activity
Links
PCB Fab

Accessing AVR EEPROM memory in AVRGCC


By admin January 4, 2011 January 5, 2011 AVR Tutorial

AVR microcontrollers have some amount of EEPROM memory on chip. For instance Atmega328 has 1K of byte addressable EEPROM.
EEPROM memory can be used to store and read variables during program execution and is nonvolatile. It means that it retains values
when power supply is off. EEPROM memory comes handy when we need to store calibration values, remember program state before
powering off (or power failure) or simply store constants in EEPROM memory when you are short of program memory space especially
when using smaller AVRs. Think of simple security system – EEPROM is ideal place to store lock combinations and code sequences and
passwords. AVR Datasheets claim that EEPROM can withhold at least 100000 write/erase cycles.

Accessing EEPROM
Standard C functions don’t understands how one or another memory is accessed. So reading and writing EEPROM has to be done by
following special logical system. Simple EEPROM byte read and write operations has to be done via special registers. Atmega328 has
following registers to control EEPROM:

16-bit EEAR (EEARH and EEARL) – EEPROM address register;


EEDR – EEPROM 8-bit data register;
EECR – EEPROM control register.

A s Atmega328 has 1K of EEPROM memory highest cell address will be 0x3FF meaning that only 10 bits of 16-bit EEAR register are
needed. EEPROM writing process is controlled via EECR register. In order to avoid failures there is some sequence of writing process:

Wait until EEPE bit becomes zero;


Write EEPROM address to EEAR register;
Write data to EEDR;
Set EEMPE bit while keeping EEPE bit zero;
In four clock cycles set EEPE bit to initiate writing.

You will find nice read and write examples in datasheet, so there is no need to repeat this here. Lets do more interesting thing – use an
interrupt to write to EEPROM. As you may know Atmega328 has one dedicated interrupt EE_READY_vect, that may be set to occur every
time when EEPROM becomes ready for writing or reading. Usually you would have to poll for EEPE bit become zero in loop – this require
active processing power. Interrupt driven EEPROM writing may be more efficient especially when memory blocs has to be accessed. Lets
write simple Interrupt driven AVR EEPROM writing routine and write to it a simple message string.
1 #include <avr/io.h>
2 #include <avr/interrupt.h>
3 //EEPROM address initial 0
4 volatile uint16_t eepromaddress;
5 //string array index initial 0
6 volatile uint8_t i;
7 //message to be written to EEPROM
8 uint8_t message[] ="Write to EEPROM";
9 //EEPROM writing ISR
10ISR(EE_READY_vect)
11{
12/*check if not end of string and address
13didn't reach end of EEPROM*/
14if ((message[i])&&(eepromaddress<=E2END))
15{
16 //loads address and increments for next load
17 EEAR=eepromaddress++;
18 //loads current byte and increments index for next load
19 EEDR=message[i++];
20 //master write enable
21 EECR|=(1<<EEMPE);
22 //strobe eeprom write
23 EECR|=(1<<EEPE);
24}
25else
26{
27 //disable eeprom ready interrupt
28 EECR &= ~(1<<EERIE);
29}
30}
31int main(void)
32{
33//Enable eeprom ready interrupt
34EECR |= (1<<EERIE);
35//enable global interrupts
36sei();
37 while(1)
38 {
39 //do other tasks or sleep
40 }
41}

As you can see ISR simply takes bytes from message buffer and writes it to EEPROM memory until buffer is empty or EEPROM end is
reached. Using EE_READY interrupt leaves EEPROM writing completely to hardware and frees MCU resources for other tasks. In other
words EEPROM itself asks for another byte when ready. This way you improve performance and reduce power consumption. Same
interrupt source can be used for reading EEPROM.

Using EEPROM library from AVRLibC


We discussed how you can access EEPROM memory by using special registers and safe logic. TO avoid possible errors it is logical to use
standard eeprom.h library from AVRLibC that comes with AVRGCC tools. To start working with EEPROM routines we need to include
eeprom library in to our source code:

1#include <avr/eeprom.h>

This opens access to several useful routines that allow us to read/write/update bytes, words, double words , floats and even memory
blocks. Lets see how simple byte write and read looks when using eeprom.h library.

1 #include <avr/io.h>
2 #include <avr/eeprom.h>
3 //use last EEPROM cell
4 #define EEADDR 0x3FF
5 //data will be written to EEPROM
6 #define EEDATA 100
7 int main(void)
8 {
9 //put EEPROM data to this variable
10volatile uint8_t EEByte;
11//write EEPROM
12eeprom_write_byte ((uint8_t*)EEADDR, EEDATA);
13//read from EEPROM
14EEByte = eeprom_read_byte((uint8_t*)EEADDR);
15while(1)
16{
17 //do nothing
18}
19}

We have written number byte value of 100 to EEPROM address location 0x3FF and read back to some variable. Same expressions can be
used if you need to write word, double word or or even float. Just use one of prop[er functions like eeprom_read_word().

Working with EEPROM memory blocks


We have discussed one way of dealing with EEPROM memory blocks – using interrupt driven writing from buffer. But if you don’t want to
write your own routine, then you can use one of standard functions from library. There are three functions for this:

1void eeprom_write_block (const void *__src, void *__dst, size_t __n);


2
3void eeprom_read_block (void *__dst, const void *__src, size_t __n);
4
5void eeprom_update_block (const void *__src, void *__dst, size_t __n);

You can write, read and update memory blocks in EEPROM. Functions may not look usual to some of you they use void pointers instead
usual data-types like uint8_t. Good thing is that these functions are universal allowing to deal with any data type. Lets see how this works.
Lets take eeprom_write_block() function it has three arguments:

const void *__src – pointer to RAM location;

void *__dst – pointer to EEPROM location;

size_t __n – number of bytes to be written.


Actually there is no big difference what type of pointers are used, the only thing important to us is the number of bytes needs to be written.
Lets write simple program demonstrating block write and read routines.

1 #include <avr/io.h>
2 #include <avr/eeprom.h>
3 //start from first EEPROM cell
4 #define EEADDR 0
5 //block size to be copied
6 #define BLKSIZE 16
7 //message to be written to EEPROM
8 uint8_t message[] ="Write to EEPROM";
9 int main(void)
10{
11//where block has to be read
12uint8_t readblock[BLKSIZE];
13//write block EEPROM
14eeprom_write_block((const void *)message, (void *)EEADDR, BLKSIZE);
15//read block from EEPROM
16eeprom_read_block ((void *)readblock, (const void *)EEADDR, BLKSIZE);
17while(1)
18{
19 //do nothing
20}
21}

As we see in example we only need to typecast pointers to a void pointers like (void *)readblock so they meet function requirements – this
action doesn’t affect pointer value itself. Our real concern now is to read and write correct number of bytes and that’s it.

Allocating variables in EEPROM with EEMEM attribute


W e learned how to perform EEPROM write and read operations by defining special addresses. This way we have to keep track of
EEPROM addresses that are used in functions. In some cases this is OK but if we need to store lots of EEPROM data it becomes
unpractical. Why not define an eeprom variable where address would be allocated automatically by compiller. This is where EEMEM
attribute comes in. Again there is no magic in it it simply means that variables with this attribute will be allocated in .eeprom memory
section. Lets see this simple example:

1 #include <avr/io.h>
2 #include <avr/eeprom.h>
3 #define BLKSIZE 16
4 #define DATA 0x10
5 uint8_t EEMEM eechar;
6 uint16_t EEMEM eeword=0x1234;
7 uint8_t EEMEM eestring[] = "Write to EEPROM";
8 int main(void)
9 {
10uint16_t sramword;
11//where block has to be read
12uint8_t readblock[BLKSIZE];
13//write byte to location eechar
14eeprom_write_byte(&eechar, DATA);
15sramword=eeprom_read_word(&eeword);
16//read block from EEPROM
17eeprom_read_block ((void *)readblock, (const void *)eestring, BLKSIZE);
18while(1)
19{
20 //do nothing
21}
22}

We have declared one EEPROM variable:

1uint8_t EEMEM eechar;


This will automatically allocates one byte in EEPROM memory with initial zero value. Second two variables have some defined values:

1uint16_t EEMEM eeword=0x1234;


2
3uint8_t EEMEM eestring[] = "Write to EEPROM";

Here we have some initial values assigned to EEPROM variables. But these have to be stored in EEPROM memory. Compiler recognizes
these values and creates separate .eep file along with .hex.

When chip is being flashed, .eep file also has to be uploaded in order to have initial EEPROM values. Otherwise your program will fail trying
to use them.

This is end of another tutorial. Comments and corrections are always welcome.

JLCPCB: Prototype 10 PCBs for $2 (2-layer,100*100mm)

China's Largest PCB Prototype Manufacturer, 290,000+ Customers & 8,000+ Online Orders Per Day

PCB Pricing: https://jlcpcb.com/quote

Share this:
Click to share on Facebook (Opens in new window)
Click to share on Google+ (Opens in new window)
Click to share on Twitter (Opens in new window)
Click to share on Reddit (Opens in new window)
Click to share on LinkedIn (Opens in new window)

Tagged AVR EEPROM memory, AVR Tutorial, EEMEM, write eeprom.


« Controlling 4 servos with Arduino-Python interface
Small fully featured atxmega32 scope »

4 Comments

1. DT
January 5, 2011 at 2:02 am

uint8_t readblock[15];

This should be BLKSIZE instead of 15 else you’ll get a buffer overflow.

2. admin
January 5, 2011 at 2:06 am

Oops missed that. Thanks.

3. bud
March 27, 2011 at 9:17 am

thank you this is the most complete eeprom tut i have found yet

4. FAITH + 1
June 10, 2016 at 8:30 pm

nice tutorial.

Leave a Reply

Connect with:

Your email address will not be published. Required fields are marked *

Comment

Name *

Email *

Website

Post Comment

Notify me of follow-up comments by email.

Notify me of new posts by email.


Most popular

Programming AVR I2C interface

Using Direct Memory Access (DMA) in


STM32 projects

Multichannel ADC using DMA on


STM32

Search for: SEARCH

Search

Recent Comments

TipuCrack on Looking for digital


oscilloscope? – Try DSO138 from
Gearbest
admin on 6 gadgets for the modern
handyman
Bob the Builder on 6 gadgets for the
modern handyman
Smithc976 on The accessories make
the phone
Jeet Bhadania on Interfacing GPS
Module with AVR

Categories

68HC Projects
Arduino
ARM Cortex
ARM Cortex Tutorial
ARM7 Projects
ARM9 Projects
AVR Projects
AVR Tutorial
BASIC Stamp
ChipKIT Projects
CPLD Projects
DSP Projects
dsPIC
FPGA Projects
Handy Circuits
Linux board projects
Misc
MSC-51 Projects
MSP430 Projects
MSP430 Tutorial
Netduino
Other MCU Projects
PIC Projects
PIC32
Raspberry Pi Tutorial
Technology
Uncategorized
ZiLOG

Archives

Archives Select Month

We Recommend

Recent Tutorials

Using Raspberry Pi sftp server


February 24, 2016

Raspberry Pi – formatting and mounting USB drive


September 15, 2015
Multichannel ADC using DMA on STM32
May 14, 2014

Introduction to MSP430 Interrupts


April 6, 2014

Use fixed integer types to enhance portability


March 18, 2014

Login

Username

Password

Remember Me

Login →

Register
Lost Password
Connect with:

Users Online

17 Users Online

Latest posts from scienceprog.com

Taking The Plunge Into Alternative Energy October 25, 2017


Sloth Is the Progress Booster: What Makes the Technological World Move Ahead? October 19, 2017
Why Ethanol is a Fantastic Fuel and Source of Energy October 17, 2017
The Latest Uses of EEG Headsets October 13, 2017
How to install underfloor ventilation October 12, 2017

Copyright © Embedded projects from around the web|Privacy Policy

POWERED BY PARABOLA & WORDPRESS.

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish.Accept Read More
Skip to toolbar

About WordPress
WordPress.org
Documentation
Support Forums
Feedback
Log in
Register

Search Search

Potrebbero piacerti anche