Mahlzeit, nachdem ich nun glaub ich schon 15.000 Stunden irgendwelche Foren durchforstet und mir glaub ich 32tausend8unddrölfzig Artikel durchgelesen habe wende ich mich in meiner Verzweiflung an professionelle Kräfte aus dem Netz: Ich möcht ganz banal meinen EEPROM beschreiben, und zwar in die Speicherzellen 10...200 die Nummer der jeweiligen Speicherzelle. Dies sollte eigentlich kein unmögliches Unterfangen sein, ich stelle mich aber offenbar zu bl... an. Der von mir verwendete Quellcode (siehe Anhang) funktioniert im Schrittbetrieb einwandfrei und auch im ganz normalen on-chip-debug ist alles prima. Nch dem debugging oder nach freiem Lauf des Programms ist der EEPROM aber nach wie vor mit 0xff's beschrieben. Mein ATMEGA32 steckt auf einem STK500 und ich debugge mit einem JTAG-ICE aus dem AVR-Studio 4.08. Im übrigen funktioniert es prima, wenn ich die Funktionen aus der Bibliothek <eeprom.h> verwende. Ich hoffe, daß irgendwelchen Leuten von Euch etwas einfällt und danke schon im Voraus für die Mühe, mir eine Antwort zu schreiben. Jürgen
Warum diese ganzen "antiken" Anweisungen (sbi, outw etc.)? Was funktioniert nicht, wenn man das Beispiel von Seite 19 des ATmega32-Datenblatts (Stand 12/03) uebernimmt (C Code example EEPROM_write)? Was spricht gegen die Verwendung von avr-libcs eeprom.h bei einem ATmega32?
> Im übrigen funktioniert es prima, wenn ich die Funktionen aus der > Bibliothek <eeprom.h> verwende. Was spricht dann dagegen, diese zu nehmen? (Die Bibliothek ist übrigens die avr-libc, das <avr/eeprom.h> ist nur die Headerdatei für diesen Teil der Bibliothek.) Schließlich kannst Du natürlich einfach auch den Sourcecode für das EEPROM-Handling der avr-libc ansehen... Btw., inp(), outw() und wie sie alle heißen sind deprecated und werden in der nächsten `major' Version der avr-libc nicht mehr enthalten sein. In ``if (data != EEDR)'' hast Du ja die neue Variante für das Lesen benutzt, warum dann der Mix mit der historischen Syntax? Wofür soll sowas eigentlich gut sein?: { ; // Empty } Die Adresse zweimal auszugeben, ist nicht sehr sinnvoll. EEWE muß innerhalb von 4 Takten nach EEMWE gesetzt werden. Daher klammert man beide normalerweise in cli()/sei() ein (bzw. wenn man sich nicht sicher ist, ob die Interrupts gestattet sind, muß man statt des sei() das alte SREG sichern und danach wiederherstellen). Aber Du schießt Dir nicht aus Versehen den EEPROM-Inhalt mit dem nächsten chip erase ab, oder?
Als erstes möchte ich euch recht herzlich für die Mühe danken, die ihr euch gemacht habt, um mir zu antworten. O.K., also meinen alten C-Befehlssatz werde ich nächstens reformieren, obwohl ich sagen muß, daß mir sbi(in irgendeinem Register, irgendein Bit) leichter lesbar erscheint als (irgendein Register) |= (1<<irgendein Bit); Sei's drum. Trotz alledem müßten die alten Befehle eigentlich noch funktionieren. Außerdem habe ich jetzt die neuen Befehle vom Datenblatt Seite 19 übernommen und es noch mal probiert. Effekt: der EEPROM ist leer. Diese { ; // Empty } -Anweisung ist einfach zur besseren Lesbarkeit für andere Leute, die mit dem von mir geschriebenen Quatsch klar kommen müssen. Und das doppelt beschriebene Adressregister ist irgendwie nur zur Sicherheit gedacht, werde ich aber auch weglassen. Diese Interrupt-anweisungen (cli() und sei()) sind bei meiner Funktion noch nicht enthalten, weil ich wirklich erstmal die Funktion des EEPROM-Beschreibens testen wollte. Da komme ich direkt zum Punkt, warum ich die elementaren Anweisungen und nicht die aus der libc verwenden möchte: Ich möchte eigentlich, daß das Beschreiben meines EEPROMs interruptgesteuert funktioniert. Dazu möchte ich einen Ringbuffer anlegen, der sich dann automatisch entleert. Das funktioniert sowohl bei meiner UART als auch bei meinem SPI hervorragend. Ich weiß nicht, ob ich irgendwie falsch liege, aber das EEPROM-Beschreiben ist doch ebenfalls ein peripherer Vorgang, der mit der CPU nichts zu tun hat, oder? Jetzt noch zum letzten Vorschlag: Wo bekomme ich den Quellcode meiner libc-Funktionen her und womit kann ich ihn lesen? Bitte lacht nicht über mich, aber ich habe meinen ganzen Rechner durchwühlt und bin auf kein brauchbares Ergebnis gestoßen. Im Verzeichnis Winavr\avr\lib schienen ja ganz brauchbare Dinge zu stehen, als ich sie aber mit einem normalen Editor geöffnet habe, bekam ich nur wildeste Hieroglyphen zu sehen. Achso, und wegen dieser chip-erase-Geschichte und dem EEPROM abschießen bin ich mir eigentlich ziemlich sicher, weil es ja mit den Bibliotheks-funktionen super funktioniert. Ich werde mich jetzt glaube ich mit dem Oszi hinsetzen und versuchen, inwiefern ich mit den Bibliotheksfunktionen interruptgesteuert arbeiten kann. Ich muß auf alle Fälle wissen, ob sie durch andere Interrupts unterbrochen werden können. Ich danke abschließend nochmal für Eure Bemühungen. Gruß Jürgen
Hallo Sportfreund Niemand wird ueber dich lachen. (-; Hab leider auch keine Ahnung warum es bei dir nicht klappt. Im uebrigen ist es ein sehr guter Ansatz den alten Befehlssatz abzustreifen und den neuen Weg zu betreten. Viel Erfolg noch und falls mir was einfaellt meld ich mich bei dir. Bis denne
Warum ein leeres Klammerpaar mit Semikolon drin ohne Bezug auf eine Schleife etc. die Lesbarkeit verbessern soll, bleibt mir ein Rätsel, aber sei's drum. Die Quellen findest Du entweder, indem Du Dir das Source-Paket von WinAVR installierst -- das sind dann alle Quellen, auch vom Compiler etc. Oder Du gehst zur avr-libc Homepage: http://savannah.nongnu.org/projects/avr-libc Dort kannst Du entweder das Archiv aus der download area holen oder Dich manuell durchs CVS hangeln.
hier ein Schnippsel der vielleicht weiterhilft: #include <inttypes.h> #include <avr/interrupt.h> void my_eeprom_write_byte(uint16_t *addr, uint8_t val) { cli(); /* disable all ints */ /* Wait for completion of previous write */ while(EECR & (1<<EEWE)) asm volatile ("nop"::); /* Set up address and Data Registers */ EEAR = *addr; EEDR = val; /* Write logical one to EEMWE */ EECR |= (1<<EEMWE); /* Start eeprom write by setting EEWE */ EECR |= (1<<EEWE); /* Wait for completion of this write */ while(EECR & (1<<EEWE)) asm volatile ("nop"::); sei(); /* re-enable all ints */ } zur Anwendung "puffer in einer ISR in eeprom schreiben" mglw. zu beachten: - cli/sei in einem SIGNAL ISR (EE_RDY) ist ueberfluessig, also weglassen. - zweites while ist mglw. ueberfluessig, wenn man sicherstellt dass der eeprom nicht von anderen routinen ohne abfrage des status genutzt wird. im vorliegenden beispiel "paranoia" um sicherzustellen, dass die daten im eeprom abgelegt sind, bevor der ruecksprung erfolgt. der schreibvorgang dauert relativ lange, also blockiert die zweite warteschleife in einem ISR den controller mglw. zu lange. - das while...nop kann natuerlich ("eleganter") durch loop_until_... ersetzt werden
Erneuter Dank meinerseits gilt denen, die versucht haben, mir zu helfen. An meiner Formulierung wird deutlich, daß alles nicht so funktioniert, wie ich es mir vorstelle. 1.Habe ich mittlerweile die Einsicht gewonnen (bin mir zu 75% sicher), daß der EEPROM-Schreibvorgang von der CPU gesteuert wird und es kein explizites peripheres Modul dafür gibt (wie z.B. für UART oder SPI). Außerdem braucht dieser Schreibvorgang immens viel Zeit und die CPU ist in dieser Zeit eben für nichts anderes zu gebrauchen. Damit habe ich mich nunmehr abgefunden und akzeptiere dies. 2.Habe ich festgestellt, daß auf meinem Controller nur die vorgefertigten Konstrukte aus der libc laufen. (Ich danke dir trotzdem, mtthomas, aber auch dein Programm funktioniert auf meinem ATMEGA32 nicht). Wie gesagt, er spielt das Programm bis zu Ende durch, auf dem Speicher zeigt sich aber kein Ergebnis, wohingegen mit der eeprom_write_block-Funktion alles prima läuft. Das ist mir aber mittlerweile auch egal. 3.Habe ich versucht, den Quelltext aus dem oben angegebenen Link zu entpacken. Dabei geht nur eines der drei Pakete zu entpacken und in diesem ist diese eeprom-Geschichte in Assembler geschrieben. Dies läßt sich natürlich für mein c-Programm schwer nutzen. Alles in allem höre ich jetzt ganz einfach auf, mir über den EEPROM eine Platte zu machen und aktualisiere ihn ganz einfach am Anfang meines Programms. Das ist nicht sehr kunstvoll und ohne jeden Schnörkel, sollte aber funktionieren. Und wenn der EEPROM aktualisiert werden soll, dann muß das Programm eben von vorne gestartet werden. Ich danke euch 3 Leuten nochmals herzlich und würde mich freuen, euch evtl. auch mal helfen zu können (Ich glaube, das wird nie passieren, oder?) Grüße Jürgen
> 1.Habe ich mittlerweile die Einsicht gewonnen (bin mir zu 75% > sicher), daß der EEPROM-Schreibvorgang von der CPU gesteuert wird > und es kein explizites peripheres Modul dafür gibt (wie z.B. für > UART oder SPI). Nein, EEPROM ist peripher -- sonst hätte ja der EEPROM-Interrupt gar keinen Sinn. Lesen passiert ohnehin synchron, nur beim Schreiben muß gewartet werden. > 3.Habe ich versucht, den Quelltext aus dem oben angegebenen Link zu > entpacken. Dabei geht nur eines der drei Pakete zu entpacken und in > diesem ist diese eeprom-Geschichte in Assembler geschrieben. Dies > läßt sich natürlich für mein c-Programm schwer nutzen. Naja, so viel Magie ist ja in den paar Zeilen Assemblercode nun auch nicht drin. Kurze C-Übersetzung: void eeprom_write_byte(const uint8_t *addr, uint8_t val) { uint8_t savesreg; while (EECR & _BV(EEWE)) ; EEARH = (uint16_t)addr >> 8; EEARL = (uint16_t)addr & 0xff; EEDR = val; savesreg = SREG; cli(); EECR |= _BV(EEMWE); EECR |= _BV(EEWE); SREG = savesreg; } (Der daraus generierte Code ist drei Befehle länger als die Assemblerversion aus der Bibliothek. ;-)
MECKERMODUS ON ASM_FUNDI ON >(Der daraus generierte Code ist drei Befehle länger als die >Assemblerversion aus der Bibliothek. ;-) Ja ja, klingt wenig, wenn man aber bedenkt, dass die Assemblerroutine 8 Befehle hat, sind das 37,5% mehr !!! MECKERMODUS OFF ASM_FUNDI OFF Wer übrigens so wie ich (schäm) immer noch Windows benutzt und trotzdem einen Blick auf den libc-Source werfen will: die .bz2 Sourcen lassen sich mit dem von Cygwin mitinstallierten bzip2.exe entpacken. Einfach im Verzeichnis der .bz2-Datei bunzip2 dateiname.bz2 eingeben, die resultierende Datei ist vom Typ .tar Nach dem Entpacken noch die Endung von <leer> auf .tar ändern, das wars. Stefan
Nein, es sind 11 vs. 14 Befehle. Klar, sind 22 % Einsparung, klingt viel, aber erinnere Dich an den alten Spruch: ``Never try optimizing something until you've profiled it.'' Mit anderen Worten: sofern Deine Applikation nicht gerade den lieben langen Tag EEPROMs beschreibt, wirst Du Dir für die Einsparung vermutlich nicht viel kaufen können (und wenn sie das macht, willst Du vermutlich genau wie Jürgen ohnehin auf interruptgesteuerte Routinen umsteigen). Sollte ja auch keine Kritik am Assemblercode sein, sondern nur eine grobe Angabe liefern, wie gering letztlich das Einsparpotential von sorgfältig handgefeiltem Assemblercode wirklich ist. Manche Leute vermuten hier wohl eher 50 % und mehr. > die .bz2 Sourcen lassen sich mit dem von Cygwin mitinstallierten > bzip2.exe entpacken. Ich dachte, ich hätte gehört, daß aktuelle Winzips das auch könnten? Die Endung mußt Du übrigens nicht unbedingt auf .tar ändern, da es dem tar sowieso egal ist, wie seine Datei heißt. Wenn Du den Cygwin-tar dabei hast, kannste dann auch gleich tar -xvjf dateiname.tbz schreiben. ;-)
Hallo Jörg: Habe ich auch nicht ganz ernstgemeint - ich hoffe, das ist so rübergekommen ;-) Übrigens habe ich bei eeprom_read_byte statt eeprom_write_byte geschaut, deswegen die 8 Befehle, Asche auf mein Haupt. Früher wurde ja überall rumerzählt, Assembler sei ca. Faktor 10 effizienter als jede Hochsprache, wie man sieht, sieht man davon nicht mehr viel. Das mit WinZip werde ich mal ausprobieren, ich benutzte normalerweise den TotalCommander, der kann in (fast) jedes Archiv wie in ein Unterverzeichnis reinschauen, nur eben in .tar nicht. Gruß, Stefan
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.