Forum: Compiler & IDEs Beschreiben des EEPROM beim ATMEGA32


von Jürgen Päßler (Gast)


Angehängte Dateien:

Lesenswert?

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

von mthomas (Gast)


Lesenswert?

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?

von Jörg Wunsch (Gast)


Lesenswert?

> 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?

von Jürgen Päßler (Gast)


Lesenswert?

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

von Ruffi (Gast)


Lesenswert?

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

von Jörg Wunsch (Gast)


Lesenswert?

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.

von mthomas (Gast)


Lesenswert?

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

von Jürgen Päßler (Gast)


Lesenswert?

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

von Jörg Wunsch (Gast)


Lesenswert?

> 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. ;-)

von Stefan Kleinwort (Gast)


Lesenswert?

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

von Jörg Wunsch (Gast)


Lesenswert?

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. ;-)

von Stefan Kleinwort (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.