will using eeprom_update_block be more efficient?

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

I have a few lines of code where I do something like this

 

for (char e = 0;e<24;e++)    eeprom_update_byte(33+e,mapper[e] );

 

I was reading up on the eeprom write/read/update commands and I saw the block commands. It looks like they work like memset. So I could just as easily use.

eeprom_write_block(???, mapper, 24);

But I'm not sure how you tell it where to write? Or does it have start at zero? I'm guessing it is written to be more efficient code wise?

 

 

 

Last Edited: Wed. May 23, 2018 - 03:07 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I’d say more for convenience than efficiency. Maintaining the loop is trivial vs the execution time of the flash write.

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

Surely you would use eeprom_update_block.
.
It should work the same as if you call update_byte in a loop.
AVR EEPROM is byte orientated on a Mega and Tiny. So there is no advantage in writing a page at a time. Each changed byte takes 5ms.
External chips like 24Cxxx or 25Cxxx are page oriented. Write one byte means the whole page e.g. 128 bytes in 5ms.
.
David.
.
Edit. I was a little unfair. An ATmega328 with 1kB eeprom compares with a 1kB 24C08 which has a 16-byte page size.
In practice, you write N bytes of eeprom as a one-off. Then only update the occasional byte at runtime. The 24C08 will always be more efficient for writing. The AVR eeprom is quicker to read.

Last Edited: Wed. May 23, 2018 - 05:55 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As others have said, the core of eeprom_update_block is just a loop:

http://svn.savannah.gnu.org/view...

 

71 	1:      ld      r18, -X
72 	        XCALL   eeprom_update_r18
73 	2:      subi    n_lo, lo8(1)
74 	
75 	#if     RAMEND > 0xFF  ||  E2END > 0xFF
76 	        sbci    n_hi, hi8(1)
77 	#endif
78 	
79 	        brsh    1b

However this is more about the structure of your code than the efficiency of any loop. Write your code to operate on the data in the "obvious way" so it's clear to the maintainer what's going on. If you are writing an array then it simply makes sense to update_block rather than you writing each element yourself.

 

BTW this:

eeprom_update_byte(33+e,mapper[e] );

looks highly suspicious. Why are you hard coding the 33 base address in that? Why aren't you letting the linker allocate locations in EEPROM with EEMEM? (you almost certainly let the linker allocate your RAM addresses, so why not those in EEPROM too?)

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

I was not aware of EEMEM. I did lay out my own memory map for my eeprom and I can see letting the compiler mange this would be far better. 

 

Thx all for the info.

 

 

 

 

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

Just to say the way that would work is:

int widthEE EEMEM;
int heightEE EEMEM;
uint8_t rateEE EEMMEM;
uint8_t mapperEE[24] EEMEM;
uint8_t mapper[24]; // copy in RAM

eeprom_update_word(&widthEE, 1024);
eeprom_update_word(&widthEE, 768);
eeprom_update_byte(&rateEE, 47);
eeprom_update_block(mapperEE, mapper, sizeof(mapperEE));

...

eeprom_read_block(mapper, mapperEE, sizeof(mapper));

 

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

Cliff and I always disagree on this.

 

EEPROM is often used for configuration data that you want to survive between builds (or compiler versions)

If your application is of this type,    I would specify the locations myself.    (and use EESAVE fuse)

 

If you only use EEPROM for short term non-volatile "variables",    it does not matter where the Compiler and Linker choose to locate them.

 

If your application uses both styles,   locate the "fixed" configuration stuff at the end of EEPROM.

And keep your fingers crossed that EEMEM is "likely" to start at the beginning of EEPROM.

 

David.

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

Well two things:

 

1) If you are going to perist over versions do it like this:

typedef struct {
    int width;
    int height;
    uint8_t rate;
    uint8_t mapper[24];
} eeLayout_t;

Then in later versions always add "new stuff" to the end of the struct. The existing members are going to have the same layout.

 

2) If you are really going to allocate locations yourself then do NOT hard code offsets like "33" in your code. Instead do it methodically:

#define EE_WIDTH_LOC 0
#define EE_HEIGHT_LOC     EE_WIDTH_LOC  + sizeof(int)
#define EE_RATE_LOC       EE_HEIGHT_LOC + sizeof(int)
#define EE_MAPPER_LOC     EE_RATE_LOC   + sizeof(uint8_t)
#define EE_NEXTTHING_LOC  EE_MAPPER_LOC + 24 * sizeof(uint8_t)
etc.

(and actually the hard coded 24 there is probably wrong - the dimension of mapper[] should be defined just once and then that define used wherever 24 (or whatever) would then appear).

 

Later:

eeprom_update_block(EE_MAPPER_LOC, mapper, sizeof(mapper));

(+ throw in casts as the compiler may require)

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

EEPROM is often used for configuration data that you want to survive between builds (or compiler versions)

If your application is of this type,    I would specify the locations myself.    (and use EESAVE fuse)

This is closer to what I do but more so a save features for my users.  Sort of like a profile and there is an option in my software to see the eeprom layout. Not that I could not rewrite it but it would be a PIA. And all old profiles would need to back backed up. Although I do have to admit I need to use defines, just need to get around to it. 

 

 

 Cliff and I always disagree on this.

Great the two guys most instrumental to my avr learning;)

 

Last Edited: Wed. May 23, 2018 - 01:22 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
in later versions always add "new stuff" to the end of the struct.

I would also include a version identifier for the struct - then newer code reading older data can tell what is actually available for reading ...

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

Well two things:

 

1) If you are going to perist over versions do it like this:

typedef struct {
    int width;
    int height;
    uint8_t rate;
    uint8_t mapper[24];
} eeLayout_t;

Then in later versions always add "new stuff" to the end of the struct. The existing members are going to have the same layout.

 

2) If you are really going to allocate locations yourself then do NOT hard code offsets like "33" in your code. Instead do it methodically:

#define EE_WIDTH_LOC 0
#define EE_HEIGHT_LOC     EE_WIDTH_LOC  + sizeof(int)
#define EE_RATE_LOC       EE_HEIGHT_LOC + sizeof(int)
#define EE_MAPPER_LOC     EE_RATE_LOC   + sizeof(uint8_t)
#define EE_NEXTTHING_LOC  EE_MAPPER_LOC + 24 * sizeof(uint8_t)
etc.

(and actually the hard coded 24 there is probably wrong - the dimension of mapper[] should be defined just once and then that define used wherever 24 (or whatever) would then appear).

 

Later:

eeprom_update_block(EE_MAPPER_LOC, mapper, sizeof(mapper));

(+ throw in casts as the compiler may require)

 

Another option is a "hybrid" approach. I've used variations of this method to great effect:

typedef struct {
    int width;
    int height;
    uint8_t rate;
    uint8_t mapper[24];
} eeLayout_t;

#define eeprom (*(const eeLayout_t *)33)

Then you know that your EEPROM configuration will always start at location 33, and you can let the compiler handle the offsets to each variable within the configuration.

 

The #define lets you access those variables like so:

eeprom_update_block(&config, &eeprom, sizeof eeprom);
uint8_t rate = eeprom_read_byte(&eeprom.rate);

 

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

Can anyone point a reference or explain the width height rate?I'm not fully grasping this. 

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

They are my example variables. I'm sure you've got your own things you want to store like frequency, volume, flow_rate, amp_gain or whatever else you can think of.

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

"

I would also include a version identifier for the struct - then newer code reading older data can tell what is actually available for reading ...

"

Well, I would add ... the length of the structure (then, structures of different lengths would coexist : suppose I want to know the number of lines of a LCD, and decide baudrate is important, too; empty/unusable  parts of the EEPROM could be slowly detected / reused, making wearout slower -if wearout is relevant with modern ICs-)

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

clawson wrote:

They are my example variables. I'm sure you've got your own things you want to store like frequency, volume, flow_rate, amp_gain or whatever else you can think of.

I thought that originally until I saw both of you use the same names. Just wanted to make sure. 

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

dbrion0606 wrote:
Well, I would add ... the length of the structure 

I'd have thought that would generally be known from the version of the structure - but, yes, I guess it could be useful ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...