Posted by Internetwarrior: Sun. Jan 31, 2010 - 06:16 PM
1
2
3
4
5
Total votes: 0
Just a note concerning the endurance of E/W cycles.
Each E/W only affects the lifetime of the particular cell/byte.
For instance, you can write to cell address 0 ~100k times, then write to cell address 1 ~100k times.
But just as been said before, this is just a matter of probability, where the expected lifespan is at least 100k E/W. Of course this differs and when using multiple cells for storing a variable(int or large variable) the variation in lifetime is also affected to the worse.
For instance, the probability of getting a "bad" cell is at least doubled and this "bad" cell alone decides the lifetime of the variable.
In short, a double (4 cells) is 4 time more likely to have a shorter lifespan than a uint8_t (1 cell).
This is just a simplification, the distribution is probably a Gaussian distribution in reality.
However, when using block writes the E/W cycles are less likely to fail due to lifetime issues compared to single cell writes of same size.
For instance, a struct written as a block containing 4 bytes are less likely to fail than 4 single byte writes.
errors are:
warning: operation on 'Disp' may be undefined
error: expected declaration specifiers or '...' before '(' token
error: conflicting types for 'eeprom_write_byte'
note: an argument type that has a default promotion can't match an empty parameter name list declaration
c:/winavr-20080411/lib/gcc/../../avr/include/avr/eeprom.h:236: error: previous definition of 'eeprom_write_byte' was here
That gives you a location in EEMEM (EEPROM) to hold values and keeps you "Disp" counting variable in RAM, writing it after each update to the EEPROM variable you defined then reading it back.
Thanks Clawson for the quick reply. I changed a few things as you recommended but probably need to go back and review tut on pointers. I'm still getting plenty of warnings and errors. Here's a bigger chunk to show you what my intentions are.
// check for startup mode and run or goto Calib *******************************
while(1) {
if ((PINC & (1<<PC4)) == 0) // read buttons
SelBut = ON;
if ((PINC & (1<<PC5)) == 0)
EntBut = ON;
if ((SelBut == ON) && (EntBut == ON)) {// Goto Calibration
Calib();
SelBut = OFF;
EntBut = OFF;
}
else if ((SelBut == ON) && (EntBut == OFF)) {// Choose Display Menu
uint8_t Disp = 0;
while (SelBut == ON) {
Menu(Disp);
if (EntBut == ON) {
eprom_write_byte (&eeprom_var,Disp);
}
Disp = Disp++;
}
SelBut = OFF;
EntBut = OFF;
}
else {// Do the work and return
Disp = eeprom_read_byte(&eeprom_var);
GetSens();
Menu(Disp);
}
}
return 0;
} // End Program
That'd be the interesting thing to see and because each warning/error includes the source file line number some indication of which lines it's referring to would be good too
Posted by JohanEkdahl: Fri. Mar 12, 2010 - 07:36 AM
1
2
3
4
5
Total votes: 0
Just a side note, but
Disp = Disp++;
is overkill.
Disp++;
will do.
As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.
No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.
"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]
At the moment, we now have access to the eeprom memory, via the routines now provided by eeprom.h. There are three main types of EEPROM access: byte, word and block. Each type has both a write and a read variant, for obvious reasons. The names of the routines exposed by our new headers are:
any information on improving the EEPROM endurance? using data looping data structures?
To improve endurance, its better to work not on the EEPROM directly.
Work only on a copy inside the SRAM and write back only if needed and changed.
E.g. on a user key press or undervoltage detection.
Posted by abcminiuser: Wed. May 12, 2010 - 10:22 PM
1
2
3
4
5
Total votes: 0
Quote:
any information on improving the EEPROM endurance? using data looping data structures?
NEVER loop on data from the EEPROM directly; it's slow for readbacks, and writing to it continuously will quickly destroy it. EEPROM has a write cycle lifetime of about 100,000 writes - whether this applies to each individual cell or an internal page of cells has been a matter of debate. Always read in from EEPROM into a RAM variable, and only write back once you know the value has changed (test it beforehand with a second read) and you are sure you absolutely need to retain the new value.
- Dean :twisted:
Make Atmel Studio better with my free extensions. Open source and feedback welcome!
liuroot, If I understand you correctly, and the above two posts not, then yes, datalooping is good. (Never heard of this term before just now).
If you need to store 10 bytes in a 1024 byte eeprom, you could program the data into the first unused section of 10 bytes. Once you reach the end, you erase everything, and start over. You need one from the 2^80th states of the 10 bytes to signal: "not used yet". Using 0xff ... 0xff would be best. You can write your 10 bytes of data to the eeprom 10 million times this way.
The cost is of course that you'll have to read up to 99% of your eeprom at startup to find the area that holds your data. Or you'll have to do even more complex tricks than this. Maybe programming 0xff -> 0xfe doesn't require an erase, thus you might be able to store a 0-8 counter in a single byte, with just one erase cycle. Tricky, not guaranteed to work by the datasheet etc etc.
Anyway. I'm posting to say thanks Dean... Had me up and running in 15 minutes. :-)
uint16_t address=0x0004 then address++ is 0x0006.
if uint8_t address=0x0004 then address++ is 0x0005
No. ++ applied to an integer ALWAYS increments it by one.
It's when you use ++ with a POINTER that ++ increases it by the size of the type that the pointer points at. But these EEPROM "addresses" are really integers not pointers - that's why there's a typecast converting their interpretation to "pointer to unsigned 16 bit integer" before the value is passed to the e_r_w() function. So the ++ in this case will always increment by one.
If you want the increments to be by the number of bytes of the data type then declare 'address' as a pointer in the first place in which case the typecast will not be required:
All this does kind of raise the question of what on earth are you doing with absolute addressing of EEPROM anyway? You have heard of "EEMEM" and the "linker" have you?
then that reads a character from eeprom and also the fourth word of the data array in eeprom. You and I don't know (and have no reason to need to know) where the linker has chosen to locate 'c' and data[3]. It could be 0x0006 or it could be 0x003C - but who cares - like named variables in RAM the linker, not you, decides where they will be located.
If you build this then as well as a .hex you'll get a project.eep which can be programmed into EEPROM using ISP and will set the locations set aside for data[0]..data[3] to 4, 91, 217 and 38.
After the for() loop has been run the four locations will now contain 0, 1, 2 and 3
Cliff
PS It probably helps if you actually read the article at the start of this thread - all this is explained in better detail than I can manage.
It might be overkill, but with a few nice manouvres, including use of sizeof(), we could probably get rid of the literal value 2 above.
As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.
No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.
"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]
Not quite, the size field in e_w_b() is always BYTES so assuming the 'size' that is transmitted and stored into the 'size' variable isn't really the "size" but rather the "number of data values about to follow" then in the uint16_t case you need to double the value as each entry in the array occupies 2 bytes, not 1.
To avoid confusing yourself and, more importantly, the NEXT reader of your code I'd reconsider whether 'size' is a good name to use here. I think I'd choose something like 'num_elements' and on the e_w_b() line I'd do something like:
BTW, once again, by having the distant source transmit 'address' as the EEPROM location you are pre-empting the linker so it now becomes your responsibility to position everything in EEPROM and make sure there are no overlaps and so on.
sizeof(localblock[0])means the size of the first element of array?
Exactly. If the array is uint32_t[] then that sizeof() is 4, for uint16_t it is 2 and for uint8_t it is 1. So this code automatically adapts to whatever width the array is defined as.
element[0] is just as good as element[n] to test for size but all arrays have element[0] but not all necessarily go up to n which is why I used [0]
but how do i specify the location in EEPROM where I want my variables to be stored?
You don't. Have you ever wanted your variables in RAM at a specific address? If not then why is it important in EEPROM? In both cases the LINKER is presented with everything to be stored there and it picks a sensible layout that does not waste bytes.
You can over-ride positioning with linker scripts or --section-starts but what's the point?
If you want to you can forget the linker and named variables altogether and just do something like:
#define my_int ((void *)0) // int my_int
#define my long ((void *)2) // long my_long
#define my_array ((void *)6) // uchar my_array[10]
#define my char ((void *)16) // char my_char
...
eeprom_write_byte(my_char, 'A');
eeprom_write_word(my_int, 12345);
eeprom_write_dword(my_long, 0x12345678);
strcpy(ram_array, "Hello");
eeprom_write_block(ram_array, my_array, 10);
char c = eeprom_read_byte(my_char);
int n = eeprom_read_word(my_int);
...
etc.
Now you are responsible for the EEPROM layout but you have to be very cautious of errors. Say you wrote:
#define my_int ((void *)0) // int my_int
#define my long ((void *)1) // long my_long
#define my_array ((void *)6) // uchar my_array[10]
#define my char ((void *)16) // char my_char
Looks very similar doesn't it? But a write to 'my_long' will over-write the second byte of the int. The linker is far better at laying things out that you or I.
Another idea if you need a fixed layout is:
typedef struct {
int my_int;
long my_long;
uchar my_array[10];
char my_char;
} ee_vars_type;
ee_vars_type ee_var EEMEM;
eeprom_write_byte(&ee_var.my_char, 'A');
etc.
The only "unknown" position in this is the actual base address of ee_vars in EEMEM but if it's the only EEMEM variable (holding all the variables you want) it's a fair bet it's at 0x0000.
You can now add variables and maintain the layout as long as they are always added to the end of the struct{}
Apologies for the cross post. You guys respond way too fast for me to keep up. I posted the location question in the GCC forum, and deleted it from this thread in time it took Clawson write this small essay of an answer. I really should learn to type faster ... :oops:
Anyhat, I only intend to have one variable declared in EEPROM which will define the layout of the entire EEPROM. Can i be guaranteed that this single variable will always be at address 0x00?
The reason I'm hammering on this is because IAR compiler tend to start my EEPROM variables at address 0x01 (how silly is that?) unless i specifically tell it otherwise, e.g.
TEeprom __eeprom stEeprom @EEPROM_START_ADDRESS;
There is a special place in Hell reserved for engineers whose code works the first time.
Anyhat, I only intend to have one variable declared in EEPROM which will define the layout of the entire EEPROM. Can i be guaranteed that this single variable will always be at address 0x00?
Use the stuct{} method I showed above. By inspection I think you'll find that the linker does base the only EEPROM var at 0x0000 but to force it you could use:
typedef struct {
int my_int;
long my_long;
uchar my_array[10];
char my_char;
} ee_vars_type;
ee_vars_type ee_var __attribute__((section(".myeeprom")));
then in the LDFLAGS use:
--section-start=.myeeprom=0x810000
which will have the same effect as using EEMEM but guarantees that 'ee_var' is located at 0x0000 in the EEPROM.
Quote:
this is because IAR compiler tend to start my EEPROM variables at address 0x01 (how silly is that?)
That actually sounds VERY smart to me. It's well known (if AVRs are operated without BOD) for EEPROM location 0x0000 to be corrupted as the power rails rise/fall. It's often suggested to avoid using location 0 and it sounds like IAR are doing this automatically.
With this in mind you may want to use 0x810001 in the --section-start above.
Cliff
PS I locked the cross post in GCC to avoid accidents. If you like I can split this last part of this thread off as a separate thread with a name similar to the GCC thread and move it there but I think the foregoing IS on topic for this thread in fact.
PPS to answer the question you asked in GCC you can use --section-start on code, RAM and EEPROM. The only differences are that code addresses start at 0x000000, RAM at 0x800000 and EEPROM at 0x810000 but in all you use __attribute__((section(".yourname"))) and then later --section-start=.yourname=0x??????
I got what I was looking for with regard to EEPROM, but am still curious as to whether I can specify a location for variables in PROGMEM. So maybe we can move the rest of the discussion to a more suited thread.
scrap that, you just answered my question, thanks.
PPPS type slower dammit! :P
There is a special place in Hell reserved for engineers whose code works the first time.
I know it's slightly off topic but anything in code flash by it's very nature is not going to be "variable" but if you are talking about constant arrays I don't see why it matters to you where the linker chooses to place them though the --section-start with __attribute__section() will do the trick but this time you are in even more dangerous territory as some of what goes into code flash MUST be positioned by the linker so you don't want to risk any overlaps (putting fixed data at the very end of the flash is usually pretty safe). But, unless this is about replacing pages of data with SPM I don't see any point in trying to preempt the linker.
to header file. I need it use in multiple functions in different C files.
If I define eeprom address like other variable, I get error like this:
menu.o:(.eeprom+0x0): multiple definition of `ILG'
main.o:(.eeprom+0x0): first defined here
The same rules applies as for all shared variables. You put the definition with the initial value in ONE of your .c files then in a shared .h file you put:
extern float EEMEM ILG;
There's a tutorial article about "managing large projects" here that explains this.
Nice tutorial. I just wanted to point out that casting an array or a pointer to a void * is completely unnecessary. Conversion from any data pointer to void * is implicit in both C and C++. Also taking an address of an array is not necessary either, array's name itself is a pointer to it's first element when used in a value context, which is what we want to pass to functions like eeprom_read_block.
Posted by abcminiuser: Wed. Jan 12, 2011 - 06:53 AM
1
2
3
4
5
Total votes: 0
Jason,
Good points. I'm actually aware of both of them (and was back when I wrote this!) but as they say, clarity is the key. While unnecessary, the added syntax makes it clear to the reader that the memory address of those variables are being passed to the function. If they substitute a uint64_t there instead of the character array, this way the code won't break with a cryptic error.
Cheers!
- Dean :twisted:
Make Atmel Studio better with my free extensions. Open source and feedback welcome!
Good points. I'm actually aware of both of them (and was back when I wrote this!) but as they say, clarity is the key. While unnecessary, the added syntax makes it clear to the reader that the memory address of those variables are being passed to the function.
I'll have to disagree with you here, I think code is a lot clearer without casts which I consider unnecessary clutter in this case.
However aesthetics are not the only reason why I prefer the code I typed, it's actually more robust and maintainable code (read further).
abcminiuser wrote:
If they substitute a uint64_t there instead of the character array, this way the code won't break with a cryptic error.
Instead it will break at runtime. If you change the type of the variable from char array to uint64_t cast will make the code silently compile and cause buffer overflow because you would be reading 10 bytes into an 8 byte variable. Without a cast the code will fail to compile, giving you a chance to catch the bug and fix it.
Furthermore, the reason why I prefer string instead of &string is because it's more consistent and maintainable, and less error prone.
Consider what will happen if you pass &string and change the type of the variable from an array to a pointer. The code would again compile without errors and fail at runtime. I believe someone was actually bitten by this earlier in this thread.
By passing string instead code will work with both arrays and pointers.
i'm trying to write and read to/from eeprom but i have a few issues. i'm using a m64, avr studio4. 1st, when i compile i get these warnings but not sure how to correct them
Quote:
../eeprom.c:60: warning: pointer targets in passing argument 1 of '__eewr_word_m64' differ in signedness
../eeprom.c:61: warning: pointer targets in passing argument 1 of '__eewr_word_m64' differ in signedness
../eeprom.c:62: warning: passing argument 2 of '__eewr_block_m64' discards qualifiers from pointer target type
../eeprom.c:72: warning: pointer targets in passing argument 1 of '__eerd_word_m64' differ in signedness
../eeprom.c:73: warning: pointer targets in passing argument 1 of '__eerd_word_m64' differ in signedness
and then the result of my code is (sending it wirelessly to my laptop)
It's warning about param2 which is the "void * __dst" in the prototype and which you cast as "(const void*)". The warning is about the loss of the const qualifier.
http://www.fourwalledcubicle.com/
With a donate button for 'bundles' should you be interested.
Smiley
- Log in or register to post comments
TopJust a note concerning the endurance of E/W cycles.
Each E/W only affects the lifetime of the particular cell/byte.
For instance, you can write to cell address 0 ~100k times, then write to cell address 1 ~100k times.
But just as been said before, this is just a matter of probability, where the expected lifespan is at least 100k E/W. Of course this differs and when using multiple cells for storing a variable(int or large variable) the variation in lifetime is also affected to the worse.
For instance, the probability of getting a "bad" cell is at least doubled and this "bad" cell alone decides the lifetime of the variable.
In short, a double (4 cells) is 4 time more likely to have a shorter lifespan than a uint8_t (1 cell).
This is just a simplification, the distribution is probably a Gaussian distribution in reality.
However, when using block writes the E/W cycles are less likely to fail due to lifetime issues compared to single cell writes of same size.
For instance, a struct written as a block containing 4 bytes are less likely to fail than 4 single byte writes.
- Log in or register to post comments
TopNoob needs a little help here. I read Dean's tut and am still getting compile errors I don't understand.
errors are:
warning: operation on 'Disp' may be undefined
error: expected declaration specifiers or '...' before '(' token
error: conflicting types for 'eeprom_write_byte'
note: an argument type that has a default promotion can't match an empty parameter name list declaration
c:/winavr-20080411/lib/gcc/../../avr/include/avr/eeprom.h:236: error: previous definition of 'eeprom_write_byte' was here
- Log in or register to post comments
TopWhy have you got a function declaration in the middle of that? There's already a declaration for eeprom_read_byte in and it is:
then you are trying to change that with a malformed parameter type (don't cast in a declaration) and one parameter missing
Try simply something like:
That gives you a location in EEMEM (EEPROM) to hold values and keeps you "Disp" counting variable in RAM, writing it after each update to the EEPROM variable you defined then reading it back.
- Log in or register to post comments
TopThanks Clawson for the quick reply. I changed a few things as you recommended but probably need to go back and review tut on pointers. I'm still getting plenty of warnings and errors. Here's a bigger chunk to show you what my intentions are.
- Log in or register to post comments
TopThat'd be the interesting thing to see and because each warning/error includes the source file line number some indication of which lines it's referring to would be good too
- Log in or register to post comments
TopJust a side note, but
is overkill.
will do.
As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.
No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.
"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]
- Log in or register to post comments
TopHI abcminiuser
This is really a good stuff.I want similar directive for flash.
i also want to know the syntax of defining interrupts in avr-gcc.
Thanks & Regards,
P.Raghuveer
Software developer
09553926573
Hyderabad
India
- Log in or register to post comments
TopLook at my PROGMEM ( https://www.avrfreaks.net/index.p... ) and Interrupts ( https://www.avrfreaks.net/index.p... ) tutorials.
- Dean :twisted:
Make Atmel Studio better with my free extensions. Open source and feedback welcome!
- Log in or register to post comments
TopThere's an interrupts tutorial, too. Microcontroller datasheets have an overview of flash memory mgmt and interrupts, as does avr-libc.
- Log in or register to post comments
TopI think you've got the two first arguments to eeprom_write_block in the wrong order.
From eeprom.h:
- Log in or register to post comments
TopI do indeed - I'll fix that up. Thanks!
- Dean :twisted:
Make Atmel Studio better with my free extensions. Open source and feedback welcome!
- Log in or register to post comments
Topany information on improving the EEPROM endurance? using data looping data structures?
- Log in or register to post comments
TopTo improve endurance, its better to work not on the EEPROM directly.
Work only on a copy inside the SRAM and write back only if needed and changed.
E.g. on a user key press or undervoltage detection.
See also:
https://www.avrfreaks.net/index.p...
Peter
- Log in or register to post comments
TopNEVER loop on data from the EEPROM directly; it's slow for readbacks, and writing to it continuously will quickly destroy it. EEPROM has a write cycle lifetime of about 100,000 writes - whether this applies to each individual cell or an internal page of cells has been a matter of debate. Always read in from EEPROM into a RAM variable, and only write back once you know the value has changed (test it beforehand with a second read) and you are sure you absolutely need to retain the new value.
- Dean :twisted:
Make Atmel Studio better with my free extensions. Open source and feedback welcome!
- Log in or register to post comments
Topliuroot, If I understand you correctly, and the above two posts not, then yes, datalooping is good. (Never heard of this term before just now).
If you need to store 10 bytes in a 1024 byte eeprom, you could program the data into the first unused section of 10 bytes. Once you reach the end, you erase everything, and start over. You need one from the 2^80th states of the 10 bytes to signal: "not used yet". Using 0xff ... 0xff would be best. You can write your 10 bytes of data to the eeprom 10 million times this way.
The cost is of course that you'll have to read up to 99% of your eeprom at startup to find the area that holds your data. Or you'll have to do even more complex tricks than this. Maybe programming 0xff -> 0xfe doesn't require an erase, thus you might be able to store a 0-8 counter in a single byte, with just one erase cycle. Tricky, not guaranteed to work by the datasheet etc etc.
Anyway. I'm posting to say thanks Dean... Had me up and running in 15 minutes. :-)
- Log in or register to post comments
TopThank you so much . I like your tutorial!!!!!!
- Log in or register to post comments
TopDoes this read the 16 bit data from EEPROM?
- Log in or register to post comments
TopYes "word"=16 bits.
- Log in or register to post comments
Topafter address++ what is the value of pointer? is it 0006?
- Log in or register to post comments
TopThat depends on how you defined address.
Regards,
Steve A.
The Board helps those that help themselves.
- Log in or register to post comments
Topword1=data of address 0x0004
and what should be word2?
word2=data of address 0x0006?
- Log in or register to post comments
TopI got it.....
if
uint16_t address=0x0004 then address++ is 0x0006.
if uint8_t address=0x0004 then address++ is 0x0005
Thank you
- Log in or register to post comments
TopNo. ++ applied to an integer ALWAYS increments it by one.
It's when you use ++ with a POINTER that ++ increases it by the size of the type that the pointer points at. But these EEPROM "addresses" are really integers not pointers - that's why there's a typecast converting their interpretation to "pointer to unsigned 16 bit integer" before the value is passed to the e_r_w() function. So the ++ in this case will always increment by one.
If you want the increments to be by the number of bytes of the data type then declare 'address' as a pointer in the first place in which case the typecast will not be required:
Now 'address' points at location 0x0008.
All this does kind of raise the question of what on earth are you doing with absolute addressing of EEPROM anyway? You have heard of "EEMEM" and the "linker" have you?
If I write:
then that reads a character from eeprom and also the fourth word of the data array in eeprom. You and I don't know (and have no reason to need to know) where the linker has chosen to locate 'c' and data[3]. It could be 0x0006 or it could be 0x003C - but who cares - like named variables in RAM the linker, not you, decides where they will be located.
- Log in or register to post comments
TopCan I use the EEMEM same for writing the variables in EEPROM without giving the address where to write??
- Log in or register to post comments
TopYes. You can start with default values if you want too:
If you build this then as well as a .hex you'll get a project.eep which can be programmed into EEPROM using ISP and will set the locations set aside for data[0]..data[3] to 4, 91, 217 and 38.
After the for() loop has been run the four locations will now contain 0, 1, 2 and 3
Cliff
PS It probably helps if you actually read the article at the start of this thread - all this is explained in better detail than I can manage.
- Log in or register to post comments
TopIS there any way I write a block of word instead of block of bytes.
following is the code to write a block of bytes.
- Log in or register to post comments
TopA block is a block is a block. Only difference is that your words each are double the size of a byte, so I'd think that you'd
It might be overkill, but with a few nice manouvres, including use of sizeof(), we could probably get rid of the literal value 2 above.
As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.
No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.
"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]
- Log in or register to post comments
TopYou just answered your own question. Which bit of eeprom_write_block() don't you understand? Maybe an example helps:
After that has run the EEPROM will contain those data values I set in the struct{}
(-23456 = 0xA460, 'A' = 0x41, rest is obvious)
Attachment(s):
- Log in or register to post comments
TopAbove code will write 8 bit datas
And above code will read 16 bit datas
Am I correct?
- Log in or register to post comments
TopI mean write 16 bit data
- Log in or register to post comments
TopNot quite, the size field in e_w_b() is always BYTES so assuming the 'size' that is transmitted and stored into the 'size' variable isn't really the "size" but rather the "number of data values about to follow" then in the uint16_t case you need to double the value as each entry in the array occupies 2 bytes, not 1.
To avoid confusing yourself and, more importantly, the NEXT reader of your code I'd reconsider whether 'size' is a good name to use here. I think I'd choose something like 'num_elements' and on the e_w_b() line I'd do something like:
BTW, once again, by having the distant source transmit 'address' as the EEPROM location you are pre-empting the linker so it now becomes your responsibility to position everything in EEPROM and make sure there are no overlaps and so on.
- Log in or register to post comments
TopI did not understand why we are using localblock[0].
sizeof(localblock[0])means the size of the first element of array?
- Log in or register to post comments
TopExactly. If the array is uint32_t[] then that sizeof() is 4, for uint16_t it is 2 and for uint8_t it is 1. So this code automatically adapts to whatever width the array is defined as.
element[0] is just as good as element[n] to test for size but all arrays have element[0] but not all necessarily go up to n which is why I used [0]
- Log in or register to post comments
TopGreat tutorial. Thanks.
In this example
shouldn't it be either
or
?
There is a special place in Hell reserved for engineers whose code works the first time.
- Log in or register to post comments
TopYou don't. Have you ever wanted your variables in RAM at a specific address? If not then why is it important in EEPROM? In both cases the LINKER is presented with everything to be stored there and it picks a sensible layout that does not waste bytes.
You can over-ride positioning with linker scripts or --section-starts but what's the point?
If you want to you can forget the linker and named variables altogether and just do something like:
Now you are responsible for the EEPROM layout but you have to be very cautious of errors. Say you wrote:
Looks very similar doesn't it? But a write to 'my_long' will over-write the second byte of the int. The linker is far better at laying things out that you or I.
Another idea if you need a fixed layout is:
The only "unknown" position in this is the actual base address of ee_vars in EEMEM but if it's the only EEMEM variable (holding all the variables you want) it's a fair bet it's at 0x0000.
You can now add variables and maintain the layout as long as they are always added to the end of the struct{}
Cliff
- Log in or register to post comments
TopApologies for the cross post. You guys respond way too fast for me to keep up. I posted the location question in the GCC forum, and deleted it from this thread in time it took Clawson write this small essay of an answer. I really should learn to type faster ... :oops:
Anyhat, I only intend to have one variable declared in EEPROM which will define the layout of the entire EEPROM. Can i be guaranteed that this single variable will always be at address 0x00?
The reason I'm hammering on this is because IAR compiler tend to start my EEPROM variables at address 0x01 (how silly is that?) unless i specifically tell it otherwise, e.g.
There is a special place in Hell reserved for engineers whose code works the first time.
- Log in or register to post comments
TopUse the stuct{} method I showed above. By inspection I think you'll find that the linker does base the only EEPROM var at 0x0000 but to force it you could use:
then in the LDFLAGS use:
which will have the same effect as using EEMEM but guarantees that 'ee_var' is located at 0x0000 in the EEPROM.
That actually sounds VERY smart to me. It's well known (if AVRs are operated without BOD) for EEPROM location 0x0000 to be corrupted as the power rails rise/fall. It's often suggested to avoid using location 0 and it sounds like IAR are doing this automatically.
With this in mind you may want to use 0x810001 in the --section-start above.
Cliff
PS I locked the cross post in GCC to avoid accidents. If you like I can split this last part of this thread off as a separate thread with a name similar to the GCC thread and move it there but I think the foregoing IS on topic for this thread in fact.
PPS to answer the question you asked in GCC you can use --section-start on code, RAM and EEPROM. The only differences are that code addresses start at 0x000000, RAM at 0x800000 and EEPROM at 0x810000 but in all you use __attribute__((section(".yourname"))) and then later --section-start=.yourname=0x??????
- Log in or register to post comments
TopThanks. I'll follow your example code above.
I got what I was looking for with regard to EEPROM, but am still curious as to whether I can specify a location for variables in PROGMEM. So maybe we can move the rest of the discussion to a more suited thread.
scrap that, you just answered my question, thanks.
PPPS type slower dammit! :P
There is a special place in Hell reserved for engineers whose code works the first time.
- Log in or register to post comments
TopI know it's slightly off topic but anything in code flash by it's very nature is not going to be "variable" but if you are talking about constant arrays I don't see why it matters to you where the linker chooses to place them though the --section-start with __attribute__section() will do the trick but this time you are in even more dangerous territory as some of what goes into code flash MUST be positioned by the linker so you don't want to risk any overlaps (putting fixed data at the very end of the flash is usually pretty safe). But, unless this is about replacing pages of data with SPM I don't see any point in trying to preempt the linker.
- Log in or register to post comments
TopThis isn't important or anything, but doesn't EEPROM stand for "Electronically Erasable Programmable Read-Only Memory"?
The tutorial omits the "Programmable" part when explaining it. Not a big deal, of course.
Thanks again for the wonderful information!
- Log in or register to post comments
TopHello, how to include eeprom address like this
to header file. I need it use in multiple functions in different C files.
If I define eeprom address like other variable, I get error like this:
menu.o:(.eeprom+0x0): multiple definition of `ILG'
main.o:(.eeprom+0x0): first defined here
- Log in or register to post comments
TopThe same rules applies as for all shared variables. You put the definition with the initial value in ONE of your .c files then in a shared .h file you put:
There's a tutorial article about "managing large projects" here that explains this.
- Log in or register to post comments
Topthanks my mistake, I tried define it with assigned value.
- Log in or register to post comments
TopThank you...............
- Log in or register to post comments
TopHello,
Nice tutorial. I just wanted to point out that casting an array or a pointer to a void * is completely unnecessary. Conversion from any data pointer to void * is implicit in both C and C++. Also taking an address of an array is not necessary either, array's name itself is a pointer to it's first element when used in a value context, which is what we want to pass to functions like eeprom_read_block.
So this:
Can be rewritten like this:
eeprom_read_block(SRAMstring, NonVolatileString, 10)
- Log in or register to post comments
TopJason,
Good points. I'm actually aware of both of them (and was back when I wrote this!) but as they say, clarity is the key. While unnecessary, the added syntax makes it clear to the reader that the memory address of those variables are being passed to the function. If they substitute a uint64_t there instead of the character array, this way the code won't break with a cryptic error.
Cheers!
- Dean :twisted:
Make Atmel Studio better with my free extensions. Open source and feedback welcome!
- Log in or register to post comments
TopHi Dean,
I'll have to disagree with you here, I think code is a lot clearer without casts which I consider unnecessary clutter in this case.
However aesthetics are not the only reason why I prefer the code I typed, it's actually more robust and maintainable code (read further).
Instead it will break at runtime. If you change the type of the variable from char array to uint64_t cast will make the code silently compile and cause buffer overflow because you would be reading 10 bytes into an 8 byte variable. Without a cast the code will fail to compile, giving you a chance to catch the bug and fix it.
Furthermore, the reason why I prefer string instead of &string is because it's more consistent and maintainable, and less error prone.
Consider what will happen if you pass &string and change the type of the variable from an array to a pointer. The code would again compile without errors and fail at runtime. I believe someone was actually bitten by this earlier in this thread.
By passing string instead code will work with both arrays and pointers.
- Log in or register to post comments
Tophello,
i'm trying to write and read to/from eeprom but i have a few issues. i'm using a m64, avr studio4. 1st, when i compile i get these warnings but not sure how to correct them
and then the result of my code is (sending it wirelessly to my laptop)
when it should be
the code is shown below. THANK YOU!!
EDIT: code corrected and warnings eliminated
- Log in or register to post comments
TopThis thread is not for diagnosing EEPROM usage problems. It is for discussing the article in the first post.
Moderator.
PS As for your warnings. Take for example:
where:
Now look at the prototype in eeprom.h:
uint16_t is "unsigned int". When you use just "int" then by default it is interpreted as "signed int".
THAT is why you get a signedness warning. Either cast or use the right type.
Also consider:
and the prototype in eeprom.h
It's warning about param2 which is the "void * __dst" in the prototype and which you cast as "(const void*)". The warning is about the loss of the const qualifier.
- Log in or register to post comments
TopPages