Forum: Mikrocontroller und Digitale Elektronik Eprom auf AVR nutzen


von Thomas K. (Firma: Draht_Igel) (magnoval)


Lesenswert?

Hallo,

für ein Projekt möchte ich gerne das Eeprom auf einem Mega328 nutzen.

Leider habe ich noch nie das Eeprom benutzt, ich arbeite mich gerade mit 
hilfe des Tutorials ein.

Wenn ich nun wie im Tutorial uint16_t eeFooWord EEMEM = 12345; schreibe, 
wird dann eeFooWord bei jedem Programmstart mit 12345 initialisiert, und 
ich muss erst den zuletzt gespeicherten Wert aus dem Eeprom lesen?

von Georg G. (df2au)


Lesenswert?

Der Sinn des EEPROM ist doch, dass Werte auch bei abgeschalteter Vcc 
erhalten bleiben. Insofern ist es unsinnig, beim Programmstart jedes mal 
den Wert neu ins EEPROM zu schreiben.

von Einer K. (Gast)


Lesenswert?

Thomas K. schrieb:
> Wenn ich nun wie im Tutorial uint16_t eeFooWord EEMEM = 12345; schreibe,
> wird dann eeFooWord bei jedem Programmstart mit 12345 initialisiert, und
> ich muss erst den zuletzt gespeicherten Wert aus dem Eeprom lesen?

Der Linker sollte eine *.eep Datei erzeugen.
Diese muss dann auch per ISP ausgespielt werden.

Und dann ja, dann kannst du die Werte beim Programmstart aus dem EEPROM 
lesen.

Thomas K. schrieb:
> eeFooWord bei jedem Programmstart mit 12345 initialisiert,
eeFooWord ist keine Variable im RAM.
Wird also nicht beim Programmstart initialisiert.

von Thomas K. (Firma: Draht_Igel) (magnoval)


Lesenswert?

Arduino F. schrieb:
> eeFooWord ist keine Variable im RAM.
> Wird also nicht beim Programmstart initialisiert.

hab ich vielleicht blöd geschrieben. Klar wird bei jeden Programmstart 
der Wert aus dem Eeprom neu gelesen, um damit zu arbeiten. Aber beim 
ersten Start steht dann da 12345, sprich, 12345 wird nur beim ersten 
compilieren und flashen ins Eeprom geschrieben?

von Einer K. (Gast)


Lesenswert?

Hmmm..
Was verstehst du an meiner Aussage nicht?

Ich versuche es nochmal:

Thomas K. schrieb:
> sprich, 12345 wird nur beim ersten
> compilieren und flashen ins Eeprom geschrieben?

Du kannst jederzeit neue Werte ins EEPROM schreiben.
Irgendeinen Automatismus gibt es da nicht.
Du bist für alles verantwortlich.

von Thomas K. (Firma: Draht_Igel) (magnoval)


Lesenswert?

Arduino F. schrieb:
> Hmmm..
> Was verstehst du an meiner Aussage nicht?
>
> Ich versuche es nochmal:

Hmm... ich versuchs auch nochmal, ich glaub wir reden (schreiben) 
aneinander vorbei :-)

Ich schreibe mein Programm im Studio, und bei der Deklaration der 
globalen Variablen steht dann z.B.

uint8_t p1_time EEMEM = 0;
uint8_t p2_time EEMEM = 0;
uint8_t p3_time EEMEM = 0;
uint8_t p4_time EEMEM = 0;
uint8_t p5_time EEMEM = 0;
uint8_t p6_time EEMEM = 0;

u.s.w.

Am Anfang weis ich ja nicht, was im Eeprom steht, habs ja noch nicht 
benutzt. Wenn ich meinen Code nun compiliere und den uc flashe, ohne 
preserve Eeprom, steht dann beim allerersten laden aus dem Eeprom "0" an 
der Adresse, die sich hinter dem Namen der Variablen verbirgt?

von Einer K. (Gast)


Lesenswert?

Wenn du das *.eep File auf den µC brennst, landen die Daten, also die 
Nullen, im EEPROM.
Die Variablen liegen im EEPROM.
Die Adressen der Variablen zeigen ins EEPROM.
Du kannst diese Variablen NICHT im normalen Programm nutzen.

Wenn du sie im Programm verwursten möchtest, muss du sie da raus holen. 
Denn du brauchst, um damit arbeiten zu können, ein Duplikat im RAM.

von Oliver S. (oliverso)


Lesenswert?

Thomas K. schrieb:
> Ich schreibe mein Programm im Studio, und bei der Deklaration der
> globalen Variablen steht dann z.B.
>
> uint8_t p1_time EEMEM = 0;
> uint8_t p2_time EEMEM = 0;
> uint8_t p3_time EEMEM = 0;
> uint8_t p4_time EEMEM = 0;
> uint8_t p5_time EEMEM = 0;
> uint8_t p6_time EEMEM = 0;
>
> u.s.w.

Dann sind die Werte beim auslesen halt alle 0, wenn du die Daten auch 
vorher ins Eeprom geschrieben hast.

Es gibt zwei Möglichkeiten, Daten ins Eeprom zu bekommen: Aus deinem 
Programm aus hineinschreiben, oder von außen mit dem Programmer 
hineinprogrammieren.

Im o.a. Fall erzeugt die Toolchain eine .eep-Datei mit den Werten der 
einzelnen „Variablen“ des Eeprom. Diese musst du dann auch dort 
reinprogrammieren.

Oliver

von Stefan F. (Gast)


Lesenswert?

EEMEM finde ich persönlich irreführend. Es verleitet dazu, diese 
Variable wie normale Variablen im RAM zu benutzen und genau das geht 
eben nicht.

Benutze lieber die Funktionen aus der Datei avr/eeprom.h und lies die 
Erklärungen dazu dann sollte alles klar sein.

http://www.nongnu.org/avr-libc/user-manual/group__avr__eeprom.html

von Thomas K. (Firma: Draht_Igel) (magnoval)


Lesenswert?

So, erst mal danke an alle,

habs einfach mal probiert, und es klappt alles.
Einziges Manko: Atmel Studio 7 erzeugt mir keine eep Datei, auch wenns 
in dder Toolchain aktiviert ist. Hab dann einfach die elf gebrannt...
Kann man das einstellen, dass beim Flashen automatisch auch das Eeprom 
beschrieben wird?

von Einer K. (Gast)


Lesenswert?

Stefan U. schrieb:
> Benutze lieber die Funktionen aus der Datei avr/eeprom.h
Wieso "lieber"?
Das ist doch sowieso nötig!
Ein "lieber" gibt es da leider nicht.
Alternativlos.

Stefan U. schrieb:
> EEMEM finde ich persönlich irreführend.
Dann solltest du an dir arbeiten.
An den Variablen steht doch extra EEMEM dran.
Klarer geht es doch nicht.
So wie es auch bei PROGMEM Variablen ist.
Oder möchtest du auch auf PROGMEM verzichten?
Das möchte ich mal gerne sehen, wie du das dann anstellst....


Nein!
Ich stimme dir nicht zu!

Das verlegen von Variablen in die EEMEM und PROGMEM Sections, ermöglicht 
dem Kompiler/Linker die Adressen zu berechnen.
Das ist eine deutliche Erleichterung.
Erheblich weniger fehlerträchtig, als das manuelle festlegen der 
Adressen.
Und das Vorbesetzen des Speichers (Flash oder EEPROM) wäre ohne gar 
nicht wirklich möglich.

von Axel S. (a-za-z0-9)


Lesenswert?

Thomas K. schrieb:

> habs einfach mal probiert, und es klappt alles.
> Einziges Manko: Atmel Studio 7 erzeugt mir keine eep Datei, auch wenns
> in dder Toolchain aktiviert ist. Hab dann einfach die elf gebrannt...
> Kann man das einstellen, dass beim Flashen automatisch auch das Eeprom
> beschrieben wird?

Wenn dein Programmiertool das .elf direkt brennen kann, dann extrahiert 
es auch die .eeprom section und schreibt sie ins EEPROM. Den Umweg über 
ein .eep File (neben dem .hex File) muß man nur gehen, wenn das 
Programmiertool kein ELF kann.

Nochmal zum Mitmeißeln: die Initialwerte, die dein Programm den EEMEM 
Variablen zuweist, landen in der .eeprom section des .elf (im Prinzip 
genauso wie initialisierte globale Variaben in .data). Beim Brennen des 
Programms werden sie ins EEPROM geschrieben. Innerhalb des Programms 
kann man auf die Variablen mittels der Funktionen aus avr/eeprom.h 
zugreifen; lesend wie schreibend. Dazu mußt du an der Stelle, wo diese 
Funktionen eine Adresse im EEPROM erwarten, die Adresse einer EEMEM 
Variable verwenden.
1
uint8_t EEMEM x_backup=42;
2
...
3
uint8_t x= eeprom_read_byte(&x_backup);
4
...
5
eeprom_write_byte(&x_backup, x);

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

> So wie es auch bei PROGMEM Variablen ist.

Hmm, da hast du wohl Recht. Ist im Prinzip das Selbe.

> Oder möchtest du auch auf PROGMEM verzichten?

nein, ganz sicher nicht. Da muss man aufpassen, die xxx_P Funktionen zu 
benutzen. Für das EEprom gibt es aber z.B. leider kein printf_E(...).

von Adam P. (adamap)


Lesenswert?

Hey,

du könntest auch z.B. die ersten 2 oder 4 Byte im EEPROM mit einer 
Kennung versehen und falls die beim Prog.-Start noch nicht vorhanden 
sein sollte default-Werte schreiben. Würde dann auf einen ersten Start 
oder auf ein "defektes" EEPROM deuten.
1
uint16_t kennung;
2
struct eeprom_daten daten;
3
4
lese_eeprom_kennung(&kennung);
5
6
if(kennung != 0xCAFE)
7
{
8
    schreibe_eeprom_default_daten();
9
}
10
11
lese_eeprom_daten(&daten);

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Adam P. schrieb:
> du könntest auch z.B. die ersten 2 oder 4 Byte im EEPROM mit einer
> Kennung versehen
Das ist leider nicht ausreichend.
Der Compiler/Linker kann die EEMEM Variablen nach belieben umsortieren. 
Und, das tut er auch.

Erst bei der Verwendung von struct hat man eine reproduzierbare 
Reihenfolge. Oftmals möchte man ja das Programm verbessern, aber die 
schon gespeicherten EEPROM Daten beibehalten.

von Adam P. (adamap)


Lesenswert?

Arduino F. schrieb:
> Der Compiler/Linker kann die EEMEM Variablen nach belieben umsortieren.
> Und, das tut er auch.

Wenn ich festlege das in Byte 0 und 1 im EEPROM meine Kennung 
gespeichert wird, dann hat das doch nichts mit dem Compiler/Linker zu 
tun.

Ich spreche hier nicht von diesen EEPROM Dateien die irgendwie generiert 
werden - sondern vom Source, so wie ich es programmiere so wird es auch 
abgespeichert, sei es als Array oder Struct (da sollte man das 
allignment beachten)

: Bearbeitet durch User
von Axel S. (a-za-z0-9)


Lesenswert?

Arduino F. schrieb:
> Adam P. schrieb:
>> du könntest auch z.B. die ersten 2 oder 4 Byte im EEPROM mit einer
>> Kennung versehen

> Das ist leider nicht ausreichend.
> Der Compiler/Linker kann die EEMEM Variablen nach belieben umsortieren.

Das funktioniert ganz hervorragend, wenn man sich nicht darauf festlegt, 
daß die Kennung in den "ersten 2 oder 4 Byte" stehen muß. Das ist ja 
auch vollkommen unnötig. Sie muß nur an der erwarteten Position stehen.
1
/* defines and macros */
2
#define MAGIC !0xBAD     // marker in EEPROM for valid calibration
3
4
/* constants in EEPROM */
5
EEMEM uint32_t ee_magic;
6
EEMEM float ee_cal1;
7
EEMEM float ee_cal2;
8
9
void read_calibration(void)
10
{
11
    uint32_t magic= eeprom_read_dword(&ee_magic);
12
    if (magic == MAGIC) {
13
        cal1= eeprom_read_float(&ee_cal1);
14
        cal2= eeprom_read_float(&ee_cal2);
15
    } else {
16
        /* use default calibration values */
17
        ...
18
    }
19
}
20
21
void write_calibration(void)
22
{
23
    eeprom_write_dword(&ee_magic, MAGIC);
24
    eeprom_write_float(&ee_cal1, cal1);
25
    eeprom_write_float(&ee_cal2, cal2);
26
}

von M. K. (sylaina)


Lesenswert?

Thomas K. schrieb:
> Wenn ich nun wie im Tutorial uint16_t eeFooWord EEMEM = 12345; schreibe,
> wird dann eeFooWord bei jedem Programmstart mit 12345 initialisiert, und
> ich muss erst den zuletzt gespeicherten Wert aus dem Eeprom lesen?

So ist es Quasi. Mit
1
uint16_t eeFooWord EEMEM = 12345;

wird zunächst eine Variable eeFooWord definiert, die den Wert 12345 
haben soll. Das EEMEM sagt dem Compiler nur, dass er dafür keinen 
Speicher im SRAM freihalten muss/soll da diese Variable aus dem EEPROM 
kommt.

Versuchst du später mit z.B.
1
myValue = eeFooWord;
auf den Wert von eeFooWord zuzugreifen klappt das nicht denn eeFooWord 
hat die entsprechend vom Compiler vergebene Adresse in der sie im EEPROM 
abgespeichert ist. Mit dieser Anweisung jedoch wird auf das SRAM 
zugegriffen, sprich die EEPROM-Adresse wird auf das SRAM angewendet, und 
da steht irgend etwas aber nicht das, was du erwarten würdest, nämlich 
der Wert von eeFooWord. Willst du eeFooWord benutzten musst du das mit 
einer entsprechenden Lesefunktion für das EEPROM machen wie sie in der 
eeprom.h definiert ist, also z.B. so:
1
myValue = eeprom_read_word(&eeFooWord);

von Einer K. (Gast)


Lesenswert?

Axel S. schrieb:
> Das funktioniert ganz hervorragend, wenn man sich nicht darauf festlegt,
> daß die Kennung in den "ersten 2 oder 4 Byte" stehen muß.
Das will unser Adam P. aber tun!

Siehe hier, da sagt er es ganz klar:
Adam P. schrieb:
> Wenn ich festlege das in Byte 0 und 1 im EEPROM meine Kennung
> gespeichert wird, dann hat das doch nichts mit dem Compiler/Linker zu
> tun.
Und damit geht das nicht mit der EEMEM Adressierung konform.


> Irgendwann ist der Augenblick da, wo wir uns
> entscheiden und handeln müssen und nicht
> mehr zurückblicken dürfen.


Und hier muss die Entscheidung getroffen werden, ob man die Adressierung 
per Hand durchzieht, oder ob man es den Compiler machen lässt.

Per Hand wäre aus meiner Sicht eine Dummheit.
Denn der Compiler berechnet die Adressen zuverlässiger, als es ein 
Mensch kann.
Zumindest auf lange Sicht gesehen.

von M. K. (sylaina)


Lesenswert?

Arduino F. schrieb:
> Und hier muss die Entscheidung getroffen werden, ob man die Adressierung
> per Hand durchzieht, oder ob man es den Compiler machen lässt.
>
> Per Hand wäre aus meiner Sicht eine Dummheit.
> Denn der Compiler berechnet die Adressen zuverlässiger, als es ein
> Mensch.

Finde ich, ehrlich gesagt, nicht so. Wenn man es nur selbst macht, dann 
sollte man sich die Strukturierung "vorher" überlegen aber wenn man dazu 
ein Konzept hat, so behaupte ich mal, kann man ein EEPROM genau so gut 
bestimmen wie es der Compiler kann.

von Einer K. (Gast)


Lesenswert?

M. K. schrieb:
> aber wenn man dazu
> ein Konzept hat, so behaupte ich mal, kann man ein EEPROM genau so gut
> bestimmen wie es der Compiler kann.
Du hast die Größen aller Datentypen auf dem Schirm. Auch die, welche du 
vor Jahren selber definiert hast.
Du scheust nicht die endlosen und völlig unnötigen Debug Sitzungen, weil 
du dich mal wieder verzählt hast.
Oder kannst du dich niemals verzählen/verrechnen?

Gut, ich kann nicht bestimmen, womit du deine Zeit verplempern möchtest. 
Und wenn du deine Zeit in der Adressierung versenken möchtest, anstatt 
dem Compiler die Arbeit zu überlassen, men zu...
Meinen Segen du hast.

von M. K. (sylaina)


Lesenswert?

Arduino F. schrieb:
> Gut, ich kann nicht bestimmen, womit du deine Zeit verplempern möchtest.
> Und wenn du deine Zeit in der Adressierung versenken möchtest, anstatt
> dem Compiler die Arbeit zu überlassen, men zu...
> Meinen Segen du hast.

Wenn ich bedenke wie oft ich jetzt schon z.B. nen 24LC1025 eingesetzt 
habe...also da hilft mir die eeprom.h nicht bei, da muss ich das selbst 
machen.
Und ja, ich weiß wie groß die einzelnen Datentypen sind, auch die, die 
ich selbst definiert habe. Dass das ne Fleißarbeit ist, keine Frage, 
aber ein EEPROM zu strukturieren ist jetzt aber mal wirklich kein 
Problem.
Ja, wenn ich das interne EEPROM eines AVRs nutze benutze ich auch die 
eeprom.h, macht mir ja weniger Arbeit. Aber deswegen ist der Compiler 
nicht zwingen zuverlässiger, aber auch nicht unzuverlässiger.

von Einer K. (Gast)


Lesenswert?

Hier dreht es sich um das interne EEPROM.
Klar, kannst du einen Nebenkriegsschauplatz aufmachen...
Nur, was hast du davon?


Und dass du besser/zuverlässiger rechen kannst, als der Compiler, das 
glaubst du dir doch selber nicht.
Als Mensch kommt man da nicht ran.
Meiner Erfahrung nach, sind das recht schwer zu findende Fehler.

M. K. schrieb:
> Dass das ne Fleißarbeit ist, keine Frage,
Ich würde mal sagen, dass es eine der Lebensaufgaben eines 
Programmierers ist, fehlerträchtige Fleißaufgaben an Computer zu 
delegieren.
Warum du davon abweichen möchtest, ist mir ein Rätsel.

M. K. schrieb:
> z.B. nen 24LC1025 eingesetzt
Auch hier musst du nicht selber rechnen!
Auch das kannst du dem Compiler überlassen.
Siehe, struct und offsetof()

Noch mal ganz klar:
Ich halte nicht dich für dumm, sondern den Vorschlag die Adressen selber 
zu berechnen, wenn man doch eine Maschine vor sich hat, die das gerne 
für einen macht.
Und vor allen Dingen (immer?) korrekt macht.

Und mischen, kann man die beiden Prinzipien eher nicht. So wie man auch 
nicht bei einem Auto aus beiden Türen gleichzeitig aussteigen kann.

> Irgendwann ist der Augenblick da, wo wir uns
> entscheiden ... müssen ...

von M. K. (sylaina)


Lesenswert?

Arduino F. schrieb:
> Hier dreht es sich um das interne EEPROM.
> Klar, kannst du einen Nebenkriegsschauplatz aufmachen...
> Nur, was hast du davon?

Ob das EEPROM intern oder extern ist ist doch wurscht.

Arduino F. schrieb:
> Ich würde mal sagen, dass es eine der Lebensaufgaben eines
> Programmierens ist, fehlerträchtige Fleißaufgaben an Computer zu
> delegieren.
> Warum du davon abweichen möchtest, ist mir ein Rätsel.

Ich glaub, wir reden hier aneinander vorbei.

Arduino F. schrieb:
> Auch hier musst du nicht selber rechnen!
> Auch das kannst du dem Compiler überlassen.
> Siehe, struct und offsetof()

Och, jetzt muss ich doch strukturieren oder wer definiert die structs? 
Das meinte ich doch mit meinem obigen Post dass man sich die 
Strukturierung vorher überlegen muss, da haben wir uns wohl 
missverstanden ;)

von Einer K. (Gast)


Lesenswert?

M. K. schrieb:
> da haben wir uns wohl
> missverstanden ;)
Durchaus möglich.

M. K. schrieb:
> Ob das EEPROM intern oder extern ist ist doch wurscht.
Nicht ganz.

In die EEMEM Section kannst du die Variablen unstrukturiert rein werfen, 
und der Compiler rechnet richtig.

Da es (normalerweise) keine I2C_EEMEM Section gibt, wird man dann dem 
Automatismus durch eine Strukturierung helfen müssen.

//--
1. Ich mag Strukturen.
2. Ich mag Automatismen.
3. Ich hasse stumpfe und dabei auch noch unnötige+fehlerträchtige 
Fleißarbeit.

Wenn ich durch 1 + 2 die 3 vermeiden kann, habe ich das Gefühl es 
richtig gemacht zu haben.

Wenn ich feste Adressen vergebe, so wie Adam P. es vorschlägt, dann 
rollen sich mir die Zehennägel auf.

von Adam P. (adamap)


Lesenswert?

Arduino F. schrieb:
> Wenn ich feste Adressen vergebe, so wie Adam P. es vorschlägt, dann
> rollen sich mir die Zehennägel auf.

Ja gut, dass ist dann wohl Geschmackssache, ich weiß lieber wo was ist 
und bau mir meine Struktur von Hand.
Dies bezieht sich auf ARM µC (Flash sowie SD-Karte).

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.