[TUT] [C] Using the EEPROM memory in AVR-GCC

Go To Last Post
353 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

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:

#include 

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:

#include 

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:

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:

#include 

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.

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.

#include 

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.

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

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

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:

#include 

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:

#include 

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.

#include 

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:

#include 

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:

#include 

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:

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:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Last Edited: Sat. Feb 4, 2012 - 02:21 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks again Dean! You've picked another great topic that I've been wanting to learn.

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

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

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

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

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

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.

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

Minor mistake, but I found that:

SRAMint = eeprom_read_byte(&NonVolatileInt);

should be:

SRAMint = eeprom_read_word(&NonVolatileInt);

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

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

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

thanks Dean. that helped me heaps. ur great at explaing things. :)

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

Hi,

Not sure why, but as soon as I put this line in my code

#include  

AVR Studio locks up on me when I Build. I am using a STK500 with a Tiny13. Any ideas?

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

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:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Thanks Dean, that fixed it. Excellent tutorial.

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

Dean,

***
EEPROM words can be written and read in much the same way, except they require a pointer to an int:

	   
#include  

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

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

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 , 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:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

Last Edited: Sun. Jul 9, 2006 - 12:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Many thanks for this excellent tutorial!

Cemo

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

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.

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

I stand corrected - I had no idea that GCC aligned the two flash sections differently. Cheers.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

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

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

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.

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

Oops, thank you for the correction.

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

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 :)

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

WriteDoubleToEeprom(123.45);

and then read it back by

a=ReadDoubleFromEeprom();

******************************

As for the structures, suppose we have structure ST like this:

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

ST EEMEM EEStruct;

and also an ordinary variable of type ST

ST mystructure;

Now, suppose we initiate mystructure like this:

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:

void WriteStructureToEeprom(ST a){
   eeprom_write_block((const void*)&a, (void*)&EEStruct, sizeof(ST));
}

like this: (note the sizeof(ST) statement in the function)

WriteStructureToEeprom(mystructure);

and read the whole structure back from eeprom by calling this function:

ST ReadStructureFromEeprom(void){
   ST temp;
   eeprom_read_block((void*)&temp, (const void*)&EEStruct, sizeof(ST));
   return(temp);
}

like this:

mystructure=ReadStructureFromEeprom();

Cheers,

Cemo

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

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:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

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

float a;
printf("Variable a = %3.2f",a);

causes the compiler warning

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.

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

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

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.

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

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:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

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.

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

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:

#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:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

cool!

yeah.. turns out I had winavr20050215 installed.
:oops:
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!

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

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!

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

No problem - glad I could help!

Best of luck to you in your projects.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

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]

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

Quote:

You can reply me at my e-mail address
aliasgherman@yahoo.com

I could, but I wont. If you have a question I'll answer it here so I can help others. Whether or not you'll put in the effort to read what I have gone through the effort of writing is up to you.

Writing and reading ints is easy, if you read the entire tutorial ;). What you're after is the eeprom_*_word routines:

Quote:
Our second variable is an int, so we need the eeprom_read_word routine:

#include 

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:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

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:

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

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

Murray,

Maybe put all your EEPROM variables into a single struct{} so you can determine the positioning. For example:

typedef struct {
 int fred;
 char c;
 long bob ;
} struct_t;

struct_t EEMEM my_struct = { 37, 'a', 12345678 };

produces a .eep file:

:070000002500614E61BC0008
:00000001FF

in which the 37 (0x25), 'a' (0x61) and 12345678 (0xBC614E) are in known positions.

Cliff

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

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

Resistance is futile…… You will be compiled!

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

Cheers John!

I sadly don't have the talent to write a book of my own - Smokey possesses what I do not. I've become quite adept at writing specific tutorials, but I just can't seem to "glue" them all together into one big book.

Nice story - selling the parts is a good idea! Now, if only I received a $1 donation for each reader of each of my tutorials ;).

I don't mind giving away my time for free for the community. If I'm doing specific work for an individual/company I do charge (a modest amount), but since I have a choice to contribute here, contributing is its own reward.

- Dean :twisted:

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

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

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!

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

Hi Dean,

thanks for this great tutorial, it helped a lot.

I think I found another small bug:

#include 

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?

    uint8_t  SRAMstring[10];   

Kind regards,
Alex

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

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

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

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

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

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:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

An 8-bit character is stored at address 600 in eeprom. How to read it ?

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

My first example shows how:

eeprom_read_byte((uint8_t*)600);

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Thankyou very much.

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

Hello!!!

I've tried this helpfull tutorial and it has given me some points of view. If you look example AtMega128 manual, you can see a sample code of how to use eeprom. I won't work.

I switched to this tutorial and now I can Write and Read data to EEPROM. BUT. If I make a program which saves data in to eeprom and then afterwards reads it... works fine...

When I comment the line in the code where I write the data and read it afterwards, it won't work. It just doesn't simply save the data in the eeprom.

If anybody has a some sort of solution for this. I just insert new program in to the flash.

Or my eeprom might be corrupted, cause I've ran non-L version of AtMega128 on 3,3 volts.

Or is it just me :)

Still waiting for my final developement board :)

Best regards
Juha

SW Design Engineer
Finland

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

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.

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

clawson wrote:
Sounds like you probably need to set the EESAVE fuse in your AVR. Otherwise each time you put a new program into it the EEPROM is being wiped when the "chip erase" is performed.

I just love the power of forums!!! Thank you! Never thought that would do the trick. I double checked the fuse bits and there it is! :)

Have nice weekend, you propably saved it for 47,34% :D

SW Design Engineer
Finland

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

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

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.

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

hello!

Have you tried like this?

void parceInput(char s[]) -->
void parceInput(char s*)

SW Design Engineer
Finland

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

bitfox,

But those are identical? (an array name is a pointer to a block of bytes of that array type)

Cliff

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

It doesn't build if I use void parceInput(char s*)

../atmega8515EEPROM.c:24: error: expected ';', ',' or ')' before '*' token

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

That's because he got it wrong. He meant:

void parceInput(char *s)

Pages