| Author |
Message |
|
|
Posted: May 09, 2006 - 10:13 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
For an updated version of this tutorial in PDF format, please see this page of my website.
My second tutorial. This tutorial will centre around GCC's handling of data stored into EEPROM memory.
What is the EEPROM memory and why would I use it?
Most of the AVRs in Atmel's product line contain at least some internal EEPROM memory. EEPROM, short for Electronically Erasable Read-Only memory, is a form of non-volatile memory with a reasonably long lifespan. Because it is non-volatile, it will retain its information during periods of no AVR power and thus is a great place for storing sparingly changing data such as device parameters.
The AVR internal EEPROM memory has a limited lifespan of 100,000 writes - reads are unlimited.
How is is accessed?
The AVR's internal EEPROM is accessed via special registers inside the AVR, which control the address to be written to (EEPROM uses byte addressing), the data to be written (or the data which has been read) as well as the flags to instruct the EEPROM controller to perform a write or a read.
The C language does not have any standards mandating how memory other than a single flat model (SRAM in AVRs) is accessed or addressed. Because of this, just like storing data into program memory via your program, every compiler has a unique implementation based on what the author believed was the most logical system.
This tutorial will focus on the GCC compiler.
Using the AVRLibC EEPROM library routines:
The AVRLibC, included with WinAVR, contains prebuilt library routines for EEPROM access and manipulation. Before we can make use of those routines, we need to include the eeprom library header:
Code:
#include <avr/eeprom.h>
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:
uint8_t eeprom_read_byte (const uint8_t *addr)
void eeprom_write_byte (uint8_t *addr, uint8_t value)
uint16_t eeprom_read_word (const uint16_t *addr)
void eeprom_write_word (uint16_t *addr, uint16_t value)
void eeprom_read_block (void *pointer_ram, const void *pointer_eeprom, size_t n)
void eeprom_write_block (void *pointer_eeprom, const void *pointer_ram, size_t n)
In AVR-GCC, a word is two bytes while a block is an arbitrary number of bytes which you supply (think string buffers).
To start, lets try a simple example and try to read a single byte of EEPROM memory, let's say at location 46. Our code might look like:
Code:
#include <avr/eeprom.h>
void main(void)
{
uint8_t ByteOfData;
ByteOfData = eeprom_read_byte((uint8_t*)46);
}
This will read out location 46 of the EEPROM and put it into our new variable named "ByteOfData". How does it work? Firstly, we declare our byte variable, which I'm sure you're familiar with:
Code:
uint8_t ByteOfData;
Now, we then call our eeprom_read_byte routine, which expects a pointer to a byte in the EEPROM space. We're working with a constant and known address value of 46, so we add in the typecast to transform that number 46 into a pointer for the eeprom_read_byte function.
EEPROM words can be written and read in much the same way, except they require a pointer to an int:
Code:
#include <avr/eeprom.h>
void main(void)
{
uint16_t WordOfData;
WordOfData = eeprom_read_word((uint16_t*)46);
}
But what about larger datatypes, or strings? This is where the block commands come in.
EEPROM Block Access
The block commands of the AVRLibC eeprom.h header differ from the word and byte functions shown above. Unlike it's smaller cousins, the block commands are both routines which return nothing, and thus operate on a variable you supply internally. Let's look at the function declaration for the block reading command.
Code:
void eeprom_read_block (void *pointer_ram, const void *pointer_eeprom, size_t n)
Wow! It looks hard, but in practise it's not. It may be using a concept you're not familiar with though, void-type pointers.
Normal pointers specify the size of the data type in their declaration (or typecast), for example "uint8_t*" is a pointer to an unsigned byte and "int16_t*" is a pointer to a signed int. But "void" is not a data type, so what does it mean?
Void pointers are useful when the exact type of the data being pointed to is not known by a function, or is unimportant. A Void is mearly a pointer to a memory location, with the data stored at that location being important but the type of data stored at that location not being important. Why is a void pointer used?
Using a void pointer means that the block read/write functions can deal with any datatype you like, since all the function does is copy data from one address space to another. The function doesn't care what data it copies, only that it copies the correct number of bytes.
Ok, that's enough of a derail - back to our function. The block commands expect a void pointer to a RAM location, a void pointer to an EEPROM location and a value specifying the number of bytes to be written or read from the buffers. In our first example let's try to read out 10 bytes of memory starting from EEPROM address 12 into a string.
Code:
#include <avr/eeprom.h>
void main(void)
{
uint8_t StringOfData[10];
eeprom_read_block((void*)&StringOfData, (const void*)12, 10);
}
Again, looks hard doesn't it! But it isn't; let's break down the arguments we're sending to the eeprom_read_block function.
Code:
(void*)&StringOfData
The first argument is the RAM pointer. The eeprom_read_block routine modifes our RAM buffer and so the pointer type it's expecting is a void pointer. Our buffer is of the type uint8_t, so we need to typecast its address to the necessary void type.
Code:
(const void*)12
Reading the EEPROM won't change it, so the second parameter is a pointer of the type const void. We're currently using a fixed constant as an address, so we need to typecast that constant to a pointer just like with the byte and word reading examples.
Code:
10
Obviously, this the number of bytes to be read. We're using a constant but a variable could be supplied instead.
The block write function is used in the same manner, except for the write routine the RAM pointer is of the type const void and the EEPROM is just a plain void pointer.
Using the EEMEM attribute
You should now know how to read and write to the EEPROM using fixed addresses. But that's not very practical! In a large application, maintaining all the fixed addresses is an absolute nightmare at best. But there's a solution - the EEMEM attribute.
Defined by the same eeprom.h header, the EEMEM attribute instructs the GCC compiler to assign your variable into the EEPROM address space, instead of the SRAM address space like a normal variable. For example, we could allocate addresses for several variables, like so:
Code:
#include <avr/eeprom.h>
uint8_t EEMEM NonVolatileChar;
uint16_t EEMEM NonVolatileInt;
uint8_t EEMEM NonVolatileString[10];
Although the compiler allocates addresses to your EEMEM variables, it cannot directly access them. For example, the following code will NOT function as intended:
Code:
#include <avr/eeprom.h>
uint8_t EEMEM NonVolatileChar;
uint16_t EEMEM NonVolatileInt;
uint8_t EEMEM NonVolatileString[10];
int main(void)
{
uint8_t SRAMchar;
SRAMchar = NonVolatileChar;
}
That code will instead assign the RAM variable "SRAMchar" to whatever is located in SRAM at the address of "NonVolatileChar", and so the result will be incorrect. Like variables stored in program memory (see tutorial here) we need to still use the eeprom read and write routines discussed above.
So lets try to fix our broken code. We're trying to read out a single byte of memory. Let's try to use the eeprom_read_byte routine.
Code:
#include <avr/eeprom.h>
uint8_t EEMEM NonVolatileChar;
uint16_t EEMEM NonVolatileInt;
uint8_t EEMEM NonVolatileString[10];
int main(void)
{
uint8_t SRAMchar;
SRAMchar = eeprom_read_byte(&NonVolatileChar);
}
It works! Why don't we try to read out the other variables while we're at it. Our second variable is an int, so we need the eeprom_read_word routine:
Code:
#include <avr/eeprom.h>
uint8_t EEMEM NonVolatileChar;
uint16_t EEMEM NonVolatileInt;
uint8_t EEMEM NonVolatileString[10];
int main(void)
{
uint8_t SRAMchar;
uint16_t SRAMint;
SRAMchar = eeprom_read_byte(&NonVolatileChar);
SRAMint = eeprom_read_word(&NonVolatileInt);
}
And our last one is a string, so we'll have to use the block read command:
Code:
#include <avr/eeprom.h>
uint8_t EEMEM NonVolatileChar;
uint16_t EEMEM NonVolatileInt;
uint8_t EEMEM NonVolatileString[10];
int main(void)
{
uint8_t SRAMchar;
uint16_t SRAMint;
uint8_t SRAMstring[10];
SRAMchar = eeprom_read_byte(&NonVolatileChar);
SRAMint = eeprom_read_word(&NonVolatileInt);
eeprom_read_block((void*)&SRAMstring, (const void*)&NonVolatileString, 10);
}
Setting initial values
Finally, I'll discuss the issue of setting an initial value to your EEPROM variables.
Upon compilation of your program with the default makefile, GCC will output two Intel-HEX format files. One will be your .HEX which contains your program data (and which is loaded into your AVR's memory), and the other will be a .EEP file. The .EEP file contains the default EEPROM values, which you can load into your AVR via your programmer's EEPROM programming functions.
To set a default EEPROM value in GCC, simply assign a value to your EEMEM variable, like thus:
Code:
uint8_t EEMEM SomeVariable = 12;
Note that if the EEP file isn't loaded, your program will most likely run with the entire EEPROM being set to 0xFF, or at least unknown data. You should devise a way to ensure that no problems will arise via some sort of protection scheme (eg, loading in several values and checking against known start values).
For an updated version of this tutorial in PDF format, please see this page of my website.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
Last edited by abcminiuser on Feb 04, 2012 - 02:21 PM; edited 11 times in total
|
| |
|
|
|
|
|
Posted: May 15, 2006 - 02:57 AM |
|


Joined: Nov 14, 2005
Posts: 169
Location: Philadelphia, USA
|
|
| Thanks again Dean! You've picked another great topic that I've been wanting to learn. |
|
|
| |
|
|
|
|
|
Posted: Jun 01, 2006 - 06:26 PM |
|

Joined: Nov 17, 2005
Posts: 95
|
|
|
abcminiuser wrote:
My second tutorial. This tutorial will center around GCC's handling of data stored into EEPROM memory.
Do you plan to publish a pdf version of this fine tutorial?
Pop |
|
|
| |
|
|
|
|
|
Posted: Jun 02, 2006 - 12:54 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
|
pop48m wrote:
abcminiuser wrote:
My second tutorial. This tutorial will center around GCC's handling of data stored into EEPROM memory.
Do you plan to publish a pdf version of this fine tutorial?
Pop
Oh yes, I forgot! I've added a PDF version to the original post. Cheers!
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jun 02, 2006 - 03:30 PM |
|


Joined: Aug 04, 2004
Posts: 1822
Location: Davie, FL
|
|
I usually provide a default value in my code in case the eeprom wasn't loaded.
IE:
uint8_t setting;
setting = eeprom_read_byte(EEPROM_SETTING_OFFSET);
if (setting == 0xff) {
setting = DEFAULT;
This assumes that unprogrammed eeprom contains all ones.
I sometimes also check the value read against some range of legal
values just in case the eeprom contains an illegal value that would cause
a program malfunction, and if so use a defined default setting. You could
also write the default setting into the eeprom if the value contained was
unset or out of range, though this isn't usually necessary since the correct
value is now in sram. |
|
|
| |
|
|
|
|
|
Posted: Jun 08, 2006 - 03:55 AM |
|

Joined: Apr 12, 2001
Posts: 46
|
|
Minor mistake, but I found that:
SRAMint = eeprom_read_byte(&NonVolatileInt);
should be:
SRAMint = eeprom_read_word(&NonVolatileInt); |
|
|
| |
|
|
|
|
|
Posted: Jun 08, 2006 - 06:29 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
Darn it! There's always something I manage to miss . Thanks Brian, I've updated my OP.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jun 20, 2006 - 02:59 PM |
|


Joined: Feb 24, 2006
Posts: 232
Location: Australia (BRISBANE)
|
|
thanks Dean. that helped me heaps. ur great at explaing things.  |
|
|
| |
|
|
|
|
|
Posted: Jun 21, 2006 - 05:04 AM |
|

Joined: Jan 18, 2006
Posts: 116
Location: Gorokan NSW Australia
|
|
Hi,
Not sure why, but as soon as I put this line in my code
Code:
#include <avr/eeprom.h>
AVR Studio locks up on me when I Build. I am using a STK500 with a Tiny13. Any ideas? |
|
|
| |
|
|
|
|
|
Posted: Jun 21, 2006 - 05:07 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
You need to install the latest service packs and plugin updates. You can get SP2 from the Atmel website (SP3 is currently in beta), which should include the GCC plugin update to prevent the freezes.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jun 21, 2006 - 10:14 PM |
|

Joined: Jan 18, 2006
Posts: 116
Location: Gorokan NSW Australia
|
|
| Thanks Dean, that fixed it. Excellent tutorial. |
|
|
| |
|
|
|
|
|
Posted: Jul 09, 2006 - 12:26 PM |
|

Joined: Sep 03, 2005
Posts: 795
Location: Christchurch, NZ
|
|
Dean,
***
EEPROM words can be written and read in much the same way, except they require a pointer to an int:
Code:
#include <avr/eeprom.h>
void main(void)
{
uint16_t WordOfData;
WordOfData = eeprom_read_byte((uint16_t*)46);
}
***
Shouldn't this be:
WordOfData = eeprom_read_word((uint16_t*)46);
I am trying to port AVR101 to AVR-GCC. I thought I'd use the eeprom.h functions as, from what I understand, they do not require interrupts to be disabled. Functions written in C (for some compliers), evidently can exceed "a 4 cycle limit" and you must disable interrupts for correct operation.
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?
The functions in AVR101 originally used u16 pointers so I cast them to u08 pointers to get the code to compile without warnings, when using the <avr/eeprom.h> functions.
I am aware of other forum messages saying that this AVR101 only works for values up to 255, which is OK by me . . . at this stage! |
|
|
| |
|
|
|
|
|
Posted: Jul 09, 2006 - 12:35 PM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
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  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
Last edited by abcminiuser on Jul 09, 2006 - 01:59 PM; edited 1 time in total
|
| |
|
|
|
|
|
Posted: Jul 09, 2006 - 01:54 PM |
|

Joined: Sep 24, 2004
Posts: 24
Location: Istanbul, Turkey
|
|
Many thanks for this excellent tutorial!
Cemo |
|
|
| |
|
|
|
|
|
Posted: Jul 09, 2006 - 05:03 PM |
|

Joined: Dec 08, 2004
Posts: 4719
Location: Nova Scotia, Canada
|
|
|
abcminiuser wrote:
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.
Almost. Pointers to functions in WinAVR point to word-aligned addresses. For one thing, this allows binary compatibility with the AVR architecture's IJMP instruction, which internally expects a word-aligned pointer.
It also coincidentally allows 16-bit function pointers to reach any address in any AVR up to and including the ATmega128/1280/1281.
But pointers to data in flash is still byte-aligned. This is quite necessary, otherwise storing data in flash would become an extremely wasteful proposition... a 10-character string would require 20 bytes of Flash storage, with the high-order of every Flash word being wasted.
As a result, the decision has been made that all PROGMEM data should be placed as low in Flash memory as possible. Specifically, it goes immediately after the interrupt vectors and before any other executable code. That way, unless you have almost 64 kB of PROGMEM variables, you'll be sure not to overflow the 16-bit data pointer size.
This means that data pointers to Flash can reach any address in ann AVR up to the ATmega64x.
Access to data living above the 64 kB mark on devices that have it, needs to jump through special hoops. |
|
|
| |
|
|
|
|
|
Posted: Jul 09, 2006 - 10:43 PM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
I stand corrected - I had no idea that GCC aligned the two flash sections differently. Cheers.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jul 10, 2006 - 05:46 AM |
|

Joined: Sep 03, 2005
Posts: 795
Location: Christchurch, NZ
|
|
Dean,
Just remember until someone actually writes something down in black and white there would be NO opportunity to find errors!
Until I read the tutorial I had never used the internal EEPROM in my ATmega32. An hour or two and I got things working up to the stage you got to in the tutorial, so I think that makes a pretty good tutorial.
I had read something about pointers being 2 bytes, but couldn't find the reference. Probably wouldn't have helped anyhow!
So, AVR pointers can point to 65536 bytes, ints or longs of information.
Thank you for clearing that one up.
Regards,
davef |
|
|
| |
|
|
|
|
|
Posted: Jul 10, 2006 - 12:11 PM |
|

Joined: Dec 08, 2004
Posts: 4719
Location: Nova Scotia, Canada
|
|
65536 bytes, (or any 8-bit data types)
32768 ints, (or any 16-bit data types)
16384 longs, (or any 32-bit data types)
or any combination of the above. |
|
|
| |
|
|
|
|
|
Posted: Jul 10, 2006 - 12:19 PM |
|

Joined: Sep 03, 2005
Posts: 795
Location: Christchurch, NZ
|
|
| Oops, thank you for the correction. |
|
|
| |
|
|
|
|
|
Posted: Jul 17, 2006 - 10:37 PM |
|

Joined: Sep 24, 2004
Posts: 24
Location: Istanbul, Turkey
|
|
I would like to contribute to this wonderful tutorial by adding two examples about writing/reading doubles and structures from Eeprom for newbies like me
Code:
double EEMEM EEVar;
double a;
void WriteDoubleToEeprom(double x){
eeprom_write_block((const void*)&x, (void*)&EEVar, sizeof(double));
}
double ReadDoubleFromEeprom(void){
double temp;
eeprom_read_block((void*)&temp, (const void*)&EEVar, sizeof(double));
return(temp);
}
for example, we can easily write any double value to eeprom by
Code:
WriteDoubleToEeprom(123.45);
and then read it back by
Code:
a=ReadDoubleFromEeprom();
******************************
As for the structures, suppose we have structure ST like this:
Code:
typedef struct SStructure{
int8_t varintbyte;
int16_t varintword;
double vardouble;
char varchar[10];
}ST;
we have to define a EEPROM variable of ST type
Code:
ST EEMEM EEStruct;
and also an ordinary variable of type ST
Code:
ST mystructure;
Now, suppose we initiate mystructure like this:
Code:
mystructure.varintbyte=10;
mystructure.varintword=516;
mystructure.vardouble=123.45;
strcpy(mystructure.varchar,"Share it");
We can write the whole structure to eeprom without bothering with the size, individual members, etc. by calling this function:
Code:
void WriteStructureToEeprom(ST a){
eeprom_write_block((const void*)&a, (void*)&EEStruct, sizeof(ST));
}
like this: (note the sizeof(ST) statement in the function)
Code:
WriteStructureToEeprom(mystructure);
and read the whole structure back from eeprom by calling this function:
Code:
ST ReadStructureFromEeprom(void){
ST temp;
eeprom_read_block((void*)&temp, (const void*)&EEStruct, sizeof(ST));
return(temp);
}
like this:
Code:
mystructure=ReadStructureFromEeprom();
Cheers,
Cemo |
|
|
| |
|
|
|
|
|
Posted: Jul 17, 2006 - 10:44 PM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
Excellent, but do remember that the "double" data type does not exist in GCC at present. It is currently a direct alias to the "float" data type.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jul 18, 2006 - 06:11 AM |
|

Joined: Sep 24, 2004
Posts: 24
Location: Istanbul, Turkey
|
|
Yes, you are right. The reason why I habitually use double instead of float is that printf produces a warning when printing a float variable with %f format specifier.
I mean, something like this
Code:
float a;
printf("Variable a = %3.2f",a);
causes the compiler warning
Code:
warning: double format, float arg (arg 2)
I think the correct way, as you pointed out, is to use the float data type and cast it to double when using it with printf in order to get rid of the compiler warning.
Code:
printf("Variable a = %3.2f",(double)a);
So, one can replace all the double's with float's in the examples in my previous post.
Cheers,
Cemo |
|
|
| |
|
|
|
|
|
Posted: Jul 19, 2006 - 01:33 AM |
|

Joined: Jul 18, 2006
Posts: 9
|
|
| The only thing I'd say to writing structures out to EEPROM like this is that it implies that you have the RAM space available to create an image of what's in EEPROM. On the other hand, if you have a large number of say, configuration variables that you want to store in EEPROM, storing them individually or dereferencing each element of a structure seems like it could save some RAM... Can't say from direct experience, but that's how it looks to me. |
|
|
| |
|
|
|
|
|
Posted: Jul 19, 2006 - 05:12 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
I personally have all my EEPROM variables inside a single stuct, named EEPROMVars. This allows me to very easily tell which variables are in EEPROM or not, and has not discernable effect on performance. I only read out variables one at a time which means that no extra RAM is wasted.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Aug 08, 2006 - 08:13 AM |
|

Joined: Aug 16, 2005
Posts: 330
|
|
excellent tutorial!
one problem - I can't seem to use the EEMEM directive.
I get compile errors.
yes, I'm including the eeprom.h
and yes, basic eeprom read and write commands are working if I don't use the EEMEM directive.
I thought I had the latest version of winavr and avrstudio installed, but maybe not? can you please specify what install version of winavr you wrote this code for? (and avr-libc if necessary?) thanks!
this might also come in handy in a couple of years if newer versions of winavr don't work with this syntax. |
|
|
| |
|
|
|
|
|
Posted: Aug 08, 2006 - 08:20 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
I am using AVRLibC 1.4.4 for my tutorial, and WinAVR 20060421 - the latest released version.
If the EEMEM macro is not present in your EEPROM.h header file, then you can add it manually:
Code:
#define EEMEM __attribute__((section(".eeprom")))
In my current header file it is also available under the macro name "EEPROM". I'm not sure if this was present in earlier versions - does changing the "EEMEM" instances to "EEPROM" fix your problem?
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Aug 08, 2006 - 08:35 AM |
|

Joined: Aug 16, 2005
Posts: 330
|
|
cool!
yeah.. turns out I had winavr20050215 installed.
I should probably read these forums more often so I'm up to date with everything that happens.
the earlier eeprom.h doesn't have a #define for EEPROM either.
adding the define for EEMEM in the main code listing worked.
I downloaded the new winavr now.
will have a bash at installing it next.
thankyou so much! |
|
|
| |
|
|
|
|
|
Posted: Sep 26, 2006 - 02:49 AM |
|

Joined: Jul 18, 2002
Posts: 1
|
|
| Many Many Many thanks to you! I was dreading learning how to access the eeprom, and you summed it up just right. I was able to figgure it out in just an hour or two! Again, thank you so much! |
|
|
| |
|
|
|
|
|
Posted: Sep 26, 2006 - 02:52 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
No problem - glad I could help!
Best of luck to you in your projects.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Apr 02, 2007 - 09:45 AM |
|

Joined: Apr 02, 2007
Posts: 8
|
|
16 bit address but 8 bit data
For example I want to read the byte at address 260 of my EEPROM (ATMega8515).
Now I can't use (uint8_t *) as an address pointer as address is not in 8-bits.
Also I can't eeprom_read_word because it treats the address as two addresses for two 8-bit data locations.
I need a function like this
eeprom_read_byte ( (uint16_t *) 260 )
Please tell me how to work around this problem. You can reply me at my e-mail address
aliasgherman@yahoo.com
Thankyou,
Ali Asgher Mansoor Habiby[/b] |
|
|
| |
|
|
|
|
|
Posted: Apr 02, 2007 - 09:51 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
|
Quote:
You can reply me at my e-mail address
aliasgherman@yahoo.com
I could, but I wont. If you have a question I'll answer it here so I can help others. Whether or not you'll put in the effort to read what I have gone through the effort of writing is up to you.
Writing and reading ints is easy, if you read the entire tutorial . What you're after is the eeprom_*_word routines:
Quote:
Our second variable is an int, so we need the eeprom_read_word routine:
Code:
#include <avr/eeprom.h>
uint8_t EEMEM NonVolatileChar;
uint16_t EEMEM NonVolatileInt;
uint8_t EEMEM NonVolatileString[10];
int main(void)
{
uint8_t SRAMchar;
uint16_t SRAMint;
SRAMchar = eeprom_read_byte(&NonVolatileChar);
SRAMint = eeprom_read_word(&NonVolatileInt);
}
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: May 04, 2007 - 04:51 AM |
|

Joined: Mar 13, 2006
Posts: 19
|
|
Thanks for the tutorial.
Does anyone know how i can get the compile to create a eeprom file of initial values if i use fixed address?
I know this code works:
Code:
uint8_t EEMEM SomeVariable = 12;
but i need to use fixed address as i need to preserve EEPROM values after a flash update (via bootloader). aka if i use the above code i can not guarantee that the compile will pick the same location in the new firmware version.
Let me know if i need to explain..
Cheers
Murray |
|
|
| |
|
|
|
|
|
Posted: May 04, 2007 - 10:34 AM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Murray,
Maybe put all your EEPROM variables into a single struct{} so you can determine the positioning. For example:
Code:
typedef struct {
int fred;
char c;
long bob ;
} struct_t;
struct_t EEMEM my_struct = { 37, 'a', 12345678 };
produces a .eep file:
Code:
:070000002500614E61BC0008
:00000001FF
in which the 37 (0x25), 'a' (0x61) and 12345678 (0xBC614E) are in known positions.
Cliff |
_________________
|
| |
|
|
|
|
|
Posted: May 04, 2007 - 05:52 PM |
|


Joined: Feb 14, 2007
Posts: 1858
Location: San Diego California
|
|
Yeaaaa Dean!!!! “The Author”
Looks like 1/3 of the memory chapter of a very good book, to the rest of us at least!
Reads like you’re an author, looks like you took the time to write like an author, seems like your eager audience is awaiting your next chapter, to me.
Consider this life observation of two men with the same life span.
Both lifelong labors create only one indicial functioning commercial program that sells 500k copies to its intended vertical market.
But one man is much richer from the same effort in life. Why?
Because, becoming rich is accruing a different state of mine.
While they were both working on the project only one was selling every part he could during development. He wrote several books (from his notes) on each topic he learned throughout his life. He sold several new small programs. Created from the various parts of the main program like the same multi-media routines for family photo albums. He sold his programs security registration routines to other programmers including the other man in this story.
When no one was willing to pay the price he cut the price in half not stopping at zero like most in life would. No, he would give it away for free! PLUS $15.00 shipping and handling and made several thousand dollars from a program no one would pay for.
Warning, becoming rich is accruing a marketing state of mine.
It would be so easy to turn these Tut’s into a very good book that will produce extra income for life with the same labor.
Sorry it’s my job to aspire people to become rich, as they might then be able to loan me some money.
Cheers,
John |
|
|
| |
|
|
|
|
|
Posted: May 06, 2007 - 01:49 PM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
Cheers John!
I sadly don't have the talent to write a book of my own - Smokey possesses what I do not. I've become quite adept at writing specific tutorials, but I just can't seem to "glue" them all together into one big book.
Nice story - selling the parts is a good idea! Now, if only I received a $1 donation for each reader of each of my tutorials .
I don't mind giving away my time for free for the community. If I'm doing specific work for an individual/company I do charge (a modest amount), but since I have a choice to contribute here, contributing is its own reward.
- Dean
EDIT: And I also enjoy all the kudos writing stuff for free brings!  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: May 06, 2007 - 05:30 PM |
|


Joined: Feb 14, 2007
Posts: 1858
Location: San Diego California
|
|
|
abcminiuser wrote:
Cheers John!
I sadly don't have the talent to write a book of my own - Smokey possesses what I do not. I've become quite adept at writing specific tutorials, but I just can't seem to "glue" them all together into one big book.
...
Ask the forum if they agree with your assessment of not having the talent. Currently you are transitioning different subjects within your Tut’s. You will learn how to transition chapters too. Plus, are you kidding most the stuff I have to read they just say “Now I need to change the subject because you need to know this next”. Not much of a transition required with technical writing as the author is just boring me with his transition story anyway. I just want to know how.
All I'm saying is consider saving your work and make plans to turn it into a revenue stream in your future. You will get better (more confidence is all you need now) and continue learning and it will become easier with each Tut you write. Self-doubt is the biggest excuse people use not to try. (and laziness – You don’t have that!)
It doesn’t have to be much of a book to make you money. Remember Chernobyl nuclear plant accident. Within the week a 30 page ‘book’ was written on how to protect your family from fallout. The author had wanted to know how to protect is family and then sold his labor as a 30 page ‘book’ for $12.00 with a money back guarantee. He placed adds in a small weekly local publications in cities within 100 miles of every nuclear plant in the US. $2,100 in advertising made $18,000 in 5 months. Here’s a secret American’s won’t take the time to return anything for less than $15.00 to $25.00.
It’s planning and marketing that makes you easy money in life. Not perfect writing.
Cheers,
John |
_________________ Resistance is futile…… You will be compiled!
|
| |
|
|
|
|
|
Posted: Jun 19, 2007 - 08:09 AM |
|

Joined: Dec 18, 2006
Posts: 6
|
|
Hi Dean,
thanks for this great tutorial, it helped a lot.
I think I found another small bug:
Code:
#include <avr/eeprom.h>
uint8_t EEMEM NonVolatileChar;
uint16_t EEMEM NonVolatileInt;
uint8_t EEMEM NonVolatileString[10];
int main(void)
{
uint8_t SRAMchar;
uint16_t SRAMint;
uint8_t SRAMstring;
SRAMchar = eeprom_read_byte(&NonVolatileChar);
SRAMint = eeprom_read_word(&NonVolatileInt);
eeprom_read_block((void*)&SRAMstring, (const void*)&NonVolatileString, 10);
}
Shouldn't it be like this?
Code:
uint8_t SRAMstring[10];
Kind regards,
Alex |
|
|
| |
|
|
|
|
|
Posted: Jun 19, 2007 - 01:56 PM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
Yes it should, good catch. I'll correct that now.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jul 21, 2007 - 10:07 PM |
|

Joined: May 22, 2007
Posts: 4
|
|
@abcminiuser:
You mentioned that you just read out the variables from EEPROM as you need them. I have some data that I am storing in the EEPROM, and I was debating whether to read it out as I need it, or read it into variables in RAM.
The data is being used in a loop that's running maybe every 100 ms or so. I'm not running out of SRAM or anything, but I also don't mind the 4 clock cycle delay caused by reading from the EEPROM. Anyone have any suggestions as to which way is better/more appropriate? |
|
|
| |
|
|
|
|
|
Posted: Jul 22, 2007 - 09:19 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
It's entirely up to you, if neither the increased RAM nor the increased fetch time is a problem. Reading from EEPROM does not wear out its lifespan, so whichever method you choose will be the one you deem most appropriate.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Aug 01, 2007 - 08:42 AM |
|

Joined: Apr 02, 2007
Posts: 8
|
|
| An 8-bit character is stored at address 600 in eeprom. How to read it ? |
|
|
| |
|
|
|
|
|
Posted: Aug 01, 2007 - 08:47 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
My first example shows how:
Code:
eeprom_read_byte((uint8_t*)600);
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Aug 03, 2007 - 01:15 PM |
|

Joined: Apr 02, 2007
Posts: 8
|
|
|
|
|
|
|
Posted: Aug 24, 2007 - 02:58 PM |
|


Joined: Nov 23, 2005
Posts: 27
Location: Seinäjoki, Finland
|
|
Hello!!!
I've tried this helpfull tutorial and it has given me some points of view. If you look example AtMega128 manual, you can see a sample code of how to use eeprom. I won't work.
I switched to this tutorial and now I can Write and Read data to EEPROM. BUT. If I make a program which saves data in to eeprom and then afterwards reads it... works fine...
When I comment the line in the code where I write the data and read it afterwards, it won't work. It just doesn't simply save the data in the eeprom.
If anybody has a some sort of solution for this. I just insert new program in to the flash.
Or my eeprom might be corrupted, cause I've ran non-L version of AtMega128 on 3,3 volts.
Or is it just me
Still waiting for my final developement board
Best regards
Juha |
|
|
| |
|
|
|
|
|
Posted: Aug 24, 2007 - 03:08 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| Sounds like you probably need to set the EESAVE fuse in your AVR. Otherwise each time you put a new program into it the EEPROM is being wiped when the "chip erase" is performed. |
_________________
|
| |
|
|
|
|
|
Posted: Aug 24, 2007 - 03:33 PM |
|


Joined: Nov 23, 2005
Posts: 27
Location: Seinäjoki, Finland
|
|
|
clawson wrote:
Sounds like you probably need to set the EESAVE fuse in your AVR. Otherwise each time you put a new program into it the EEPROM is being wiped when the "chip erase" is performed.
I just love the power of forums!!! Thank you! Never thought that would do the trick. I double checked the fuse bits and there it is!
Have nice weekend, you propably saved it for 47,34%  |
|
|
| |
|
|
|
|
|
Posted: Aug 30, 2007 - 03:17 AM |
|

Joined: Feb 18, 2007
Posts: 38
|
|
I have a problem writing to EEPROM of atmega8515. I get a string send to parceInput but when i read the EEPROM all I get is ( ¼ ) that. If I put something in the EEPROM using EEMEM, reading it works just fine. Someone please explain how to write a string to EEPROM in one function and read it in another.
Here is the code I tried
Code:
uint8_t EEMEM EEPROMString[10]; // this is before main()
void parceInput(char s[])
{
if ((s[0] == 'r') && (s[1] == 'e') && (s[2] == 'a') && (s[3] == 'd'))
{
sendString("Reading EEPROM \r\n");
readEEPROM(); // read whats in eeprom
}
else
{
sendString("Saving to EEPROM : ");
sendString(s);
sendChar('\r');
sendChar('\n');
eeprom_is_ready(); // dont know what this is, says in EEPROM.h to use it.
eeprom_write_block((const void*)&s, (void*)&EEPROMString, 10);// write a string to the EEPROM
}
}
// readEEPROM
void readEEPROM()
{
eeprom_is_ready();
uint8_t SRAMstring[10];
eeprom_read_block((void*)&SRAMstring, (const void*)&EEPROMString, 10); // read whats in EEPROM
sendString((char *)SRAMstring);
}
Thanks in advance. |
|
|
| |
|
|
|
|
|
Posted: Aug 30, 2007 - 02:46 PM |
|


Joined: Nov 23, 2005
Posts: 27
Location: Seinäjoki, Finland
|
|
hello!
Have you tried like this?
void parceInput(char s[]) -->
void parceInput(char s*) |
_________________ SW Design Engineer
Finland
|
| |
|
|
|
|
|
Posted: Aug 30, 2007 - 04:00 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
bitfox,
But those are identical? (an array name is a pointer to a block of bytes of that array type)
Cliff |
_________________
|
| |
|
|
|
|
|
Posted: Aug 30, 2007 - 06:06 PM |
|

Joined: Feb 18, 2007
Posts: 38
|
|
It doesn't build if I use void parceInput(char s*)
../atmega8515EEPROM.c:24: error: expected ';', ',' or ')' before '*' token |
|
|
| |
|
|
|
|
|
Posted: Aug 30, 2007 - 06:18 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
That's because he got it wrong. He meant:
Code:
void parceInput(char *s)
|
_________________
|
| |
|
|
|
|
|
Posted: Aug 30, 2007 - 06:29 PM |
|

Joined: Feb 18, 2007
Posts: 38
|
|
| I still get that weird looking character. I started a new topic in the GCC forum, it seemed more appropriate. Please, if u have any suggestions, post there. |
|
|
| |
|
|
|
|
|
Posted: Sep 03, 2007 - 01:32 PM |
|


Joined: Apr 12, 2007
Posts: 298
Location: Windsor, UK
|
|
char array[10];
'&array' is a pointer to the /address/ of the first element.
'array' is a pointer to the first element.
So you need to remove the '&' |
_________________ Author of simavr - Follow me on twitter : @buserror
|
| |
|
|
|
|
|
Posted: Dec 03, 2007 - 01:50 PM |
|

Joined: Nov 01, 2003
Posts: 679
Location: Amadora, Portugal
|
|
I think noone has mentioned it before in this thread, so I'll do it
Quote:
6.5.5. Preventing EEPROM Data Corruption
Well, guess what? Simple usage of the target’s internal EEPROM will lead to spurious and frequent data corruption. The problem is caused mainly on the device’s power down and power fluctuation, and it’s a universal problem that happens with any “unprotected” kind of processor.
When power is cut (or provided) from a device, it actually decays “slowly” and not instantaneously, mainly because of capacitors in the circuit. There’s a point where power is starting to be insufficient for the target, and it starts to behave strangely, like jumping around and executing random pieces of code. That’s when parts of your own EEPROM write routines get executed and corrupt your data! It may also happen that power is turned off right in the middle of a write sequence, leaving your data inconsistent.
In cases of power fluctuation, known as “brown-out”, the problem process is similar. Power goes down to a point that makes the device malfunction, even though not completely off.
The solution to prevent EEPROM data corruption is 2-fold:
1) The device needs protection against the “power fluctuation” – a brown-out detector, which puts and keeps the device in RESET while the power level is below a threshold considered as “minimum safe value” for the device. A normal power-down can be considered a special case of brownout, in which power doesn’t come back.
2) Even with brownout protection, data can still get corrupted, because the device can be turned off or reset while a large (more than 1 byte) data structure is being written in the EEPROM. So, you need software protection or redundancy, by using some kind of checksum to validate your data, and optionally multiple data copies so that you don’t loose all of it (in case data is critical).
Many AVRs have a built-in brownout detector that can be enabled. It can be done when programming the device's fuses. There are also external chips that do brown-out detection and have other features as well (like a watchdog, some bytes of FLASH, etc). These devices connect to the uC’s RESET pin.
|
|
|
| |
|
|
|
|
|
Posted: Jan 20, 2008 - 10:35 PM |
|

Joined: Aug 10, 2006
Posts: 43
|
|
Dear Dean,
still there are fellows (like me) meeting your *excellent* tutorial just now. I have read all the discussion followed it, too, but did not get answer to my special question:
Is there any way of storing my EEPROM variable at a specific address? I need to force an array to be stored on page boundary. Can I do it?
Cheers, Istvan |
|
|
| |
|
|
|
|
|
Posted: Jan 21, 2008 - 12:12 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
Istvan,
I can't see why you'd need that - the EEPROM is not paged, so there are no performance benefits, nor any indication of how big a "page" is, since it's byte-addressed.
However, you could do one of two things. First, you could just use a pointer to your desired address:
Code:
eeprom_read_byte((uint8_t*)600);
Which would present problems if your other automatic variables overlap that area. The second way is to use GCC's sections to create a new EEPROM section at the desired location - there are some threads about this which you can search out. However, while the section method will allow you to create automatic variables in the new EEPROM section, you'll still run into problems if your normal EEPROM variables overlap.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jan 27, 2008 - 02:17 PM |
|

Joined: Aug 10, 2006
Posts: 43
|
|
Hi Dean,
thanks for the fast response.
My program implements an extremely fast assembly loop (only 9 statements) to generate a stored waveform. To be fast enough, this loop handles only the lower part of a pointer, so my data must be aligned to some address represented as 0x...00 (I meant a page is an area of 256 locations starting at nn00 and ending at 00ff).
Is there any way of direct alinging?
Thanks, Istvan |
|
|
| |
|
|
|
|
|
Posted: Jan 28, 2008 - 11:00 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
The EEPROM is byte addressed, so no pages. You could I suppose just change the lower byte address every loop cycle and increment the upper address once every 256 cycles, but that would produce some jitter in your waveform due to the extra cycles being used on the 256'th iteration. Better to just use an extra cycle and load the full address.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jan 28, 2008 - 11:21 AM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| Alternatively it should be possible to put a named section into EEPROM space done in a similar way to the existing .eeprom at present and with a --section-start passed to the linker. |
_________________
|
| |
|
|
|
|
|
Posted: Jan 28, 2008 - 05:24 PM |
|

Joined: Aug 10, 2006
Posts: 43
|
|
|
abcminiuser wrote:
The EEPROM is byte addressed, so no pages. You could I suppose just change the lower byte address every loop cycle and increment the upper address once every 256 cycles, but that would produce some jitter in your waveform due to the extra cycles being used on the 256'th iteration. Better to just use an extra cycle and load the full address.
- Dean
I'm afraid my English is too bad to describe my wish.
I know EEPROM is byte addressed, but... e.g. in Intel386 assembly, if I want to fit a table to a 16 bit boundary (i.e. the lowest 4 bits of the address are 0 and the others are anything else) it is called a "paragraph". Similarly, if the lowest 8 bits are 0, then this is a "page" boundary.
Due to the upper address byte is intended to be eliminated, I have to care the table to be fit to proper address. So I am looking for the way to build something like this:
ldi zh,high table
clr zl
...
...
...
.eeprom
.org 0x100
table:
.byte x, y, z, etc
Now I have solved my original question by mixing with assembly, but I am still interested whether it can be solved in pure C?
Thanks, Istvan |
|
|
| |
|
|
|
|
|
Posted: Jan 28, 2008 - 06:15 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| Yes it can - use a named section and place it with the linker (like I said above) |
_________________
|
| |
|
|
|
|
|
Posted: Jan 28, 2008 - 06:24 PM |
|

Joined: Aug 10, 2006
Posts: 43
|
|
|
clawson wrote:
Yes it can - use a named section and place it with the linker (like I said above)
Could you please drop me a link where I could read about the details? I'm a bit afraid of editing makefile...
Thanks forward,
Istvan |
|
|
| |
|
|
|
|
|
Posted: Jan 28, 2008 - 06:32 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
|
|
|
|
Posted: Feb 14, 2008 - 08:40 PM |
|

Joined: Jan 24, 2008
Posts: 22
|
|
I have found it useful to have two stacks in eeprom. One at 0x4 with increasing address and one at 0x1FF (on my mega16) and two stack pointers at 0x0 resp 0x2. I can store linked lists this way, vey useful.
One thing though, the data sheet says the mega16 has 512 bytes of EEPROM but it seems it is 513 bytes as i can address 0x0 -> 0x200, can anyone confirm this or is this where my bug is lying? I am absolutely positive that i can address 0x200 but i was thinking it might be reserved or something like that. |
|
|
| |
|
|
|
|
|
Posted: Feb 23, 2008 - 12:39 AM |
|

Joined: Feb 12, 2008
Posts: 2
|
|
Hi,
Thank you for your excellent tutorial!
I am using the STK500 with the ATMega8515 chip and programming in C using AVR studio with GCC compiler.
When you use the eeprom_write_byte / eeprom_read_byte commands in your program, can the assembled .hex file just be loaded into the flash memory and will that be sufficient to store my data into the eeprom?
If I run my code as is it simulates fine on the AVR simulator, however, when I load the file onto the the chip, the output is entirely different.
The code basically cycles through an input string and displays the corresponding values in PORT B (LED's)
Code:
#include <avr/io.h>
#include <stdlib.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#define F_CPU 1000000UL //1 Mz
int main(void)
{
DDRB = 0x3f; //set 0-5 LED's to output
char tex[20] = "ABCDE";
int i=0;
eeprom_write_byte((uint8_t*)65, 0x01); //A
eeprom_write_byte((uint8_t*)66, 0x03); //B
eeprom_write_byte((uint8_t*)67, 0x09); //C
eeprom_write_byte((uint8_t*)68, 0x19); //D
eeprom_write_byte((uint8_t*)69, 0x11); //E
for (;;)
{
while (tex[i] != '\0')
{
uint8_t byteofdata= eeprom_read_byte((uint8_t*)tex[i]);
PORTB = byteofdata;
_delay_ms(2000);
_delay_ms(2000);
i++;
}
i = 0;
}
return(0);
}
Thanks! |
|
|
| |
|
|
|
|
|
Posted: Feb 23, 2008 - 03:29 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
Yes, just loading the HEX into the chip would be sufficient in your case -- if you move to using the EEMEM attribute in the future with initialized values, you'll also need to program in the generated .EEP file into your chip.
In your case, you've got a problem. Your write code is fine, and should result in the letters A, B, C, D and E being stored to consecutive EEPROM addresses. However, your read loop reads in bytes from EEPROM, but at the address of your "tex" array, which is located in SRAM. Since the location of the tex array will almost definitely be different to your hard-coded EEPROM addresses (of 65 through 69), the program will output different values to the LEDs.
Also, unless you are using the latest WinAVR/avrlib-c distribution, the _delay_ms() macro has a limit of only about 20ms -- check the user manual.
The "correct" code would be:
Code:
#include <avr/io.h>
#include <stdlib.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#define F_CPU 1000000UL // 1 MHz
char texEEPROM[20] EEMEM; // Create a variable located in the EEPROM space
int main(void)
{
char tex[20] = "ABCDE";
uint8_t texByte;
DDRB = 0x3f; //set 0-5 LED's to output
// Copy the "tex" array to the EEPROM, at the location of the texEEPROM array
for (texByte = 0; texByte < sizeof(tex); texByte++)
eeprom_write_byte(&texEEPROM[texByte], tex[texByte]);
for (;;)
{
uint8_t ReadByte;
texByte = 0;
// Read out the texEEPROM array from EEPROM and display on LEDs
do
{
ReadByte = eeprom_read_byte(&texEEPROM[texByte]);
PORTB = ReadByte;
for (uint8_t DLoops = 0; DLoops < 100; DLoops++)
_delay_ms(20);
} while (ReadByte != '\0');
}
return 0;
}
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Feb 25, 2008 - 11:18 PM |
|

Joined: Feb 12, 2008
Posts: 2
|
|
Thanks Dean,
However, I am trying to do something a little different. Basically, when the string shows A, B, C... I want the LED's (PORT B) to specifically be 0x01, 0x03, 0x09...as seen in the write_byte command (these values must be hardcoded).
So in order to do this, I hardcoded these values in the eeprom locations corresponding to the ASCII values of A,B,C...
So when i=1, tex[i] = 65 (ascii value of 'A')
Next I read eeprom_read_byte((uint8_t*)65) which should be 0x01 right?
When I run this code in the AVR simulator I get 0x01 in PORT B, but when I load the code onto the chip itself, the LED's on the STK500, don't display 0x01.
Thanks in advance! |
|
|
| |
|
|
|
|
|
Posted: Feb 26, 2008 - 04:55 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
Most likely then your _delay_ms function isn't working as expected. Unless you have the absolute latest library version the maximum ms delay value is around 20ms. Try replacing your calls to _delay_ms with the code:
Code:
for (uint8_t DLoops = 0; DLoops < 100; DLoops++)
_delay_ms(20);
And ensure you compile with the right F_CPU CPU speed value - if the AVR is out of the box, it will be running off its internal 1MHz RC oscillator and not your external clock/crystal.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Apr 17, 2008 - 01:05 AM |
|

Joined: Dec 18, 2007
Posts: 1
|
|
Great tutorial! For anyone else who had trouble finding information on (at compile time) retrieving the size of the EEPROM (for example, you want to start storing things at the end, rather than the beginning), the constant for the last address in the EEPROM is
E2END
There are corresponding constants for Flash and other sizes, allowing you to write more portable code. I think, based on other information I found, that when using the IAR compiler, the equivalent definition is __EEPROM_SIZE__
Good luck! |
|
|
| |
|
|
|
|
|
Posted: May 19, 2008 - 09:35 PM |
|

Joined: May 19, 2008
Posts: 17
|
|
hi, thx for the tutorial!!!
i'm working on my first project in C on a ATmega8 (actually it's a porting of an asm project in C).
i've got some problems when i read a data from the eeprom (i can't understend where i'm wrong)
the piece of code is:
Quote:
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/eeprom.h>
void readEeprom(void)
{
uint8_t eepromData;
...
//read idCube
eeprom_busy_wait();
eepromData = eeprom_read_byte((uint8_t*)6);
if (eepromData == 0xff)
idCube = idCubeDefault; (*)
else
idCube = eepromData;
...
}
and i get the following error:
Quote:
../MicrelCube3_2.c:352: error: expected expression before '=' token
on the line with the (*)
i just can't figure out what's wrong...
thx,
b. |
|
|
| |
|
|
|
|
|
Posted: May 20, 2008 - 03:59 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
You need to declare idCube, the compiler is complaining that it doesn't know what "idCube" is. Try sticking:
Code:
uint8_t idCube;
At the start of the program (after "uint8_t eepromData;").
Also, a suggestion. Try using the ternary operator for the assignment to clean up the code:
Code:
idCube = (eepromData == 0xff) ? idCubeDefault : eepromData;
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: May 20, 2008 - 11:48 AM |
|

Joined: May 19, 2008
Posts: 17
|
|
Hi,
i've defined idCube, in my header, but because of the source project in asm i had definitions like:
#deine idCube = 1
and that '=' caused all my troubles...
thx for the help,
b. |
|
|
| |
|
|
|
|
|
Posted: May 20, 2008 - 11:59 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
That means that idCube is a constant token, not a variable. You can't assign values to a macro, only variables.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jun 08, 2008 - 01:03 AM |
|

Joined: Nov 29, 2007
Posts: 29
|
|
Dean,
How does one initialize an eeprom array?
uint8_t EEMEM SomeVariable = 12; works fine for a single byte..., but what if it is SomeVariable[10] and one wishes to initialize a particular element or two?
Thanks,
John |
|
|
| |
|
|
|
|
|
Posted: Jun 08, 2008 - 05:38 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
You can initialize the EEPROM array just like a normal C array:
Code:
uint8_t EEArray[5] EEMEM = {1, 2, 3, 4, 5};
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jun 08, 2008 - 05:49 AM |
|

Joined: Nov 29, 2007
Posts: 29
|
|
Egads man!..., don't you ever sleep?!
That, of course does the trick for the array.
Thanks, again
John |
|
|
| |
|
|
|
|
|
Posted: Jun 08, 2008 - 06:40 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
Sl...eep? I'll have to go look that up in the dictionary .
Glad I could help.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jul 18, 2008 - 11:39 AM |
|

Joined: Jun 23, 2008
Posts: 7
Location: Philippines
|
|
Hi everyone. I've got stuck on this EEPROM problem. I am using an ATmega169 and JTAGICE as debugger/programmer. I just want to verify that i am succesfully writing a data to the EEPROM. So I make a code to write and then read the data.
Code:
#include <avr/eeprom.h>
void main(void)
{
uint8_t mbyte;
uint8_t rbyte;
for(mbyte=0;mybte<100;mbyte++)
eeprom_write_byte((uint8_t *) mbyte,mbyte);
//just write data 00 to 99 at address 00-99
for(mbyte=0;mbyte<100;mbyte++)
rbyte=eeprom_read_byte((uint8_t *)mbyte);
//read data from address 00-99
while(1);//endless loop
}
This code works pretty well and I confirm it during debugging and step by step execution. But when i tried to comment the portion of eeprom writing, and then run the debugger, it seems that all data i read are all 0xFF(at all address). Is there something wrong?.. Hope someone could help me on this.Thank you so much, more power!..
jasperman |
|
|
| |
|
|
|
|
|
Posted: Jul 18, 2008 - 11:42 AM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| Each time you start to debug it erases the chip and downloads the code. During the chip erase the EEPROM will also be wiped. To avoid that try setting the EESAVE fuse. |
_________________
|
| |
|
|
|
|
|
Posted: Jul 19, 2008 - 03:46 AM |
|

Joined: Jun 23, 2008
Posts: 7
Location: Philippines
|
|
|
Quote:
Each time you start to debug it erases the chip and downloads the code. During the chip erase the EEPROM will also be wiped. To avoid that try setting the EESAVE fuse.
I already try that, using the "Preserve EEPROM during Chip erase", but i still get the same result.. Is there anything else i forgot about settings?..
jasperman |
|
|
| |
|
|
|
|
|
Posted: Jul 31, 2008 - 04:00 AM |
|

Joined: Jun 23, 2008
Posts: 7
Location: Philippines
|
|
Hi guys!
I have already figured out with my problem on the EEPROM. I decided to share it here so that it can help also others with troubles the same as mine..
First is you must enable the "Preserve eeprom during programming" Fuse bit.
Second, since I am using a JTAG ICE, you must enable also the "Preserve eeprom during programming" in the JTAG settings. This is what i mislooked.
JTAG settings can be achieve on the "Debug" menu of the AVR studio, click on the "JTAG ICE options". It will open you a new window with options on the "Connections", "Debug", "Breakpoints" and "Status". Under the "Debug" options, you must enable the "Preserve eeprom during programming".
You must take note that even though you enable the "preserve eeprom" fuse bits but did not enable the "preserve eeprom" on the JTAG settings, then your eeprom will always be erased everytime you start the JTAG ICE.
Hope this might help others with the same problem as mine.
jasperman |
|
|
| |
|
|
|
|
|
Posted: Sep 15, 2008 - 03:03 PM |
|


Joined: May 03, 2005
Posts: 293
Location: Windsor, CA
|
|
So I'm trying to use the eeprom to store the mac and IP address.
Not knowing the structure of the eeprom hex file, I let GCC do it by declaring the values using the EEMEM attribute:
Code:
uint8_t EEMEM mymac[6] = {0x54,0x55,0x58,0x10,0x00,0x24};
uint8_t EEMEM myip[4] = {192,168,2,101};
I took the eeprom file that it generated and renamed it so it wouldn't get overwritten the next time I compiled. The file looks like this by the way in a hex editor:
Code:
3A 31 30 30 30 30 30 30 30 35 34 35 35 35 38 31 30 30 30 32 34 43 30 41 38 30 32 36 35 46 46 46 46 46 46 46 46 46 46 46 46 46 32 0D 0A 3A 31 30 30 30 31 30 30 30
I make sure the fuse is set where the eeprom isn't overwritten anymore.
Now that I have my eeprom file I comment out the above lines and just make the variables empty arrays:
Code:
uint8_t mymac[6];
uint8_t myip[4];
I then try to read into the arrays:
Code:
eeprom_read_block((void*)&mymac, (const void*)0, 6);
eeprom_read_block((void*)&myip, (const void*)6, 4);
I get garbage out every time.
What's odd to me is that I don't see the hex mac address in the eeprom. In short, I know I'm doing it wrong but I feel that I've followed the tutorial pretty closely.
Anyone else use eeprom this way? |
|
|
| |
|
|
|
|
|
Posted: Sep 15, 2008 - 04:59 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
I make sure the fuse is set where the eeprom isn't overwritten anymore.
Try reading the EEPROM contents back out to a different .hex after you have just programmed it. Then program the app code and read out the EEPROM yet again. Does the data appear to be intact across all steps? Also does your app code contain any form of eeprom_write_*() that might be corrupting the data? |
_________________
|
| |
|
|
|
|
|
Posted: Sep 15, 2008 - 06:12 PM |
|


Joined: May 03, 2005
Posts: 293
Location: Windsor, CA
|
|
I just read the eeprom after a programming and shows the same as above followed by a lot of 0x46's (FF's) surrounded by address fields.
Does it make sense how it writes those bytes? As an example, take the first byte of the mac address (0x54). In the eeprom, it appears to be in the two bytes 0x35, 0x34. Putting a "3" in front of each number makes no sense to me unless that's how the hex file structure is supposed to be for an eprom.
Also, I have no eeprom writing in my program, just reading in those two lines. |
|
|
| |
|
|
|
|
|
Posted: Sep 15, 2008 - 06:47 PM |
|


Joined: May 03, 2005
Posts: 293
Location: Windsor, CA
|
|
Well my program appears to be working since if I write a new eeprom file with a new ip address, the program switches to it.
I just don't understand why the eeprom file looks that way in a hex editor.
EDIT: All was/is working. I was looking at the wrong screen of my hexeditor. |
|
|
| |
|
|
|
|
|
Posted: Sep 16, 2008 - 09:00 AM |
|

Joined: Sep 02, 2005
Posts: 112
|
|
I'm experimenting and building a dot matrix display, and want to store the font (max 16*16 px) inside the Atmegas eeprom. I need advice about how to store the pixel information.
The "problem" is that I don't want to store 16*16 bits for characters which don't need the size. As you all know, 'M' is much wider than '!'.. No need to store '!' 16px wide, right? My idea is to store a "size byte" (using upper/lower 4 bits for width/heigth) to each char which tells me how wide/high it is.
For example, let's say ' ! ' is 1 bit wide, 8 bits high (data byte 0xFD), and ' " ' is 3 bits wide, 8 bits high (data bytes 0xC0, 0x00, 0xC0).. And let's pretend another char is a 16*16 char. I can store the description byte telling me how wide/high they all are, but how do I store the actual data in the eeprom in custom size? How do I know where to read the data?
I hope you get the idea of what I'm looking for. Is it possible to do something like this? Suggestions?
Thank you in advance,
/D |
|
|
| |
|
|
|
|
|
Posted: Sep 16, 2008 - 09:54 AM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
daffy,
Just out of interest, why use the EEPROM and not simply const data in code flash or is the idea here that the font is some how user editable (but that's going to make it a nightmare if a small block of data needs to be replaced by a larger block!)
As for the "compression". You seem to have described a solution that works there anyway. Obviously to display character N you either need an index for the start locations of all the defintions or you start at the first character, read its width/height then skip that many bytes to the next width/height and do this N times to get to character N. If space allows perhaps an index is a better idea?
To prepare the data (assuming you already have it all defined as 16x16) I'd just put together a quick PC program to process this and output it in the "compressed" form. The advantage of this is that you can then later edit the 16x16 grids and just crank the handle to output a new dataset.
Cliff |
_________________
|
| |
|
|
|
|
|
Posted: Sep 16, 2008 - 10:32 AM |
|

Joined: Sep 02, 2005
Posts: 112
|
|
| edit: double post |
Last edited by daffy on Sep 16, 2008 - 10:46 AM; edited 1 time in total
|
| |
|
|
|
|
|
Posted: Sep 16, 2008 - 10:35 AM |
|

Joined: Sep 02, 2005
Posts: 112
|
|
|
clawson wrote:
Just out of interest, why use the EEPROM and not simply const data in code flash or is the idea here that the font is some how user editable (but that's going to make it a nightmare if a small block of data needs to be replaced by a larger block!)
As you thought, my plan is to be able to write/create the font "outside" the avr, and insert it later. I'll write a small app where I can specify heigth/width per char, and then send it via rs232 to the display.
Quote:
As for the "compression". You seem to have described a solution that works there anyway. Obviously to display character N you either need an index for the start locations of all the defintions or you start at the first character, read its width/height then skip that many bytes to the next width/height and do this N times to get to character N. If space allows perhaps an index is a better idea?
Ah.. Do you mean I keep a separate list with eeprom start locations of every character? (And that location describes how many bytes the character consist of, followed by the data bytes?)
Edit: Yes, that must be what you mean.. But how do I figure out the start locations when storing the font in the first place?
Quote:
To prepare the data (assuming you already have it all defined as 16x16) I'd just put together a quick PC program to process this and output it in the "compressed" form.
Exactly my plan. Write a PC app in which I create the font, save the font to the display. Would be convenient =)
Quote:
The advantage of this is that you can then later edit the 16x16 grids and just crank the handle to output a new dataset.
I don't understand what you mean? (it's certainly something good though
Thanks for the reply!
/D |
|
|
| |
|
|
|
|
|
Posted: Sep 28, 2008 - 08:53 PM |
|

Joined: Jun 15, 2008
Posts: 116
|
|
My application uses 6 parameters which I want to be able to set by a 2x8 LCD and three buttons so I do not need my laptop. I use the following code:
uint16_t wtht;
wtht = eeprom_read_word((uint16_t*)46);
while (1)
{
lcd_clear();
lcd_gotoxy(0, 0);
lcd_string("WTHT ");
lcd_int(wtht);
lcd_gotoxy(0, 1);
lcd_string("- + NEXT");
delay_ms(50);
if ( (PINB & (1 << PB0)) == 0 )
{ --wtht; delay_ms(100); }
if ( (PINB & (1 << PB4)) == 0 )
{ ++wtht; delay_ms(100); }
if ( (PINB & (1 << PB5)) == 0 )
{ break; }
}
eeprom_write_word((uint16_t*)46,wtht);
delay_ms(500);
Works great and can be multiplied for all my other parameters.
I took the value 46 because it was in the tutorial, I tried to read the datasheet of the MEGA48 but do not understand how I can determine the numbers I am allowed to use. Can anyone explain?
Erik |
|
|
| |
|
|
|
|
|
Posted: Sep 28, 2008 - 09:45 PM |
|


Joined: Mar 27, 2002
Posts: 18749
Location: Lund, Sweden
|
|
|
Quote:
I took the value 46 because it was in the tutorial, I tried to read the datasheet of the MEGA48 but do not understand how I can determine the numbers I am allowed to use. Can anyone explain?
Yes. That is a totally arbitrary address in EEPROM that Dean chose:
abcminiuser wrote:
let's say at location 46
The addresses you are allowed to use are from zero to the size of the EEPROM minus one. The mega48 has 256 bytes of EEPROM so the legal addresses are 0 to 255. |
|
|
| |
|
|
|
|
|
Posted: Sep 30, 2008 - 07:39 PM |
|

Joined: Jun 15, 2008
Posts: 116
|
|
Sometimes life is easier than expected,
As I use 16 bit parameters I have to skip one adress between every parameter, it works great, thanks for the reply |
|
|
| |
|
|
|
|
|
Posted: Oct 24, 2008 - 12:09 PM |
|

Joined: Oct 24, 2008
Posts: 3
Location: Schloss Holte, Deutschland
|
|
Hallo, I'm a really newbie at programming avr-controllers. At the moment i want to learn to work with the eeprom memory. But i have a big problem. After i have included avr/eeprom.h i get following error message:
Unknown EEPROM register(s) location
 |
|
|
| |
|
|
|
|
|
Posted: Oct 24, 2008 - 12:15 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| Which AVR are you building for? |
_________________
|
| |
|
|
|
|
|
Posted: Oct 24, 2008 - 12:17 PM |
|

Joined: Oct 24, 2008
Posts: 3
Location: Schloss Holte, Deutschland
|
|
|
|
|
|
|
Posted: Oct 24, 2008 - 12:18 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
|
|
|
|
Posted: Oct 24, 2008 - 12:21 PM |
|

Joined: Oct 24, 2008
Posts: 3
Location: Schloss Holte, Deutschland
|
|
| Does this mean, that i can't work with eeprom.h on mega128a1 |
|
|
| |
|
|
|
|
|
Posted: Oct 24, 2008 - 12:27 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| Nope but you can't use pre-written routines in the current avr-libc's eeprom.h so you'll have to hit the registers directly yourself. |
_________________
|
| |
|
|
|
|
|
Posted: Dec 15, 2008 - 11:05 PM |
|

Joined: Sep 20, 2008
Posts: 16
|
|
Great Tutorial Thanks helped me when my AVR books couldn't.
Dean |
|
|
| |
|
|
|
|
|
Posted: Dec 25, 2008 - 04:00 PM |
|


Joined: Dec 22, 2005
Posts: 1275
Location: shiraz , iran
|
|
Dean thanks for your tutorial!
but i think the max Endurance is
Endurance: 100,000 Write/Erase Cycles. |
_________________ I love Digital
and you who involved in it!
|
| |
|
|
|
|
|
Posted: Dec 25, 2008 - 11:41 PM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
Quite right Ali! The original AVRs had endurances of 10,000 writes for FLASH, and 100,000 for EEPROM. Later with the newer versions (MEGA and TINY) the FLASH endurance was extended to 100,000 also. Looks like I managed to mix the two up - the EEPROM lifespan was never extended.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jan 15, 2009 - 01:39 PM |
|

Joined: Oct 30, 2001
Posts: 10
|
|
Can anyone help me out with a multidimensional array. I have the following array:
Code:
unsigned int EEMEM eaiConfig[19][2] = {{15,30},{10,20},{3,10},{5,10},{8,15},
{10,20},{10,20},{5,10},{8,15},{3,10},
{10,20},{3,10},{3,10},{3,10},{3,10},
{10,20},{10,20},{10,20},{3,10}};
//minimum run,max run.
I would like to read elements out individually. I know I can't do:
Code:
a = eaiConfig[x][y];
...so would it be something like:
Code:
a = eeprom_read_word(????)
Thanks in advance |
|
|
| |
|
|
|
|
|
Posted: Jan 15, 2009 - 01:49 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Code:
a = eeprom_read_word(&eaiConfig[x][y])
|
_________________
|
| |
|
|
|
|
|
Posted: Jan 16, 2009 - 01:54 AM |
|

Joined: Oct 30, 2001
Posts: 10
|
|
|
|
|
|
|
Posted: Feb 04, 2009 - 09:33 AM |
|

Joined: Sep 02, 2005
Posts: 112
|
|
Hello,
I'm wondering if i can read data from the eeprom into a buffer, with a specific start position in the buffer?
Something like this: (not working)
Code:
char sram_buf[30];
unsigned char EEMEM _eeprom_string = {"test\n"};
eeprom_read_block(&sram_buf[10], (const void *)&_eeprom_string, 5);
What I'm trying to do is to read the word "test" into the sram_buffer, with a 10 bytes offset. Is it possible to do such things?
Thank you in advance,
/D |
|
|
| |
|
|
|
|
|
Posted: Feb 04, 2009 - 09:38 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
Sure, that'll work just fine. What isn't working for you? 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.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Feb 04, 2009 - 09:46 AM |
|

Joined: Sep 02, 2005
Posts: 112
|
|
|
abcminiuser wrote:
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.
Aaaahh... Spot on! Thanks! |
|
|
| |
|
|
|
|
|
Posted: Mar 04, 2009 - 07:46 AM |
|

Joined: May 31, 2006
Posts: 67
|
|
Hello guys, I have been programming AVRs using ASM for quite sometime already, and I am currently into learning C, and stumbling in loads of programming problems at that, especially regarding EEPROM.
I have declared/initialized my array like this:
Code:
uint8_t EEMEM memory[16][14];
And a snippet of my code is like this:
Code:
u16 i, j;
output[0] = target;
for (i=1, j=0 ; i<=16 ; i++, j++)
{
output[i] = eeprom_read_byte(&memory[target][j]);
}
output[18] = '\0';
USART_printstream(output); // prints the whole array of string
Problem is, the program can't get over the
Code:
output[i] = eeprom_read_byte(&memory[target][j]);
part. So it just hangs.
I'm kinda noob at C, so any ideas? TIA!  |
_________________ Mark
|
| |
|
|
|
|
|
Posted: Mar 13, 2009 - 06:18 AM |
|

Joined: Mar 13, 2009
Posts: 2
|
|
Hi,
While on this topic, if a programmer is designed to look for EEPROM and USERMEM just above the maximum flash code address for the device, only one hex file need be generated for code and data, instead of multiple files. In that case can GCC support placement of data outside the flash address area? What will be your comments on such a scheme?
With regards,
Laktronics |
|
|
| |
|
|
|
|
|
Posted: Mar 13, 2009 - 09:15 AM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Your post should really be in the GCC forum but to do what you suggest would either need a different handling for each size of AVR or the data would have to be placed after the largest (256K) device but this then faces problems when 512K AVRs arrive. Also the programmer software would need to know about this split so all the various programmers (Ponyprog, avrdude, AVR Studio, etc, etc) would need to be updated to recognise where code ends and EEPROM data begins.
Anyway, what's the problem with using two files (which make a very definite split and can easily be handled by any programming software) ?
PS By the way if you just modify the rule that generates the .hex to not do the "-R .eeprom" then that data will be written into the .hex file alongside the code flash data (but at an address offset of 0x810000). The problem you'll face (because your programming software won't understand this) is that it will say "code image is too large for device" when you try to program it as it thinks you have code stretching out to 8MB+ (that offset picked so it would be bigger than the largest AVR might ever get) |
_________________
|
| |
|
|
|
|
|
Posted: Mar 14, 2009 - 03:20 AM |
|

Joined: Mar 13, 2009
Posts: 2
|
|
Hello Clawson,
Thank you for your reply. Yes, you are right, I should post this question in the GCC Forum to hear their point of view.
I have posted in this forum to get a feedback from users on this scheme of initialising the EEPROM and USER Memory while programming. PIC ICs for example use such a scheme to embed EEPROM data within the main code so that users need not have to worry about handling two or more files (including USER MEM if available), in Assembly language. Also, Atmel's 89S8252 places its EEPROM address immediately after the Flash address only while programming. It helps much in documentation if number of files to be handled are few. Further, the device programming software need to open only one file during programming, thus saving some programming time.
As far as the device programming software is concerned, it is always aware of the chip specific memory map so that any data placed just above the flash address of the specific device in the hex file can be mapped on to the EEPROM/USER MEM area. So, it is not necessary to keep the data at the end of the flash address of the highest end AVR device.
Moving the EEPROM data to address just above the flash address in assembly can easily be done using ORG and DB/DW Directives.
Also, being a programmer specific architecture, there is no need to modify any of the existing programmer designs.
Thanking you once again for your valuable comments,
With regards,
Laktronics |
|
|
| |
|
|
|
|
|
Posted: Mar 14, 2009 - 01:50 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
As far as the device programming software is concerned, it is always aware of the chip specific memory map so that any data placed just above the flash address of the specific device in the hex file can be mapped on to the EEPROM/USER MEM area.
That maybe true of PIC programming software - presumably because it was done like this from day one. I'm afraid your idea kind of missed the boat for AVR where there are just too many different programming programs in existence now for them all to be updated to recognise this code/EPPROM split thing. Else what happens when someone uses a toolchain that builds combined .hex files but tries to feed it to programming software that does not uderstand the split? If Intel .hex contained an embedded version number then programmers could reject files they don't "understand" but that's not the case.
Probably the best hope would be to develop/use programming software that could interpret the ELF format. Clearly all the binary data is in that file and the various sections could be pulled out and programmed appropriately. Given that the source of avrdude is open I guess it would be the best base for developing something like that.
Cliff |
_________________
|
| |
|
|
|
|
|
Posted: Apr 22, 2009 - 08:46 AM |
|

Joined: Feb 25, 2009
Posts: 52
Location: Germany
|
|
Hi,
firstly i would like to thank Dean for this tutorial. Though, for a beginner like me, there will always be tons of question. Here it goes;
1. Ali_dehbidi wrote :
Quote:
but i think the max endurance is 100,000 Write/Erase Cycles
I respectfully agree with Endurance is 100,000 Write/Erase Cycles, but doubtful with the 'max'. As i read from the Atmega48/88/168 User guide stating
Quote:
The EEPROM has an endurance of at least 100,000 write/erase cycles
2. i read earlier regarding the performance question. So if i want to have a high performance, does it mean that i would strive for low usage of RAM and possibly low fetch-time?
3. referring to the BOD, if i understand fully from what is discussed previously, does it means that i only need to set my BOD fuse bit with the threshold voltage desired? Then this will protect malfunction of my EEPROM, what is the min voltage value of the EEPROM before it goes crazy?
Regards,
Nicholas |
Last edited by nicolaisi on Apr 24, 2009 - 02:35 PM; edited 1 time in total
|
| |
|
|
|
|
|
Posted: Apr 24, 2009 - 08:30 AM |
|

Joined: Jan 01, 2009
Posts: 37
Location: Home SoPCo., State Polytechnic of Jakarta
|
|
This an useful tutorial for me
Thanks a lot  |
_________________ ArcticSoul
Industrial Electronic Engineering, College Student
|
| |
|
|
|
|
|
Posted: May 06, 2009 - 09:05 PM |
|

Joined: Sep 24, 2008
Posts: 37
|
|
| note if global interrupts are enabled; you must disable them "cli();" before performing a read; and enable them afterwards; otherwise the mcu will go into reset. |
|
|
| |
|
|
|
|
|
Posted: May 19, 2009 - 05:01 PM |
|


Joined: Oct 08, 2008
Posts: 87
Location: N. California
|
|
| How would one go about reading and writing a floating point variable from/to EEPROM? |
|
|
| |
|
|
|
|
|
Posted: May 19, 2009 - 05:06 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Code:
float f;
eeprom_write_block(&f, e_adr, sizeof(f));
eeprom_read_block(&f, e_adr, sizeof(f));
(actually sizeof(f) is 4 as 32 bit IEEE754 floats are used) |
_________________
|
| |
|
|
|
|
|
Posted: May 19, 2009 - 05:54 PM |
|


Joined: Oct 08, 2008
Posts: 87
Location: N. California
|
|
|
hayashi_leo wrote:
note if global interrupts are enabled; you must disable them "cli();" before performing a read; and enable them afterwards; otherwise the mcu will go into reset.
Is this correct, or is this handled by the eeprom.h functions? |
|
|
| |
|
|
|
|
|
Posted: May 26, 2009 - 04:12 PM |
|


Joined: Oct 08, 2008
Posts: 87
Location: N. California
|
|
Let's say you have stored a function pointer, or a structure containing a function pointer in EEMEM. How do you pull it out and call the function?
struct mystruct{
char text;
int (*f_ptr)(int);
};
..
..
struct mystruct mydata[] EEMEM = {
{1, &f1},
{2, &f2}
}
int (*f2_ptr)(int) = NULL;
int result;
f2_ptr=(int*)eeprom_read_word(&mydata[0].f_ptr);
result = f2_ptr(332);
Should the (int*) be (unsigned int*).
I get various compiler errors on the same line:
warning: passing argument 1 of 'eeprom_read_word' from incompatible pointer type
warning: assignment from incompatible pointer type |
Last edited by split63 on May 26, 2009 - 04:21 PM; edited 1 time in total
|
| |
|
|
|
|
|
Posted: May 26, 2009 - 04:19 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
split63,
Do yourself a favour and get into the habit of typedef'in things as it'll make your code simpler to read:
Code:
typedef int (*f_ptr_type)(int);
typedef struct {
char * text;
f_ptr_type f_ptr;
} mystruct_type;
Put that into a shared .h, then in a .c file:
Code:
mystruct_type mydata[] EEMEM = {
{1, &f1},
{2, &f2}
}
f_ptr_type f2_ptr = NULL;
f2_ptr = (f_ptr_type) eeprom_read_word(&mydata[0].f_ptr);
n = f2_ptr( m );
This keeps the "complexity" of the function pointer type definition in one place and replaces uses of it with the easily digestible 'f_ptr_type' (which you might have your own name for). As I suggested in another thread, splitting the declaration and the definition of mydata[] so it can be easily made extern is further helped by typedef'ing the struct {}
Cliff |
_________________
|
| |
|
|
|
|
|
Posted: May 27, 2009 - 04:05 AM |
|


Joined: Oct 08, 2008
Posts: 87
Location: N. California
|
|
from a much earlier post on page 1:
Quote:
double ReadDoubleFromEeprom(void){
double temp;
eeprom_read_block((void*)&temp, (const void*)&EEVar, sizeof(double));
return(temp);
Can someone explain why the (void*) cast is necessary and what it does in this case?
I found that in the case of characters, I have not needed this. But when I tried this for a float, I had to add the (void*).
char temp[10];
eeprom_read_block(&temp,&EEVar, 10); |
|
|
| |
|
|
|
|
|
Posted: May 27, 2009 - 10:21 AM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Well start by looking at avr/eeprom.h where the prototype for eeprom_read_block is:
Code:
static __inline__ void
eeprom_read_block (void *__dst, const void *__src, size_t __n)
So it's destination pointer is given as void *. The reason for this is that the authors of eeprom_read_block() cannot possibly know what the given pointer might be pointing at. You could do:
Code:
char c;
int n;
long l;
struct {
char * p;
int array[10];
} s;
eeprom_read_block((void *)&c, &e_c, 1);
eeprom_read_block((void *)&n, &e_n, 2);
eeprom_read_block((void *)&l, &e_l, 4);
eeprom_read_block((void *)&s, &e_s, 12);
In the first the first parameter is a pointer to char, in the second a pointer to int, in the third a pointer to long and in the fourth a pointer to a 12 byte struct.
So when the type that a pointer variable is pointing at may not be known the C language allows for "void *" which kind of means "this could be pointing at anything".
The typecast is simply to tell the compiler to interpret the pointers as "void *" at the moment the eeprom_read_block() line is being compiled so they will match the defined paramater type given in the prototype.
Cliff |
_________________
|
| |
|
|
|
|
|
Posted: Jun 19, 2009 - 09:43 AM |
|

Joined: Nov 11, 2005
Posts: 5
|
|
|
Code:
#include <avr/eeprom.h>
uint8_t EEMEM NonVolatileChar;
uint16_t EEMEM NonVolatileInt;
uint8_t EEMEM NonVolatileString[10];
int main(void)
{
uint8_t SRAMchar;
uint16_t SRAMint;
uint8_t SRAMstring[10];
SRAMchar = eeprom_read_byte(&NonVolatileChar);
SRAMint = eeprom_read_word(&NonVolatileInt);
eeprom_read_block((void*)&SRAMstring, (const void*)&NonVolatileString, 10);
}
Hi, this is my first post here and I'm trying to use the EEPROM with GCC.
Shouldn't be the last line:
Code:
eeprom_read_block((void*)SRAMstring, (const void*)NonVolatileString, 10);
or
Code:
eeprom_read_block((void*)&SRAMstring[0], (const void*)&NonVolatileString[0], 10);
since the arrays are already the addresses the '&' operators need to be avoided.
Please correct me if I am wrong.
Cheers |
|
|
| |
|
|
|
|
|
Posted: Jun 19, 2009 - 09:50 AM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| In the case of using the array name it doesn't matter if you use & or not. |
_________________
|
| |
|
|
|
|
|
Posted: Jul 08, 2009 - 03:14 PM |
|

Joined: Mar 25, 2009
Posts: 5
|
|
Hello!
I write in the EEPROM :
char tex1[20] = "12.05 BedTi 130";
when i read it i want to use only the 130 value to comapre it with another value if (something) then display a message on lcd. If anyone can tell me how to read only the 130?
I use AVR studio 4 , GCC compiler.
Thank you in advance, |
|
|
| |
|
|
|
|
|
Posted: Jul 08, 2009 - 08:40 PM |
|

Joined: Nov 17, 2004
Posts: 13956
Location: Vancouver, BC
|
|
| If the string will always be the same length, then just read characters 12 through 14. If it might change, read the entire string and just look at the last three characters. To get it from a string to a number (if this is what you want), use atoi(). |
_________________ Regards,
Steve A.
The Board helps those that help themselves.
|
| |
|
|
|
|
|
Posted: Jul 17, 2009 - 12:19 PM |
|

Joined: Oct 30, 2008
Posts: 26
|
|
plz give me some example code to write data in EEPROM using "void eeprom_write_word (uint16_t *addr, uint16_t value)"  |
|
|
| |
|
|
|
|
|
Posted: Jul 17, 2009 - 12:28 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Code:
#include <avr/io.h>
#include <avr/eeprom.h>
uint16_t EEMEM EEint;
int main(void) {
uint16_t i;
i = PINC | (PINB << 8); // set it to something useful
eeprom_write_word(&EEint, i);
}
|
_________________
|
| |
|
|
|
|
|
Posted: Aug 09, 2009 - 12:35 AM |
|

Joined: Sep 13, 2008
Posts: 13
|
|
|
|
|
|
|
Posted: Aug 25, 2009 - 10:03 PM |
|

Joined: Aug 25, 2009
Posts: 1
|
|
Hi, i think you made an error in your code...
-edit- wh00ps, &array_name is the same as &array_name[0], so it's okay, sorry  |
Last edited by BosByte on Aug 26, 2009 - 11:23 AM; edited 3 times in total
|
| |
|
|
|
|
|
Posted: Aug 26, 2009 - 11:06 AM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| Suggest you take a look at the generated code both with and without the '&' - notice anything? |
_________________
|
| |
|
|
|
|
|
Posted: Sep 08, 2009 - 11:56 AM |
|

Joined: Nov 01, 2003
Posts: 127
Location: Greece
|
|
| What about negative numbers? |
|
|
| |
|
|
|
|
|
Posted: Sep 08, 2009 - 12:09 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| Just store retrieve as uchar/uint then cast the signed interpretation onto them |
_________________
|
| |
|
|
|
|
|
Posted: Sep 14, 2009 - 01:07 PM |
|

Joined: Nov 01, 2003
Posts: 127
Location: Greece
|
|
sorry for this but I am stuck.
Here is my code
Code:
uint16_t EEMEM Eapp = 200;
char s[4]="";
uint16_t temp = 0;
temp = eeprom_read_word(&Eapp);
itoa((signed int)temp,s,4);
s is always "3020"
What is going wrong with my code? |
|
|
| |
|
|
|
|
|
Posted: Sep 14, 2009 - 02:32 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Well did you realise that 4 in your itoa() is asking for the conversion to be made in base 4? So 3020 means 0 units, 2 lots of 4^1, 0 lots of 4^2 and 3 lots of 4^3. IOW 8 + (3 * 64). Which, if I got my sums right is 200 in decimal. You may want to try ",10" rather than ",4"  |
_________________
|
| |
|
|
|
|
|
Posted: Sep 14, 2009 - 03:19 PM |
|

Joined: Nov 01, 2003
Posts: 127
Location: Greece
|
|
Ok.
I am so embarrassed now!!!
Somehow I thought 4 was the size of s!
Thank you very much. I ate 6 hours trying to figure out what was going on!
Thanks again. |
|
|
| |
|
|
|
|
|
Posted: Sep 14, 2009 - 07:07 PM |
|


Joined: Mar 27, 2002
Posts: 18749
Location: Lund, Sweden
|
|
You are welcome to locate the thread "The Stupid Things We Do" in the OT Forum and contribute to it, just as we have. Everyone does Really Stupid Things [tm], so don't be too embarrassed.  |
|
|
| |
|
|
|
|
|
Posted: Dec 04, 2009 - 02:33 AM |
|

Joined: Nov 26, 2009
Posts: 4
|
|
hi all
i'm working with STK500 and Atmega128 microcontroller.
i'm newbie in C programming.Currently i try to make a program that when a character is receive from a microcontroller, it will write the received character into the EEPROM. Start from address 0 and increment this address location for the next character.Upon finishing writing 1 character into the EEPROM, i also want to read previous written character and transmit to the PC for verifications that the characters written to the EEPROM is correct.Below is my coding:
Code:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#define BUFFER_SIZE 10
#define BAUD_57600_BPS 15
#define TRUE 1
#define FALSE 0
volatile uint8_t rxBuffer [BUFFER_SIZE];
volatile uint8_t readPtr;
volatile uint8_t writePtr;
volatile uint8_t txComplete;
uint8_t addressWrite EEMEM = 0;
uint8_t addressRead EEMEM = 0;
//Inizialize USART '0'
void USART_Init (uint16_t data)
{
/* Set baud rate */
UBRR0H = (uint8_t)(data>>8);
UBRR0L = (uint8_t)data;
//Double Speed Operation
UCSR0A = 1 << U2X;
//Enable Transmitter and receiver;enable RX interrupt;enable TX interupt
UCSR0B |= (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<< TXCIE);
//Set frame format 8bit
UCSR0C |= (1<<UCSZ1)|(1<<UCSZ0);
}
void transmitData (uint8_t data)
{
UDR0 = data;
}
uint8_t bufferEmpty (void)
{
uint8_t emptyFlag;
emptyFlag = FALSE;
if(readPtr == writePtr)
{ //buffer is empty
emptyFlag = TRUE;
}
return(emptyFlag);
}
void writeBuffer (uint8_t data)
{
rxBuffer [writePtr] = data;
writePtr++;
if (writePtr >= BUFFER_SIZE)
{
writePtr = 0;
}
}
uint8_t readBuffer (void)
{
uint8_t data;
data = rxBuffer [readPtr];
readPtr++;
if (readPtr >= BUFFER_SIZE)
{
readPtr = 0;
}
return (data);
}
uint8_t bufferFull (void)
{
uint8_t fullFlag;
uint8_t tempPtr;
fullFlag = FALSE;
tempPtr = writePtr;
if (tempPtr++ >= BUFFER_SIZE)
{
tempPtr = 0;
}
if (tempPtr == readPtr)
{
fullFlag = TRUE;
}
return (fullFlag);
}
ISR(USART0_TX_vect)
{
txComplete = TRUE;
}
ISR(USART0_RX_vect)
{
if (bufferFull() == FALSE)
{
writeBuffer (UDR0);
}
}
int main(void)
{
uint8_t readByte;
// Initialize transmission complete flag.
txComplete = TRUE;
//initialize USART_Init
USART_Init(BAUD_57600_BPS);
//Enable Global Interupt
sei();
// loop forever
while(1)
{
if (bufferEmpty() == FALSE)
{
//write byte to a EEPROM;location to place the byte;read byte from buffer.
eeprom_write_byte(&addressWrite,readBuffer());
//increament location to next character
addressWrite++;
if (txComplete == TRUE)
{
//read previous written character
addressRead = addressWrite;
addressRead--;
txComplete = FALSE;
//read byte from EEPROM
readByte = eeprom_read_byte(&addressWrite);
//transmit to PC what EEPROM read
transmitData(readByte);
}
}
}
return 0;
}
When i try this,it give me unknown data.i hope anybody can help me with this.Sorry for my bad english
Rgrd
Dahlia |
Last edited by dahlia on Dec 07, 2009 - 03:03 AM; edited 1 time in total
|
| |
|
|
|
|
|
Posted: Dec 04, 2009 - 10:27 AM |
|


Joined: Mar 27, 2002
Posts: 18749
Location: Lund, Sweden
|
|
Dahlia!
1) Rather than adding yet another subject to this thread, you would have been better off starting your own thread, and
2) I suspect no-one is going to bother to look at your code the way it iss presented right now. All indentation is lost as you have just pasted it as normal text. Do this: i)Click the edit button for your message, ii)mark the source code, iii) click the "Code" button, and finally iv) click the submit button. Your code should now be shown with all textual structure (as indentations etc) intact. Now people might gete interested in looking at your code. |
|
|
| |
|
|
|
|
|
Posted: Dec 07, 2009 - 02:37 AM |
|

Joined: Nov 26, 2009
Posts: 4
|
|
| ok.i will do that.thanks.. |
|
|
| |
|
|
|
|
|
Posted: Jan 16, 2010 - 05:14 AM |
|

Joined: Jul 23, 2009
Posts: 17
|
|
Hi everyone!
I'm a newbie here, sorry for the dumb question...
I use EEPROM in avr-gcc to store data like this:
Code:
uint8_t EEMEM ee_num;
uint8_t EEMEM ee_string[16];
uint8_t num = 8;
uint8_t* sting = "testing";
eeprom_write_byte((void*)&ee_num, num);
eeprom_write_block((const void*)&string, (void*)&ee_string, 7);
uint8_t* readstr;
eeprom_read_block((void*)&readstr, (const void*)&ee_string, 7);
rprintf("String: \"");
rprintfStr(readstr);
rprintf("\"");
rprintfCRLF();
rprintf("Number: ");
rprintfNum(10, 3, FALSE, ' ',eeprom_read_byte((const void*)&ee_num));
My problem is that numeric data, that I write into the EEPROM, like the 'num' variable above, remains in the eeprom after resetting the device, however strings doesn't.
I write a string into the EEPROM, I can read it back, but after resetting the device, it simply disappears, reading it results in an empty string "".
Could you give me any hints on this? Thanks.
Peter |
|
|
| |
|
|
|
|
|
Posted: Jan 16, 2010 - 05:16 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
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.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jan 16, 2010 - 05:49 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
Ah:
Code:
(const void*)&string
This is casting the address of the string pointer to a const void pointer, rather than reinterpreting the pointer's destination type. You are writing the pointer value itself (plus a bunch of other garbage beyond it) to the EEPROM and reading it back, rather than the actual string contents like you desire.
Change the casts to remove the address operator:
Code:
(const void*)string
In the read and write calls.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jan 16, 2010 - 06:30 AM |
|

Joined: Jul 23, 2009
Posts: 17
|
|
|
abcminiuser wrote:
Ah:
Code:
(const void*)&string
This is casting the address of the string pointer to a const void pointer, rather than reinterpreting the pointer's destination type. You are writing the pointer value itself (plus a bunch of other garbage beyond it) to the EEPROM and reading it back, rather than the actual string contents like you desire.
Change the casts to remove the address operator:
Code:
(const void*)string
In the read and write calls.
- Dean
Thanks for your great help, i've figured out the above code works great with static strings , regardless of what I write at the length field. (I even get the whole string back, if i set length smaller than the length of the string!)
Here's the full code I'm working on:
Code:
char *parts[15];
char *last;
char *token;
char **item = parts;
token = strtok_r(cmdlineGetArgStr(1), " ", &last);
while (token) {
*(item++) = token;
token = strtok_r(NULL, " ", &last);
}
*item = NULL;
uint8_t* string = "hello";
eeprom_write_byte((void*)&ee_rdr1_len, strlen(parts[1]));
rprintf("Setting reader1 name to: ");
rprintfStr(parts[1]);
eeprom_write_block((const void*)&parts[1], (void*)&ee_rdr1_name, strlen(parts[1]));
//eeprom_write_byte((void*)&ee_rdr1_len, strlen(string));
//rprintf("Setting reader1 name to: ");
//rprintfStr(string);
//eeprom_write_block((const void*)&string, (void*)&ee_rdr1_name, strlen(string));
This is a command line parser, I'm getting a parameter, tokenize it along the spaces, and I'd like to store the second token into EEPROM. The 4 lines at the bottom work great, I can read the string back after reboot. The 4 lines above that, doesn't. I can read it back perfectly, but after a reboot, the string disappears.
Maybe the problem is that the token parts[1] is not zero-terminated?
Peter |
|
|
| |
|
|
|
|
|
Posted: Jan 16, 2010 - 06:36 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
|
Quote:
(I even get the whole string back, if i set length smaller than the length of the string!)
That is because you are initializing the string at the start of the routine - that way, even if you read back zero bytes, you still end up with the correct original string. If you try to copy the string into a separate buffer, you'll see that it will fail miserably. The EEPROM routines won't automatically NULL terminate your read strings -- it's assumed that you take care of that.
Note that this method:
Code:
uint8_t* string = "hello";
And this method:
Code:
uint8_t string[] = "hello";
Have slightly different meanings, but the latter is usually better from a code perspective (mostly because other buffers you declare with fixed sizes retain the same syntax).
If the strings are not null-terminated, strlen() will return an invalid result and you'll get garbage back.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jan 16, 2010 - 06:44 AM |
|

Joined: Jul 23, 2009
Posts: 17
|
|
|
abcminiuser wrote:
If the strings are not null-terminated, strlen() will return an invalid result and you'll get garbage back.
- Dean
Well, then it's clearly not the case here, because the value of ee_rdr1_len is always correct.
I wonder what's the difference between "parts[1]" and "string". From the perspective of the eeprom_write_block function, they're just pointers, I think.
Peter |
|
|
| |
|
|
|
|
|
Posted: Jan 16, 2010 - 07:03 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
|
Code:
(const void*)&parts[1]
You're doing it again - remove the "&" sign. In this case, you've got a pointer-to-a-pointer-to-a-char, or interpreted in a different way, an array of strings. When you use the array notation parts[1], you are dereferencing the double pointer once, leaving you with a pointer to the desired string. You need to pass that pointer to the EEPROM functions directly rather than passing it's address.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jan 16, 2010 - 07:10 AM |
|

Joined: Jul 23, 2009
Posts: 17
|
|
|
abcminiuser wrote:
Code:
(const void*)&parts[1]
You're doing it again - remove the "&" sign. In this case, you've got a pointer-to-a-pointer-to-a-char, or interpreted in a different way, an array of strings. When you use the array notation parts[1], you are dereferencing the double pointer once, leaving you with a pointer to the desired string. You need to pass that pointer to the EEPROM functions directly rather than passing it's address.
- Dean
If I remove the & sign, it stops working, this way I can't read it back at all. If & is there, I can at least read it back until reboot.
Peter |
|
|
| |
|
|
|
|
|
Posted: Jan 16, 2010 - 11:49 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
The more I read, the less it makes sense. Your parts variable is an array of pointers to char - but you're not actually allocating space for the strings. What you want is something like:
Code:
char parts[15][15];
Which will make parts an array of arrays. What you have now is causing the controller to store many bytes into an unallocated space, which is very bad.
Take this example:
Code:
char* Test1 = "AAA";
char* Test2;
strcpy(Test2, Test1, strlen(Test1));
Here we have Test2, a raw pointer to unallocated space, and so *any* writes to it's destination will cause data corruption.
A corrected sample would be:
Code:
char Test1[] = "AAA";
char Test2[10];
strcpy(Test2, Test1, strlen(Test1));
Which forces Test2 to have a stack allocation of 10 bytes, so we can safely copy strings of up to 9 bytes (the tenth byte is the null terminator) without issue.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jan 22, 2010 - 01:29 AM |
|

Joined: Jul 23, 2009
Posts: 17
|
|
|
abcminiuser wrote:
The more I read, the less it makes sense. Your parts variable is an array of pointers to char - but you're not actually allocating space for the strings. What you want is something like:
Code:
char parts[15][15];
Which will make parts an array of arrays. What you have now is causing the controller to store many bytes into an unallocated space, which is very bad.
Take this example:
Code:
char* Test1 = "AAA";
char* Test2;
strcpy(Test2, Test1, strlen(Test1));
Here we have Test2, a raw pointer to unallocated space, and so *any* writes to it's destination will cause data corruption.
A corrected sample would be:
Code:
char Test1[] = "AAA";
char Test2[10];
strcpy(Test2, Test1, strlen(Test1));
Which forces Test2 to have a stack allocation of 10 bytes, so we can safely copy strings of up to 9 bytes (the tenth byte is the null terminator) without issue.
- Dean
Dean, thank very much! I've corrected my code, and everything works perfectly.
regards,
Peter |
|
|
| |
|
|
|
|
|
Posted: Jan 29, 2010 - 05:28 PM |
|

Joined: May 06, 2009
Posts: 12
Location: Stockholm, Sweden
|
|
Excellent guide.
The freaks owes you a bundle! |
|
|
| |
|
|
|
|
|
Posted: Jan 29, 2010 - 08:29 PM |
|


Joined: Nov 17, 2004
Posts: 6144
Location: Great Smokey Mountains.
|
|
|
Internetwarrior wrote:
Excellent guide.
The freaks owes you a bundle!
Dean has a website:
http://www.fourwalledcubicle.com/
With a donate button for 'bundles' should you be interested.
Smiley |
_________________ FREE TUTORIAL: 'Quick Start Guide for Using the WinAVR C Compiler with ATMEL's AVR Butterfly' AVAILABLE AT: http://www.smileymicros.com
|
| |
|
|
|
|
|
Posted: Jan 31, 2010 - 06:16 PM |
|

Joined: May 06, 2009
Posts: 12
Location: Stockholm, Sweden
|
|
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. |
|
|
| |
|
|
|
|
|
Posted: Mar 11, 2010 - 04:45 PM |
|

Joined: Jan 18, 2010
Posts: 2
|
|
Noob needs a little help here. I read Dean's tut and am still getting compile errors I don't understand.
Code:
// Start code snippet
uint8_t Disp;
Disp = Disp++;
void eeprom_write_byte ((uint8_t*)Disp);
Disp = eeprom_read_byte(const Disp);
// end snippet
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 |
|
|
| |
|
|
|
|
|
Posted: Mar 11, 2010 - 04:53 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Why have you got a function declaration in the middle of that? There's already a declaration for eeprom_read_byte in <avr/eeprom.h> and it is:
Code:
void eeprom_write_byte (uint8_t *__p, uint8_t __value);
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:
Code:
uint8_t EEMEM my_var_in_EEPROM;
uint8_t Disp = 0;
while (Disp+1) {
Disp = Disp++;
eeprom_write_byte (&my_var_in_EEPROM, Disp);
Disp = eeprom_read_byte(&my_var_in_EEPROM);
}
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. |
_________________
|
| |
|
|
|
|
|
Posted: Mar 11, 2010 - 06:46 PM |
|

Joined: Jan 18, 2010
Posts: 2
|
|
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.
Code:
// 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
|
|
|
| |
|
|
|
|
|
Posted: Mar 11, 2010 - 09:27 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
I'm still getting plenty of warnings and errors.
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: Mar 12, 2010 - 07:36 AM |
|


Joined: Mar 27, 2002
Posts: 18749
Location: Lund, Sweden
|
|
Just a side note, but
Code:
Disp = Disp++;
is overkill.
Code:
Disp++;
will do. |
|
|
| |
|
|
|
|
|
Posted: Apr 23, 2010 - 03:24 AM |
|

Joined: Mar 18, 2010
Posts: 52
|
|
HI 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
|
| |
|
|
|
|
|
Posted: Apr 23, 2010 - 03:32 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
|
|
|
|
|
Posted: Apr 23, 2010 - 03:40 AM |
|


Joined: Jan 23, 2010
Posts: 840
Location: Edmonton, Alberta
|
|
| There's an interrupts tutorial, too. Microcontroller datasheets have an overview of flash memory mgmt and interrupts, as does avr-libc. |
|
|
| |
|
|
|
|
|
Posted: May 09, 2010 - 01:39 PM |
|

Joined: Dec 08, 2009
Posts: 4
Location: Denmark
|
|
|
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)
|
|
|
| |
|
|
|
|
|
Posted: May 09, 2010 - 01:40 PM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
|
|
|
|
|
Posted: May 12, 2010 - 06:52 PM |
|

Joined: Apr 28, 2010
Posts: 1
|
|
| any information on improving the EEPROM endurance? using data looping data structures? |
|
|
| |
|
|
|
|
|
Posted: May 12, 2010 - 08:04 PM |
|

Joined: Sep 05, 2001
Posts: 2508
|
|
|
liuroot wrote:
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.
See also:
http://www.avrfreaks.net/index.php?name ... mp;t=91306
Peter |
|
|
| |
|
|
|
|
|
Posted: May 12, 2010 - 11:22 PM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
|
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  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jul 30, 2010 - 10:05 PM |
|

Joined: Feb 10, 2007
Posts: 83
|
|
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.  |
|
|
| |
|
|
|
|
|
Posted: Aug 17, 2010 - 10:07 PM |
|


Joined: Jun 14, 2010
Posts: 18
Location: Riverside USA
|
|
| Thank you so much . I like your tutorial!!!!!! |
|
|
| |
|
|
|
|
|
Posted: Aug 31, 2010 - 04:34 PM |
|

Joined: Jun 14, 2010
Posts: 128
|
|
|
Code:
eeprom_read_word((uint16_t*)address);
Does this read the 16 bit data from EEPROM? |
|
|
| |
|
|
|
|
|
Posted: Aug 31, 2010 - 04:35 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| Yes "word"=16 bits. |
_________________
|
| |
|
|
|
|
|
Posted: Aug 31, 2010 - 04:38 PM |
|

Joined: Jun 14, 2010
Posts: 128
|
|
|
Code:
address=0x0004;
eeprom_read_word((uint16_t*)address++);
after address++ what is the value of pointer? is it 0006? |
|
|
| |
|
|
|
|
|
Posted: Aug 31, 2010 - 04:43 PM |
|

Joined: Nov 17, 2004
Posts: 13956
Location: Vancouver, BC
|
|
| That depends on how you defined address. |
_________________ Regards,
Steve A.
The Board helps those that help themselves.
|
| |
|
|
|
|
|
Posted: Aug 31, 2010 - 04:47 PM |
|

Joined: Jun 14, 2010
Posts: 128
|
|
|
Code:
address=0x0004;
word1=eeprom_read_word((uint16_t*)address++);
word2=eeprom_read_word((uint16_t*)address++);
....
word1=data of address 0x0004
and what should be word2?
word2=data of address 0x0006? |
|
|
| |
|
|
|
|
|
Posted: Aug 31, 2010 - 05:00 PM |
|

Joined: Jun 14, 2010
Posts: 128
|
|
I got it.....
if
uint16_t address=0x0004 then address++ is 0x0006.
if uint8_t address=0x0004 then address++ is 0x0005
Thank you |
|
|
| |
|
|
|
|
|
Posted: Aug 31, 2010 - 05:45 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
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:
Code:
uint16_t * address = (uint16_t *) 0x0006;
word1 = eeprom_read_word(address++);
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:
Code:
char c EEMEM;
uint16_t data[10] EEMEM;
char cram;
uint16_t data_word;
cram = eeprom_read_byte(c);
data_word = eeprom_read_word(&data[3]);
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. |
_________________
|
| |
|
|
|
|
|
Posted: Aug 31, 2010 - 08:57 PM |
|

Joined: Jun 14, 2010
Posts: 128
|
|
| Can I use the EEMEM same for writing the variables in EEPROM without giving the address where to write?? |
|
|
| |
|
|
|
|
|
Posted: Aug 31, 2010 - 09:04 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Yes. You can start with default values if you want too:
Code:
uint8_t data[4] EEMEM = { 4, 91, 217, 38 };
for (i=0; i<4; i++) {
eeprom_write_byte(&data[i], i);
}
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. |
_________________
|
| |
|
|
|
|
|
Posted: Sep 02, 2010 - 03:24 PM |
|

Joined: Jun 14, 2010
Posts: 128
|
|
IS there any way I write a block of word instead of block of bytes.
following is the code to write a block of bytes.
Quote:
void eeprom_write_block (void *pointer_eeprom, const void *pointer_ram, size_t n)
|
|
|
| |
|
|
|
|
|
Posted: Sep 02, 2010 - 04:08 PM |
|


Joined: Mar 27, 2002
Posts: 18749
Location: Lund, Sweden
|
|
A 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
Code:
eeprom_write_block (pointer_to_where_words_should_end_up_in_eeprom, pointer_to_where_words_are_in_ram, number_of_words*2)
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. |
|
|
| |
|
|
|
|
|
Posted: Sep 02, 2010 - 04:20 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
You just answered your own question. Which bit of eeprom_write_block() don't you understand? Maybe an example helps:
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{}
(-23456 = 0xA460, 'A' = 0x41, rest is obvious) |
_________________
|
| |
|
|
|
|
|
Posted: Sep 02, 2010 - 04:50 PM |
|

Joined: Jun 14, 2010
Posts: 128
|
|
|
Code:
uint8_t localBlock[80];
uint16_t size;
uint16_t address;
size = (USARTReceive() << 8);
size |= USARTReceive();
address = (USARTReceive() << 8);
address |= USARTReceive();
int i = 0;
for(i = 0; i < size && i < sizeof(localBlock); i++)
{
localBlock[i] = USARTReceive();
}
eeprom_write_block((const void*)localBlock,(void*)address,size);
Above code will write 8 bit datas
Code:
uint16_t localBlock[80];
uint16_t size;
uint16_t address;
size = (USARTReceive() << 8);
size |= USARTReceive();
address = (USARTReceive() << 8);
address |= USARTReceive();
int i = 0;
for(i = 0; i < size && i < sizeof(localBlock); i++)
{
localBlock[i] = USARTReceive();
}
eeprom_write_block((const void*)localBlock,(void*)address,size);
And above code will read 16 bit datas
Am I correct? |
|
|
| |
|
|
|
|
|
Posted: Sep 02, 2010 - 04:51 PM |
|

Joined: Jun 14, 2010
Posts: 128
|
|
|
Quote:
And above code will read 16 bit datas
I mean write 16 bit data |
|
|
| |
|
|
|
|
|
Posted: Sep 02, 2010 - 05:02 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
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:
Code:
eeprom_write_block((const void*)localBlock,(void*)address, num_elements * sizeof(localblock[0]));
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. |
_________________
|
| |
|
|
|
|
|
Posted: Sep 02, 2010 - 05:35 PM |
|

Joined: Jun 14, 2010
Posts: 128
|
|
|
Code:
eeprom_write_block((const void*)localBlock,(void*)address, num_elements * sizeof(localblock[0]));
I did not understand why we are using localblock[0].
sizeof(localblock[0])means the size of the first element of array? |
|
|
| |
|
|
|
|
|
Posted: Sep 02, 2010 - 05:42 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
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] |
_________________
|
| |
|
|
|
|
|
Posted: Sep 09, 2010 - 02:58 PM |
|

Joined: Feb 18, 2008
Posts: 41
|
|
Great tutorial. Thanks.
In this example
Quote:
Code:
#include <avr/eeprom.h>
void main(void)
{
uint8_t StringOfData[10];
eeprom_read_block((void*)&StringOfData, (const void*)12, 10);
}
shouldn't it be either
Code:
eeprom_read_block((void*)StringOfData, (const void*)12, 10);
or
Code:
eeprom_read_block((void*)&StringOfData[0], (const void*)12, 10);
? |
_________________ There is a special place in Hell reserved for engineers whose code works the first time.
Last edited by ettienne on Sep 09, 2010 - 03:28 PM; edited 1 time in total
|
| |
|
|
|
|
|
Posted: Sep 09, 2010 - 03:21 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
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:
Code:
#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:
Code:
#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:
Code:
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{}
Cliff |
_________________
|
| |
|
|
|
|
|
Posted: Sep 09, 2010 - 03:41 PM |
|

Joined: Feb 18, 2008
Posts: 41
|
|
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 ...
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.
Code:
TEeprom __eeprom stEeprom @EEPROM_START_ADDRESS;
|
_________________ There is a special place in Hell reserved for engineers whose code works the first time.
|
| |
|
|
|
|
|
Posted: Sep 09, 2010 - 03:54 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
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:
Code:
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:
Code:
--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?????? |
_________________
|
| |
|
|
|
|
|
Posted: Sep 09, 2010 - 04:03 PM |
|

Joined: Feb 18, 2008
Posts: 41
|
|
Thanks. 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!  |
_________________ There is a special place in Hell reserved for engineers whose code works the first time.
|
| |
|
|
|
|
|
Posted: Sep 09, 2010 - 04:10 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| 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. |
_________________
|
| |
|
|
|
|
|
Posted: Sep 22, 2010 - 07:21 PM |
|

Joined: Mar 10, 2010
Posts: 7
|
|
This 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! |
|
|
| |
|
|
|
|
|
Posted: Oct 05, 2010 - 03:04 PM |
|

Joined: Jan 26, 2008
Posts: 2
|
|
| Hello, how to include eeprom address like this
Code:
float EEMEM ILG = 0.166;
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 |
|
|
| |
|
|
|
|
|
Posted: Oct 05, 2010 - 03:15 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
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:
Code:
extern float EEMEM ILG;
There's a tutorial article about "managing large projects" here that explains this. |
_________________
|
| |
|
|
|
|
|
Posted: Oct 05, 2010 - 03:41 PM |
|

Joined: Jan 26, 2008
Posts: 2
|
|
| thanks my mistake, I tried define it with assigned value. |
|
|
| |
|
|
|
|
|
Posted: Nov 22, 2010 - 09:06 AM |
|

Joined: Jan 12, 2009
Posts: 17
Location: Cochin
|
|
|
|
|
|
|
Posted: Jan 12, 2011 - 03:41 AM |
|

Joined: Jan 12, 2011
Posts: 2
|
|
Hello,
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:
abcminiuser wrote:
eeprom_read_block((void*)&SRAMstring, (const void*)&NonVolatileString, 10);
Can be rewritten like this:
eeprom_read_block(SRAMstring, NonVolatileString, 10) |
|
|
| |
|
|
|
|
|
Posted: Jan 12, 2011 - 06:53 AM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
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  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Jan 12, 2011 - 12:43 PM |
|

Joined: Jan 12, 2011
Posts: 2
|
|
Hi Dean,
abcminiuser wrote:
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.
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. |
|
|
| |
|
|
|
|
|
Posted: Feb 08, 2011 - 10:20 PM |
|

Joined: Feb 17, 2010
Posts: 157
|
|
hello,
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)
Quote:
<NUL>2<NUL><NUL><NUL>34560<NUL><NUL><NUL>
when it should be
Quote:
12<NUL><NUL><NUL>3456789<NUL>
the code is shown below. THANK YOU!!
Code:
#define F_CPU 7372800UL
#define BAUDRATE 19200
#define UBRR_VALUE ((F_CPU/(BAUDRATE*16UL)) - 1)
#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <avr/sleep.h>
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#define true 1
#define false 0
unsigned int EEMEM eeEtot;
unsigned int EEMEM eeEs_month;
double EEMEM eeEw_month;
unsigned int Etot, Es_month;
double Ew_month;
char Etot_str[5];
char Es_m_str[4];
char Ew_m_str[4];
char TxData[13];
void USART_init()
{
UBRR0L = UBRR_VALUE;
UBRR0H = (UBRR_VALUE >> 8);
UCSR0B |= (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0);
}
void USART_TX(unsigned int byt)
{
while(!(UCSR0A & (1 << UDRE0))){}
UDR0 = byt;
}
int main(void)
{
USART_init();
int j;
while (1)
{
Etot = 12;
Es_month = 3456;
Ew_month = 789;
// WRITE
cli();
/*60*/eeprom_write_word(&eeEtot, Etot);
/*61*/eeprom_write_word(&eeEs_month, Es_month);
/*62*/eeprom_write_block((const void*)&Ew_month, (void*)&eeEw_month, sizeof(double));
sei();
Etot = 0;
Es_month = 0;
Ew_month = 0;
_delay_ms(500);
// READ
cli();
/*72*/Etot = eeprom_read_word(&eeEtot);
/*73*/Es_month = eeprom_read_word(&eeEs_month);
eeprom_read_block((void*)&Ew_month,(const void*)&eeEw_month, sizeof(double));
sei();
// Tx
itoa((int)Etot,Etot_str,10);
itoa((int)Es_month,Es_m_str,10);
itoa((int)Ew_month,Ew_m_str,10);
for (j=0; j<13; j++)
{ TxData[j]=0; }
for(j=0; j<5; j++)
{ TxData[j] = Etot_str[j]; }
for(j=0; j<4; j++)
{ TxData[j + 5] = Es_m_str[j]; }
for(j=0; j<4; j++)
{ TxData[j + 9] = Ew_m_str[j]; }
for (j=0; j<13; j++)
{ USART_TX(TxData[j]); }
_delay_ms(2000);
}
return 0;
}
EDIT: code corrected and warnings eliminated |
Last edited by schamton on Feb 10, 2011 - 04:38 PM; edited 3 times in total
|
| |
|
|
|
|
|
Posted: Feb 09, 2011 - 11:34 AM |
|


Joined: Jul 18, 2005
Posts: 62922
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: 62922
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: 62922
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: 526
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: 9878
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: 526
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: 62922
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: 62922
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: 62922
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: 62922
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 |
_________________
|
| |
|
|
|
|
|
Posted: Aug 28, 2011 - 03:22 PM |
|

Joined: Aug 28, 2011
Posts: 2
|
|
Thank you Cliff - it's obvious when you see it written down, but I just couldn't get my head round it. |
|
|
| |
|
|
|
|
|
Posted: Sep 16, 2011 - 01:07 PM |
|

Joined: Sep 16, 2011
Posts: 1
|
|
|
|
|
|
|
Posted: Mar 05, 2012 - 06:38 PM |
|

Joined: Feb 29, 2012
Posts: 27
|
|
Hello Everyone,
I have a very simple question. Would these eeprom instructions work for the avr atmega1284p microcontroller.The datasheet is below ,please kindly have a look as i am a newbie and understand very little of programming language
http://www.atmel.com/Images/8059S.pdf
Please kindly respond as soon as possible as i need to learn this programming and then write the code for my greenhouse project. Thank you |
|
|
| |
|
|
|
|
|
Posted: Mar 05, 2012 - 07:34 PM |
|


Joined: Mar 27, 2002
Posts: 18749
Location: Lund, Sweden
|
|
|
Quote:
I have a very simple question. Would these eeprom instructions work for the avr atmega1284p microcontroller.
I have a very simple answer: Yes.  |
|
|
| |
|
|
|
|
|
Posted: Apr 02, 2012 - 02:26 PM |
|

Joined: Apr 02, 2012
Posts: 2
|
|
help me pls! for my bugs (
Code:
EEMEM char ok_test[] = "Test Ok!\n\r";
EEMEM char copy_right[]="8-bit Test device super puper multi pulti, C 2012 Vr.SuperWriter";
void SendStr(char *string)
{
while (*string!='\0') /
{
SendByte(*string);
string++; /
}
}
void SendByte(char byte)
{
while(!(UCSRA & (1<<UDRE)));
UDR=byte;
}
int main(void)
{
USART_Init(51);
char *u;
string[]=""
u=string;
eeprom_read_block(u,ok_test,sizeof(ok_test));
SendStr(u);
eeprom_read_block(u,copy_right,sizeof(copy_right));
SendStr(u);
In terminal correct writing message Test Ok!
but next message endlessly repeated ((
Another said that if eeprom_read_block(u,copy_right,16) displays correctly the first 16 characters
Where did I go wrong? |
|
|
| |
|
|
|
|
|
Posted: Apr 02, 2012 - 02:41 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
eeprom_read_block(u,ok_test,sizeof(ok_test));
u is a pointer but is only pointing at ONE BYTE of allocated storage?!? I'm not going to count all the characters in copy_right[] but maybe try something like:
Code:
int main(void)
{
USART_Init(51);
char u[50];
...
But why make a RAM copy anyway? Why not make SendStr() read direct from EEPROM? (if you might also have a SendStr() to read from RAM then add an E or something):
Code:
void SendStrE(char *string)
{
while (eeprom_read_byte(string) != '\0')
{
SendByte(eeprom_reasd_byte(string));
string++; /
}
}
int main(void) {
USART_Init(51);
SendStrE(ok_test);
SendStrE(copy_right);
}
|
_________________
|
| |
|
|
|
|
|
Posted: Apr 02, 2012 - 03:12 PM |
|

Joined: Apr 02, 2012
Posts: 2
|
|
|
Code:
while (eeprom_read_byte(string) != '\0')
Compiler error:
Error 1 invalid conversion from 'char*' to 'const uint8_t*' |
|
|
| |
|
|
|
|
|
Posted: Apr 04, 2012 - 07:58 PM |
|

Joined: Mar 28, 2012
Posts: 9
|
|
| I'm a newbie. Other than the non-volatility, are there other reasons why you would use EEPROM instead of flash? Flash also stores data without power applied, corect? |
|
|
| |
|
|
|
|
|
Posted: Apr 04, 2012 - 08:01 PM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
|
Quote:
I'm a newbie. Other than the non-volatility, are there other reasons why you would use EEPROM instead of flash? Flash also stores data without power applied, corect?
Flash can only be written in pages (batches of 128 or so byte blocks) and can only be modified from the bootloader section of the chip. The EEPROM is byte addressable, and can be altered from anywhere. Special fuses in the newer chips allow the EEPROM contents to be preserved between application reprogrammings, while any custom flash data would be destroyed.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Apr 07, 2012 - 02:01 PM |
|

Joined: Jun 25, 2011
Posts: 55
Location: IRAN
|
|
HI
i have a qustion!
when i use void eeprom_update_byte (uint8_t *__p, uint8_t __value); or like this function?
or when are these beter to use ?
and can i use e.g,
void eeprom_write_byte (uint8_t *__p, uint8_t __value);
insted
void eeprom_update_byte (uint8_t *__p, uint8_t __value);
?
thanks |
|
|
| |
|
|
|
|
|
Posted: Apr 07, 2012 - 02:15 PM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
Always use the update function - it takes a few extra cycles (not very many at all) but will skip the writing of EEPROM cells that are already in the desired state. That means that you will generally save time overall if most of the bytes' values haven't changed, and it will save the lifespan of the EEPROM.
The write functions are provided for backwards compatibility and shouldn't be used in new applications.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Apr 07, 2012 - 02:25 PM |
|

Joined: Jun 25, 2011
Posts: 55
Location: IRAN
|
|
thanks alot for rapid answer!
Quote:
The write functions are provided for backwards compatibility and shouldn't be used in new applications.
now, i "should" or "must" use the update function insted The write functions for any application ? |
|
|
| |
|
|
|
|
|
Posted: Apr 07, 2012 - 02:48 PM |
|


Joined: Mar 27, 2002
Posts: 18749
Location: Lund, Sweden
|
|
|
Quote:
now, i "should" or "must" use the update function instead The write functions for any application ?
There is no absolute truth re this, no one single dictated way to do things. Dean already explained the pros and cons of both set of functions. Let's try again:
The update set of functions execute slightly slower, but generally imposes less wear on the EEPROM.
The write set of functions execute slightly faster, but potentially wears down the EEPROM faster. When it is said about some function that it "should not be used in new applications" this often means that there is a plan to remove the function eventually.
With that information you are absolutely free to pick either the write or the update version of the functions, and then be prepared for the consequences of your choice:
If you have extremely tight demands on performance you might go for the write functions, but when they are possibly removed from avrlibc you will have to implement your own. If such tight demands are not present, you of-course go with the update versions because they impose less wear on EEPROM and they will most likely remain in avrlibc for the foreseeable future. |
|
|
| |
|
|
|
|
|
Posted: Apr 07, 2012 - 03:03 PM |
|

Joined: Jun 25, 2011
Posts: 55
Location: IRAN
|
|
|
|
|
|
|
Posted: Apr 07, 2012 - 05:14 PM |
|


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway
|
|
Note that the time required to read the EEPROM is very little, when compared to the time required to write to it - so if your data to write doesn't change much, you can actually save time overall with the update functions as well as preserve the EEPROM's lifespan. I'd say that using the write functions over the update functions would be something done 1% of the time, and as a general rule the update functions should always be used unless you absolutely know what you are doing.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: Apr 11, 2012 - 08:23 AM |
|

Joined: Sep 03, 2011
Posts: 15
|
|
Hello, I was trying in many ways to figure out where I was wrong, please, help. This is my code:
Code:
GetAbsPos(101,&Apos);
eeprom_write_block((const void*)&Apos, (void*)&EEVar, sizeof(long));
/*for(uint8_t i=0;i<4;i++)
{
uint8_t Data;
Data=Pomocna;
__EEPUT((i+10),Data);
Pomocna>>=8;
}*/
MotorStop(101);
}
Whatever I tried, there was nothing in .eep file.
I tried and Optimization -Os. I included eeprom.h header, and nothing.Defined EEVar as EEMEM.
I am new in all this, and I got assignment to program robot!
Thank you. |
|
|
| |
|
|
|
|
|
Posted: Apr 11, 2012 - 09:26 AM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
Whatever I tried, there was nothing in .eep file.
There is nothing in what you show that would create a .eep file??
You appear to be using eeprom_write_block(). (BTW that should be eeprom_update_block() these days). That is a run time function it does not create fixed .eep data at compile time.
If you wrote something like
Code:
char text[] EEMEM = "Hello world";
struct {
int n;
char c;
long l;
} eedata EEMEM = {
12345,
'A',
0xBABEFACE
};
then either of those WOULD create .eep data. |
_________________
|
| |
|
|
|
|
|
Posted: Apr 11, 2012 - 02:41 PM |
|

Joined: Sep 03, 2011
Posts: 15
|
|
I must correct myself. I defined EEVar like EEMEM, and I've gotten .eep but full with zeros. I have no write in EEPROM!
Thank you. |
|
|
| |
|
|
|
|
|
Posted: Apr 11, 2012 - 03:28 PM |
|


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
Short of a crystal ball I don't know how it's possible to help you without seeing the code you are talking about. If I use the code I showed above I get:
Code:
E:\avr>type test.eep
:1000000048656C6C6F20776F726C6400393041CE3C
:03001000FABEBA7B
:00000001FF
< | |