eeprom read and write

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi guys! i have strange problem for read and write the eeprom on an atmega328p...

i included in the project, the header file eeprom.h

in the code i wrote:

if press the button
eeprom_write_word (100,100); //Save the number 100 in location memory 100

and then i wrote:

VAR = (int)eeprom_read_word(100);

when i press the button the write code go running... and i can see in "VAR" the value "100"

but if i reboot the micro i can't have the 100 value in the eeprom... like if that is a volatile location memory...

i use the same code in an atmega16 and work correctly...

where is the wrong?

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

Post code please.

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

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

Also note that you should not be using absolute addressing like "100". Just let the linker position EEMEM vars like it does for vars in RAM and flash (PROGMEM). That is:

int this_in_EE EEMEM;
int this_in_RAM;

eeprom_write_word(&this_in_EE, 100);

this_in_RAM = eeprom_read_word(&this_in_EE);

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

clawson wrote:
Also note that you should not be using absolute addressing like "100".

Why is using an absolute address a problem? (you did use should not)
Am I missing something?

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

If you have absolute (self-chosen) addresses and addresses assigned by the linker in your code, chances are that your variables will overlap.

Also, when writing code that is supposed to be portable between smaller and larger devices, there's a chance that a self-chosen address is not available on the smaller device.

The linker will not report EEMEM usage correctly.

I tend to post off-topic replies when I've noticed some interesting detail.
Feel free to stop me.

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

Quote:

Why is using an absolute address a problem? (you did use should not)
Am I missing something?

Oh it's not a problem if you want to do the job of a linker. In a "normal" C program you'd be quite at liberty to do this too:

int n;
long l;
char c;

int main(void) {
  l = n * c;
}

replace with:

#define addrN 0x60
#define addrL 0x62
#define addrC 0x66

int main(void) {
  *((long *)addrL) = *((int *)addrN) * *((char *)addrC);
}

They both generate the same code:

  l = n * c;
   1f08c:	40 91 66 00 	lds	r20, 0x0066
   1f090:	50 e0       	ldi	r21, 0x00	; 0
   1f092:	20 91 60 00 	lds	r18, 0x0060
   1f096:	30 91 61 00 	lds	r19, 0x0061
   1f09a:	42 9f       	mul	r20, r18
   1f09c:	c0 01       	movw	r24, r0
   1f09e:	43 9f       	mul	r20, r19
   1f0a0:	90 0d       	add	r25, r0
   1f0a2:	52 9f       	mul	r21, r18
   1f0a4:	90 0d       	add	r25, r0
   1f0a6:	11 24       	eor	r1, r1
   1f0a8:	aa 27       	eor	r26, r26
   1f0aa:	97 fd       	sbrc	r25, 7
   1f0ac:	a0 95       	com	r26
   1f0ae:	ba 2f       	mov	r27, r26
   1f0b0:	80 93 62 00 	sts	0x0062, r24
   1f0b4:	90 93 63 00 	sts	0x0063, r25
   1f0b8:	a0 93 64 00 	sts	0x0064, r26
   1f0bc:	b0 93 65 00 	sts	0x0065, r27
  *((long *)addrL) = *((int *)addrN) * *((char *)addrC);
   1f0c0:	40 91 66 00 	lds	r20, 0x0066
   1f0c4:	50 e0       	ldi	r21, 0x00	; 0
   1f0c6:	20 91 60 00 	lds	r18, 0x0060
   1f0ca:	30 91 61 00 	lds	r19, 0x0061
   1f0ce:	42 9f       	mul	r20, r18
   1f0d0:	c0 01       	movw	r24, r0
   1f0d2:	43 9f       	mul	r20, r19
   1f0d4:	90 0d       	add	r25, r0
   1f0d6:	52 9f       	mul	r21, r18
   1f0d8:	90 0d       	add	r25, r0
   1f0da:	11 24       	eor	r1, r1
   1f0dc:	aa 27       	eor	r26, r26
   1f0de:	97 fd       	sbrc	r25, 7
   1f0e0:	a0 95       	com	r26
   1f0e2:	ba 2f       	mov	r27, r26
   1f0e4:	80 93 62 00 	sts	0x0062, r24
   1f0e8:	90 93 63 00 	sts	0x0063, r25
   1f0ec:	a0 93 64 00 	sts	0x0064, r26
   1f0f0:	b0 93 65 00 	sts	0x0065, r27

However personally I am happier for the linker to lay out those variables in memory for me. For the #define one I had to think (OK not THAT hard in this example) as to what offsets to use to make room for 2, 4 and 1 bytes and I also had to know that the "safe" place to start storing my made up variables was 0x0060 (this was mega16).

I just don't see why you'd want to take on the job of the linker when you have a perfectly good linker to nicely layout and prevent overlaps in memory for you?

If I added a "char foo[3];" at the front of the above in the "normal" version the linker would just pick a new layout, in the latter I'd have to go down my list of manually chosen addresses adding 3 to each:

#define addrFOO 0x60
#define addrN 0x63
#define addrL 0x65
#define addrC 0x69

Now maybe OP had a perfectly valid reason for choosing the arbitrary 100 and good luck to him but I rather suspect (based on 10's of prior threads like this) it's simply misunderstanding or ignorance of the planned use that lead to this.

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

While I wouldn't hardcode addresses as immediate values wherever I use them, I too fail to see what the problem would be with using specific addresses for a tiny resource like eeprom.

On the contrary, I would prefer to stay completely in charge of what goes where. That allows me to distribute the wear, as opposed to ruining the darn thing way ahead of time.

Sid

Life... is a state of mind

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

I would agree 100% about avoiding absolute locations in SRAM or FLASH. Just let the compiler and linker sort them out. A new build or version release will not care whether the variables mave moved.

However, you commonly use EEPROM for configuration or parameters. And you want to retain this data when the firmware is updated.

So you would have to be very careful with how your toolchain allocates EEPROM storage.

If you use only absolute locations, you can ensure that your EEPROM data will be accessible regardless of the toolchain.

As a parallel, think of a SD Card. The configuration data, FAT locations etc are all at fixed offsets in a 512 byte 'sector'. And have a specified endianness. Hence you can use AVR, ARM, SPARC, ... and still access safely regardless of language or tools.

David.

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

Quote:

So you would have to be very careful with how your toolchain allocates EEPROM storage.

If that's a concern:
struct {
 int this;
 char has
 long a;
 float fixed;
 short layout;
} EEMEM config_info;

Quote:

FAT locations etc are all at fixed offsets in a 512 byte 'sector'

Yup:
typedef struct _MBR_BLOCK { 
  U8 Res[450]; 
  U8 Type; 
  U8 Res1[3]; 
  U32 StartSector; 
  U32 TotalSector; 
  U8 Res2[50]; 
} MBR_BLOCK,* PMBR_BLOCK; 

typedef struct _BPB_BLOCK { 
  U8 BS_jmpBoo[3]; 
  U8 BS_OEMName[8]; 
  U16 BPB_BytesPerSec;		// 
  U8 BPB_SecPerClus;		// 
  U16 BPB_RsvdSecCn;		// 
   
  U8 BPB_NumFATs; 
  U16 BPB_RootEntCnt;		// 
  U16 BPB_TotSec16; 
  U8 BPB_Media; 
  U16 BPB_FATSz16; 
  U16 BPB_SecPerTrk; 
  U16 BPB_NumHeads; 
  U32 BPB_HiddSec; 
   
  U32 BPB_TotSec32; 
  U32 BPB_FATSz32;		// 
  U16 BPB_ExtFlags; 
  U16 BPB_FSVer; 
  U32 BPB_RootClus;		// 
   
  U16 BPB_FSInfo; 
  U16 BPB_BkBootSec; 
  U8 BPB_Reserved[12]; 
   
  U8 BS_DrvNum; 
  U8 BS_Reserved1; 
  U8 BS_BootSig; 
  U32 BS_VolID; 
  U8 BS_VolLab[11]; 
  U8 BS_FilSysType[8]; 
  U8 ExecutableCode[420]; 
  U8 Marker[2]; 
 
} BPB_BLOCK,*PBPB_BLOCK; 

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

You still don't know where exactly that config_info will be stored if other structs in EEPROM are added or removed as the firmware evolves.

I tend to post off-topic replies when I've noticed some interesting detail.
Feel free to stop me.

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

I personally fail to see the point of the RAM variable absolute positioning example as an argument that absolute positioning should not be used in eeproms.

The absolute positioning in eeprom can be very useful in some cases while I'm not sure of the advantage of placing RAM variables in absolute positions.

One example I can think of for EEPROM is for chips with multiple RC calibration bytes (like mega8) that can be stored in a specific position in eeprom by the programmer device so that the programmed code can read it and set the OSCCAL without a single change of line between different chips.

Another example is when you store data in the eeprom that you intend to read using the programmer, unless you know the position of each variable it will be hard to do.

You can also store default values for settings that a user shouldn't access, these can be read from the application to apply them as defaults and they can be changed with a change of the eeprom data using the programmer device without having to recompile the code to apply new defaults values to the eeprom variables in the C code.

Alex

"For every effect there is a root cause. Find and address the root cause rather than try to fix the effect, as there is no end to the latter."
Author Unknown

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

I am still waiting for an explanation as to how it is a problem to use specific addresses for storing stuff in eeprom.

In my tiny little brain, using specific addresses is the only sensible way to use eeprom for data that changes over time.

Sid

Life... is a state of mind

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

It is not a problem per se, but tell the linker where you want the variables to be placed (in its own section). The linker will then do it for you.

A quick search revealed this thread, which deals with progmem, but it outlines the steps you need to take:

https://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=56333

And I found one on eeprom sections:

https://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=911429

I tend to post off-topic replies when I've noticed some interesting detail.
Feel free to stop me.