www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik EEPROM Zugriff beim ATMega


Autor: Christian S. (mueke)
Datum:

Bewertung
0 lesenswert
nicht 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?
uint8_t i1;
uint16_t i;

                        // Anfangsadresse generieren
      i = temp * 5;
      // Warten bis EEPROM bereit ist
      eeprom_busy_wait();
      // Word STEPS in EEPROM schrieben
      eeprom_write_word(&i, STEPS);
      // Adresse um 2 erhöhen (2Byte (1Word) weiter)
      i1 = (uint8_t)i + 2;
      // Warten bis EEPROM bereit ist
      eeprom_busy_wait();
      // Byte FREQ in EEPROM schreiben 
      eeprom_write_byte(&i1, FREQ);
      // Adresse um 1 erhöhen (1Byte weiter)
      i1++;
      // Warten bis EEPROM bereit ist
      eeprom_busy_wait();
      // Byte VREF in EEPROM schreiben 
      eeprom_write_byte(&i1, VREF);
      // Adresse um 1 erhöhen (1Byte weiter)
      i1++;
      // Warten bis EEPROM bereit ist
      eeprom_busy_wait();
      // Byte L297 in EEPROM schreiben 
      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

Autor: l00k (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Christian S. (mueke)
Datum:

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

Aber wenn ich diese "&" entferne, bekomme ich folgende Warnungen:
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

Autor: l00k (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Christian S. (mueke)
Datum:

Bewertung
0 lesenswert
nicht 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
eeprom_write_byte((uint8_t *)i1, VREF)
 bekomme ich folgende Warnung:
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

Autor: l00k (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
void eeprom_write_byte  (  uint8_t *  addr,  uint8_t val )  

aber ich glaube die ist Schrott...

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

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

Autor: l00k (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag:

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

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

Autor: Christian S. (mueke)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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-Tu...

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

Autor: Mueke (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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:
#include <avr/eeprom.h>

#define START_ADDR    127

#define STEPS_ADDR   (uint16_t*)(START_ADDR)
#define FREQ_ADDR    (uint8_t*)(START_ADDR + 2)
#define VREF_ADDR    (uint8_t*)(START_ADDR + 3)
#define L297_ADDR    (uint8_t*)(START_ADDR + 4)

uint16_t Steps;
uint8_t  Freq;
uint8_t  VRef;
uint8_t  L297;

void foo()
{
  eeprom_write_word( STEPS_ADDR, Steps );
  eeprom_write_byte( FREQ_ADDR, Freq );
  eeprom_write_byte( VREF_ADDR, VRef );
  eeprom_write_byte( L297_ADDR, L297 );
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eine andere Möglichkeit, die das lästige und fehlerträchtige
Bytezählen bei den #define vermeidet, wäre das hier:
#include <avr/eeprom.h>

#define START_ADDR    ((void*)127)

struct config_t {
   uint16_t Steps;
   uint8_t  Freq;
   uint8_t  VRef;
   uint8_t  L297;
};

struct config_t Config;

void foo()
{
  eeprom_write_block( &Config, START_ADDR, sizeof Config );
}

int main()
{
  Config.Steps = 15;
  Config.Freq = 18;
  Config.VRef = 19;
  Config.L297 = 20;

  foo();

  while( 1 )
    ;
}

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.

Autor: Christian S. (mueke)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.
#include <avr/eeprom.h>

struct config_t {
   uint16_t Steps;
   uint8_t  Freq;
   uint8_t  VRef;
   uint8_t  L297;
};

struct config_t Config;

void foo( void* StartAddr )
{
  eeprom_write_block( &Config, StartAddr, sizeof Config );
}

int main()
{
  uint8_t Command = 0xE2;

  //
  // wohin soll geschrieben werden
  //
  uint8_t * Addr = (uint8_t*)( ( Command & 0x0F ) * 5 );

  //
  // was soll geschrieben werden
  //
  Config.Steps = 15;
  Config.Freq = 18;
  Config.VRef = 19;
  Config.L297 = 20;

  foo( Addr );

  while( 1 )
    ;
}

  

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oder eben mit einzelnen writes
#include <avr/eeprom.h>

uint16_t Steps;
uint8_t  Freq;
uint8_t  VRef;
uint8_t  L297;

void foo( uint8_t* Addr )
{
  eeprom_write_word( (uint16_t*)Addr, Steps );
  Addr += sizeof Steps;
  eeprom_write_byte( Addr, Freq );
  Addr += sizeof Freq;
  eeprom_write_byte( Addr, VRef );
  Addr += sizeof VRef;
  eeprom_write_byte( Addr, L297 );
}

int main()
{
  uint8_t Command = 0xE2;

  //
  // wohin soll geschrieben werden
  //
  uint8_t * Addr = (uint8_t*)( ( Command & 0x0F ) * 5 );

  //
  // was soll geschrieben werden
  //
  Steps = 15;
  Freq = 18;
  VRef = 19;
  L297 = 20;

  foo( Addr );

  while( 1 )
    ;
}

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

Autor: Christian S. (mueke)
Datum:

Bewertung
0 lesenswert
nicht 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;

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Christian S. (mueke)
Datum:

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.