AVR-GCC Power-Down Tutorial: 1. Fallgrube 1: Sehr häufig wird der Fehler gemacht, daß zuerst versucht wird, den Power-Down Modus zu implementieren ohne eine funktionierende Entprellroutine zu haben. Wenn der Power-Down Modus durch Tastendruck erfolgen soll, muß man zuerst eine Entprellroutine haben. Man fängt den Hausbau ja auch nicht mit dem Dach zuerst an, sondern mit dem Fundament. Und für jede Aufgabe, die per Tastendruck erfolgen soll, ist nunmal eine einwandfrei funktionierende Tastenroutine das Fundament. Anzeichen für eine ungenügende Entprellroutine können sein: - man drückt die Taste und der MC geht (manchmal) nicht in Power Down. - er geht in Power-Down, wacht aber (manchmal) nie wieder auf. - er wacht auf, obwohl man keine Taste gedrückt hat (Störimpuls). Die hier verwende Entprellroutine wurde ja schon an mehreren Stellen erkärt: Beitrag "Tasten entprellen - Bulletproof" Beitrag "Universelle Tastenabfrage" http://www.avrfreaks.net/index.php?module=Freaks%20Academy&func=viewItem&item_type=project&item_id=1801 2. Fallgrube 2: Der AVR-GCC enthält leider das Macro sleep_mode(), welches sehr gefährlich ist, da es in den meisten Fällen unerwünschte Nebeneffekte hat. Diese Macro greift nämlich nicht atomar auf das MCUCR zu, was in größeren Programmen Probleme geben kann und wird. Außerdem folgt das SLEEP nicht direkt auf das SEI einer vorhergehenden atomaren Operation zum Aktivieren des Aufwachinterrupts. Deshalb sollte man auf dieses Macro unbedingt verzichten! 3. Beispielprogramm: Das Programm implementiert einen LED-Fader mit SW-PWM. Getestet wurde es auf dem STK500 mit dem ATtiny13. Die PWM, das Faden und die Tastenentprellung werden im Timerinterrupt gemacht. Dadurch kann man gut sehen, wann der MC im Power-Down ist und wann nicht. Neben der bekannten Tastaturroutine wird auch ein Bitmacro werwendet, damit man einfacher Bitvariablen implementieren kann. Dadurch wird das Programm leserlicher. Eine Erklärung findet man z.B. hier: http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=67368 Zeile 42: Zum Aufwachen wird der Pin-Change-Interrupt verwendet. Nach dem Aufwachen disabled er sich selber. Das wird häufig gemacht, damit die CPU nicht mit unnötigen Interrupts geflutet wird. Zeile 103: Hier ist erstmal das harmlosere Kommando, um in den Idle-Modus zu gehen. Dabei ist nur zu beachten, daß Änderungen des Sleep-Mode grundsätzlich atomar sein sollten. In diesem Beispiel ist es zwar nicht nötig, aber in größeren Programmen kann es durchaus sein, daß auch Interrupts das MCUCR-Register zugreifen. Z.B. ein Timerinterrupt setzt nach einem Timeout den Power-Down-Mode oder ein externer Interrupt schaltet die Flanke um. Ehe man sich also die Karten legt, wenn das Programm größer wird und man nicht mehr an den Sleep-Mode denkt, ist es daher sicherer, gleich von Anfang an sauber zu programmieren und Seiteneffekte von vornherein zu vermeiden. Zeile 112: Hier kommt die wichtigste Funktion, wo man besonders sorgfältig arbeiten muß. Fehler hierbei können sich selten bemerkbar machen und sind daher äußerst schwer zu finden. Die Verbraucher abzuschalten bedarf wohl keiner Erklärung. Dann sollte man alle nicht zum Aufwachen benötigten Interrupts abschalten, warum? Nun, sie können zwar nicht neu auslösen, wenn man im Power-Down ist, aber sie können just zum Zeitpunkt des Sleep anhängig sein und dann wird das Sleep nicht ausgeführt (bzw. nur für einen CPU-Takt). Es wird ja nur die Takt-Domäne abgeschaltet, nicht aber die Interruptlogik. Zum Schluß muß man natürlich noch den Aufwachinterrupt scharf machen und den Power-Down Mode setzen. Und alle diese Aktionen müssen atomar erfolgen, damit nicht ein Interrupt davon was rückgängig macht (z.B. SW-PWM schaltet LED wieder ein usw.). Nach einer atomaren Funktion (SEI-Befehl am Ende) wird der nächste Befehl immer direkt ausgeführt, d.h. das SLEEP erfolgt, ohne das ein Interrupt dazwischen funken kann. Hier kann man sich jetzt schön die Gefährlichkeit des sleep_mode() Macros ansehen, einfach oben den Kommentar vor USE_SLEEP_MODE löschen und nichts geht mehr. Nach dem Sleep werden dann alle benötigten Interrupts wieder eingeschaltet. Zeile 141: Hier wird geprüft, ob der entprellte Zustand der Aufwachtaste auch dem am Pin anliegenden Signal entspricht, also die Entprellung abgeschlossen ist. Da der Taster aber low-aktiv ist, das entprellte Bit aber high-aktiv, wird auf Ungleichheit getestet (Exklusiv-ODER). Bevor das Entprellen nicht beendet ist, darf der Power-Down nicht ausgeführt werden, da ja die Entprellung über den Timerinterrupt erfolgt und der dann nicht mehr laufen würde. Man sieht auch schön, wie die CPU kurz aufwacht, um das Loslassen nach dem Power-Down zu entprellen. In der Praxis würde man dann die LED natürlich nicht einschalten. Ist das Entprellen beendet, wird die Taste ausgewertet. Sie schaltet nun zwischen Wachen und Schlafen hin und her. Dafür wird eine Variable genommen, damit erneut versucht werden kann in den Power-Down zu gehen, wenn schon ein Pin-Change-Interrupt anhängig ist oder wenn die Entprellung feststellt, daß es nur ein Störimpuls war. Zeile 146: Hier wird jetzt endlich die Power-Down Funktion aufgerufen, solange die Variable wahr ist. Peter Dannegger
Peter Dannegger schrieb: > Der AVR-GCC enthält leider das Macro sleep_mode(), welches sehr > gefährlich ist, ... Wenn du denkst, dass damit was nicht in Ordnung wäre, dann diskutier das bitte auf der avr-libc-dev Mailingliste, damit es korrigiert werden kann. Davon, dass du hier irgendwo in der Versenkung ein Tutorial postest, hat über kurz oder lang niemand mehr was. Eigentlich sind für deine Ansprüche die separaten Teilstücke sleep_enable(), sleep_cpu() udn sleep_disable() gedacht. Wenn du denkst, dass deren Dokumentation noch irgendwie unzureichend wäre und/oder die ,Gefährlichkeit' des einfachen sleep_mode() nicht ausreichend beschrieben wäre, dann würden wir uns über einen entsprechenden Patch für die Dokumentation freuen. Wenn dein Englisch nicht super-duper sein sollte, ist das auch nicht tragisch, das wird dann schon noch korrekturgelesen.
Er will halt seine Entprellroutine in der Lib sehen und sich dadurch unsterblich machen. MfG
Geprellter schrieb: > Er will halt seine Entprellroutine in der Lib sehen und sich dadurch > unsterblich machen. Die Entprellroutine ist gut, ist aber halt nicht so elementar, dass sie Gegenstand der Bibliothek selbst wäre. Allerdings hätte ich nichts dagegen einzuwenden, wenn er daraus ein komplettes Beispiel zimmern würde, das dann hierher kommt: http://www.nongnu.org/avr-libc/user-manual/group__demos.html Setzt aber voraus, dass es außer dem Quelltext selbst eine Doxygen- Doku dazu gibt.
@peter: würdest du auch noch deine atomic.h veröffentlichen? Das Atomic-Block interessiert mich... Gruß Fabian
die atomic.h ist doch Bestandteil der GCC Installation.. Fabian B. schrieb: > @peter: würdest du auch noch deine atomic.h veröffentlichen? Das > Atomic-Block interessiert mich... > > Gruß > Fabian
>Neben der bekannten Tastaturroutine wird auch ein Bitmacro werwendet, >damit man einfacher Bitvariablen implementieren kann. Dadurch wird das >Programm leserlicher. Davon halte ich persönlich nichts... verwirrt bloß und sorgt für noch mehr Chaos... Ein Tut sollte immer so wenig nicht Lib-Fkt. verwenden wie möglich. (Meine Meinung) Oder erklärst du erst wie man ein Wohnzimmer streicht und dann wie man das Haus baut... Diese Macros sind nicht unbedingt für die Funktion des Tut/Beispiel notwendig, also weg damit... Die Tasterentprelldingsbums ist natürlich notwendig sonst sieht man sonstwas...
Hallo Peter, ich habe gerade deinen Code für meinen Atiny13 unter WINAVR mit avr-gcc -Wall -Os -fpack-struct -fshort-enums -funsigned-char -funsigned-bitfields -mmcu=attiny13 -DF_CPU=8000000UL -MMD -MP -MF"main.d" -MT"main.d" -c -o"main.o" "../main.c" compilieren wollen und folgende Fehlermeldung bekommen. Kannst du mir sagen was ich falsch mache ? ../main.c: In function 'get_key_press': ../main.c:87: error: 'for' loop initial declaration used outside C99 mode ../main.c: In function 'go_idle': ../main.c:112: error: 'for' loop initial declaration used outside C99 mode ../main.c: In function 'go_power_down': ../main.c:121: error: 'for' loop initial declaration used outside C99 mode make: *** [main.o] Error 1 Gruss, Jörg
Sorry doppelpost. Danke @ A. K. hat funktioniert. Sollte ich das Standardmäßig bei all meinen Projekten setzen ? Gruss, Jörg
Hallo Jörg, -std=gnu99 Sagt dem Compiler, dass er die gnu99 erweiterung benutzen soll... kommt also darauf an ob in deinem Code derartiges vorkommt :-) http://www.rn-wissen.de/index.php/Avr-gcc BTW: kommst Du aus dem Bergischen ?
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.