Forum: Mikrocontroller und Digitale Elektronik AVR Frage zu EEPROM Zugriff


von Marco (Gast)


Lesenswert?

Hi und hallo,

ich versuche gerade mal Daten im EEPROM eines Controllers zu speichern. 
Dazu bin ich auf ein Beispiel gestoßen:

http://blog.cc-robotics.de/2009/03/20/einstellungen-im-eeprom-eines-avr-speichern/

Bei der ein oder anderen Sache, habe ich noch nicht ganz raus, was da 
wirklich passiert. Bei Folgendem z.B.:
1
#define EEPROM_SECTION  __attribute__ ((section (".eeprom")))

Wenn ich das richtig verstehe, wird EEPROM_SECTION durch irgendwas 
ersetzt, nur durch was genau. Da habe ich noch nicht den richtigen 
Durchblick.

Wird dann überall wo später im Code "EEPROM_SECTION" steht das 
"__attribute__ ((section (".eeprom")))" eingefügt?

Was bedeutet das "__attribute__ ((section (".eeprom")))"? Ist das 
einfach eine Compileranweisung für EEPROM oder was?

Würde mich freuen, wenn jemand vielleicht ein klein wenig Licht ins 
Dunkle bringen könnte.

Besten Dank!
Beste Grüße
Marco

von Krapao (Gast)


Lesenswert?

Das Ersetzen hast du richtig erkannt.

Es ist eine einfache Anweisung für den C-Präprozessor
#define ABC xyz
ersetzt im Programm die Makros AVC durch den xyz.

Das _attribute_ ((section (".eeprom"))) ist eine Besonderheit der AVR 
GCC Toolchain. Mit einem _attribute_ werden Bezeichner im Programm mit 
einem Kennzeichen (einem Attribut) ausgestattet. Es gibt noch andere 
Attribute, die im GCC Manual auch beschrieben sind.

Hier ist es das Kennzeichen section (".eeprom"). Sektionen sind 
Abschnitte im Speicher des µC, Hier ein Abschnitt im EEPROM. Das damit 
ausgezeichnete Element landet also später im EEPROM. Typischerweise 
werden so Daten gekennzeichnet.

Andere Sektionen sind .text für Programmcode im Flash und .data und .bss 
für Programmdaten im RAM (.data = initialisierte Daten hat auch ein 
Original im Flash). Diese Attribute kann man aber im Quelltext 
weglassen, weil der Compiler und Linker wissen wo Code und Daten hin 
sollen.

Wenn man aber Daten ausschliesslich im Flash haben möchte, verwendet man 
ein entsprechendes Attribut. Das gibt es wieder als Makro PROGMEM für 
Präprozessor. Näheres dazu im AVR-GCC-Tutorial.

Die Sektionen ("das Speicherlayout") selbst sind in Linker Control 
Skripten beschrieben, die in einem der vielen Unterordner der AVR GCC 
Toolchain für jeden AVR bzw. jede AVR Architektur eindeutig sind. 
Zusammen mit dem Startupcode (der u.a. den Stack initialisiert und die 
Daten aus dem Flash in .data im RAM kopiert) den Bibliotheksfunktionen 
und letztlich deinem Programmcode machen sie das fertige Programm aus.

von Marco (Gast)


Lesenswert?

Hi und hallo,

vielen Dank. Da werde ich wohl noch ein wenig einlesen müssen!

Ich habe jetzt einmal versucht das Beispiel umzusetzen. Leider stoße ich 
da nun auf ein Problem.

Ich habe mir jetzt eine ee.c und eine ee.h angelegt. Der Code folgt 
unten.

Mein Problem liegt jetzt nun darin, dass ich die Fehlermeldung bekomme, 
dass "eeprom_def_brightness", "eeprom_def_TempID" usw. mehrfach 
definiert sind: "multiple definition of 'dummy'",  "multiple definition 
of 'eeprom_def_brightness'".

Ich weiß aber im Moment nicht, wie ich die Sachen anders definieren 
könnte. Ich müsste die doch dann irgendwie als extern definieren oder 
so!?

Jemand eine Idee?

Besten Dank!
Beste Grüße
Marco


Hier die ee.h:
1
#define EEPROM_SECTION  __attribute__ ((section (".eeprom"))) 
2
/* 
3
** this global variables are stored in EEPROM 
4
*/ 
5
uint16_t  dummy          EEPROM_SECTION  = 0;  // avoid using lowest addresses 
6
//—————————————————————————— 
7
// section 1: default settings 
8
uint8_t   eeprom_def_brightness EEPROM_SECTION  = 1;  // EEPROM address 0002 
9
uint16_t  eeprom_def_TempID     EEPROM_SECTION  = 2;  // EEPROM address 0003 
10
uint8_t   eeprom_def_TempUnit   EEPROM_SECTION  = 3;  // EEPROM address 0005 
11
uint16_t  eeprom_def_Filter     EEPROM_SECTION  = 4;  // EEPROM address 0006 
12
uint8_t   eeprom_def_CANspeed   EEPROM_SECTION  = 5;  // EEPROM address 0008 
13
// placeholder 
14
uint16_t  eeprom_def_dummy1     EEPROM_SECTION  = 6;  // EEPROM address 0009 
15
uint16_t  eeprom_def_dummy2     EEPROM_SECTION  = 7;  // EEPROM address 000B 
16
uint8_t   eeprom_def_dummy3     EEPROM_SECTION  = 8;  // EEPROM address 000D 
17
uint8_t   eeprom_def_dummy4     EEPROM_SECTION  = 9;  // EEPROM address 000E 
18
uint8_t   eeprom_def_dummy5     EEPROM_SECTION  = 10; // EEPROM address 000F 
19
//—————————————————————————— 
20
// section 2: user settings 
21
uint8_t   eeprom_usr_brightness EEPROM_SECTION  = 11;  // EEPROM address 0010 
22
uint16_t  eeprom_usr_TempID     EEPROM_SECTION  = 12;  // EEPROM address 0011 
23
uint8_t   eeprom_usr_TempUnit   EEPROM_SECTION  = 13;  // EEPROM address 0013 
24
uint16_t  eeprom_usr_Filter     EEPROM_SECTION  = 14;  // EEPROM address 0014 
25
uint8_t   eeprom_usr_CANspeed   EEPROM_SECTION  = 15;  // EEPROM address 0016 
26
// placeholder 
27
uint16_t  eeprom_usr_dummy11    EEPROM_SECTION  = 16;  // EEPROM address 0017 
28
uint16_t  eeprom_usr_dummy12    EEPROM_SECTION  = 17;  // EEPROM address 0019 
29
uint8_t   eeprom_usr_dummy13    EEPROM_SECTION  = 18;  // EEPROM address 001B 
30
uint8_t   eeprom_usr_dummy14    EEPROM_SECTION  = 19;  // EEPROM address 001C 
31
uint8_t   eeprom_usr_dummy15    EEPROM_SECTION  = 20;  // EEPROM address 001D
32
33
//——– 
34
// EEPROM 
35
//——– 
36
// settings 
37
#define CAN_Speed 15 
38
#define CAN_Filter 14 
39
#define Temp_ID 12

Weiter habe ich eine ee.c:
1
#include   <inttypes.h>        
2
#include        <stdint.h>
3
#include  "eeprom.h"          
4
5
// returns the dataset from eeprom 
6
uint16_t get_eeprom_word(uint8_t setting) 
7
{ 
8
  uint16_t   eeprom_word; 
9
  switch (setting) 
10
  { 
11
    case 12: 
12
      eeprom_word = eeprom_read_word( &eeprom_usr_TempID ); 
13
      break; 
14
    case 14: 
15
      eeprom_word = eeprom_read_word( &eeprom_usr_Filter ); 
16
      break; 
17
    default: 
18
      break; 
19
  } 
20
  return eeprom_word; 
21
} 
22
// save data to eeprom 
23
void set_eeprom_word( uint16_t eeprom_word, uint8_t setting ) 
24
{ 
25
  switch (setting) 
26
  { 
27
    case 12: 
28
      eeprom_write_word( &eeprom_usr_TempID, eeprom_word ); 
29
        break; 
30
    case 14: 
31
      eeprom_write_word( &eeprom_usr_Filter, eeprom_word ); 
32
        break; 
33
    default: 
34
      break; 
35
  } 
36
} 
37
// returns the dataset from eeprom 
38
uint8_t get_eeprom_byte(uint8_t setting) 
39
{ 
40
  uint8_t   eeprom_byte; 
41
  switch (setting) 
42
  { 
43
    case 15: 
44
      eeprom_byte = eeprom_read_byte( &eeprom_usr_CANspeed ); 
45
        break; 
46
    default: 
47
      break; 
48
  } 
49
  return eeprom_byte; 
50
} 
51
// save data to eeprom 
52
void set_eeprom_byte( uint8_t eeprom_byte, uint8_t setting ) 
53
{ 
54
  switch (setting) 
55
  { 
56
    case 15: 
57
      eeprom_write_byte( &eeprom_usr_CANspeed, eeprom_byte ); 
58
        break; 
59
    default: 
60
      break; 
61
  } 
62
}

In der main.c versuche ich dann Folgendes:
1
...
2
#include  "eeprom.h"
3
...
4
int main(void)
5
{
6
7
    CANspeed = get_eeprom_byte(CAN_Speed);
8
    set_eeprom_byte(CANspeed, CAN_Speed);
9
    ...

von Krapao (Gast)


Lesenswert?

Das Beispiel hast du so "lauffähig" irgendwo gefunden? Dann halte ich 
von dem Beispiel nicht viel.

Die Datei sog. ee.h ist kein Includefile mit Deklarationen sondern 
enthält Definitionen, so wie sie normalerweise in ein C-Quelltext 
gehören.

Zum Unterschied Deklaration und Definition siehe ein C-Buch oder

http://www.mikrocontroller.net/articles/Include-Files_(C)
http://www.mikrocontroller.net/articles/Funktionen_auslagern_(C)
http://www.mikrocontroller.net/articles/FAQ#Header_File.2C_wie_geht_das.3F

von Krapao (Gast)


Lesenswert?

Die ersten beiden Links sind von der Forensoftware verhunzt.

von Marco (Gast)


Lesenswert?

Hallo,

vielen Dank!

Ich werde das Ganze mal ein wenig umstellen und dann noch ein wenig 
damit experimentieren.

Besten Dank!
Beste Grüße
Marco

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.