Hallo allerseits, in Beitrag "Re: Tiny45 stürzt ab trotz Minimalprogramm" stellte sich die Frage, ob zu viele Interrupts (z.B. durch Prellen) einen Absturz verursachen können. Ich bezweifele aber, dass es 'zu viele Interrupts' überhaupt gibt. Wenn ein Interrupt auftritt, werden andere Interrupts doch bis zum Ende der ISR gesperrt, und dann nach Priorität abgearbeitet. Was kann da zum Absturz führen?
Du musst dich überhaupt erstmal fragen was ein "Absturz" ist. --> der uC reagiert z.B. nicht mehr (oder nicht so, wie er soll) Es kann also bei "zu vielen" Interrupts passieren, dass der uC quasi im Interrupt hängen bleibt, da zur Ausführung des Hauptprogramms gar keine Zeit mehr bleibt...
Der Schubi wrote: > Interrupt hängen bleibt, da zur Ausführung des Hauptprogramms gar keine > Zeit mehr bleibt... Nein kann nicht passieren, da nach einem Interrupt mindestens (immer) ein paar Befehle aus dem Hauptprogramm abgearbeitet werden. Es kann also traege werden, aber nicht vollkommen zum Erliegen kommen.
Wo steht denn das? Wenn ein Interrupt abgearbeitet wird und ein neuer Interrupt eintrifft, warum sollte dann das Hauptprogramm abgearbeitet werden? Interrupt hat Priorität.
Nein hat er nicht, das soll das Aushungern des Hauptprogramms verhindern, was auch Sinn macht. Und wo meinste wohl wird das stehen? "When the AVR exits from an interrupt, it will always return to the main program and execute one more instruction before any pending interrupt is served."
Dein Problem sind nicht die Interrupts, sondern das Sleep. Wenn zum Zeitpunkt des Sleep die Interrupts disabled sind, dann wars das. Ohne Interrupts kann nur ein Reset das Sleep beenden. Du mußt also folgenden Ablauf unbedingt einhalten. Schau mal in die sleep.h:
1 | Example:
|
2 | \code |
3 | #include <avr/interrupt.h> |
4 | #include <avr/sleep.h> |
5 | |
6 | ...
|
7 | cli(); |
8 | if (some_condition) { |
9 | sleep_enable(); |
10 | sei(); |
11 | sleep_cpu(); |
12 | sleep_disable(); |
13 | }
|
14 | sei(); |
15 | \endcode |
Peter
Danke. Wieder was dazugelernt :-) Allerdings ist ein Befehl im Hauptprogramm pro ausgeführtem Interrupt nicht wirklich viel, oder?
>Wo steht denn das? >Wenn ein Interrupt abgearbeitet wird und ein neuer Interrupt eintrifft, >warum sollte dann das Hauptprogramm abgearbeitet werden? Interrupt hat >Priorität. AVRs arbeiten nach Rückkehr aus einem Interrupt vor Sprung auf den Vektor eines anstehenden Interrupts noch einen Befehl des Hauptprogramms ab. Zitat aus dem Datenblatt zum ATmega8, Kapitel "AVR CPU Core", Abschnitt "Reset and Interrupt Handling", ca. S. 12: "When the AVR exits from an interrupt, it will always return to the main program and execute one more instruction before any pending interrupt is served."
Verzeihung, ich habe mich unpräzise ausgedrückt - es wird nur der aufrufende Pin-Change interrupt deaktiviert, und der sleep mode idle aktiviert. Hier das Programm direkt: Beitrag "Re: Tiny45 stürzt ab trotz Minimalprogramm" Oder verstehe ich falsch?
concept wrote: > Verzeihung, ich habe mich unpräzise ausgedrückt - es wird nur der > aufrufende Pin-Change interrupt deaktiviert, und der sleep mode idle > aktiviert. > > Hier das Programm direkt: > > Beitrag "Re: Tiny45 stürzt ab trotz Minimalprogramm" Das Programm sieht o.k. aus. Es hat bloß kaum Ausgaben. Einzig die eine LED blitzt kaum merkbar im Timerinterrupt ganz kurz auf (~1 µS). Wie stellst Du also fest, daß es scheinbar abstürzt? Erzähl mal, was Du wann erwartest und was wie reagiert. Peter
Zusammenfassung: AVR (tiny45) soll aus power-down auf Tastendruck aufwachen. Datenblatt: http://www.atmel.com/dyn/resources/prod_documents/doc2586.pdf Problem (wacht nach einigen Tastendrücken nicht mehr auf) wird sehr wahrscheinlich verursacht durch PCINT in zusammenhang mit Prellen und deaktivieren des PCINT im GIMSK. Verwendung von INT0 bzw. deaktivieren des einzelnen PCINT-Pins in PCMSK ruft keinen 'Absturz' hervor.
1 | Autor: Bernhard R. (barnyhh) |
2 | Datum: 30.03.2008 17:36 |
3 | |
4 | Hypothese: |
5 | |
6 | Es gibt anscheinend irgendeine Situation, in der folgendes passiert: |
7 | - PCIE wird auf 0 gesetzt (disabled) (in der PCINT-Routine) |
8 | - PCIE wird auf 1 gesetzt (enabled) (in der Timer-Routine) |
9 | >>>>> Die PCINT-Logik glaubt irrtümlich, sie sei disabled |
10 | rsp. |
11 | >>>>> Die PCINT-Logik "verschlabbert" alle nachfolgenden Pegelwechsel am Pin. |
Ungesichterte Ursache evtl. in 9.2.2 Pin Change Interrupt Timing ? Ob der AVR tatsächlich im power-down-mode bleibt, ließe sich evtl. durch Benutzen eines anderen PCINT-Pins und dann Auslösen von INT0 herausfinden (wenn er aufwacht, hat er wohl geschlafen :-).
Ach so, es ist übrigens keine LED oder so angeschlossen, ist ein reines Testprogramm. Beim Betätigen des Tasters / bei jedem PCINT sollte es einen Impuls geben, mit einem wenig prellenden Taster funktioniert das häufig, mit einem prellenden (1ms) Mikroschalter gibt es den Impuls nur bei der fallenden Flanke (Taster drücken).
.. und dann keine Reaktion auf den Tastendruck mehr.
So, ich hab Dein Programm ausprobiert und es funktioniert nicht. Aber ich hab den Fehler gefunden, es liegt am sleep_mode(); Ersetze Deine Mainloop hiermit:
1 | for (;;) |
2 | {
|
3 | asm volatile("sleep"); // nur Sleep und nichts weiter ! |
4 | // sleep_mode(); // das ist nicht Interrupt fest !
|
5 | }
|
und dann läuft es. Das Kommando sleep_mode(); hat jemand geschrieben, der nicht daran gedacht hat, daß Du das MCUCR in nem Interrupt manipulierst. Es macht noch irgendwas mit dem MCUCR-Register rum und wenn da ein Interrupt einschlägt, dann steht der ganze Laden forever. Peter
P.S.: Sämtliche sleep Funktionen gehen nicht, wenn Du sie in Interrupts verwendest. Dann mußt Du alles selber machen, siehe Anhang. Peter
P.P.S.: Das sleep_mode(); muß man so umdefinieren:
1 | #ifdef sleep_mode
|
2 | #undef sleep_mode
|
3 | #define sleep_mode()\
|
4 | cli();\
|
5 | MCUCR |= 1<<SE;\
|
6 | sei();\
|
7 | asm volatile("sleep");\
|
8 | cli();\
|
9 | MCUCR &= ~(1<<SE);\
|
10 | sei();
|
11 | #endif
|
Dann kann man set_sleep_mode(); wieder benutzen. Peter
oder man arbeitet so
1 | sleep_mode(XYZ); |
2 | sleep_enable(); |
3 | sei(); |
4 | while (1) { |
5 | sleep_cpu(); |
6 | }
|
was das Gleiche macht wie Peters erster Vorschlag. Du solltest ein *.LST und *.LSS File erzeugen lassen (im Makefile) und dir dann dort den erzeugten ASM-Code des Compilers anschauen. Gruß Hagen
Es steht ja eigentlich alles in der sleep.h: "As this combined macro might cause race conditions ..." Man muß es eben bloß lesen, statt einfach so ohne Überlegung die Macros hinzuschreiben. Unverständlich finde ich aber, warum diese tickende Zeitbombe sleep_mode(); überhaupt definiert wurde. Hier hat man ja den Vorteil, daß die Mainloop es schön oft aufruft und der Fehler schnell auftritt. Wenn man aber reale Programme hat und die dann nur alle 24h einfrieren, dann legt man sich die Karten (oder schmeißt den ganze AVR-Krempel aus dem Fenster und nimmt nen PIC). Peter
Super, danke für die Erklärung! > Man muß es eben bloß lesen, statt einfach so ohne Überlegung die Macros > hinzuschreiben. Das ist richtig, aber als Anfänger ist man noch in unbekannten Gewässern - und verläßt sich auf's Tutorial und den Compiler. Nächstesmal weiß ich's ein bißchen besser.
concept wrote: > Super, danke für die Erklärung! > >> Man muß es eben bloß lesen, statt einfach so ohne Überlegung die Macros >> hinzuschreiben. War nicht böß gemeint, ich hab ja selber das Grübeln gekriegt. Ich habs erst beim Anschauen des Assemblerlistings gesehen, daß dieses Macro nicht das macht, was ich erwartet hätte. Ich hab dann sämtliche Macros rausgeschmissen und von Hand gemacht und dann gings. Dann erst hab ich mir die sleep.h gründlicher vorgenommen. Peter
Alles klar ;-) Mich wundert allerdings, dass der Fehler nicht (zumindest nicht sofort) auftrat, wenn der Interrupt über die Pin-Maske ausgeschaltet worden ist. Vielleicht, weil das Interrupt-Timing nicht so lange dauert, und die Wahrscheinlichkeit der 'race condition' beim Prellen kleiner war. Jedenfalls schön, dass jetzt Verlaß auf's Programm ist, wenn ich nachher daran arbeite / spiele.
Hi. Nur mal so aus Neugier: > Sämtliche sleep Funktionen gehen nicht, wenn Du sie in Interrupts > verwendest. Mal hypothetisch: Ein Gerät mit Batterie und Stromversorgung soll bei Wegfall der Stromversorgung im Batteriebetrieb in den Speep-Modus verfallen um die Entladezeit (strom) der Batterie zu reduzieren. Bei einem System das 20, 30 oder mehr mA an Strom konsumiert, bleibt da nicht viel Zeit, den Spannungsausfall zu bemerken und schnell schlafen zu gehen. Wie würde man sowas dann lösen wenn der Sleep-Mode nicht in einer Interruproutine ausgelöst werden kann? Polling wäre ja bei den meisten Anwendungen viel zu langsam.
Er meinte damit die im Header definierten Sleep-C-Funktionen, nicht die Sleep-Funktion des Controllers im allgemeinen.
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.