PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : EEPROM - Adresse



Andun
14.03.2006, 09:33
Moin

Also folgendes Problem: Ich will auf den EEPROM schreiben und lesen (so ein zufall aber auch...)

Jetzt will ich nach dem Neustart wieder auf die selben Daten zugreifen. Dafür muss ich aber wissen welche Adresse die Daten haben. Und mein Problem ist jetzt, dass ich nciht weiß wie das mit den Adressen aussieht. Das Datenblatt hat mir da irgendwie nicht wirklich geholfen.

Achja und noch was: Wenn ich mit eeprom_wirte_byte(adresse, inhalt) einen Wert schreibe, dann muss doch vorher noch kein Platz definiert sein müssen, oder irre ich mich da? So versteh ich nämlich diese Sonderheiten des EEPROM.

Also meine eigentlcih Frage ums mal auf den Punkt zu bringen: Ich will bei jedem Start zuerst die ersten beiden Bytes im Speicher auslesen, weil ich mir gedacht habe, in diesen zu speichern, wo ich hinten weiter machen kann mit schreiben.
Wenn ich die Daten dann auslese, dann setzte ich diesen "Pointer" wieder auf den Anfang und ich kann den Speicher wieder voll schreiben.

Ich hoffe ihr habt verstanden was ich von euch will. Also wo fängt denn jetzt der Speicher im EEPROM an? Einfach bei 0x00? und ist dann das 2. Byte bei 0x08? oder wie ist das zu verstehen?

Danke

Andun

SprinterSB
14.03.2006, 09:53
Du kannst
1) Dir die Adressen der Daten selber raussuchen, also etwa schreiben (void*) 0x123
2) Du kannst Daten ins EEPROM lokatieren:


#define EEMEM __attribute__ ((section (".eeprom")))

foo_t foo_sram;
foo_t foo1 EEMEM;
foo_t foo2 EEMEM =
{
.member1 = 1,
.member2 = 2
};

eeprom_read_block (&foo_sram, &foo1, sizeof (foo_t));
foo_sram.member1 = eeprom_read_word (&foo2.member1);

Andun
14.03.2006, 10:25
Moin

Danke schon mal für deine Antwort. Ich glaube die habe ich auch verstanden. Allerdings beantwortet das meine Frage glaub ich noch nicht ganz so gut. Das Problem was ich hab, ist dass ich ja auch nach nem RESET wieder auf die selben Daten zugreifen will. Dann hab ich im Speicher die adresse von foo1 und foo2 nicht mehr, oder?
Deswegen dachte ich mir, ich schreib die Ausgangsadresse meiner Daten immer an Speicherposition 0.

Dann les ich dort immer den Pointer aus, wo cih den nächsten Wert im EEPROM hinschreiben muss.

Hab cih da nen Denkfehler drin, oder bin cih nur zu blöd zu merken, dass du mir das schon beantwortet hast?

Danke

Andun

Nachtrag:
Hier mal mein Code bis jetzt:


adress = eeprom_read_word(0x00);
#if DEBUG
uart_puts("Ich werde bei "); PrintInt(adress); uart_puts(" anfangen in den EEPROM zu schreiben.");
#endif
eeprom_write_byte((uint8_t*)adress, sek[0]); adress += 8;
eeprom_write_byte((uint8_t*)adress, min[0]); adress += 8;
eeprom_write_byte((uint8_t*)adress, hour[0]); adress += 8;
eeprom_write_byte((uint8_t*)adress, date[0]); adress += 8;
eeprom_write_byte((uint8_t*)adress, mon[0]); adress += 8;
eeprom_write_byte((uint8_t*)adress, Sensordaten.luftdruck); adress += 8;
eeprom_write_byte((uint8_t*)adress, Sensordaten.feuchte_komp); adress += 8;
eeprom_write_byte((uint8_t*)adress, Sensordaten.temperatur_lin); adress += 8;
eeprom_write_word(0x00, adress);

SprinterSB
14.03.2006, 10:36
foo1 und foo2 stehen im EEPROM, die Adressen werden zur Compilezeit festgelegt, oder was meinst du?

Wenn du so was machen willst, würde ich dir anraten, ne Struktur zu machen, wo das ganze Zeug drin ist, anstatt die Daten überall zu verstreuen.

Zudem belegt ein Byte nur ein Byte im EEPROM, nichte derer 8.

Evtl musst du auch was für die Konsistenz überlegen, wenn mitten im Schreiben des Saft ausgeschaltet wird.

Daten kannst du auch im SRAM einen RESET überstehen lassen, wenn es kein PowerOn-RESET oder so ist. Beispiele dazu gibt es im GCC-Artikel.

SprinterSB
14.03.2006, 10:46
typedef struct
{
uint8_t sec;
uint8_t min;
uint8_t hour;
uint8_t mon;
uint8_t year;
} time_t;

typedef struct
{
uint16_t luftdruck;
uint16_t feuchte_komp;
uint16_t temperatur_lin;
} sensor_data_t

typedef struct
{
time_t time;
sensor_data_t sensor;
} mess_data_t;

mess_data_t data;
mess_data_t * pdataEE;

pdataEE = (mess_data_t*) 0x2;

eeprom_write_block (&data, pdataEE, sizeof (data));
pdataEE++;

Andun
14.03.2006, 10:48
Also, stimmt. Das mit den 8 Byte war ein denkfehler ... ich hab irgendwie in Bit gedacht ... ???

Ne Struktur zu machen, ginge auch, hast recht. Aber mir geht es im Moment gar nciht um Sicherheit, ich will eigentlcih erstmal nur was funktionierendes auf die Beine stellen, da ich es etwas eilig habe. (Normalerweise würde ich das auch ordentlicher machen)

Also, die Daten im SRAM überleben zu lassen ist mir nicht sicher genug, da die Daten bzw. die Adressen der Daten auch nach einer kompletten Trennung vom Strom noch da sein sollen.

Also generell die Frage: Ist das denn möglich, so einfach bei 0x00 die Adresse zu hinterlegen und dann so zu benutzen?

(Achja, ist der cast zu den Pointern so richtig mit (uint8_t*)adress ?)

Danke

Andun

SprinterSB
14.03.2006, 10:54
SO wie du adress benutzt, sollte es ohnehin vom Typ uint8_t* sein. Ansonsten kannst du bös auf die Nase fallen mit adress++ oder adress+=10. Zwar merkst du das nicht, weil du den Fehler beim Lesen und Schreiben machst, aber du hast dann viele "Löcher" in der EEPROM-Nutzung.

Den EE-Routinen sollte es egal sein, da müsste auch ein void* gehen.

Andun
14.03.2006, 11:04
Aha, ok. Ich werde das ganze jetzt erstmal in ein Struct bauen, scheint doch irgendwie sicherer, aber muss ich jetzt eigentlcih die adress immer um 1 weiter zählen um zum nächsten byte zu kommen oder um 8? Also geht das in Byte oder Bit?

Ich werde das ganze, aber dann jetzt gleich auch einfach mit adress += sizeof(struct Messung) machen. Dass sollte doch dann gehen, oder?

In die Struktur tu ich dann die 8Bytes mit der Uhrzeit und den Messdaten.

Andun

SprinterSB
14.03.2006, 11:09
Die Semantik von

blah_t * pointer;
int n;

pointer += n; // Das ist (wenn man pointer als int ansieht) pointer += n*sizeof (blah_t)

Ist Pointer also ein Zeiger auf long und steht pointer auf 0x9, dann steht er nach point++ auf 0xd (zumindest auf avr).

Andun
14.03.2006, 11:13
Achsoooooo, also zeigt der Pointer wenn ich ihn um 1 hochzähle auf den nächsten Wert, wenn man annimmt, dass alle gleich groß sind.

(Mein Satz klingt wahrscheinlich bescheuert, aber ich bin mir sicher, dass ich es verstanden habe. Erklären können muss cih es ja nciht unbedingt :D)

Gut, dann leg ich jetzt die Struktur an und speichere diese und erhöhe dann den Pointer (der ein Pointer auf diese Struktur ist) um 1. Dann zeigt der zeiger direkt hinter die Struktur im Speicher.

So, das ist doch endlcih richitg verstanden oder?

Andun
14.03.2006, 11:58
So, ich denke so müsste es klappen. Der Compiler meldet keinen Fehler mehr ich hoffe nur, die Logik stimmt auch so.



typedef struct {
uint8_t min, sek, hour, date, mon, year, druck, feuchte, temp;
} Messung;
. . .
Messung aktMessung;
Messung * adress;
Messung * i;
...
int main() {
...
case 6: //Teil einer Eingabe Aufforderung
uart_puts("Alle Werte aus dem EEPROM auslesen\r\n");
adress = (Messung*) eeprom_read_word(0x00);
for(i=(Messung*)0x02; i < adress; i++) {
//Ich will die Werte solange auslesen, bis ich bei der letzten Eingetragenen Messung angekommen bin
eeprom_read_block(&aktMessung, i, sizeof(Messung));
//Ausgabe von aktMessung über uart...
//...
}
break;
case 7:
uart_puts("EEPROM Zeiger reseten.\r\n");
eeprom_write_word(0, ((uint16_t)(Messung*)0x02));
/*Ist das so richtig, oder zeigt er dann wo falsch hin. Ich dachte mir, ich nehm 2 mal die breite der Struktur und dann muss dass ganze ja aber natürlich wieder zum uint16_t werden für die funktion. */
break;
//...
} // Ende main();
//...
void speichern() { //Speichert die Werte aus aktMessung in den EEPROM
#if DEBUG
uart_puts("Alle Werte der letzten aktuellen Messung speichern.\r\n");
#endif

adress = (Messung*) eeprom_read_word(0x00);
//Überprüfung ob noch Platz ist im EEPROM
if( (uint16_t)adress < 60) { /*512 Byte im Speicher / 8Byte pro Struktur = 64. Sicherheitshalbe hab ich 60 genommen.*/
#if DEBUG
uart_puts("Ich werde bei "); PrintInt((uint16_t)adress); uart_puts(" anfangen in den EEPROM zu schreiben.\r\n");
#endif
eeprom_write_block( &aktMessung, adress, sizeof(aktMessung)); adress += 1;
eeprom_write_word(0x00, (uint16_t)adress);
}
else {
uart_puts("FEHLER: Kein Platz mehr im EEPROM!!!\r\n");
}
}


Könnte sich das vielleicht nochmal jemand ansehen und mich über logische Fehler aufklären? Ich werde es nachher auf den Mega16 spielen, aber ich seh das schon kommen, dass da ncihts geht und ich den Fehler nciht finde ...

Danke

Andun

SprinterSB
14.03.2006, 19:34
So auf Anhieb sieht's ganz ok aus.

Für die letzte Adresse des EEPROMs gibt's das Define E2END (avr/io.h):
if ((uint16_t) adress <= E2END+1-sizeof(Messung)) {...}

Der Cast auf einen Pointer wechselt nur den Typ, der Wert als ganze Zahl betrachtet bleibt gleich.

case 7:
(uint16_t)(Messung*)0x02 ist nicht die "Breite" der Struktur, es ist 2 und der Ort für die erste Messung. (0x02 = sizeof(void*), d.h. vor der ersten Messung steht irgendein Pointer).

Mit EEPROM-Adresse 0 hatte ich schon mal Probleme, im Wiki hab ich in den AVR-Errata was dazu geschrieben.

Andun
15.03.2006, 10:31
Moin

Danke für deine Hinweise. Das mit dem Ende vom EEPROM ist ein praktischer Hinweis, danke.

Zu dem Fehler der EEPROM Adresse 0. Ich bin nicht so ganz bewandert mit den Geschichten was mir das Makefile alles abnimmt. Wo muss das genau rein? Hier:


# Link: create ELF output file from object files.
.SECONDARY : $(TARGET).elf
.PRECIOUS : $(OBJ)
%.elf: $(OBJ)
@echo
@echo $(MSG_LINKING) $@
$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)

Oder wo muss ich da was ändern? Ich steig da leider nciht so 100%ig durch.


case 7:
(uint16_t)(Messung*)0x02 ist nicht die "Breite" der Struktur, es ist 2 und der Ort für die erste Messung. (0x02 = sizeof(void*), d.h. vor der ersten Messung steht irgendein Pointer).

Ähm ... ok, ich glaube ich hab verstanden, was du mir sagen willst, aber heißt dass jetzt ich muss das ändern, oder kann ich das so lassen? Bzw. sollte ich da was ändern? Ich hab das so verstanden, dass ich in den ersten beiden Bytes(0 und 1) das WORD mit der Adresse speichere und dann im 3. Byte (0x02) anfange die Daten zu speichern. Ist da ein denkfehler drinn, oder meinst du nur ich kann mir das doppelte Casten sparen?

Danke

Andun

Nachtrag:

Achja, wie sieht das eigentlcih bei sizeof() aus? Übergeb ich da als Argument den Typ oder eine Instanz des Types? Also eine feste schon deklarierte Variable oder nur den Datentyp?

SprinterSB
15.03.2006, 21:17
Am Makefile musst du nix ändern. Du lässt ja nicht gcc (bzw ld) die Lokatierung der EEPROM-Daten übernehmen, sondern suchst dir die Adressen selbst aus. Du speicherst also das Word nicht ab 0x0, sondern ab 0x1 und die erste Messung ab 0x3. That's it.

Das mit dem Rumgecaste hab ich nur gesagt, weil der Code so aussieht als wär die nicht klar, was du da eigentlich treibst... Geht aber schon so wie es da steht.

sizeof frisst beides. Sei mutig und probier's aus, oder steuert dein Prog nen Atommeiler?

Andun
15.03.2006, 23:30
Hehe, Atommeiler ... :D (Hat heute einer die Simpsons Folge gesehen? "Wie hat Homer Simpson die Kernschmelze ausgelöst? In dem Testwagen befand sich kein atomares Material?" )

Also das mit dem EEPROM hab ich mir dann grade komplizieter vorgestellt. Hab irgendwann um 20 Ecken denken wollen ... :D Das werd ich mal anpassen auch wenn cih bis jetzt bei der 0 noch keinen Fehler gefunden habe.

Also das System läuft jetzt seit Mittags und zeichnet mir schön alle 10 Minuten das "Wetter" auf. Geht gut. Ich hab halt leider immer nur für 10h Platz .... :D Ich hab schon mal ausgeleert. :D

Ihr könnt morgen ein Diagramm meines Temperaturverlaufes haben, wenn ihr wollt. :D

Danke und gute Nacht

Andun

SprinterSB
17.03.2006, 21:25
Die Zeit brauchst du nicht jedesmal mit zu speichern, oder? Es genügt doch, die Zeil am Anfang einmal zu speichern. Danach erfolgen die Messungen wohl in regelmässigen Intervallen. Damit würde es immerhin für gut einen Tag reichen.