Circular Buffer in EEPROM

Go To Last Post
18 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I look for a Circular Buffer example to use in internal eeprom of mega128 .
If you have it please let me know.
(In C language is preferred.)

thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Any particular reason for this? I can only think of wear leveling, but then you'd wear out a few cells quickly (storing the IN/OUT) pointers. Keep in mind that each EEPROM cell is good for only 100,000 writes.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Atmels application note "AVR101: High Endurance EEPROM Storage"
explains implementing a circular buffer in an EEPROM.
http://www.atmel.com/dyn/products/app_notes.asp?family_id=607

Regards
Sebastian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am going to use it because in Reset condition the correct position in the eeprom is lost.
I think I need to have two index buffer one for data and one for address.
But an example will help me more.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

you have two indexes with a circular buffer -the head and tail. use the head pointer to put data in, the tail pointer to take the data out. If head==tail then buffer is empty or overun

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you want to store events which occupy e.g. 5 bytes per event and want to store 100 events, I use the following approach:

- use a 'buffer' in EEPROM big enough for 101 events
- before storing an event in the next free event buffer, erase the event after that by erasing just the first byte (the computation of next and one after next buffers is done modulo 101)

This is an ordinary circular buffer.

After a reset, just 'count' the number of used event buffers (those, where the first byte !=0xFF). The first unused buffer (first byte ==0xFF) is used as write pointer for the next event.

To erase all events (e.g. after readout with a PC), set the count to zero and erase every first byte of the 101 event buffers.

Jörg.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
you have two indexes with a circular buffer -the head and tail. use the head pointer to put data in, the tail pointer to take the data out. If head==tail then buffer is empty or overun

Your solution is proper when we almost wanna write and read simultantanosely.
My problem is if the system writes some data in the EEPROM regulatory, if the system is exposed to the Reset condition the system needs to be able to identify correct position in the EEPROM and write new data in following of the last data.
So I thought about the circular Buffer and need an example.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Jörg's suggestion is probably about as wear-leveling-efficient a solution as you can hope to find, as long as you can reserve a particular bit pattern to use as the "empty" indicator.

Here's a possible way that I might go about implementing Jörg's suggestion:

When the system is first programmed, "format" the buffer space in EEPROM to all contain the EMPTY bit pattern.

For ease of bookkeeping, maintain "head" and "tail" indexes in SRAM to speed up adding/removing entries in the buffer.

Whenever the system reboots, you'll need to initialize "head" and "tail" to reflect the EEPROM's current state. Do so by reading through the entire EEPROM space to identify the first non-EMPTY cell that you find. Continue reading past that point until you locate the first EMPTY cell. Set "head" to point to that location. Continue scanning until you find the first cell that is non-EMPTY. Set "tail" to point to that location. (Wrap around to index zero as necessary.)

If you scan the entire EEPROM storage space without finding the necessary conditions, then the buffer is either overflowed or empty. In either case, the solution is the same: set both "head" and "tail" to zero effectively reinitialiing the buffer.

When you need to add a new entry to the EEPROM storage, you first have to check for a buffer overflow by identifying the possibility that incrementing "head" may make it equal to "tail". If that is the case, a decision must be made whether to "bump up" tail (thus discarding the oldest data) or abort the write (thus discarding the new data).

Once that has been dealt with, if you want to go ahead with the new data insertion, start by writing the EMPTY marker into the data location ("head" + 1). (Make sure to account for wrapping around to index zero as necessary.) Then write the desired new data into location ("head"). Finally, increment "head".

When you want to remove the oldest data from the buffer, you first need to check and see if the buffer has anything in it to start with by checking whether "tail" and "head" are equal. If they are equal, then there's nothing to discard, so abort. Otherwise, write the EMPTY marker into the data location ("tail"). Then increment "tail".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

perhaps a better solution would be, use ram?
the contents of ram are not destroyed by a reset, as long as power is not lost.

You would need to figure out how to tell your compiler not to initialize this ram area.

Also you can examine certian registers (RTM) and know what kind of reset you just experianced, POR ect. if it is a POR then don't trust the contents of RAM.

Troy.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TroyC wrote:
perhaps a better solution would be, use ram?
the contents of ram are not destroyed by a reset, as long as power is not lost.

You would need to figure out how to tell your compiler not to initialize this ram area.

Also you can examine certian registers (RTM) and know what kind of reset you just experianced, POR ect. if it is a POR then don't trust the contents of RAM.

Troy.

EEPROM is reliable solution specially on POR and you know mega128 has 4k internal EEPROM.I think its problem is just long time to write in comprison with RAM.But in addition it is OK to me.

I am going to test J"org's and lfmorrison's solution,they look ok to me also.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lfmorrison:
I could not have explained it better!

What I mostly do is still a bit different. As I want to have permanent (fast) access to all event data, I use a copy of the EEPROM event buffer in RAM.
Means:
After Power-Up I copy the complete event buffer to RAM and then do all the described operations in RAM. This is considerably faster. New events are 'created' in a periodic interrupt (mostly every second) and only written to RAM. This is again very fast as it does not depend on EEPROM write times. In the main loop I then check whether RAM and EEPROM write pointers are equal. If not, the new RAM data is transfered to EEPROM.
Jörg.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think lfmorrison's suggestion is more efficient and easy to do.Specially it is possible to read and write
independently but as I found in your suggestion we need to put FF in some bytes by PC before doing anything and use again PC after the buffer completion to make it marked.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
.. we need to put FF in some bytes by PC..

??

I use 0xFF as a marker for free event buffer because this is the default value for an erased EEPROM cell. So this is true after programming the chip, too.
After reading the event data from the EEPROM, you may just send an erase command from the PC. The controller can then erase the buffer markers and set the event counter to zero.

Quote:
...use again PC after the buffer completion to make it marked.

Sorry, I do not understand this. What do you mean with 'buffer completion'?
The PC has does only tell the conroller to send event data or to erase the complete event buffer. Nothing more is needed.
It would also be possible to erase single events, but this does not normaly make any sense. After the PC has read the events, they can be safely stored on the PCs harddisk and can then be completely erased on the controller to free as much event buffers as possible.

Jörg.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your first reply (Oct 27) after the edit is more clear.

Cheers

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks all you guys and a special thanks to lfmorrison.

Cheers

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I use an ascension number that increments each time a record is written to a circular buffer of records in EEPROM. At initialization, I search for the largest ascension number in EEPROM, except for all ones, which is the value it gets set to upon erasure.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

where do you record the ascension number?
If you record it in EEPROM it means you lose half of the space out in EEPROM and your write procedure takes time twice as usual.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

the ascension number is a 16 bit integer that is a data item in a structure that has several other items. What I'm doing may be different than you are trying to do. I'm storing structures filled with status data in EEPROM. Each structure is about 15 bytes. I store one such structure when a certain event happens. I use the ascension scheme to find where to resume writing after a power-up. Can't use head/tail pointers for EEPROM like you can for RAM.