Search |
 |
|
 |
| Author |
Message |
|
|
Posted: Mar 21, 2010 - 08:55 PM |
|

Joined: Sep 05, 2001
Posts: 2496
|
|
Reading the EEPROM need longer than reading the SRAM.
Writing the EEPROM need over 1000 times longer and was also limited in count.
Thus I use always the follwing approach:
I manipulate not the EEPROM directly, I establish an image on the SRAM and do all the access on it.
And to update the SRAM image (e.g. after reset) or write back to the EEPROM, I call a function to do so.
Since the AVR-GCC routines cause a big code bloat, I wrote my own function.
Since reading or writing the EEPROM need many similar steps, I combined both into a single function.
Also to avoid unneeded EEPROM wearout, I write only, if the EEPROM content was different to the new value.
Following the eeprom.c:
Code:
#include <util/atomic.h>
void eeprom_rw( uint16_t eep, uint8_t *sram, uint8_t len, uint8_t write )
{
uint8_t val;
do{
EEAR = eep;
EECR |= 1<<EERE; // read
val = EEDR;
if( write ){ // write or read action
if( *sram != val ){ // if not equal
EEDR = *sram; // load data
ATOMIC_BLOCK(ATOMIC_FORCEON){
EECR |= 1<<EEMPE;
EECR |= 1<<EEPE; // write
}
while( EECR & 1<<EEPE ); // wait until write done
}
}else{
*sram = val;
}
sram++;
eep++;
}while( --len ); // 1..256 byte
}
And the eeprom.h:
Code:
void eeprom_rw( uint16_t eep, uint8_t *sram, uint8_t len, uint8_t write );
#define eeprom_read(sram, eep, len) eeprom_rw( eep, (void*)sram, len, 0 )
#define eeprom_write(eep, sram, len) eeprom_rw( eep, (void*)sram, len, 1 )
Then I combine all parameters, which must be stored, into a struct and update always the whole struct.
Since unneeded EEPROM wearout was suppressed, you can always store the whole struct, even if only one parameter was changed.
Following an example code:
Code:
#include <avr/io.h>
#include "eeprom.h"
#define EE_ADDR 1
struct{
uint32_t p0;
float p1;
int16_t p2;
uint8_t p3;
}eeprom_data;
int main( void )
{
eeprom_read( &eeprom_data, EE_ADDR, sizeof(eeprom_data) );
eeprom_data.p0++;
eeprom_write( EE_ADDR, &eeprom_data, sizeof(eeprom_data) );
for(;;){
}
}
Peter |
|
|
| |
|
|
|
|
|
Posted: Mar 26, 2010 - 10:00 PM |
|

Joined: Mar 15, 2010
Posts: 49
|
|
You're writing one byte at a time, sequentially. According to the avr-libc FAQ (any independent confirmation?), when you write one byte, the hardware is actually erasing and rewriting an entire page, typically 4 bytes. So if you want to maximize EEPROM lifetime, consider having your block-writing routine spread the bytes across pages by rotating the two MSBs of the address down to the LSB positions. The details vary by EEPROM page size and capacity.
This works best if you're using less than 1/4th of the EEPROM (for 4-byte pages) and doesn't help at all if you're updating 3/4ths or more. |
|
|
| |
|
|
|
|
|
Posted: Mar 27, 2010 - 01:46 AM |
|

Joined: Nov 17, 2004
Posts: 13815
Location: Vancouver, BC
|
|
|
Quote:
According to the avr-libc FAQ (any independent confirmation?), when you write one byte, the hardware is actually erasing and rewriting an entire page, typically 4 bytes.
I have never heard this before, and looking through all the Atmel application notes concerning EEPROM that I could find turned up nothing. App note avr103 seems to directly contradict the page assertion. And avr101, which specifically deals with extending the life of EEPROM fails to mention it. |
_________________ Regards,
Steve A.
The Board helps those that help themselves.
|
| |
|
|
|
|
|
Posted: Mar 27, 2010 - 10:41 AM |
|

Joined: Sep 05, 2001
Posts: 2496
|
|
|
bretm wrote:
You're writing one byte at a time, sequentially.
Yes.
Until now, I have no ATtiny/ATmega seen, which support page write from the application.
Thus no page write can be implemented.
Page write was only possible with an external programmer.
Peter |
|
|
| |
|
|
|
|
|
Posted: Mar 27, 2010 - 01:30 PM |
|

Joined: Feb 09, 2010
Posts: 6
|
|
That's a nice solution to bulk reading and writing the EEPROM, which is handy as I was thinking about doing just that.
It's a shame there doesn't appear to be a way of doing a page-wide write though, if that's what is happening behind the scenes.
A good (IMO) addition to the code would be to extend it to structures >255 bytes long so an array of program data could, for instance, be read out of EEPROM at startup. |
|
|
| |
|
|
|
|
|
Posted: Apr 02, 2010 - 09:31 PM |
|

Joined: Mar 15, 2010
Posts: 49
|
|
|
Koshchi wrote:
I have never heard this before, and looking through all the Atmel application notes concerning EEPROM that I could find turned up nothing.
The source of this seems to be avr-libc developer Bob Paddock, based on info recieved "from the factory":
http://lists.gnu.org/archive/html/avr-l ... 00000.html
"The factory has confirmed, via my FAE, that the listed Endurance figures are on a page bases, and not a byte bases."
http://blog.designer-iii.com/avr_eeprom ... dress-zero
Commenting on adding the FAQ entry
Contradicts this:
http://www.atmel.com/dyn/resources/prod ... oc2546.pdf
"When writing to EEPROM one byte is written at a time."
I think I'll just sacrifice a couple of pages of EEPROM to see what happens. Keep writing to one byte on one page and to four bytes on another page until the bytes stop reading back correctly. |
|
|
| |
|
|
|
|
|
Posted: Apr 02, 2010 - 09:45 PM |
|

Joined: Jun 21, 2005
Posts: 881
Location: Chicago area, USA
|
|
|
bretm wrote:
I think I'll just sacrifice a couple of pages of EEPROM to see what happens. Keep writing to one byte on one page and to four bytes on another page until the bytes stop reading back correctly.
I have tried that. Other freaks also tried similar things. See this thread, for example.
Eugene Zharkov |
|
|
| |
|
|
|
|
|
Posted: Apr 02, 2010 - 11:44 PM |
|

Joined: Mar 15, 2010
Posts: 49
|
|
Ok, that seems pretty definitive. And bpaddock posted there, too. Sorry to pollute the thread with bad info!  |
|
|
| |
|
|
|
|
|
|
|
|