Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
abcminiuser
PostPosted: May 09, 2006 - 10:13 AM
Moderator


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 Twisted Evil

_________________
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
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
timwhunt
PostPosted: May 15, 2006 - 02:57 AM
Hangaround


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.
 
 View user's profile Send private message  
Reply with quote Back to top
pop48m
PostPosted: Jun 01, 2006 - 06:26 PM
Wannabe


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
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jun 02, 2006 - 12:54 AM
Moderator


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! Embarassed I've added a PDF version to the original post. Cheers!

- Dean Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
kscharf
PostPosted: Jun 02, 2006 - 03:30 PM
Posting Freak


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.
 
 View user's profile Send private message  
Reply with quote Back to top
BrianMcCann
PostPosted: Jun 08, 2006 - 03:55 AM
Rookie


Joined: Apr 12, 2001
Posts: 46


Minor mistake, but I found that:

SRAMint = eeprom_read_byte(&NonVolatileInt);

should be:

SRAMint = eeprom_read_word(&NonVolatileInt);
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jun 08, 2006 - 06:29 AM
Moderator


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway

Darn it! There's always something I manage to miss Razz. Thanks Brian, I've updated my OP.

- Dean Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
danrulz01
PostPosted: Jun 20, 2006 - 02:59 PM
Hangaround


Joined: Feb 24, 2006
Posts: 232
Location: Australia (BRISBANE)

thanks Dean. that helped me heaps. ur great at explaing things. Smile
 
 View user's profile Send private message  
Reply with quote Back to top
Taipan
PostPosted: Jun 21, 2006 - 05:04 AM
Hangaround


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?
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jun 21, 2006 - 05:07 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
Taipan
PostPosted: Jun 21, 2006 - 10:14 PM
Hangaround


Joined: Jan 18, 2006
Posts: 116
Location: Gorokan NSW Australia

Thanks Dean, that fixed it. Excellent tutorial.
 
 View user's profile Send private message  
Reply with quote Back to top
davef
PostPosted: Jul 09, 2006 - 12:26 PM
Resident


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!
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jul 09, 2006 - 12:35 PM
Moderator


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 Twisted Evil

_________________
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
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
cemox
PostPosted: Jul 09, 2006 - 01:54 PM
Rookie


Joined: Sep 24, 2004
Posts: 24
Location: Istanbul, Turkey

Many thanks for this excellent tutorial!

Cemo
 
 View user's profile Send private message  
Reply with quote Back to top
lfmorrison
PostPosted: Jul 09, 2006 - 05:03 PM
Raving lunatic


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.
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jul 09, 2006 - 10:43 PM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
davef
PostPosted: Jul 10, 2006 - 05:46 AM
Resident


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
 
 View user's profile Send private message  
Reply with quote Back to top
lfmorrison
PostPosted: Jul 10, 2006 - 12:11 PM
Raving lunatic


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.
 
 View user's profile Send private message  
Reply with quote Back to top
davef
PostPosted: Jul 10, 2006 - 12:19 PM
Resident


Joined: Sep 03, 2005
Posts: 795
Location: Christchurch, NZ

Oops, thank you for the correction.
 
 View user's profile Send private message  
Reply with quote Back to top
cemox
PostPosted: Jul 17, 2006 - 10:37 PM
Rookie


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 Smile

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
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jul 17, 2006 - 10:44 PM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
cemox
PostPosted: Jul 18, 2006 - 06:11 AM
Rookie


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
 
 View user's profile Send private message  
Reply with quote Back to top
twadepgh
PostPosted: Jul 19, 2006 - 01:33 AM
Newbie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jul 19, 2006 - 05:12 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
JulianHigginson
PostPosted: Aug 08, 2006 - 08:13 AM
Hangaround


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.
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Aug 08, 2006 - 08:20 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
JulianHigginson
PostPosted: Aug 08, 2006 - 08:35 AM
Hangaround


Joined: Aug 16, 2005
Posts: 330


cool!

yeah.. turns out I had winavr20050215 installed.
Embarassed
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!
 
 View user's profile Send private message  
Reply with quote Back to top
anhinga
PostPosted: Sep 26, 2006 - 02:49 AM
Newbie


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!
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Sep 26, 2006 - 02:52 AM
Moderator


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway

No problem - glad I could help!

Best of luck to you in your projects.

- Dean Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
aliasgherman
PostPosted: Apr 02, 2007 - 09:45 AM
Newbie


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]
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Apr 02, 2007 - 09:51 AM
Moderator


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 Wink. 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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
muzzkat
PostPosted: May 04, 2007 - 04:51 AM
Newbie


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: May 04, 2007 - 10:34 AM
10k+ Postman


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

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
AllN
PostPosted: May 04, 2007 - 05:52 PM
Posting Freak


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
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: May 06, 2007 - 01:49 PM
Moderator


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 Wink.

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 Twisted Evil

EDIT: And I also enjoy all the kudos writing stuff for free brings! Wink

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
AllN
PostPosted: May 06, 2007 - 05:30 PM
Posting Freak


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!
 
 View user's profile Send private message  
Reply with quote Back to top
alex_weber
PostPosted: Jun 19, 2007 - 08:09 AM
Newbie


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
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
abcminiuser
PostPosted: Jun 19, 2007 - 01:56 PM
Moderator


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway

Yes it should, good catch. I'll correct that now.

- Dean Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
thecolororange
PostPosted: Jul 21, 2007 - 10:07 PM
Newbie


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?
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jul 22, 2007 - 09:19 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
aliasgherman
PostPosted: Aug 01, 2007 - 08:42 AM
Newbie


Joined: Apr 02, 2007
Posts: 8


An 8-bit character is stored at address 600 in eeprom. How to read it ?
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Aug 01, 2007 - 08:47 AM
Moderator


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway

My first example shows how:

Code:
eeprom_read_byte((uint8_t*)600);


- Dean Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
aliasgherman
PostPosted: Aug 03, 2007 - 01:15 PM
Newbie


Joined: Apr 02, 2007
Posts: 8


Thankyou very much.
 
 View user's profile Send private message  
Reply with quote Back to top
bitfox
PostPosted: Aug 24, 2007 - 02:58 PM
Rookie


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 Smile

Still waiting for my final developement board Smile

Best regards
Juha
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Aug 24, 2007 - 03:08 PM
10k+ Postman


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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
bitfox
PostPosted: Aug 24, 2007 - 03:33 PM
Rookie


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! Smile

Have nice weekend, you propably saved it for 47,34% Very Happy
 
 View user's profile Send private message  
Reply with quote Back to top
Dummie
PostPosted: Aug 30, 2007 - 03:17 AM
Rookie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
bitfox
PostPosted: Aug 30, 2007 - 02:46 PM
Rookie


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Aug 30, 2007 - 04:00 PM
10k+ Postman


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

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
Dummie
PostPosted: Aug 30, 2007 - 06:06 PM
Rookie


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Aug 30, 2007 - 06:18 PM
10k+ Postman


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)

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
Dummie
PostPosted: Aug 30, 2007 - 06:29 PM
Rookie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
buserror
PostPosted: Sep 03, 2007 - 01:32 PM
Hangaround


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
 
 View user's profile Send private message  
Reply with quote Back to top
Nuno
PostPosted: Dec 03, 2007 - 01:50 PM
Resident


Joined: Nov 01, 2003
Posts: 679
Location: Amadora, Portugal

I think noone has mentioned it before in this thread, so I'll do it Smile

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.
 
 View user's profile Send private message  
Reply with quote Back to top
dircon
PostPosted: Jan 20, 2008 - 10:35 PM
Rookie


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
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jan 21, 2008 - 12:12 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
dircon
PostPosted: Jan 27, 2008 - 02:17 PM
Rookie


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
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jan 28, 2008 - 11:00 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
clawson
PostPosted: Jan 28, 2008 - 11:21 AM
10k+ Postman


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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
dircon
PostPosted: Jan 28, 2008 - 05:24 PM
Rookie


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 Twisted Evil


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jan 28, 2008 - 06:15 PM
10k+ Postman


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)

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
dircon
PostPosted: Jan 28, 2008 - 06:24 PM
Rookie


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... Sad
Thanks forward,
Istvan
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jan 28, 2008 - 06:32 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England

http://www.nongnu.org/avr-libc/user-man ... tions.html

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
simonpe
PostPosted: Feb 14, 2008 - 08:40 PM
Rookie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
jdthomas
PostPosted: Feb 23, 2008 - 12:39 AM
Newbie


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!
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Feb 23, 2008 - 03:29 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
jdthomas
PostPosted: Feb 25, 2008 - 11:18 PM
Newbie


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!
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Feb 26, 2008 - 04:55 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
jeremywillden
PostPosted: Apr 17, 2008 - 01:05 AM
Newbie


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!
 
 View user's profile Send private message  
Reply with quote Back to top
bojan.m
PostPosted: May 19, 2008 - 09:35 PM
Newbie


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)

Crying or Very sad
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.
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: May 20, 2008 - 03:59 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
bojan.m
PostPosted: May 20, 2008 - 11:48 AM
Newbie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: May 20, 2008 - 11:59 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
JohnPsmith
PostPosted: Jun 08, 2008 - 01:03 AM
Rookie


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
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jun 08, 2008 - 05:38 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
JohnPsmith
PostPosted: Jun 08, 2008 - 05:49 AM
Rookie


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
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jun 08, 2008 - 06:40 AM
Moderator


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway

Sl...eep? I'll have to go look that up in the dictionary Wink.

Glad I could help.

- Dean Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
jasperman
PostPosted: Jul 18, 2008 - 11:39 AM
Newbie


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jul 18, 2008 - 11:42 AM
10k+ Postman


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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
jasperman
PostPosted: Jul 19, 2008 - 03:46 AM
Newbie


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
 
 View user's profile Send private message  
Reply with quote Back to top
jasperman
PostPosted: Jul 31, 2008 - 04:00 AM
Newbie


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
 
 View user's profile Send private message  
Reply with quote Back to top
fizgig
PostPosted: Sep 15, 2008 - 03:03 PM
Hangaround


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?
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Sep 15, 2008 - 04:59 PM
10k+ Postman


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?

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
fizgig
PostPosted: Sep 15, 2008 - 06:12 PM
Hangaround


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.
 
 View user's profile Send private message  
Reply with quote Back to top
fizgig
PostPosted: Sep 15, 2008 - 06:47 PM
Hangaround


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.
 
 View user's profile Send private message  
Reply with quote Back to top
daffy
PostPosted: Sep 16, 2008 - 09:00 AM
Hangaround


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Sep 16, 2008 - 09:54 AM
10k+ Postman


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

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
daffy
PostPosted: Sep 16, 2008 - 10:32 AM
Hangaround


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
 
 View user's profile Send private message  
Reply with quote Back to top
daffy
PostPosted: Sep 16, 2008 - 10:35 AM
Hangaround


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 Wink

Thanks for the reply!
/D
 
 View user's profile Send private message  
Reply with quote Back to top
erikjanssen
PostPosted: Sep 28, 2008 - 08:53 PM
Hangaround


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
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Sep 28, 2008 - 09:45 PM
10k+ Postman


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.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
erikjanssen
PostPosted: Sep 30, 2008 - 07:39 PM
Hangaround


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
 
 View user's profile Send private message  
Reply with quote Back to top
Tobias_SHS
PostPosted: Oct 24, 2008 - 12:09 PM
Newbie


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
Sad
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Oct 24, 2008 - 12:15 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England

Which AVR are you building for?

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
Tobias_SHS
PostPosted: Oct 24, 2008 - 12:17 PM
Newbie


Joined: Oct 24, 2008
Posts: 3
Location: Schloss Holte, Deutschland

XMEGA128A1
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Oct 24, 2008 - 12:18 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England

http://www.avrfreaks.net/index.php?name ... ght=eeprom

Sad

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
Tobias_SHS
PostPosted: Oct 24, 2008 - 12:21 PM
Newbie


Joined: Oct 24, 2008
Posts: 3
Location: Schloss Holte, Deutschland

Does this mean, that i can't work with eeprom.h on mega128a1
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Oct 24, 2008 - 12:27 PM
10k+ Postman


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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
dchester
PostPosted: Dec 15, 2008 - 11:05 PM
Newbie


Joined: Sep 20, 2008
Posts: 16


Great Tutorial Thanks helped me when my AVR books couldn't.
Dean
 
 View user's profile Send private message  
Reply with quote Back to top
Ali_dehbidi
PostPosted: Dec 25, 2008 - 04:00 PM
Posting Freak


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!
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Dec 25, 2008 - 11:41 PM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
wombat
PostPosted: Jan 15, 2009 - 01:39 PM
Newbie


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jan 15, 2009 - 01:49 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England

Code:
a = eeprom_read_word(&eaiConfig[x][y])

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
wombat
PostPosted: Jan 16, 2009 - 01:54 AM
Newbie


Joined: Oct 30, 2001
Posts: 10


of course, thanks.
 
 View user's profile Send private message  
Reply with quote Back to top
daffy
PostPosted: Feb 04, 2009 - 09:33 AM
Hangaround


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
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Feb 04, 2009 - 09:38 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
daffy
PostPosted: Feb 04, 2009 - 09:46 AM
Hangaround


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!
 
 View user's profile Send private message  
Reply with quote Back to top
mL
PostPosted: Mar 04, 2009 - 07:46 AM
Wannabe


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! Smile

_________________
Mark
 
 View user's profile Send private message  
Reply with quote Back to top
laktronics
PostPosted: Mar 13, 2009 - 06:18 AM
Newbie


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Mar 13, 2009 - 09:15 AM
10k+ Postman


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)

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
laktronics
PostPosted: Mar 14, 2009 - 03:20 AM
Newbie


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Mar 14, 2009 - 01:50 PM
10k+ Postman


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

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
nicolaisi
PostPosted: Apr 22, 2009 - 08:46 AM
Wannabe


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? Smile

Regards,
Nicholas


Last edited by nicolaisi on Apr 24, 2009 - 02:35 PM; edited 1 time in total
 
 View user's profile Send private message  
Reply with quote Back to top
rotasidteach
PostPosted: Apr 24, 2009 - 08:30 AM
Rookie


Joined: Jan 01, 2009
Posts: 37
Location: Home SoPCo., State Polytechnic of Jakarta

This an useful tutorial for me Very Happy

Thanks a lot Smile

_________________
ArcticSoul
Industrial Electronic Engineering, College Student
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
hayashi_leo
PostPosted: May 06, 2009 - 09:05 PM
Rookie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
split63
PostPosted: May 19, 2009 - 05:01 PM
Wannabe


Joined: Oct 08, 2008
Posts: 87
Location: N. California

How would one go about reading and writing a floating point variable from/to EEPROM?
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: May 19, 2009 - 05:06 PM
10k+ Postman


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)

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
split63
PostPosted: May 19, 2009 - 05:54 PM
Wannabe


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?
 
 View user's profile Send private message  
Reply with quote Back to top
split63
PostPosted: May 26, 2009 - 04:12 PM
Wannabe


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: May 26, 2009 - 04:19 PM
10k+ Postman


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

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
split63
PostPosted: May 27, 2009 - 04:05 AM
Wannabe


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);
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: May 27, 2009 - 10:21 AM
10k+ Postman


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

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
santiall
PostPosted: Jun 19, 2009 - 09:43 AM
Newbie


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jun 19, 2009 - 09:50 AM
10k+ Postman


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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
bianca22
PostPosted: Jul 08, 2009 - 03:14 PM
Newbie


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,
 
 View user's profile Send private message  
Reply with quote Back to top
Koshchi
PostPosted: Jul 08, 2009 - 08:40 PM
10k+ Postman


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.
 
 View user's profile Send private message  
Reply with quote Back to top
asif164
PostPosted: Jul 17, 2009 - 12:19 PM
Rookie


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)" Embarassed Embarassed
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jul 17, 2009 - 12:28 PM
10k+ Postman


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);
}

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
Snevzor
PostPosted: Aug 09, 2009 - 12:35 AM
Newbie


Joined: Sep 13, 2008
Posts: 13


Nice tutorial!
 
 View user's profile Send private message  
Reply with quote Back to top
BosByte
PostPosted: Aug 25, 2009 - 10:03 PM
Newbie


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 Smile


Last edited by BosByte on Aug 26, 2009 - 11:23 AM; edited 3 times in total
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Aug 26, 2009 - 11:06 AM
10k+ Postman


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?

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
kakarot
PostPosted: Sep 08, 2009 - 11:56 AM
Hangaround


Joined: Nov 01, 2003
Posts: 127
Location: Greece

What about negative numbers?
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Sep 08, 2009 - 12:09 PM
10k+ Postman


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

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
kakarot
PostPosted: Sep 14, 2009 - 01:07 PM
Hangaround


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?
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Sep 14, 2009 - 02:32 PM
10k+ Postman


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" Wink

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
kakarot
PostPosted: Sep 14, 2009 - 03:19 PM
Hangaround


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.
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Sep 14, 2009 - 07:07 PM
10k+ Postman


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. Very Happy
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
dahlia
PostPosted: Dec 04, 2009 - 02:33 AM
Newbie


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
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Dec 04, 2009 - 10:27 AM
10k+ Postman


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.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
dahlia
PostPosted: Dec 07, 2009 - 02:37 AM
Newbie


Joined: Nov 26, 2009
Posts: 4


ok.i will do that.thanks..
 
 View user's profile Send private message  
Reply with quote Back to top
_Petya_
PostPosted: Jan 16, 2010 - 05:14 AM
Newbie


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
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jan 16, 2010 - 05:16 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
abcminiuser
PostPosted: Jan 16, 2010 - 05:49 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
_Petya_
PostPosted: Jan 16, 2010 - 06:30 AM
Newbie


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 Twisted Evil


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
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jan 16, 2010 - 06:36 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
_Petya_
PostPosted: Jan 16, 2010 - 06:44 AM
Newbie


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 Twisted Evil


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
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jan 16, 2010 - 07:03 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
_Petya_
PostPosted: Jan 16, 2010 - 07:10 AM
Newbie


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 Twisted Evil


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
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jan 16, 2010 - 11:49 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
_Petya_
PostPosted: Jan 22, 2010 - 01:29 AM
Newbie


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 Twisted Evil



Dean, thank very much! I've corrected my code, and everything works perfectly.

regards,
Peter
 
 View user's profile Send private message  
Reply with quote Back to top
Internetwarrior
PostPosted: Jan 29, 2010 - 05:28 PM
Newbie


Joined: May 06, 2009
Posts: 12
Location: Stockholm, Sweden

Excellent guide.
The freaks owes you a bundle!
 
 View user's profile Send private message  
Reply with quote Back to top
smileymicros
PostPosted: Jan 29, 2010 - 08:29 PM
Raving lunatic


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
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
Internetwarrior
PostPosted: Jan 31, 2010 - 06:16 PM
Newbie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
59zoocat
PostPosted: Mar 11, 2010 - 04:45 PM
Newbie


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Mar 11, 2010 - 04:53 PM
10k+ Postman


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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
59zoocat
PostPosted: Mar 11, 2010 - 06:46 PM
Newbie


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Mar 11, 2010 - 09:27 PM
10k+ Postman


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

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Mar 12, 2010 - 07:36 AM
10k+ Postman


Joined: Mar 27, 2002
Posts: 18749
Location: Lund, Sweden

Just a side note, but
Code:
Disp = Disp++;

is overkill.

Code:
Disp++;

will do.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
raghu00832
PostPosted: Apr 23, 2010 - 03:24 AM
Wannabe


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
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
abcminiuser
PostPosted: Apr 23, 2010 - 03:32 AM
Moderator


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway

Quote:

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.


Look at my PROGMEM ( http://www.avrfreaks.net/index.php?name ... mp;t=38003 ) and Interrupts ( http://www.avrfreaks.net/index.php?name ... mp;t=89843 ) tutorials.

- Dean Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
tlucas
PostPosted: Apr 23, 2010 - 03:40 AM
Resident


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.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
rosvall
PostPosted: May 09, 2010 - 01:39 PM
Newbie


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)
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: May 09, 2010 - 01:40 PM
Moderator


Joined: Jan 23, 2004
Posts: 9878
Location: Trondheim, Norway

I do indeed - I'll fix that up. Thanks!

- Dean Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
liuroot
PostPosted: May 12, 2010 - 06:52 PM
Newbie


Joined: Apr 28, 2010
Posts: 1


any information on improving the EEPROM endurance? using data looping data structures?
 
 View user's profile Send private message  
Reply with quote Back to top
danni
PostPosted: May 12, 2010 - 08:04 PM
Raving lunatic


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
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: May 12, 2010 - 11:22 PM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
rewolff
PostPosted: Jul 30, 2010 - 10:05 PM
Wannabe


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. Smile
 
 View user's profile Send private message  
Reply with quote Back to top
opalstear
PostPosted: Aug 17, 2010 - 10:07 PM
Newbie


Joined: Jun 14, 2010
Posts: 18
Location: Riverside USA

Thank you so much . I like your tutorial!!!!!!
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
solanki
PostPosted: Aug 31, 2010 - 04:34 PM
Hangaround


Joined: Jun 14, 2010
Posts: 128


Code:

eeprom_read_word((uint16_t*)address);


Does this read the 16 bit data from EEPROM?
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Aug 31, 2010 - 04:35 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England

Yes "word"=16 bits.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
solanki
PostPosted: Aug 31, 2010 - 04:38 PM
Hangaround


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?
 
 View user's profile Send private message  
Reply with quote Back to top
Koshchi
PostPosted: Aug 31, 2010 - 04:43 PM
10k+ Postman


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.
 
 View user's profile Send private message  
Reply with quote Back to top
solanki
PostPosted: Aug 31, 2010 - 04:47 PM
Hangaround


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?
 
 View user's profile Send private message  
Reply with quote Back to top
solanki
PostPosted: Aug 31, 2010 - 05:00 PM
Hangaround


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Aug 31, 2010 - 05:45 PM
10k+ Postman


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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
solanki
PostPosted: Aug 31, 2010 - 08:57 PM
Hangaround


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??
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Aug 31, 2010 - 09:04 PM
10k+ Postman


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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
solanki
PostPosted: Sep 02, 2010 - 03:24 PM
Hangaround


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)
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Sep 02, 2010 - 04:08 PM
10k+ Postman


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.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
clawson
PostPosted: Sep 02, 2010 - 04:20 PM
10k+ Postman


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(&copy_in_RAM, &copy_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)

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
solanki
PostPosted: Sep 02, 2010 - 04:50 PM
Hangaround


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?
 
 View user's profile Send private message  
Reply with quote Back to top
solanki
PostPosted: Sep 02, 2010 - 04:51 PM
Hangaround


Joined: Jun 14, 2010
Posts: 128


Quote:


And above code will read 16 bit datas


I mean write 16 bit data
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Sep 02, 2010 - 05:02 PM
10k+ Postman


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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
solanki
PostPosted: Sep 02, 2010 - 05:35 PM
Hangaround


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?
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Sep 02, 2010 - 05:42 PM
10k+ Postman


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]

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
ettienne
PostPosted: Sep 09, 2010 - 02:58 PM
Rookie


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Sep 09, 2010 - 03:21 PM
10k+ Postman


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

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
ettienne
PostPosted: Sep 09, 2010 - 03:41 PM
Rookie


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 ... Embarassed

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.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Sep 09, 2010 - 03:54 PM
10k+ Postman


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??????

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
ettienne
PostPosted: Sep 09, 2010 - 04:03 PM
Rookie


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! Razz

_________________
There is a special place in Hell reserved for engineers whose code works the first time.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Sep 09, 2010 - 04:10 PM
10k+ Postman


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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
PlasmaCube
PostPosted: Sep 22, 2010 - 07:21 PM
Newbie


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!
 
 View user's profile Send private message  
Reply with quote Back to top
SnakeLT
PostPosted: Oct 05, 2010 - 03:04 PM
Newbie


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.oSad.eeprom+0x0): multiple definition of `ILG'
main.oSad.eeprom+0x0): first defined here
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Oct 05, 2010 - 03:15 PM
10k+ Postman


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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
SnakeLT
PostPosted: Oct 05, 2010 - 03:41 PM
Newbie


Joined: Jan 26, 2008
Posts: 2


thanks my mistake, I tried define it with assigned value.
 
 View user's profile Send private message  
Reply with quote Back to top
rejinathpa
PostPosted: Nov 22, 2010 - 09:06 AM
Newbie


Joined: Jan 12, 2009
Posts: 17
Location: Cochin

Thank you...............
 
 View user's profile Send private message  
Reply with quote Back to top
jasonx
PostPosted: Jan 12, 2011 - 03:41 AM
Newbie


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)
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Jan 12, 2011 - 06:53 AM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
jasonx
PostPosted: Jan 12, 2011 - 12:43 PM
Newbie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
schamton
PostPosted: Feb 08, 2011 - 10:20 PM
Hangaround


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Feb 09, 2011 - 11:34 AM
10k+ Postman


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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
schamton
PostPosted: Feb 09, 2011 - 06:36 PM
Hangaround


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!
 
 View user's profile Send private message  
Reply with quote Back to top
schamton
PostPosted: Feb 10, 2011 - 04:28 PM
Hangaround


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 :/
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Feb 10, 2011 - 04:48 PM
10k+ Postman


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)

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
schamton
PostPosted: Feb 10, 2011 - 05:02 PM
Hangaround


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
 
 View user's profile Send private message  
Reply with quote Back to top
A-RapESTONIA
PostPosted: Feb 20, 2011 - 07:07 PM
Newbie


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...
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Feb 20, 2011 - 07:16 PM
10k+ Postman


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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
A-RapESTONIA
PostPosted: Feb 20, 2011 - 09:53 PM
Newbie


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...
 
 View user's profile Send private message  
Reply with quote Back to top
hobbss
PostPosted: Mar 03, 2011 - 01:27 PM
Resident


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?
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Mar 03, 2011 - 03:37 PM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
hobbss
PostPosted: Mar 03, 2011 - 03:51 PM
Resident


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(&copy_in_RAM, &copy_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.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Mar 03, 2011 - 04:38 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:

would the code be:

Yes.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
rivanor
PostPosted: Mar 18, 2011 - 03:21 PM
Newbie


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? Smile
Looks like someone is changing things on us hehe.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
kax2007
PostPosted: May 15, 2011 - 12:34 PM
Newbie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: May 15, 2011 - 02:09 PM
10k+ Postman


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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
DigiAcid
PostPosted: May 21, 2011 - 09:38 PM
Newbie


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 Smile
 
 View user's profile Send private message  
Reply with quote Back to top
darshanys
PostPosted: Aug 15, 2011 - 03:19 PM
Newbie


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 Twisted Evil
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Aug 15, 2011 - 03:25 PM
10k+ Postman


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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
guyh22
PostPosted: Aug 28, 2011 - 11:56 AM
Newbie


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
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Aug 28, 2011 - 12:38 PM
10k+ Postman


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

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
guyh22
PostPosted: Aug 28, 2011 - 03:22 PM
Newbie


Joined: Aug 28, 2011
Posts: 2


Thank you Cliff Smile - it's obvious when you see it written down, but I just couldn't get my head round it.
 
 View user's profile Send private message  
Reply with quote Back to top
acmiran40@gmail.com
PostPosted: Sep 16, 2011 - 01:07 PM
Newbie


Joined: Sep 16, 2011
Posts: 1


thanks to info.
 
 View user's profile Send private message  
Reply with quote Back to top
Pro000
PostPosted: Mar 05, 2012 - 06:38 PM
Rookie


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
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Mar 05, 2012 - 07:34 PM
10k+ Postman


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. Very Happy
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
fleksagon
PostPosted: Apr 02, 2012 - 02:26 PM
Newbie


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?
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Apr 02, 2012 - 02:41 PM
10k+ Postman


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);
}

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
fleksagon
PostPosted: Apr 02, 2012 - 03:12 PM
Newbie


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*'
 
 View user's profile Send private message  
Reply with quote Back to top
Jro_sf
PostPosted: Apr 04, 2012 - 07:58 PM
Newbie


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?
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Apr 04, 2012 - 08:01 PM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
mojtaba_led
PostPosted: Apr 07, 2012 - 02:01 PM
Wannabe


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
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Apr 07, 2012 - 02:15 PM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
mojtaba_led
PostPosted: Apr 07, 2012 - 02:25 PM
Wannabe


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 ?
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Apr 07, 2012 - 02:48 PM
10k+ Postman


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.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
mojtaba_led
PostPosted: Apr 07, 2012 - 03:03 PM
Wannabe


Joined: Jun 25, 2011
Posts: 55
Location: IRAN

thanks a lot.
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Apr 07, 2012 - 05:14 PM
Moderator


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 Twisted Evil

_________________
Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
natalijana
PostPosted: Apr 11, 2012 - 08:23 AM
Newbie


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! Confused

Thank you.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Apr 11, 2012 - 09:26 AM
10k+ Postman


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.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
natalijana
PostPosted: Apr 11, 2012 - 02:41 PM
Newbie


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.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Apr 11, 2012 - 03:28 PM
10k+ Postman


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 <