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.
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
> 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.
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
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)
:
Bearbeitet durch User
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 | }
|
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); |
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).
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.