Search |
 |
|
 |
| Author |
Message |
|
|
Posted: Feb 09, 2011 - 11:34 AM |
|


Joined: Jul 18, 2005
Posts: 62354
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
This 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:
Code:
/*60*/eeprom_write_word(&eeEtot, Etot);
where:
Code:
int EEMEM eeEtot;
int Etot, Es_month;
Now look at the prototype in eeprom.h:
Code:
void eeprom_write_word (uint16_t *__p, uint16_t __value);
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:
Code:
/*62*/eeprom_write_block((void*)&eeEw_month,(const void*)&Ew_month, sizeof(double));
and the prototype in eeprom.h
Code:
void eeprom_write_block (const void *__src, void *__dst, size_t __n);
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. |
_________________
|
| |
|
|
|
|
|
Posted: Feb 09, 2011 - 06:36 PM |
|

Joined: Feb 17, 2010
Posts: 157
|
|
thanks clawson, i saw several other comments to this tutorial with eeprom issues so i thought it'd be ok.
the tutorial quotes:
Quote:
void eeprom_write_block (void *pointer_eeprom, const void *pointer_ram, size_t n)
while eeprom.h void function is:
Quote:
void eeprom_write_block (const void *__src, void *__dst, size_t __n);
warnings corrected, and the output improved:
Code:
<NUL>2<NUL><NUL><NUL>3456789<NUL>
but the first byte is corrupted. it should be
Code:
12<NUL><NUL><NUL>3456789<NUL>
any ideas? thank you! |
|
|
| |
|
|
|
|
|
Posted: Feb 10, 2011 - 04:28 PM |
|

Joined: Feb 17, 2010
Posts: 157
|
|
ahhh ok, after a few trials, basically when Es_month is 4 digits, the response has the 1st byte of Etot corrupted.
For ex:
Code:
Etot = 12657;
Es_month = 345;
Ew_month = 789;
Code:
12657345<NUL>789<NUL>
ok. If
Code:
Etot = 12657;
Es_month = 3456;
Ew_month = 789;
Code:
<NUL>26573456789<NUL>
WRONG. 1's byte corrupted. Should be 12657.
Code:
Etot = 12657;
Es_month = 345;
Ew_month = 7896;
Code:
12657345<NUL>7896
ok.
Code:
Etot = 1265;
Es_month = 3456;
Ew_month = 789;
Code:
<NUL>265<NUL>3456789<NUL>
wrong.
Code:
Etot = 1265;
Es_month = 34;
Ew_month = 789;
Code:
1265<NUL>34<NUL><NUL>789<NUL>
ok...
Dean mentioned:
Quote:
Remember that in C a zero byte is treated as a null-terminator -- if you have junk data in the first 10 bytes of the string, chances are one might be a terminator which will stop any display of the buffer contents before the contents of the EEPROM read string is reached.
and again a few comments later
Quote:
You need to read/write one more byte to EEPROM than there are characters in the string -- there's a hidden 0x00 byte at the end of each string which terminates it. Without the terminator, your string routines will become confused.
Maybe this could be the problem? I can't find why the 1st byte is getting corrupted when Es_month is a 4 digit number :/ |
|
|
| |
|
|
|
|
|
Posted: Feb 10, 2011 - 04:48 PM |
|


Joined: Jul 18, 2005
Posts: 62354
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Code:
char Etot_str[5];
char Es_m_str[4];
char Ew_m_str[4];
These are surely far too small? A string defined as [5] can hold 4 digits and the terminating 0x00. A string defined as [4] can hold just 3 digits and the 0x00. If you try to put a four digit string into [4] it will write over the start of the next string in mmeory.
Personally I always work out the worst case> For example largest itoa() is going to be 5 digits, possibly with sign so 6 characters, then you need room for the 0x00. So 7 characters. To be safe I'd blow the memory budget and just make it [8] or if I was feeling particularly flaithiúl I'd actually make it [10] to be aboslutely positive. Start cutting the [10]s back to [8]s when you thing RAM is getting low. (and test the worst case strings) |
_________________
|
| |
|
|
|
|
|
Posted: Feb 10, 2011 - 05:02 PM |
|

Joined: Feb 17, 2010
Posts: 157
|
|
|
Quote:
A string defined as [5] can hold 4 digits and the terminating 0x00. A string defined as [4] can hold just 3 digits and the 0x00.
didn't know that! Thank you very much! : )
- Eric |
|
|
| |
|
|
|
|
|
Posted: Feb 20, 2011 - 07:07 PM |
|


Joined: Jun 25, 2010
Posts: 5
Location: Estonia
|
|
Do somebody know if i could somehow monitor (make readable) my internal EEPROM to the device outside. For example: I have TI PGA309 signal conditioner which requires external EEPROM to read config data. It uses I2C aka TWI for reading. Can i somehow make my Atmega 324 memory readable by PGA309 via TWI?
Thanks! |
_________________ Estonia, Otepää is the place where you can find me...
|
| |
|
|
|
|
|
Posted: Feb 20, 2011 - 07:16 PM |
|


Joined: Jul 18, 2005
Posts: 62354
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| You can simulate whatever kind of interface the PGA309 expects to use with a microcontroller such as an AVR so the answer is yes. |
_________________
|
| |
|
|
|
|
|
Posted: Feb 20, 2011 - 09:53 PM |
|


Joined: Jun 25, 2010
Posts: 5
Location: Estonia
|
|
So practically it means mechanically write all the functions: 1)set avr in slave read mode
2)make functions which emulate the prodecure when PGA asks memory location this n that answer with a memory location from AVR eeprom?
Okay then.
It would be simpler to program PGA through UART then...
I just thought maybe there is some shortcut how to do this. |
_________________ Estonia, Otepää is the place where you can find me...
|
| |
|
|
|
|
|
Posted: Mar 03, 2011 - 01:27 PM |
|


Joined: Oct 06, 2010
Posts: 475
Location: Chicago
|
|
Question regarding the EESAVE fuse:
I am somewhat new to programming micro controllers, so please excuse me if this is a dumb question...
In my program, I declare several "variables" with the EEMEM attribute. At the beginning of the program, I read the values in (garbage if the EEP file was not downloaded). The user of the program has the capability of changing the values stored in the EEPROM. Scenario: a user sets all of the EEPROM variables to valid values. The board is then turned off. When it is turned on again, the program re-initializes its SRAM equivalent variables from EEPROM. I understand all this (isn't that the point of EEPROM?). However, if I set the ESAVE fuse, make some changes to the program and recompile it, and re-download it to the chip, what does it matter if the EEPROM is overwritten or not? Won't the compiler have given different addresses to my EEMEM variables? How will the program know where the previously saved EEMEM variables are stored? |
|
|
| |
|
|
|
|
|
Posted: Mar 03, 2011 - 03:37 PM |
|


Joined: Jan 23, 2004
Posts: 9832
Location: Trondheim, Norway
|
|
That's true, however if you place *all* your EEPROM variables into a single struct, as long as the compiler's packing and ordering rules are not changes between versions those variables should always map to the same place.
It's also useful for assembly programmers or manual EEPROM location management, sine in that case you always certain where everything is stored.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Mar 03, 2011 - 03:51 PM |
|


Joined: Oct 06, 2010
Posts: 475
Location: Chicago
|
|
That makes sense. If I create a struct with a bunch of settings, I think I would always need to read/write the EEMEM variable to/from EEPROM in its entirety (i.e., couldn't do just one of the subvariables). Is this true?
From Clawson's post on page 7:
clawson wrote:
Code:
#include <string.h>
#include <avr/eeprom.h>
typedef struct {
int16_t n;
char c;
uint8_t array[10];
uint32_t l;
} data_type;
data_type copy_in_EEPROM EEMEM;
data_type copy_in_RAM;
int main(void) {
copy_in_RAM.n = -23456;
copy_in_RAM.c = 'A';
copy_in_RAM.l = 0xDEADBEEF;
memset(copy_in_RAM.array, 0x5A, sizeof(copy_in_RAM.array));
eeprom_write_block(©_in_RAM, ©_in_EEPROM, sizeof(copy_in_RAM));
while(1);
}
After that has run the EEPROM will contain those data values I set in the struct{}
If I wanted to read the data from memory into a RAM structure, would the code be:
Code:
myStruct EEMEM eepromCopy;
myStruct RAMcopy;
eeprom_read_block((void*)&RAMcopy, (const void*)eepromCopy, sizeof(RAMcopy));
P.S. Since I boorishly forgot to say it in my first post -- thanks for taking the time to put together such a good tutorial. |
|
|
| |
|
|
|
|
|
Posted: Mar 03, 2011 - 04:38 PM |
|


Joined: Jul 18, 2005
Posts: 62354
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
would the code be:
Yes. |
_________________
|
| |
|
|
|
|
|
Posted: Mar 18, 2011 - 03:21 PM |
|

Joined: Mar 02, 2011
Posts: 11
Location: Salt Lake City
|
|
|
rosvall wrote:
abcminiuser wrote:
(...)
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:
Quote:
(...)
� void eeprom_read_block (void *pointer_ram, const void *pointer_eeprom, size_t n)
� void eeprom_write_block (const void *pointer_ram, void *pointer_eeprom, size_t n)
(...)
I think you've got the two first arguments to eeprom_write_block in the wrong order.
From eeprom.h:
Quote:
static __inline__ void
eeprom_write_block (void *__dst, const void *__src, size_t __n)
Well... I just tried writing some code using eeprom_write_block and my compiler gave me a warning so I checked and it looks like the order of my eeprom_write_block is back to the original "wrong" order. So which one is correct?
Looks like someone is changing things on us hehe. |
|
|
| |
|
|
|
|
|
Posted: May 15, 2011 - 12:34 PM |
|

Joined: Nov 25, 2007
Posts: 3
|
|
I currently use the EEPROM to store some program configuration data (i.e. thresholds, durations, ...).
Now I want to adapt the program behaviour by patching some single EEPROM bytes. As far as I know AVR-Studio can only writw down complete EEPROM-files. Which tool can be used to do that? Wouldt be great if someone knows a simple command line tool. |
|
|
| |
|
|
|
|
|
Posted: May 15, 2011 - 02:09 PM |
|


Joined: Jul 18, 2005
Posts: 62354
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
As far as I know AVR-Studio can only writw down complete EEPROM-files. Which tool can be used to do that? Wouldt be great if someone knows a simple command line tool.
Read the entire eeprom to a .hex - change one byte then write the whole thing back. |
_________________
|
| |
|
|
|
|
|
Posted: May 21, 2011 - 09:38 PM |
|

Joined: May 10, 2011
Posts: 2
|
|
Thanks so much for all your helpful tutorials mate.
They are much appreciated especially when you've left your Final Year project this late lol  |
|
|
| |
|
|
|
|
|
Posted: Aug 15, 2011 - 03:19 PM |
|

Joined: Aug 15, 2011
Posts: 1
|
|
sir i am trying to do a line follower and i am not able to program it so pls help me with it
abcminiuser wrote:
Davef,
Damnit, yet another typo. That should indeed be read_ word - I'll go fix that now. Amazing that anyone still bothers to read my tutorials with all these silly mistakes!
Quote:
In <avr/eeprom.h>, eeprom_read_byte and eeprom_write_byte use a u08 pointer for the address. Doesn't this mean you can only access 256 bytes in the EEPROM? What about the remaining 1024-256 = 968 EEPROM bytes in a ATmega32?
That tripped me up too at the start. In AVR-GCC, all pointers are an int in size, two bytes. The pointer typecast only specifies what type of data the pointer is pointing to, not the pointer's size. A (uint8_t*), (uint16_t*) and (uint32_t*) are all identical in size, they just point to increasingly larger datatypes.
For example, (uint8_t*)0x1234 is a pointer two bytes in size, pointing to a byte at the location 0x1234.
This is a problem when dealing with pointers to the AVR's flash memory, since in some AVRs this overflows an int. Because of this, pointers to flash addresses are still two bytes in size but the pointer is word rather than byte aligned, so an increase of one in the pointer's address corresponds to a jump of two bytes.
If I can think of enough material for this I might make it into a short tutorial since it seems to be such a prevalent issue.
- Dean
|
|
|
| |
|
|
|
|
|
Posted: Aug 15, 2011 - 03:25 PM |
|


Joined: Jul 18, 2005
Posts: 62354
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
trying to do a line follower
Then kindly explain what on earth the post you quoted or this entire thread has to do with your question?!? This thread is about using EEPROM with the avr-gcc compiler. |
_________________
|
| |
|
|
|
|
|
Posted: Aug 28, 2011 - 11:56 AM |
|

Joined: Aug 28, 2011
Posts: 2
|
|
I've read this thread and now know how to use EEMEM to have the compiler generate a .eep file to 'initialise' basic eeprom variable, and arrays.
I am using an 'overall structure' to hold all my eeprom variables.
I need to initialise an array of structures within the outer structure
Code:
typedef struct INNER_STRUCT1 {
uint8_t var1;
uint8_t var2;
int8_t var3;
} innerStruct1_t;
typedef struct INNER_STRUCT2 {
uint8_t var1;
uint8_t var2;
int8_t var3;
} innerStruct2_t;
typedef struct OUTER_STRUCT {
uint8_t outerVar1;
uint8_t outerVar1;
uint8_t outerVar1;
innerStruct1 innerVars1[5];
innerStruct2 innerVars2[5];
} outerVars_t;
So when I use
Code:
outerVars_t EEMEM EE_Vars = {22,100,12,?help;
is it possible initialise the inner array of structures?
or is there a better way of doing this?
Thanks |
|
|
| |
|
|
|
|
|
Posted: Aug 28, 2011 - 12:38 PM |
|


Joined: Jul 18, 2005
Posts: 62354
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Code:
outerVars_t EEMEM EE_Vars = {
22,
100,
12,
{
{ is1_var1_val, is1_var2_val, is1_var3_val }, // iV1[0]
{ is1_var1_val, is1_var2_val, is1_var3_val }, // iV1[1]
{ is1_var1_val, is1_var2_val, is1_var3_val }, // iV1[2]
{ is1_var1_val, is1_var2_val, is1_var3_val }, // iV1[3]
{ is1_var1_val, is1_var2_val, is1_var3_val } // iV1[4]
},
{
{ is2_var1_val, is2_var2_val, is2_var3_val }, // iV2[0]
{ is2_var1_val, is2_var2_val, is2_var3_val }, // iV2[1]
{ is2_var1_val, is2_var2_val, is2_var3_val }, // iV2[2]
{ is2_var1_val, is2_var2_val, is2_var3_val }, // iV2[3]
{ is2_var1_val, is2_var2_val, is2_var3_val } // iV2[4]
}
};
If your C compiler supports C99 you can also use named initializers:
Code:
outerVars_t EEMEM EE_Vars = {
.outerVar1 = 22,
.innerVars1[3].var2 = 0xF3,
.innerVars2[1].var3 = -17
};
Cliff |
_________________
|
| |
|
|
|
|
|
|
|
|