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?
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.
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.
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?
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.
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?
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.
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
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
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?
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.
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.
> 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(...).
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.
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.
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)
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
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_teeFooWordEEMEM=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:
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.
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.
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.
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.
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 ...
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 ;)
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.
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).