Pages: [1]   Go Down
Author Topic: A simple question about using EEPROM in Atmega MCU  (Read 1322 times)
0 Members and 1 Guest are viewing this topic.
Siena Italia
Offline Offline
Full Member
***
Karma: 2
Posts: 149
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The answer to this question is probably quite obvious to everyone except me, yet I don't know how to find an answer.

Writing to EEPROM has a significant, several msec, latency.  In the Arduino examples I've seen, Delay is used, but that stops everything.  My question is: is it really necessary to stop the sketch or just avoid another write until the last EEPROM action is done?  

I don't need instructions in how to avoid Delay; I do know how to do that.  I just need to know whether other non-EEPROM actions can continue during the write time.

Just in case it might affect your answer, here's an outline of what I want to do.  I have just one byte that I need to store in non-volatile memory.  In the worst case, that number will be read as much as 100 times a day, and written to perhaps <=20 times a day.  If I always use the same address, this will give a minimum life-time of 2.28 years, which is not enough for this application.  Hence I intend to use a ring of 20 addresses, giving something like 45 years.  Use of this number is not "real-time", hence the slow nature of EEPROM is of no concern, but other things I will be doing should not be delayed for that time.  If Delay is actually required, I will use an external FRAM chip even for just this one number, but that seems pretty silly.

Ciao,
Lenny
« Last Edit: November 21, 2012, 11:44:26 am by LROBBINS » Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 633
Posts: 34513
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
In the Arduino examples I've seen, Delay is used, but that stops everything.
Not sure what these examples are. I have used the EEPROM read and write with no delays in many projects.
Logged

Siena Italia
Offline Offline
Full Member
***
Karma: 2
Posts: 149
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Grumpy for the quick reply.  Clearly your programs ARE doing other things during the EEPROM write time, so there's no need for the delay.  In my application EEPROM reads and writes will never be closely spaced - the data will be coming at multi-minute intervals from a CAN bus network - so I don't even have to check a timer within the sketch and I'm all set.  Ciao, Lenny
Logged

Offline Offline
Edison Member
*
Karma: 116
Posts: 2205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Check the EEPE bit.
Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 74
Posts: 7247
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Another way is to have a FIFO queue and a timed loop to decide whether to write a byte at a correct interval.

Check if it is time to write another byte
YES - Check if there is anything in the FIFO queue - then write one byte and update the FIFO queue
NO - do other stuff
Logged


Siena Italia
Offline Offline
Full Member
***
Karma: 2
Posts: 149
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the suggestions, but they really won't be necessary in this case.  The byte that I have to save in EEPROM will change no more often than once every few minutes and it will only be written then.  It will only be read once, when the sketch resets.  There is no chance of EEPROM commands crashing into each other.
Ciao,
Lenny
Logged

Offline Offline
Edison Member
*
Karma: 26
Posts: 1339
You do some programming to solve a problem, and some to solve it in a particular language. (CC2)
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I don't understand why you mention delay in relation to eeprom access.
Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 633
Posts: 34513
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

No need for any delay at all. This is a small section of code that I use for storing an RFID token into EPROM, as you can see there are just one write after the other. I have no problems with this:-
Code:
void saveToken(int point){ // saves the token in EEprom memory at point
    EEPROM.write(point, (tokensOnBoard[0] >> 24) & 0xff);
    EEPROM.write(point+1, (tokensOnBoard[0] >> 16) & 0xff);
    EEPROM.write(point+2, (tokensOnBoard[0] >> 8) & 0xff);
    EEPROM.write(point+3, tokensOnBoard[0] & 0xff);
    EEPROM.write(point+4,value[6]);
    EEPROM.write(point+5,value[7]);
    EEPROM.write(point+6,value[8]);
 }
Logged

Siena Italia
Offline Offline
Full Member
***
Karma: 2
Posts: 149
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Grumpy_Mike's example clearly shows that successive EEPROM operations don't crash and that delay is absolutely not needed.  I think that I got confused by looking at a tutorial (I don't recall where) on using an external EEPROM chip in which delay was used.  

A similar question was posted today on the Italian board: http://arduino.cc/forum/index.php/topic,133618.0/topicseen.html and it referenced an earlier discussion (also in Italian): http://arduino.cc/forum/index.php/topic,88054.15.html

After reading those I once again had some doubts.  EEPROM.write clearly blocks following EEPROM.write commands for the 3.4 or so milliseconds needed, but is it globally blocking (like delay)?  Not wanting to immerse myself in Arduino source or ATmega documentation, I decided to just test this.  I modified a sketch posted in today's Italian thread.  This sketch calls EEPROM.write 256 times, and immediately after each EEPROM.write it calls a bit of do-nothing real math.  Commenting out the EEPROM.write call, or the calcSQRT line one finds that:

(1) the 256 successive EEPROM calls alone took (run on a NANO 3) 868 milliseconds; 3.4 milliseconds per write.
(2) 256 successive calls to the calcSQRT function took 125 milliseconds.
(3) 256 EEPROM.write calls with a call to calcSQRT after each of these also took 868 milliseconds.  In other words, EEPROM.write is NOT blocking; 1000 sqrt calculations within each 3.4 millisecond delay didn't add any time to the total.

For my purposes, this is perfect behavior.

Here's the sketch in case you want to try it yourself.
Code:
#include "EEPROM.h"

double A = 10.0;
double B = 5;
unsigned long startTime = millis();
unsigned long endTime = millis();

void setup() {
  Serial.begin(19200);
}

void loop() {    
  testEeprom();
  while (1);
}

void testEeprom() {
  Serial.println("Avvio...");
  startTime = millis();
// comment out EEPROM.write or calcSQRT lines to get seperate times  
  for (int i = 0; i < 256; i++) {
      EEPROM.write(i, (byte)i);
      calcSQRT ();
  }
  endTime = millis();
  Serial.print (startTime, DEC);
  Serial.print (",    ");
  Serial.print (endTime, DEC);
  Serial.print (",    ");
  Serial.println(endTime - startTime, DEC);
}

void calcSQRT () {
   for (long j = 0; j < 1000; j++) {
       B = sqrt (A);
   }
}

// sqrt for loop only - 125 milliseconds
// EEPROM.write only - 868 milliseconds = 3.39 milliseconds per write
// both - 868 milliseconds = EEPROM.write is nonblocking
//    (except for writes themselves)
Ciao,
Lenny
(2)
« Last Edit: November 22, 2012, 09:11:03 am by LROBBINS » Logged

Offline Offline
Edison Member
*
Karma: 26
Posts: 1339
You do some programming to solve a problem, and some to solve it in a particular language. (CC2)
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
but is it globally blocking (like delay)?

Yes and no.

Look at eeprom.h source code (additional comment on the second line is mine)

Code:
/** \ingroup avr_eeprom
    Write a byte \a __value to EEPROM address \a __p.
 */
static __inline__ void eeprom_write_byte (uint8_t *__p, uint8_t __value)
{
    do {} while (!eeprom_is_ready ());         // <<<<<<<<<<< delay()-like blocking busy wait

#if defined(EEPM0) && defined(EEPM1)
    EECR = 0; /* Set programming mode: erase and write. */
#elif defined(EEPM0) || defined(EEPM1)
# warning "Unknown EECR register, eeprom_write_byte() has become outdated."
#endif

#if E2END <= 0xFF
    EEARL = (unsigned)__p;
#else
    EEAR = (unsigned)__p;
#endif
    EEDR = __value;

    __asm__ __volatile__ (
        "/* START EEPROM WRITE CRITICAL SECTION */\n\t"
        "in r0, %[__sreg] \n\t"
        "cli \n\t"
        "sbi %[__eecr], %[__eemwe] \n\t"
        "sbi %[__eecr], %[__eewe] \n\t"
        "out %[__sreg], r0 \n\t"
        "/* END EEPROM WRITE CRITICAL SECTION */"
        :
        : [__eecr]  "i" (_SFR_IO_ADDR(EECR)),
          [__sreg]  "i" (_SFR_IO_ADDR(SREG)),
          [__eemwe] "i" (EEMWE),
          [__eewe]  "i" (EEWE)
        : "r0"
    );
}

Here's how I think it works...

A single EEPROM.write() call blocks only if there's a previous EEPROM.write() operation which is still not complete.
The act of *starting* an eeprom write operation is not blocking.

In your example, if you take out the sqrt() call, you just spend all of the 3.4 ms waiting for the eeprom to become ready after the last write().
If you insert the sqrt() call after the EEPROM.write(), you spend part of those 3.4 ms computing the sqrt(), and the rest of them waiting for the eeprom to become ready. So the wall clock time of the for() cycle is roughly the same in both cases.
Logged

Siena Italia
Offline Offline
Full Member
***
Karma: 2
Posts: 149
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Tuxduino.  That looks like a good explanation for this very nice behavior.  Ciao, Lenny
Logged

Worst state in America
Offline Offline
God Member
*****
Karma: 32
Posts: 808
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Writing to EEPROM has a significant, several msec, latency.  In the Arduino examples I've seen, Delay is used, but that stops everything.  My question is: is it really necessary to stop the sketch or just avoid another write until the last EEPROM action is done?  

Yes, several msec are required to program the EEPROM, but the library code waits for it to finish.

As a simple test, write a sketch and write all 0 bytes to your EEPROM and notice that it takes several seconds to run. If the library were not waiting (actually polling the MCU for "program complete"), your sketch would run in an instant.
Logged

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

Offline Offline
Edison Member
*
Karma: 26
Posts: 1339
You do some programming to solve a problem, and some to solve it in a particular language. (CC2)
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
the library code waits for it to finish.

It only waits for the _previous_ eeprom write to finish. This is an important difference. If the program writes one byte to eeprom at a time, no more than once in a few msec (namely 3.4) then as far as the program itself is concerned, the EEPROM.write() call _is_ immediate.
Logged

Pages: [1]   Go Up
Jump to: