How to get variables allocated contiguously in Data?

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

Hi, I have a requirement where at start up I wish to populate an array of structs & some other variables from EEPROM and occasionally(monthly), I wish to back-up the structs & variables to EEPROM. To do this code effectivily, I would like to use the eeprom eprom_write_block () & eeprom_read_block() functions.
My problem is that whilst I declare the array of structs & variables contiguously the variables are not in a contiguous block.

How can I align the vars to get 206 contiguous bytes? I have searched the Forum, but have not had a lead on placing vars at a fixed address??

struct params 
{
	uint8_t par0;
	uint8_t par1;
};				

struct params var_params[100]; 
uint8_t int_var0,var1,var2,var3,var4,var5;

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

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

There are 2 solutions, none of them is free (as with lunch).

  • place all the variables you want to back up into a single struct
  • assign all those variables to a separate named section and add that section to the linker script

JW

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

Thanks JW,
All I have to work out now is which is the cheapest lunch!

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

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

I believe I'm right in saying that you can have structures within a structure, and provided the whole shooting match is contained within one single structure, the memory allocated will still be contiguous.

Four legs good, two legs bad, three legs stable.

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

Thanks John,
I have done a small test program & it is works as JW & yourself suggest. I now need to modify the code that I was working on to implement this.
One reason for doing this, is that I an at the shoe-horning end of the project in a ATmega8.
I will leave a snippet of code later how I have implemented it for reference.

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

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

Quote:

I believe I'm right in saying that you can have structures within a structure,

As a lot of the Linux kernel source will demonstrate you are not even limited to structures in structures. You can nest to many levels, throw in some unions and arrays of unions and structures if you like. I think the C standard does impose a limit on such nesting but it's something silly like 32 or 64 or something.

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

John_A_Brown wrote:
I believe I'm right in saying that you can have structures within a structure, and provided the whole shooting match is contained within one single structure, the memory allocated will still be contiguous.
Correct. This is the solution I would suggest.

One little thing to be aware of (but which I think is unlikely to be a problem in normal circumstances on avr-gcc) is that updates of the compiler (or even different compiler options) can change the packing of a struct. Therefore, if you update your code you need to be careful that the structure layout remains compatible with whatever was stored in the EEPROM by the older version of the code.

Christopher Hicks
==

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

cmhicks wrote:
One little thing to be aware of (but which I think is unlikely to be a problem in normal circumstances on avr-gcc) is that updates of the compiler (or even different compiler options) can change the packing of a struct.

In a situation where we shared config structs between gcc on various platforms we learned to systematically use __attribute__((__packed__)).

cmhicks wrote:
Therefore, if you update your code you need to be careful that the structure layout remains compatible with whatever was stored in the EEPROM by the older version of the code.

That might be a problem without the packing issue, if you e.g. add something in the middle of the big struct.

You can salvage this partially by storing some sort of "descriptor" together with the data (say, number your config variables with a properly managed enum and store the values of the enum next to the config variable together with the size), but that inflates everything significantly.

Forward-backward compatibilities in similar situation are always an issue and there's no silver bullet solution I know of.

My second proposal (placing the config variables into a separate section and modifying the linker script accordingly) would effectively prevent to address any of these problems, so in this regard it is a solution inferior to using a single struct.

JW

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

wek wrote:
In a situation where we shared config structs between gcc on various platforms we learned to systematically use __attribute__((__packed__)).
Quite. If I anticipate this usage for a struct, I am also in the habit of only appending new stuff when I change them, and never revising existing parts of the structure.

cmhicks wrote:
Therefore, if you update your code you need to be careful that the structure layout remains compatible with whatever was stored in the EEPROM by the older version of the code.

wek wrote:
You can salvage this partially by storing some sort of "descriptor" together with the data
My usual solution to this is to include a magic number as the first byte of the struct and usually the total size of the struct as the second element. When the layout or definition of the struct changes in any way, I change to a new magic number. This magic number thereby gets stored in the EEPROM as the first byte. When you come to read one of these structs from EEPROM, you look at the first two bytes first and that immediately tells you what the layout of the rest of the struct should be, how much memory you need to allocate to hold it etc.

I can't resist pointing out that this is particularly neatly accomplished in C++ with a constructor which automatically populates the first two fields, every time such a struct is instantiated.

CH
==