Forum: Mikrocontroller und Digitale Elektronik EEPROM Zugriff beim ATMega


von Christian S. (mueke)


Lesenswert?

Hallo Leute,
ich möchte in meinem Programm bestimmte Variablen im EEPROM speichern, 
um diese später wieder laden zu können. Ich kriege das irgendwie aber 
nicht hin.
Arbeite mit der avr-libc (#include <avr/eeprom.h>).
Wenn ich jetzt aber was an eine Adresse schreiben möchte (siehe 
Quelltext) wird immer an die Adresse 0x007A geschrieben, egal was ich 
übergebe. Woran liegt das?
1
uint8_t i1;
2
uint16_t i;
3
4
                        // Anfangsadresse generieren
5
      i = temp * 5;
6
      // Warten bis EEPROM bereit ist
7
      eeprom_busy_wait();
8
      // Word STEPS in EEPROM schrieben
9
      eeprom_write_word(&i, STEPS);
10
      // Adresse um 2 erhöhen (2Byte (1Word) weiter)
11
      i1 = (uint8_t)i + 2;
12
      // Warten bis EEPROM bereit ist
13
      eeprom_busy_wait();
14
      // Byte FREQ in EEPROM schreiben 
15
      eeprom_write_byte(&i1, FREQ);
16
      // Adresse um 1 erhöhen (1Byte weiter)
17
      i1++;
18
      // Warten bis EEPROM bereit ist
19
      eeprom_busy_wait();
20
      // Byte VREF in EEPROM schreiben 
21
      eeprom_write_byte(&i1, VREF);
22
      // Adresse um 1 erhöhen (1Byte weiter)
23
      i1++;
24
      // Warten bis EEPROM bereit ist
25
      eeprom_busy_wait();
26
      // Byte L297 in EEPROM schreiben 
27
      eeprom_write_byte(&i1, L297);

Ich bitte um eure Hilfe... Oder kann es auch einfach sein, dass der 
Simulator im AVR-Studio das nicht ganz hinkriegt?

MfG
Muecke

von l00k (Gast)


Lesenswert?

Du veränderst den Inhalt von i und i1 übergibst der Funktion 
eeprom_write_word aber nur die Adresse von i/i1. Diese wird aber mit der 
Deklaration schon festgelegt und ändert sich dann nicht mehr.

Wenn Du also überall das '&'-Zeichen entfernst, sollte es klappen.

von Christian S. (mueke)


Lesenswert?

Danke...
wo dus jetzt so sagst, fällts mir wie Schuppen von den Augen.....

Aber wenn ich diese "&" entferne, bekomme ich folgende Warnungen:
1
passing argument 1 of 'eeprom_write_byte/word' makes pointer from integer without a cast

Woran liegt das. Was muss ich verbessern, dass diese nicht mehr 
erscheinen?

MfG
Muecke

von l00k (Gast)


Lesenswert?

Also der Deklaration von eeprom_write_byte nach, wird die Adresse als 
Zeiger übergeben. Warum auch immer. Demnach hättest Du es ursprünglich 
richtig gemacht.

Offensichtlich muß aber doch die Adresse als Wert übergeben werden. 
Sonst hätte er beim ersten Versuch nicht immer an die selbe Adresse 
geschrieben.

Evtl. hilft ein Cast:
eeprom_write_word((uint16_t *)i, STEPS);

Kann aber echt nicht sagen, was hier das Zeigergeraffel soll...

von Christian S. (mueke)


Lesenswert?

OK. Danke...
Bei dem eeprom_write_word(...) funktioniert das mit dem cast zum pointer 
(Keine Warnung mehr). Wenn ich dann den cast entsprechend so anwende
1
eeprom_write_byte((uint8_t *)i1, VREF)
 bekomme ich folgende Warnung:
1
cast to pointer from integer to different size

Aber es wird laut Dolumentation doch ein Pointer vom typ uint8_t * 
erwartet. Was hat denn da jetzt ne flasche Größe?

MfG
Muecke

von l00k (Gast)


Lesenswert?

Die Adresse muß in jedem Fall 16-Bit breit sein. Der M8 hat z.B. 512Byte 
EEPROM. Mit einer 8-Bit-Adresse könnte man max. 256Byte adressieren.

Die Dokumentation sagt zwar:
1
void eeprom_write_byte  (  uint8_t *  addr,  uint8_t val )

aber ich glaube die ist Schrott...

Probiers mal so:
1
eeprom_write_byte((uint16_t *)i1, VREF);

Ich weiß schon, warum ich die Biester immer in Assembler programmiere... 
;-)

von l00k (Gast)


Lesenswert?

Nachtrag:

lass i1 ganz weg. Wie gesagt, kannst Du mit i1 max. 256Byte adressieren.

Also:
eeprom_write_byte((uint16_t *)i, VREF);

von Christian S. (mueke)


Lesenswert?

Ja, ich habe mich auch schon gewundert, warum ich da ne 8bit-Adresse 
übergeben muss... Naja, so ganz gibt das kein Sinn.

Danke für die Hilfe...

MfG
Muecke

von Karl H. (kbuchegg)


Lesenswert?

Wie wäre es, wenn ihr beiden C Helden euch mal
im Tutorial anschaut wie man das richtig macht.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#EEPROM

> warum ich da ne 8bit-Adresse übergeben muss...

Ein uint8_t * ist keineswegs eine 8 Bit Adresse.
Die Adresse hat soviele Bits wie das System vorschreibt
das ein Pointer haben soll. Aber das worauf der Pointer
zeigt, das hat 8 Bit. Und nachdem ein Byte 8 Bit hat, ist
ein uint8_t * in
1
void eeprom_write_byte  (  uint8_t *  addr,  uint8_t val )

absolut ok und auch richtig. Du willst 1 Byte schreiben, also
brauchst du auch einen Pointer der auf 1 Byte zeigt.

von Mueke (Gast)


Lesenswert?

Hallo Herr Buchegger,
danke für den Tip auf das Tutorium, aber das habe ich mir schon 
angeschaut und steige da nicht wirklich durch.
Sag mir doch bitte mal konkret, was ich in dem obigen Quelltext 
verändern muss, damit im EEPROM die Variablen STEPS (18bit), FREQ, VREF 
und L297 (8bit) hintereinander geschrieben werden, ab einer bestimmten 
Anfangsadresse?+

MfG
Muecke

von Karl H. (kbuchegg)


Lesenswert?

> ab einer bestimmten Anfangsadresse?+

Ist es wichtig, dass die Anfangsadresse vergeben werden kann.
Wenn nicht, dann benutze den EEMEM Ansatz wie im Tutorial.

Wenn die Adresse allerdings wichtig ist, dann kannst du das
zb so machen:
1
#include <avr/eeprom.h>
2
3
#define START_ADDR    127
4
5
#define STEPS_ADDR   (uint16_t*)(START_ADDR)
6
#define FREQ_ADDR    (uint8_t*)(START_ADDR + 2)
7
#define VREF_ADDR    (uint8_t*)(START_ADDR + 3)
8
#define L297_ADDR    (uint8_t*)(START_ADDR + 4)
9
10
uint16_t Steps;
11
uint8_t  Freq;
12
uint8_t  VRef;
13
uint8_t  L297;
14
15
void foo()
16
{
17
  eeprom_write_word( STEPS_ADDR, Steps );
18
  eeprom_write_byte( FREQ_ADDR, Freq );
19
  eeprom_write_byte( VREF_ADDR, VRef );
20
  eeprom_write_byte( L297_ADDR, L297 );
21
}

von Karl H. (kbuchegg)


Lesenswert?

Eine andere Möglichkeit, die das lästige und fehlerträchtige
Bytezählen bei den #define vermeidet, wäre das hier:
1
#include <avr/eeprom.h>
2
3
#define START_ADDR    ((void*)127)
4
5
struct config_t {
6
   uint16_t Steps;
7
   uint8_t  Freq;
8
   uint8_t  VRef;
9
   uint8_t  L297;
10
};
11
12
struct config_t Config;
13
14
void foo()
15
{
16
  eeprom_write_block( &Config, START_ADDR, sizeof Config );
17
}
18
19
int main()
20
{
21
  Config.Steps = 15;
22
  Config.Freq = 18;
23
  Config.VRef = 19;
24
  Config.L297 = 20;
25
26
  foo();
27
28
  while( 1 )
29
    ;
30
}

Aber das Prinzip ist immer das gleiche:
Wenn ich das Zeugs auf eine bestimmte Adresse haben will, dann
nehme ich die Adresse als Zahlenwert und caste den Zahlenwert um
in den benötigten Pointertyp.

von Christian S. (mueke)


Lesenswert?

Danke für die Hilfe...

Mein Problem besteht darin, dass die Anfangsadresse erst über den 
I2C-Bus übermittelt wird. Daraus berechnen sich dann die weiteren 
Adressen.
Ich habe bei meinem uC 32 Speicherplätze vorgesehen, die über den 
I2C-Bus angesprochen werden können...
Das höherweritge Nibble bestimmt ob gelesen, oder geschrieben werden 
soll (0xC... und 0xD... laden, 0xE... und 0xF... speichern).
das untere Nibble bestimmt dann die Speicherstelle und somit auch die 
Anfangsadresse. Da ich 5Bytes in das EEPROM schreibe, multipliziere ich 
das niederwertige Nibble mit 5 und habe somit meine Anfangsadresse.

z.B.:
Es wird 0xE0 empfangen:
              speichern, da oberes Nibble = E
              Anfangsadresse = 0 * 5 = 0

Es wird 0xE2 empfangen:
              speichern, da oberes Nibble = E
              Anfangsadresse = 2 * 5 = 0xA

MfG
Muecke

von Karl H. (kbuchegg)


Lesenswert?

Christian Schmalor wrote:
> Danke für die Hilfe...
>
> Mein Problem besteht darin, dass die Anfangsadresse erst über den
> I2C-Bus übermittelt wird. Daraus berechnen sich dann die weiteren
> Adressen.

OK. Dann muss die Adresse in eine Variable.
1
#include <avr/eeprom.h>
2
3
struct config_t {
4
   uint16_t Steps;
5
   uint8_t  Freq;
6
   uint8_t  VRef;
7
   uint8_t  L297;
8
};
9
10
struct config_t Config;
11
12
void foo( void* StartAddr )
13
{
14
  eeprom_write_block( &Config, StartAddr, sizeof Config );
15
}
16
17
int main()
18
{
19
  uint8_t Command = 0xE2;
20
21
  //
22
  // wohin soll geschrieben werden
23
  //
24
  uint8_t * Addr = (uint8_t*)( ( Command & 0x0F ) * 5 );
25
26
  //
27
  // was soll geschrieben werden
28
  //
29
  Config.Steps = 15;
30
  Config.Freq = 18;
31
  Config.VRef = 19;
32
  Config.L297 = 20;
33
34
  foo( Addr );
35
36
  while( 1 )
37
    ;
38
}

  

von Karl H. (kbuchegg)


Lesenswert?

Oder eben mit einzelnen writes
1
#include <avr/eeprom.h>
2
3
uint16_t Steps;
4
uint8_t  Freq;
5
uint8_t  VRef;
6
uint8_t  L297;
7
8
void foo( uint8_t* Addr )
9
{
10
  eeprom_write_word( (uint16_t*)Addr, Steps );
11
  Addr += sizeof Steps;
12
  eeprom_write_byte( Addr, Freq );
13
  Addr += sizeof Freq;
14
  eeprom_write_byte( Addr, VRef );
15
  Addr += sizeof VRef;
16
  eeprom_write_byte( Addr, L297 );
17
}
18
19
int main()
20
{
21
  uint8_t Command = 0xE2;
22
23
  //
24
  // wohin soll geschrieben werden
25
  //
26
  uint8_t * Addr = (uint8_t*)( ( Command & 0x0F ) * 5 );
27
28
  //
29
  // was soll geschrieben werden
30
  //
31
  Steps = 15;
32
  Freq = 18;
33
  VRef = 19;
34
  L297 = 20;
35
36
  foo( Addr );
37
38
  while( 1 )
39
    ;
40
}

Aber die struct Lösung ist deutlich schöner :-)

von Christian S. (mueke)


Lesenswert?

Danke dir für deine Hilfe....

Ich werde es jetzt in meinem Programm versuchen umzusetzen...

Wenn ich das Programm jetzt simuliere im avr-studio und mir das struct 
in mein "Watch"-Window hole, kann ich alle Variablen ja ein Wert 
zuweisen, nur nicht der letzten Variable im Struct, warum? Alle anderen 
Variablen kann ich dort Werte zuweisen, ur nicht der letzten Variable im 
Struct. Ich habe die Variablen im Struct vertauscht und es geht nicht 
bei der letzten Variablke im Struct. Ich habe es so definiert:

struct config_t{
     uint16_t STEPS;
     uint8_t FREQ;
     uint8_t VREF;
     uint8_t L297;
}Config;

von Karl H. (kbuchegg)


Lesenswert?

Christian Schmalor wrote:

> Wenn ich das Programm jetzt simuliere im avr-studio und mir das struct
> in mein "Watch"-Window hole, kann ich alle Variablen ja ein Wert
> zuweisen, nur nicht der letzten Variable im Struct, warum?

Keine Ahnung.
Fehler im AVR Studio
Fehler im Debugger

von Christian S. (mueke)


Lesenswert?

OK. Danke. Das mit dem schreiben und lesen ausm EEPROM fukntioniert 
jedenfalls.
Danke schön

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.