Hallo Gemeinde,
ich habe ein Verständnisproblem (wohl auch eine Bildungslücke) mit den
eeprom_read_dword(..) bzw. eeprom_write_dword(..).
Entwicklungsumgebung: AVR Studio 7.0 mit ATxmega32A4u.
Hier mein Programmcode (der Sinn der Funktion ist nicht weiter wichtig):
temp1=eeprom_read_dword((constuint32_t*)uC_FlashReadFrom);//Warnung hier
6
temp2=eeprom_read_dword((constuint32_t*)uC_FlashReadFrom);//und hier
7
8
9
if(temp2==temp1)
10
{
11
*pReturnAddress=temp1;
12
return0;
13
}
14
15
return1;
16
}
Der Compiler gibt hier eine Warnung aus:
cast to pointer from integer of different size [-Wint-to-pointer-cast]
Nach meinen Recherchen gibt es wohl folgende Lösung:
Die Funktion eeprom_read_dword benötigt ja eine Adresse einer Variable,
die die Adresse des EEPROMS als Wert enthält, die gelesen werden soll.
Durch den cast (uint16_t) mache ich aber aus der
1
uint32_t
einen
1
uint16_t
, d.h. die oberen beiden bytes werden abgeschnitten.
1
(uint32_t*)
gibt dann wieder an, dass ab der Adresse 32bit (d.h. 4 Byte) gelesen
und als
1
uint32_t
interpretiert wird.
Was ich nicht verstehe ist, warum erst nach
1
(uint16_t)
gecastet werden muss? Führt das casten auf
1
(uint16_t)
nicht zu Problemen bei EEPROM-Adressen >655535 (sofern es überhaut
controller mit soviel EEPROM gibt)?
Danke und VG
Karsten
Karsten B. schrieb:> Ein Skalar finde ich persönlich lesbarer.
Dann solltest du Prosa schreiben oder Gedichte anstatt Programmcode.
> temp1 = eeprom_read_dword(uC_FlashReadFrom);> temp2 = eeprom_read_dword(uC_FlashReadFrom);
Okay, reimt sich schon mal. Also lieber Gedichte.
Wie wärs denn mal mit einer richtigen Antwort.
Ich bitte ja nicht aus lange Weile um Hilfe.
Die Frage stellt sich nicht nur mir!!
Da Du dich nicht so ganz klar ausgedrückt hast, was an welcher Stelle
übergeben werden sollte, bin ich sicher nicht der Einzige, der Gedichte
schreiben sollte.
Ich denke, es ist so gemeint:
Ist mir neu dass es AVRs mit so großem EEprom gibt.
Fakt ist, dass Zeiger 16 Bits groß sind, was einen maximalen Adressraum
von 64KiB für EEprom, RAM und Flash (Daten) gibt sowie 2*64KiB für Code.
Wenn du darüber hinauswillst musst du Verrenkungen machen, außer beim
Code.
Genau so! Aber du liest nicht vom Flash, sondern vom EEPROM. Das sollte
in den Namen zum Ausdruck kommen.
>{> uint32_t temp1=0, temp2=0;> //Get actual EEPROM Read address> temp1 = eeprom_read_dword(uC_FlashReadFrom); //Warnung hier> temp2 = eeprom_read_dword(uC_FlashReadFrom); //und hier> if(temp2==temp1)
Warum liest du 2x? Denkst du, da wackelt was? Wenn du einen Fehler im
EEPROM hast, wirst du meistens 2x den gleichen Wert lesen. Dagegen hilft
nur CRC bzw. FEC.
> {> *pReturnAddress=temp1;
Auch das ist eine maximal irreführende Bezeichung.
>Wie würdest Du die Funktion sonst gestalten?
So wie oben.
>Nur das ich das richtig verstehe: Bei 16-bit Zeigern sind dann auch nur>max.65K EEPROM adressierbar?
Reicht doch, soviel hat der AVR so oder so nicht. Selbst Zeiger im Flash
und RAM sind nur 16 Bit.
Hallo FAlk,
vielen Dank für die qualifizierte Antwort :)
Ja, die Namensgebung sollte da noch angepasst werden.
Stimmt, ein Skalar ist keine Adresse. In der Variablen soll ja auch die
Adresse übergeben werden, aus der im EEPROM gelesen werden soll.
Was mich nur etwas irritiert hat ist, dass die Funktion
1
eeprom_read_dword(uint32_t*)
einen Zeiger auf eine 32 Bit variable verlangt. Mein Verständnis ist
nun, dass ich der Funktion ein uint32_t-Variable übergebe, die die
anzusprechende Speicherstelle im EEPROM enthält. Die Übergabe an den
pointer im Argument von eeprom_read_dword erfolgt doch mit dem
&-Operator.
Die Funktion eeprom_read_dword() sollte sich dann den Wert holen.
eigentlich müsste die Zeile dann lauten:
Karsten B. schrieb:> Was mich nur etwas irritiert hat ist, dass die Funktion>>
1
eeprom_read_dword(uint32_t*)
> einen Zeiger auf eine 32 Bit variable verlangt.
Ja, die Funktion will den Zeiger AUF einen 32-Bit Wert, was aber nicht
bedeutet, dass der Zeiger SELBST 32 Bits hat oder haben muss. Alles,
was links vom "*" steht, gehört zum "Zeiger auf". Genauer ist der
Prototyp der Funktion
1
uint32_teeprom_read_dword(constuint32_t*addr)
d.h. das, was an addr steht, wird durch die Funktion nicht verändert.
Auch möglich wäre
1
uint32_teeprom_read_dword(constvoid*addr)
also "Zeiger auf irgendwas", der dann von der Auslesefunktion als
"Zeiger AUF einen 32-Bit Wert" uminterpretiert wird.
> uint8_t FLASH_LoadAddressPointer(uint32_t *pReturnAddress, uint32_t> uC_FlashReadFrom)> {> uint32_t temp1=0, temp2=0;> //Get actual EEPROM Read address> temp1 = eeprom_read_dword(&uC_FlashReadFrom); //kein Warnung mehr
Nein, auf gar keinen Fall &uC_FlashReadFrom. Das macht folgendes: Es
nimmt die Adresse von uC_FlashReadFrom, also die Adresse einer lokalen
Variable von FLASH_LoadAddressPointer. Diese Variable liegt irgendwo
auf dem Stack, also im SRAM. Diese Adresse wird dann an
eeprom_read_dword übergeben, welches die so übergebene Adresse als
EEPROM-Adresse interpretiert.
Richtig wäre z.B
@Karsten Brandt (karstenbrandt)
>Stimmt, ein Skalar ist keine Adresse.
Der erste Schritt zur Erkenntnis.
> In der Variablen soll ja auch die>Adresse übergeben werden, aus der im EEPROM gelesen werden soll.
Dann tu das doch einfach.
>eigentlich müsste die Zeile dann lauten:>temp1 = eeprom_read_dword(&uC_FlashReadFrom);
NEIN! Kauf dir ein C-Buch und studiere die Grundlagen von Pointern und
Variablen. Ist sicher nicht ganz trivial, aber machbar.
>Das bedeutet:>uint8_t FLASH_LoadAddressPointer(uint32_t *pReturnAddress, uint32_t >uC_FlashReadFrom)>{> uint32_t temp1=0, temp2=0;> //Get actual EEPROM Read address> temp1 = eeprom_read_dword(&uC_FlashReadFrom); //kein Warnung mehr> temp2 = eeprom_read_dword(&uC_FlashReadFrom); //und hier auch nicht
FALSCH! Sagte ich bereits!
&uC_FlashReadFrom ist hier die Adresse der lokalen Variablen (Skalar!)
uC_FlashReadFrom. Die interessiert kein Mensch. Du willst den INHALT
eines Pointers!
SO und nicht anders!
>P.S. Habe es gerde ausprobiert: Die Warnungen sind weg.
Ist trotzdem falsch! So einen Fehler kann kein Compiler der Welt
erkennen, es sei denn man nutzt den -DAULEVEL9 Schalter!
> Da habe ich den>Wald vor lauter Bäumen nicht gesehen.
Dir fehlen elementare Grundlagen.
Gut, da scheint es noch Lücken zu geben.
Vielen Dank für die Rückmeldungen.
Trotdem sollte es aber richtig sein, dass ein Zeiger eine Adresse
speichert, die mit dem &-Operator übergeben wird.
1
inti=5;
2
int*pzeiger;
3
4
pzeiger=&i;
Mit Funktionen genau so (call by reference):
1
intfoo(int*pWert)
2
{
3
//mach was mit pWert
4
}
5
6
intx=6;
7
8
foo(&x);
So hatte ich das verstanden. Und das ist auch richtig und hat bisher
immer gut funktioniert.
Die Vorschläge von Euch werde ich nochmal sacken lassen. Ich werde
nochmal lesen und die Lücken schliessen.
Genau dieser Punkt sorgt auch bei manch anderen für Verwirrung.
Trotzdem nochmal vielen Dank :)
Habe meinen Fehler gefunden:
Es war ein Denkfehler bei der Funktion
1
eeprom_read_dword(uint_32*__p)
Habe mir die Doku hierzu nochmal durchgelesen. Da habe ich wohl doch
noch ein Verständnisproblem gehabt.
Man muss dem Zeiger __p die Adresse aus dem EEPROM zuweisen, von der man
lesen möchte. Daher muss tatsächlich der Wert der Variablen dem Zeiger
zugewiesen werden:
@ Karsten Brandt (karstenbrandt)
>Habe meinen Fehler gefunden:
Wirklich?
>Habe mir die Doku hierzu nochmal durchgelesen. Da habe ich wohl doch>noch ein Verständnisproblem gehabt.
Das hast du immer noch.
>Man muss dem Zeiger __p die Adresse aus dem EEPROM zuweisen, von der man>lesen möchte.
Ja.
> Daher muss tatsächlich der Wert der Variablen dem Zeiger> zugewiesen werden:
Irreführende Formulierung! Man muss den ZEIGER übergeben.
>uint8_t FLASH_LoadAddressPointer(uint32_t *pReturnAddress, uint32_t >uC_FlashReadFrom)
Du hast irgendwie einen Hang zum Murks. SO NICHT!
> //Erst den übergebenen Wert nach 16-Bit (uint16_t) casten, da pointer >im AVR =
16 Bit
> //Dann den Inhalt der Variablen 'uC-FlashReadFrom' (=der zu lesenden >Adresse
im Flash)
> //dem Pointer __P von eeprom_read_dword() zuweisen.> // Der Zeiger zeigt auf einen Wert vom Typ unit32_t (=dword)> temp1 = eeprom_read_dword((const uint32_t*)(uint16_t)uC_FlashReadFrom);
Murks^3!!!
>uint32_t Adresse = 50;>uint32_t AdresseImExternenFlash;
Du murkst schon wieder. Bei eeprom_read_??? geht es um INTERNEN EEPROM,
keinen externen Flash. Das muss man trennen. Sonst kommt so wie bei dir
Murks raus!
>FLASH_LoadAddressPointer(&AdresseImExternenFlash, Adresse)
Nein!
>Dann macht das auch alles einen Sinn. Ich hoffe das ist halbwegs>verständlich wiedergegeben.
Ist aber falsch!
uint32_tmy_testEEMEM;// Variable im EEPROM, vom Compiler verwaltet
8
9
intmain(void){
10
FLASH_LoadAddressPointer((uint16_t)&my_test);
11
}
Hier geht es um INTERNEN EEPROM! Der unterliegt auch der Verwaltung des
Compilers, also sollte man sich an die Konventionen halten (Lehrbuch!)
und dem Compiler nicht im Wege stehen und seinen Job machen lassen.
Bei internem Flash, welcher auch vom Compiler verwaltet wird ist das
ebenso.
Wenn man EXTERNEN Flash ansprechen will, der NICHT direkt vom Compiler
verwaltet werden kann (serieller Flash, paralleler Flash mit manueller
Ansteuerung), dann kann man das auch so machen. Hab ich auch schon
getan, ist HIER auch voll OK.
Externer Flash ausserhalb der Compilerverwaltung.
Hallo Falk,
wie eingangs erwähnt, sind die Namensgebungen für meine Frage nicht von
Bedeutung. Aber zum Hintergrund: Am Controller hängt ein externes SPI
Flash mit 32 MBit, das als Ringbuffer verwendet wird. Die aktuellen
input- und outputzeiger vom BUffer werden im internen EEPROM abgelegt
bzw. gesichert. Im Programm wird mit einer Arbeitskopie gearbeitet.
Daher ist die Namensgebung in meinem Kontext durchaus sinnvoll.
Ich gehe ja auch noch mit, dass es sauber ist, das so zu machen:
Daher habe ich mich für die 2. Möglichkeit entschieden, damit das Casten
dann in der Funktion FLASH_LoadAddressPointer(..) zentral erledigt wird.
Zugegeben, nicht ganz elegant und nach Lehrbuch. An dieser Stelle ist
tatsächlich noch Verbesserungspotential, da hast Du recht.
Der Unterschied zwischen internen EEPROM, internen Programmflash und
externen Flash ist mir schon bewusst. Die Applikation läuft ja
schließlich. Ich wollte eigentlich nur die Compilerwarnungen verstehen
und beseitigen.
Das Problem der Compilerwarnung war, das ein Pointer beim AVR nur 16-Bit
breit ist, d.h. man muss auf (uint16_t) casten, wenn der übergebende
Zeiger ungleich uint16_t* ist.
Übrigens: eine sehr schöne Zusammenfassung in Deinem letzten Post.
Problem gelöst. Thread kann geschlossen werden.
@ Karsten Brandt (karstenbrandt)
>wie eingangs erwähnt, sind die Namensgebungen für meine Frage nicht von>Bedeutung.
Jain. Eine unklare Sprache führt zu unklarem Denken!
> Aber zum Hintergrund: Am Controller hängt ein externes SPI>Flash mit 32 MBit, das als Ringbuffer verwendet wird.
AHA! Da hatte ich mal wieder den richtigen Riecher!
> Die aktuellen>input- und outputzeiger vom BUffer werden im internen EEPROM abgelegt>bzw. gesichert. Im Programm wird mit einer Arbeitskopie gearbeitet.>Daher ist die Namensgebung in meinem Kontext durchaus sinnvoll.
Jetzt schon.
>Ich gehe ja auch noch mit, dass es sauber ist, das so zu machen:>uint8_t FLASH_LoadAddressPointer(uint32_t *pTarget, uint32_t *pSource)
Ja
>Dann muss ich allerdings beim Aufruf der Funktion den 2. Parameter>casten, da sonst eine Warnung ausgegeben wird:
Nö, du musst dich mal auf den Hosenboden setzen und Grundlagen lernen!
SO geht es sauber ohne Warnungen und sinnlose Casts
[c]
uint32_t FlashOutPointer_nv EEMEN = 100; // Sicherung im EEPROM,
Zugriff nur über eeprom_read_dword();
uint32_t FlashOutPointer; // Arbeitskopie im RAM
FLASH_LoadAddressPointer(&FlashOutPointer, &FlashOutPointer_nv)
[c]
>Daher habe ich mich für die 2. Möglichkeit entschieden, damit das Casten>dann in der Funktion FLASH_LoadAddressPointer(..) zentral erledigt wird.
Weil du einen starken Drang zum Murks hast? Cast sollte man immer sehr
sparsam einsetzen und WIRKLICH wissen was man tut. Einfach den Compiler
totcasten damit er Ruhe gibt ist selten guter Stil.
>Zugegeben, nicht ganz elegant und nach Lehrbuch. An dieser Stelle ist>tatsächlich noch Verbesserungspotential, da hast Du recht.
Warum nicht lehrbuchartig? Weniger Schreibarbeit und schöner UND
allgemein anerkannt. Zu langweilig?
>Der Unterschied zwischen internen EEPROM, internen Programmflash und>externen Flash ist mir schon bewusst.
Na hoffentlich.
> Die Applikation läuft ja schließlich.
Das tun alle Rumpelapplikationen, auch mit himmelschreiendem Murks.
> Ich wollte eigentlich nur die Compilerwarnungen verstehen>und beseitigen.
Gut.
>Das Problem der Compilerwarnung war, das ein Pointer beim AVR nur 16-Bit>breit ist, d.h. man muss auf (uint16_t) casten, wenn der übergebende>Zeiger ungleich uint16_t* ist.
Falsch! Du hast immer noch nicht den Unterschied zwischen der Größe
eines Pointers und der Größe des Zielobjekts verstanden.
Ein Pointer ist beim avr gcc 16 Bit breit. Das muss einen aber in den
allermeisten Fällen nicht interessieren, darum kümmert sich der
Compiler.
Dein Problem war die unsaubere Unterscheidung zwischen einem einfachen
32 Bit Skaler/Integerwert und einem Pointer auf einen 32 Bit Wert.
Um es mal im Karl Heinz Buchegger Stil zu erklären. Mein Finger ist der
Pointer, ca. 10cm lang. Damit kann ich auf einen 20m Langen LKW zeigen
oder auch auf eine 5mm große Ameise. Die Größe des Pointers hat mit der
Größe des Zielobjekts nichts zu tun.
Allerdings sollte man, wenn man auf einen LKW zeigt nicht sagen, ich
zeige auf eine Ameise. Wenn das doch nötig ist, braucht man einen Cast.
Davon sollte man aber immer sparsam Gebrauch machen, sonst verwechselt
man irgendwann wirklich mal einen LKW mit einer Ameise. ;-)
>Übrigens: eine sehr schöne Zusammenfassung in Deinem letzten Post.
Danke.
>Problem gelöst. Thread kann geschlossen werden.
Wenn ich das höre, weiß ich meistens, daß es eben nicht so ist ;-)
Wer glaubt zu wissen, muss wissen, er glaubt.
Da ist wohl immer noch der Wurm drin. Der Cast auf uint16_t beseitigt
das Symptom, also die Warnung, aber er behebt nicht das Problem.
Das eigentliche Problem ist, dass du 2 Adressbereiche hast: einmal den
externen Flash, den du über eine 32-Bit Adresse verwaltest. Diese
Adresse ist ein uint32_t und soweit auch in Ordnung. Dann hast du eine
Variable im EEPROM, welche diese Adresse speichert.
Die Adresse der EEPROM-Variablen ist aber nur 16 Bits groß.
Das Problem behabst du nun, indem die 32-Bit XFlash-Adresse zu 16 Bits
verstümmelt wird und danach als EEPROM-Adresse missbraucht, d.h. du
versuchst eine 1:1 Korrespondenz zwischen XFlash- und EEPROM-Variablen.
Willst du wirklich diese 1:1 Korrespondenz zwischen XFlash- und
EEPROM-Variablen? Oder willst du die (aktuelle) Adresse (z.B. Lese- oder
Schreibposition im XFlash) im EEPROM speichern?
@Johann L. (gjlayde) Benutzerseite
>Da ist wohl immer noch der Wurm drin. Der Cast auf uint16_t beseitigt>das Symptom, also die Warnung, aber er behebt nicht das Problem.
Eben.
>Willst du wirklich diese 1:1 Korrespondenz zwischen XFlash- und>EEPROM-Variablen?
Nein.
> Oder willst du die (aktuelle) Adresse (z.B. Lese- oder>Schreibposition im XFlash) im EEPROM speichern?
Ja, in 32 Bit.
@ Karsten Brandt (karstenbrandt)
>Die EEPROM-Funktionen in der avr-libc sind nicht ganz so einfach zu>verstehen.>Hab das jetzt über EEMEM-Variablen geregelt.
Langsam wirst du albern.
www.vieleausreden.de
Hallo Falk,
es reicht mit Deiner Respektlosigkeit. Ich habe keine Ahnung, auf
welcher Ebene Du Dich bewegst. Deine herablassende Art ist aber langsam
echt nervig. Auf oberlehrerhaftes Verhalten kann ich verzichten. Dass
bringt uns hier nicht weiter. Du brauchst hier nicht zu antworten. Es
zwingt Dich keiner. Aber wenn Du antwortest, dann bitte sachlich.
Vielleicht versetzt Du Dich ja mal in meine Situation.
Ich habe über meinen Tellerrand hinausgeblockt und gesehen, dass auch
viele andere Leute sich mit dem EEPROM und den avr-libc-Funktionen
schwer tun. Die sind sicher auch alle nicht dumm und haben keine Ahnung.
Es ist anmaßend zu behaupten, dass wäre eine Ausrede.
Ich habe nie behauptet perfekt zu allwissend zu sein. Dennoch habe ich
schon einiges an c Grundlagen (auch pointer). Vielleicht gibt es Lücken.
Aber Hey:
ich bin für Anregungen und positive Kritik offen.
Mich als dumm hinzustellen geht gar nicht. Du solltest Doch bitte die
Regeln der höflichen zwischenmenschlichen Kommunikation beherrschen!
Dieses Forum ist ja schließlich ein Ort, wo man sich austauschen kann
und Wissen weitergegeben werden sollte.
Für mich gibt es keine dummen(albernen) Fragen, sondern nur dumme
(alberne) Antworten.
Ich habe andere Quellen aufgetan, die den Sachverhalt deutlich und
verständlich beschreiben. Für mich persönlich hatte ich die
EEPROM-Funktionen nicht richtig verstanden.
@ Karsten Brandt (karstenbrandt)
>es reicht mit Deiner Respektlosigkeit.
Du solltest mal an deiner Kritikfähigkeit arbeiten.
https://de.wikipedia.org/wiki/Kritik>echt nervig. Auf oberlehrerhaftes Verhalten kann ich verzichten.
Siehe oben.
>zwingt Dich keiner. Aber wenn Du antwortest, dann bitte sachlich.
Das tue ich. Der Schuß Ironie und Sarkassmus ist gratis ;-)
>Vielleicht versetzt Du Dich ja mal in meine Situation.
Das tue ich auch. Und eben weil ich es tue, erkenne ich, was DU nicht
erkennst. Nämlich daß du entgegen deinen mehrfach vollmundigen Aussagen
das Problem NICHT verstanden hast.
Das erkennt man leicht daran, daß du in fast jeder Antwort den
Sachverhalt FALSCH wiedergegeben hast.
>Ich habe über meinen Tellerrand hinausgeblockt und gesehen, dass auch>viele andere Leute sich mit dem EEPROM und den avr-libc-Funktionen>schwer tun.
Ja? WO denn? Hast du eine Selbsthilfegruppe gefunden?
>Es ist anmaßend zu behaupten, dass wäre eine Ausrede.
Sie IST es! Deine bisherigen Antworten beweisen es!
Der Spruch "Wer glaubt zu wissen, muss wissen, er glaubt." klingt zwar
lustig, trifft hier (und anderswo) aber zu!
Das zu erkennen ist schwer. Das für sich selbst zu AKZEPTIEREN noch viel
mehr.
Das du jetzt sauer bist, ist verständlich.
>Ich habe nie behauptet perfekt zu allwissend zu sein.
Davon redet keiner.
>Dennoch habe ich>schon einiges an c Grundlagen (auch pointer).
Siehe oben ;-)
> Vielleicht gibt es Lücken.
Bei deren Schließung wir dir hier helfen wollen. Dazu gehört aber auch
ein gewisses Maß an Zuhören und und auch Zugeben, dass man auf dem
Holzweg ist und Murks macht!
Wiederum, das zu Erkennen und sich einzugestehen ist charakterlich
anspruchsvoll.
>ich bin für Anregungen und positive Kritik offen.
Die hast du mehrfach bekommen aber teilweise ignoriert. Ich bin nur ein
08/15 Hardwerker der ein bisschen programmieren kann.
Der Johann spielt in einer GANZ anderen Liga, der WEIß wie C und avr gcc
funktioniert SEHR GENAU! Wenigstens DEM solltest du genau zuhören und
auch mal ein paar Dinge glauben.
>Mich als dumm hinzustellen geht gar nicht.
Reg dich wieder ab.
> Du solltest Doch bitte die>Regeln der höflichen zwischenmenschlichen Kommunikation beherrschen!
Das tue ich, aber meinen ironisch-sarkastischen Stil werde ich so
schnell nicht ändern ;-)
(ironisch-sarkastischen? Ich glaube ich bin vom IS!) ;-)
>Für mich gibt es keine dummen(albernen) Fragen, sondern nur dumme>(alberne) Antworten.
Dazu zählen auch deine! Wie ein trotziges Kind willst du uns erklären
daß dein Murks schon OK ist. NEIN, er ist es NICHT!
>Ich habe andere Quellen aufgetan, die den Sachverhalt deutlich und>verständlich beschreiben. Für mich persönlich hatte ich die>EEPROM-Funktionen nicht richtig verstanden.
Na dann laß uns mal an deinem neuen Wissen teilhaben. Mal sehen ob du es
WIRKLICH verstanden hast oder nur glaubst es verstanden zu haben.
Trau dich!
Naja, wenn der TO schon mit den zwei Parametern der avrlibc-Funktionen
seine Schwierigkeiten hat, wird die PeDa- Lösung ihn nur noch mehr
verwirren.
Oliver
Oliver,
das mag ich nicht vermuten.
Ich verwende diese Routinen (kleine Lib) manchmal, da sie eine
Implementierung enthält, um Blockweise Daten zuwischen EEprom, SRam aus
zutauschen.
Und Schreibzugriffe auf das EEprom nur bei Daten Unterschieden
durchführt.
Uwe S. schrieb:> Und Schreibzugriffe auf das EEprom nur bei Daten Unterschieden> durchführt.
das macht auch die avr-libc die Funktionen dafür nennen sich update...
Danke Peter,
ist mir bekannt, da ich mir die Implementierung angesehen hatte, aber
bestimmt nicht alle Mitlesern hier.
Peter II schrieb:> Uwe S. schrieb:>> Und Schreibzugriffe auf das EEprom nur bei Daten Unterschieden>> durchführt.>> das macht auch die avr-libc die Funktionen dafür nennen sich update...
Warten wir doch mal ab, was Karsten mit den neuen Infos anfangen kann
und ob sein Projekt dadurch wieder "fahrt aufnehmen wird".
Hallo @all:
Nochmals vielen Dank für die Rückmeldungen.
Das Projekt hat schon immer sehr stabil gelaufen. Ja, und auch die
Zeiger, die sonst noch im Programm vorhanden sind.
Lediglich ein paar Compiler Warnungen sind noch zu beseitigen. Wie
gesagt, ich hatte einen Denkfehler bei der avr-libc. Die Brücke von
Variablen im SRAM bei Benutzung der avr-libc Funktionen war noch nicht
ganz klar.
Nachdem ich mich nochmal intensiver damit beschäftigt habe, sind nun
auch die Warnunggen
cast to pointer from integer of different size [-Wint-to-pointer-cast]
(was mein eigentliches Problem war) weg ohne die verhassten casts zu
verwenden.
Problem ist nun mit EEMEM-Variablen gelöst.
Alternativ geht das natürlich auch, indem ich eine 16-Bit SRAM Variable
(Zeiger sind 2 Byte groß beim AVR) an die Funktion übergebe, die die
Adresse enthält. Je nach Datentyp (byte, word, dword) muss dann
entsprechend in der eeprom_read_... gecastet (uint8_t*, uint32_t*)
werden.
Die uint32_t-Variable für die EEPROM-Adresse (2. Parameter) in der
FLASH_LoadAddressPointer-Funktion macht also keinen Sinn. Hier hätte ein
uint16_t völlig gereicht.
Das steht ja auch im AVR-GCC Tutorial hier im Forum.
Die Funktion im ersten Post ist ja genau so aufgebaut (vom uint32_t im
zweiten Parameter mal abgesehen) wie die im AVR-GCC Tutorial
(EEPROM-Kapitel). Wer meint, dass dies "Murks" ist, der möge das
Tutorial richtig stellen.
Meine Funktion im ersten Post ist ja nicht ganz so verkehrt. Hätte ich
im zweiten Parameter uint16_t statt uint32_t verwendet, dann wäre alles
o.k. und die beschriebene Compiler-Warnung wäre weg.
Wie gesagt, Problem erledigt. Wieder etwas dazugelernt.
Gruß
Karsten
>> Wie gesagt, Problem erledigt. Wieder etwas dazugelernt.>Oder auch nicht ;-)>Q.E.D.
Was muss ich beweisen?
Was ich eben geschrieben habe, steht auch so im AVR-GCC Tutorial. Ich
werde das AVG-GCC Tutorial nicht in Frage stellen.
Ausserden findet sich auf den Seiten der Kollegen von avrfreaks.net jede
menge Fragen zu dem Thema. So einfach kann das mit den EEPROM-Funktionen
der avr-libc ja dann doch nicht sein. Es gint auch ein hervorragendes
Tutorial zu den EEPROM-Zugriffen dort.
So ganz falsch bin ich nicht unterwegs. Das AVR-GCC Tutorial bzw. das
auf avrfreaks.net bestätigt das.
Vielleicht habe ich im vorherigen Post die eine oder andere Stelle
unglücklich formatiert. Das mag sein.
Konkret:
Variante 1:
Ich habe Variante 2 mit der EEMEM-Variable gewählt. Das ist doch ein
ganzes Stück einfacher und auch übersichtlicher.
Mehr gibt es zu diesem Thema von meiner Seite nicht zu sagen.
@ Karsten Brandt (Gast)
>Was muss ich beweisen?
Gar nichts, denn du weißt ja jetzt wie das funktioniert.
>Was ich eben geschrieben habe, steht auch so im AVR-GCC Tutorial.
Nö.
>Ich>werde das AVG-GCC Tutorial nicht in Frage stellen.
Musst du auch nicht.
>Ausserden findet sich auf den Seiten der Kollegen von avrfreaks.net jede>menge Fragen zu dem Thema. So einfach kann das mit den EEPROM-Funktionen>der avr-libc ja dann doch nicht sein.
Ach nee? Zugriffsfunktionen mit EINEM Parameter? ;-)
Dort sind mindestens genausoviel "Experten" unterwegs wie hier.
Warum soll es dem Forum besser gehen? ;-)
> Es gint auch ein hervorragendes> Tutorial zu den EEPROM-Zugriffen dort.>So ganz falsch bin ich nicht unterwegs. Das AVR-GCC Tutorial bzw. das>auf avrfreaks.net bestätigt das.
Tun sie das?
>Vielleicht habe ich im vorherigen Post die eine oder andere Stelle>unglücklich formatiert. Das mag sein.
Schon wieder?
>Konkret:>Variante 1:>uint8_t FLASH_LoadAddressPointer(uint32_t *pReturnAddress, uint16_t >uC_FlashReadFrom)>{> uint32_t temp1=0, temp2=0;> //Get actual EEPROM Read address> temp1 = eeprom_read_dword((uint32_t*)uC_FlashReadFrom); //Warnung weg> temp2 = eeprom_read_dword((uint32_t*)uC_FlashReadFrom); //und hier auch
Ja, funktioniert, ist aber handgestricktes Gefrickel. Hab ich dir schon
mehrfach zu erklären versucht. Leider vergebens. Mein pädagogisches
Talent ist halt endlich.
> if(temp2==temp1)> {> *pReturnAddress=temp1;> return 0;> }
Das hatten wir auch schon mal. Das funktioniert nicht so wie du denkst.
Damit wirst du KEINE EEPROM Lesefehler erkennen. Aber das glaubst du mir
auch nicht.
Beitrag "Re: EEPROM avr-libc Read/Write-Funktionen Warnung">uint32_t uC_FlashReadFrom=1000; //EE-Adresse muss selber verwaltet werden
Frickelmist^3.
>uint32_t FlashBufferOutPointer;>FLASH_LoadAddressPointer(&FlashBufferOutPointer, uc_FlashReadFrom)
Auch Murks. Du verstehst nicht wirklich, welche Arbeiten man besser dem
Compiler überläßt und was man sinnvoll seber verwalten soll/muss.
>Variante 2:>uint8_t FLASH_LoadAddressPointer(uint32_t *pReturnAddress, uint32_t* >uC_FlashReadFrom)>{> uint32_t temp1=0, temp2=0;> //Get actual EEPROM Read address> temp1 = eeprom_read_dword(uC_FlashReadFrom); //Warnung hier> temp2 = eeprom_read_dword(uC_FlashReadFrom); //und hier
Was für Warnungen? Glaub ich nicht so recht. Das hier ist korrekt und
erzeugt KEINERLEI Compilerwarnung, es sind auch alle Warnungen
angeschaltet (Compileroption -Wall)!
Ich wiederhole mich wiederholt, denn das da hab ich schon mehrfach
geschrieben.
>//Adresse der Variablen im EEPROM durch Compiler festgelegt>//Der Anfangswert an der Adresse im EEPROM ist 0.>uint32_t EEMEM uC_FlashReadFrom=0;
Vorsicht, ich glaube das EEMEM muss HINTER dem Variablennamen stehen.
Nö, gerade getestet, geht auch so rum.
>uint32_t FlashBufferOutPointer;>//Das die Variablenadresse (z.B. 0x01) im EEPROM (EEPROM-section) sich >befindet,>//muss hier der &-Operator verwendet werden! Der Wert der Variablen ist >nebensächlich.>FLASH_LoadAddressPointer(&FlashBufferOutPointer, &uC_FlashReadFrom)
Apfelmus ist Mus aus Äpfeln. Wenn eine Funktion eine Adresse/Pointer auf
irgendwas haben will, muss man IMMER den Adressoperator verwenden. Auch
bei ganz normalen Variablen im RAM. (Jaja, Strings/Arrays sind die tolle
Ausnahme, dort ist der Name = Adresse).
>Ich habe Variante 2 mit der EEMEM-Variable gewählt. Das ist doch ein>ganzes Stück einfacher und auch übersichtlicher.
Nicht wahr.
>Mehr gibt es zu diesem Thema von meiner Seite nicht zu sagen.
Dann ist ja alles gut.
>>So ganz falsch bin ich nicht unterwegs. Das AVR-GCC Tutorial bzw. das>>auf avrfreaks.net bestätigt das.>Tun sie das?
Ja.
>>Variante 1:>>uint8_t FLASH_LoadAddressPointer(uint32_t *pReturnAddress, uint16_t>>uC_FlashReadFrom)>>{>> uint32_t temp1=0, temp2=0;>> //Get actual EEPROM Read address>> temp1 = eeprom_read_dword((uint32_t*)uC_FlashReadFrom); //Warnung weg>> temp2 = eeprom_read_dword((uint32_t*)uC_FlashReadFrom); //und hier auch>Ja, funktioniert, ist aber handgestricktes Gefrickel. Hab ich dir schon>mehrfach zu erklären versucht. Leider vergebens. Mein pädagogisches>Talent ist halt endlich.
Wenn Du der Meinung bist, dass das nicht nach Lehrbuch ist, dann
korrigiere doch das AVR-GCC-Tutorial:
temp1=eeprom_read_dword(uC_FlashReadFrom);//Warnung weg
7
temp2=eeprom_read_dword(uC_FlashReadFrom);//und hier auch
>>Variante 2:>>uint8_t FLASH_LoadAddressPointer(uint32_t *pReturnAddress, uint32_t*>>uC_FlashReadFrom)>>{>> uint32_t temp1=0, temp2=0;>> //Get actual EEPROM Read address>> temp1 = eeprom_read_dword(uC_FlashReadFrom); //Warnung hier>> temp2 = eeprom_read_dword(uC_FlashReadFrom); //und hier>Was für Warnungen? Glaub ich nicht so recht. Das hier ist korrekt und>erzeugt KEINERLEI Compilerwarnung, es sind auch alle Warnungen>angeschaltet (Compileroption -Wall)!
Stimmt, Fehler von mir (copy-paste). Warnungen sind natürlich weg.
>>//Das die Variablenadresse (z.B. 0x01) im EEPROM (EEPROM-section) sich >>befindet,>>//muss hier der &-Operator verwendet werden! Der Wert der Variablen ist>>nebensächlich.>>FLASH_LoadAddressPointer(&FlashBufferOutPointer, &uC_FlashReadFrom)>Apfelmus ist Mus aus Äpfeln. Wenn eine Funktion eine Adresse/Pointer auf>irgendwas haben will, muss man IMMER den Adressoperator verwenden. Auch>bei ganz normalen Variablen im RAM. (Jaja, Strings/Arrays sind die tolle>Ausnahme, dort ist der Name = Adresse).
Eben, soweit reichen meine Kenntnisse auch. Den avr-libc
eeprom-Funktionen darf keine SRAM-Variable mit &-Operator übergeben
werden. Vielmehr muss deren Inhalt als Zeiger auf Datentyp gecastet
werden, z.B.
@Karsten Brandt (Gast)
>Wenn Du der Meinung bist, dass das nicht nach Lehrbuch ist, dann>korrigiere doch das AVR-GCC-Tutorial:>// Byte aus dem EEPROM lesen>uint8_t EEPReadByte(uint16_t addr)>{> return eeprom_read_byte((uint8_t *)addr);>}
In der Tat, das ist Hackermist. Mal schauen. Es ist ein eher schlechtes
Beispiel, denn auf absolute Adresse sollte man möglichst nicht zugreifen
und den Compiler seine Arbeit machen lassen. Natürlich gibt es immer
Ausnahmen. Deine Anwendung ist KEINE!
>Natürlich kannst Du auch einen Zeiger übergeben
Was sollte dagegen sprechen?
>Stimmt, Fehler von mir (copy-paste). Warnungen sind natürlich weg.
;-)
>Eben, soweit reichen meine Kenntnisse auch. Den avr-libc>eeprom-Funktionen darf keine SRAM-Variable mit &-Operator übergeben>werden.
Was nur logisch ist, denn die liegt ja nicht im EEPROM ;-)
> Vielmehr muss deren Inhalt als Zeiger auf Datentyp gecastet>werden, z.B.>(uint8_t*)IRGENDEINE_SRAM_VARIABLE.
Ne, das ist schon wieder Handgestricktes. Mach es doch einfach solide so
wie oben und alles ist gut. Den Rest macht der Compiler.
Falk B. schrieb:> In der Tat, das ist Hackermist. Mal schauen. Es ist ein eher schlechtes> Beispiel, denn auf absolute Adresse sollte man möglichst nicht zugreifen
Ma ja, man sollte vieles nicht, aber wenn man es dann doch will, dann
will man das halt. Und bei der hardwarenahen
Mikrocomtrollerprogrammierung muß man halt ab und an von der reinen
Lehre abweichen.
Oliver
>>Natürlich kannst Du auch einen Zeiger übergeben>Was sollte dagegen sprechen?
Nichts, ausser Faulheit. Der Stiel ist wirklich besser. Ich vermute, du
spielst auf Typensicherheit an.
@Oliver S. (oliverso)
>> In der Tat, das ist Hackermist. Mal schauen. Es ist ein eher schlechtes>> Beispiel, denn auf absolute Adresse sollte man möglichst nicht zugreifen>Ma ja, man sollte vieles nicht, aber wenn man es dann doch will,
Er "will" bzw. wollte es nur, weil er den korrekten Weg nicht kannte.
> dann>will man das halt. Und bei der hardwarenahen>Mikrocomtrollerprogrammierung muß man halt ab und an von der reinen>Lehre abweichen.
Deutlich seltener als du glaubst. Dieses "Problem" ist mühelos
lehrbuchartig lösbar. Und das ist auch besser so!
C ist mehr als ein aufgebohrter Assembler! Und selbst dort lässt man in
den allermeisten Fällen den Assembler die Adressen der Daten verwalten!
@ karsten brandt (Gast)
>>Was sollte dagegen sprechen?>Nichts, ausser Faulheit. Der Stiel ist wirklich besser. Ich vermute, du>spielst auf Typensicherheit an.
Ja. Und sauberer Programmier_STIL hat noch keinem geschadet.