Pfad: Home => AVR-EN => Beginner's Intro => EEPROM access    (Diese Seite in Deutsch: Flag DE) Logo

Address modes in AVRs

  1. accessing SRAM locations,
  2. accessing portregister locations,
  3. accessing EEPROM locations,
    1. Accessing EEPROM
    2. The .ESEG directive
    3. EEPROM port registers
    4. EEPROM address
    5. Reading EEPROM
    6. Writing EEPROM
  4. accessing flash memory locations.

3.1 Accessing EEPROM

All AVRs have at least 64 bytes and up to 4,096 bytes EEPROM on board. EEPROM is a memory type that keeps its content, even if the power supply of the device is down and, after a short or long period of time, is powered up again.

Un-programmed EEPROM space contains all 0xFF. The content of the EEPROM can be written in two modes:
  1. When assembling source code, anything that was written in the .ESEG section of the source code, is copied into a hex file named *.eep. The file's content can be programmed into the EEPROM using a burner software.
  2. Within the actively executed program, EEPROM locations can be cleared and re-written with different content. The procedure to clear and re-write a byte requires some time, the end of the write process can initiate an interrupt, if so enabled.
Reading from EEPROM requires a different procedure. Reading EEPROM content is fast and requires only a few clock cycles.

3.2 EEPROM initiation with the .ESEG directive

EEPROM content from the ESEG segment If you use EEPROM you might want to set the initial EEPROM content on the first controller start-up to certain values. This requires a .ESEG directive. The following places different content into the EEPROM.

.CSEG ; Code segment
  ; Instructions to be executed
.ORG 0x0000 ; The start address of the EEPROM content, default=0
  .db 1,2,3,4,'A','a' ; Bytes to be written
  .dw 1234, 4567 ; 16-bit Words to be written
  .db "Text to be written to EEPROM",0x00 ; Text string
  .dw JumpAddress
; End of the ESEG
.CSEG ; Code segment
; ... Further code for execution

After assembling and programming the .eep file to the controller, its EEPROM looks like shown in the picture.

Normally programming the flash memory not only erases the flash but erases the EEPROM content as well. If you want to keep the EEPROM content during programming the flash, set the respective preserve fuse of the device. That prevents from erasing the flash. And: if that fuse is set, do not write the .eep file again to the EEPROM. It will fail verification in most of the cases, because zeros in the EEPROM can not be overwritten by ones (only erasing produces ones).

3.3 EEPROM port registers

Accessing EEPROM Writing or reading EEPROM uses three or four port registers:
  1. An address: The lowest 8 bit of the address are to be written to the port register EEARL. If the device has more than 256 bytes EEPROM, the most significant 8 bits of the address are to be written to port register EEARH.
  2. A data port: When writing to the EEPROM the 8 bit data to be written are written to the data port register EEDR, before the write process is started. When reading from EEPROM, the data at the addressed location is appearing in port register EEDR.
  3. A control port: Write to or read access from the EEPROM is controlled in the control register EECR by manipulating bits in this register. When writing, the EEPE-Bit is one, when reading the EERE-bit is one.
Please note that the addresses given are subject to changes, so always use the names instead of fixed addresses.

3.4 Writing the EEPROM address

If your program shall read or write a single byte to/from the EEPROM, the assembler code to set the address should look like this:

.equ EepromAddress = 0x0010
; First wait until any write procedure has finished
  sbic EECR,EEPE ; Check EEPE byte
  rjmp WaitEep ; Wait further
; Set the address
  ldi R16,Low(EepromAddress)
  out EEARL,R16
  .ifdef EEARH ; If more than 256 bytes EEPROM
    ldi R16,High(EepromAddress)
    out EEARH,R16
  ; Read or write procedure
    ; Read or write procedure here

Note that changing the EEPROM address ALWAYS should check first that no programming is in progress. These are the first two words, before any settings can be made.

The .IFDEF directive adds the MSB setting only if the symbol EEARH is defined in the file, which is the case for all AVRs that have more than 256 bytes EEPROM.

If you want to read or write multiple EEPROM locations in a row, you'll have to set the LSB of the address in a loop, and, if the MSB changes, the MSB as well. As the check whether programming is finished has to be made prior to entering any address changes and as the MSB has to be set in any case (if the MSB is physically available), we cannot limit the MSB output only to cases where the MSB changes. Here, we output the MSB in all cases, which are only two additional instructions.

.equ EepStartAddr = 0x0010
.equ EepEndAddr = 0x001F
  ; Set the address to the double register in R1:R0
  ldi R16,High(EepStartAddr)
  mov R1,R16
  ldi R16,Low(EepStartAddr)
  mov R0,R16
  sbic EECR,EEPE
  rjmp EepLoop
  ; Output the LSB of the address
  out EEARL,R0
  .ifdef EEARH
    ; Output the MSB of the address
    out EEARH,R1
  ; Add Read or write procedure here
  inc R0 ; Increase LSB
  brne EepChkEnd
  inc R1
  ldi R16,Low(EepEndAddr+1)
  cp R0,R16
  brne EepLoop
  ldi R16,High(EepEndAddr+1)
  brne EepLoop

3.5 Reading from the EEPROM

Reading from the EEPROM is initiated by setting the EERE-bit in the control register EECR. This halts the CPU for four clock cycles and then writes the EEPROM content at that address to port register EEDR. That looks like this:

.equ EepAddrs = 0x0010
  sbic EECR,EEPE ; Wait until write operation finished
  rjmp EepWait
  ldi R16,Low(EepAddrs)
  out EEARL,R16
  .ifdef EEARH
    ldi R16,High(EepAddrs)
    out EEARH,R16
  sbi EECR,1<<EERE
  ; Four clock cycles pause
  in R16,EEDR ; Read byte to R16  

Reading the EEPROM content to a SRAM area In case we have to read more than one byte, we have to have more storage space. If a second byte is to be read, we'll need a second register. If more than three or four bytes are to be read, we use an SRAM space to write the bytes there, e.g. with a pointer to that in X, we would add the instruction ST X+,R16.

This here shows how we read the complete EEPROM content into an area in SRAM by using ST X+,R16. Note that the whole process needed close to one millisecond, because of delays during access reads, the check of the programming bit, the double byte check of the end and the pointer operations.

3.6 Write access to the EEPROM

To avoid unplanned write access to the EEPROM, the procedure to start a write process is a bit more complicated:
  1. First check if the last write is finished by testing the EEPE bit in the control register EECR. Otherwise wait.
  2. Then write the correct address to EEARL/EEARH.
  3. Then write the data byte to be written to EEDR.
  4. Then set the Master Programming Enable bit EEMPE in EECR, together with the programming mode bits EEPM0 (Erase only) and EEPM1 (Write only), if so desired, and the interrupt enable EEPIE-bit, if desired.
  5. Within the following four clock cycles (make sure that no interrupt can occur during these four cycles) set the Programming Enable bit EEPE in EECR.
This starts the programming of the location after two clock cycles.

The programming of the byte lasts 3.4 ms. When finished, the EEPE-bit is cleared and, if so enabled, starts an interrupt and jumps to the EEPROM-READY vector.

Text to be copied to EEPROM An example: This text in the SRAM has to be copied to EEPROM. We can do that preferably with the interrupt feature of EEPROM write or in a discrete loop that checks whether the EEPE-bit is clear and writes the next character in SRAM to the EEPROM.

Progress in writing EEPROM This is the state of the EEPROM after few characters have been written and the 16th character is currently written. In the first half of the write process the location is erased, which means that all bits at that location are set to one. In the second half, the data is written. As this lasts roughly 3.4 ms, the bar shows the progress. Both, the master write/program enable bit EEMPE and the write/program enable bit EEPE are active (high). When the write process is finished, both bits are cleared by the AVR.

Programming completed As the whole process lasts more than 140 ms, it is not recommended to perform EEPROM writes in this lengthy way. This was just an example.

One note on interrupts: if the interrupt-enable-bit EEIE is set, the EEPROM READY interrupt re-triggers every time the EEPE-bit gets clear and if no other higher-ranking interrupt is active. Your whole program can be blocked by this, if you do not write the next byte to the EEPROM in your interrupt service routine. If no more bytes are to be written, clear the interrupt enable bit.

Finally a warning: the number of write operations to EEPROM is limited to several thousand events. One day has over 80,000 seconds, a year has more than 31 million seconds, so if you want to reach the guaranteed number of write accesses in one year, you can write the same EEPROM location every 3,100 seconds or every 53 minutes.

So do not unnecessarily re-write the EEPROM and limit write accesses to several minutes or hours and do it whenever really needed (e.g. because the user just pressed a key or because the controller has re-started). It is a good idea to hold a copy of the EEPROM content in registers or SRAM and to only re-write the EEPROM if the difference is large enough.

An example for this: if you want to keep the current state of a stepper motor in two, three of four bytes in an EEPROM location, do not write the position changes to EEPROM whenever one single step has been made. Write the status only after the complete move has finished. And write only the really changed bytes to EEPROM. And hope that the LSB of the EEPROM lasts long enough.

Conclusions: Read accesses from EEPROM are very fast, but less fast than SRAM read accesses or accesses to registers. So better read the needed EEPROM content once to a location in SRAM and access this instead of the EEPROM.

Write accesses to EEPROM require longer times, are limited over the life-time of the device and should be limited to the cases where they are useful and really needed. Depending from the rest of your program and from its overall timing considerations: better use the EEPROM READY interrupt to avoid timing conflicts.

To the top of this page

©2021 by