mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AtMega32 Sleep Mode


Autor: Fritz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich möchte gerne mit einem Taster den AtMega32 schlafen legen, und auch 
wieder wecken.

habe dazu folgendes Programm von Peter Dannegger verwendet:
Beitrag "AVR-GCC Power-Down Tutorial"

Und verwende den INT1 mit PD3 als Low aktiven Interrupt.

Ich habe nur folgendes Phänomen:
In meinem INT1_vect Interrupt wird, wie bei Peter Dannegger, der INT1 
deaktiviert, danach schalte ich LEDs an ( zum testen ).

Wenn ich nun meinen µC anschalte, und die Taste drücke, gehen die LEDs 
an, und der µC geht schlafen. Ich kann ihn auch wieder wecken mit der 
Taste.

Aber, wieso gehen die LEDs an? Meines erachtens sollte er doch nur 
schlafen gehen, und erst nach dem aufwecken, den Interrupt ausführen und 
die LEDs angehen oder?

Bzw. wieso funktioniert das aufwecken überhaupt, wenn er den Interrupt 
ausführt in dem der INT1 deaktiviert wird?

Danke

Autor: c-hater (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fritz schrieb:

> habe dazu folgendes Programm von Peter Dannegger verwendet:
> Beitrag "AVR-GCC Power-Down Tutorial"

Verweise nicht auf das Original, sondern zeige deine Version, exakt so, 
wie du sie verwendest.

Es muss ein Fehler darin sein.

Autor: Dieter F. (jim_quakenbush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fritz schrieb:
> habe dazu folgendes Programm von Peter Dannegger verwendet:
> Beitrag "AVR-GCC Power-Down Tutorial"

Das Original ist für den ATTiny13 geschrieben - Du hast wohl einen 
Fehler in der Umsetzung auf den ATMega32.

Zeigen - dann kann Dir geholfen werden ...

Autor: Fritz (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, und danke für die Rückmeldung.

hier im Anhang das Programm.
Danke :)

Autor: c-hater (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fritz schrieb:

> hier im Anhang das Programm.
void go_power_down( void )
{
  ATOMIC_BLOCK(ATOMIC_FORCEON){                 // = CLI
    LED0 = LED_OFF;        // switch off external loads
    TIMSK = 0;          // other interrupts off !
    
  //  GIMSK = 1<<PCIE;        // awake interrupt on
  GICR  |= 1<<INT1;
  
    set_sleep_mode( SLEEP_MODE_PWR_DOWN);       // prepare power down
    
  }                                             // = SEI
  #ifdef USE_SLEEP_MODE
  // use never sleep_mode()
  sleep_mode();                                 // under no circumstances
  
  // its always dangerous !!!
  #else
  
  sleep_cpu();          // do SLEEP instruction only !
  
  #endif
  TIMSK = 1<<TOIE0;                            // enable other interrupts again
}

OMG. Ein schönes Beispiel dafür, wie saukompliziert die Verwendung von C 
als Sprache eine absolut simple Sache machen kann...

Aber wenn man sich diesen Scheissdreck schon antut, dann muss man es 
halt trotzdem einfach nur richtig machen. Also etwa so:
void go_power_down( void )
{
  ATOMIC_BLOCK(ATOMIC_FORCEON)
  {
    LED0 = LED_OFF;
    GICR |= 1<<INT1;
    set_sleep_mode( SLEEP_MODE_PWR_DOWN);
    GIFR = 1<<INTF1;
  }
  sleep_cpu();
}

Wenn dieser Schrottcompiler jetzt wirklich die schließende Klammer des 
Atomic-Blocks zu einer sei-Instruction übersetzt und das sleep_cpu() zu 
einer sleep-Instraction und nix weiter dazwischenballert, dann ist die 
Sache safe.

In Asm schreibt man das einfach so hin, dass es safe ist und muss sich 
nicht auf Ratespiele einlassen, wie der Compiler den Scheiss nun genau 
übersetzen wird...

Autor: Dieter F. (jim_quakenbush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fritz schrieb:
> Aber, wieso gehen die LEDs an?

Weil Du die "falsch" herum angeschlossen hast.

Was Du da bezweckst
  DDRB = 0xFF;
  PORTB |= 0x10;
  PORTB &= ~(0x20);

weiß ich nicht so recht. Aber die PWM-LED geht an (wenn Du in den 
Sleep-Mode gehst) weil Du es so definiert
#define LED_OFF    1
#define  LED_ON    0

hast. Entweder die Definition umkehren oder die LED anders herum 
anchliessen.

Das Aufwecken erfolgt rein durch das Auslösen des Interrupts - den 
könntest Du auch leer lassen, aber dann hätte das Debouncing ein 
Problem, weil der Interrupt dann x-mal aufgerufen wird, in der Zeit in 
welcher Du die Taste drückst und der Timer-Interrupt (für das 
Debouncing) nicht zum Zuge kommt.

Autor: Fritz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@c-hater:

danke, leider schafft aber auch das keine Abhilfe.
Ich werde mal das ganze "frisch" Programmieren und nicht das komplette 
Programm übernehmen, sondern erstmal debouncing, und dann Sleep 
Funktionen. Vielleicht klappt es dann.

Dieter F. schrieb:
> Fritz schrieb:
>> Aber, wieso gehen die LEDs an?
>
> Weil Du die "falsch" herum angeschlossen hast.

Nein, ich habe an PORTB 8 LEDs dran. Die 1. wird gefaded, alle anderen 
sollen nur zeigen, ob er aufgewacht ist.

> Was Du da bezweckst
>   DDRB = 0xFF;
>   PORTB |= 0x10;
>   PORTB &= ~(0x20);
>
> weiß ich nicht so recht. Aber die PWM-LED geht an (wenn Du in den
> Sleep-Mode gehst) weil Du es so definiert
> #define LED_OFF    1
> #define  LED_ON    0
>
> hast. Entweder die Definition umkehren oder die LED anders herum
> anchliessen.
>
> Das Aufwecken erfolgt rein durch das Auslösen des Interrupts - den
> könntest Du auch leer lassen, aber dann hätte das Debouncing ein
> Problem, weil der Interrupt dann x-mal aufgerufen wird, in der Zeit in
> welcher Du die Taste drückst und der Timer-Interrupt (für das
> Debouncing) nicht zum Zuge kommt.

Autor: c-hater (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fritz schrieb:

> danke, leider schafft aber auch das keine Abhilfe.

Hast du auch kontrolliert, dass der Compiler das Richtige daraus gemacht 
hat?

Der springende Punkt ist, dass zwischen dem "sei" und dem "sleep" keine 
weiteren Instruktionen liegen dürfen. AUSSCHLIESSLICH unter dieser 
Bedingung ist die Sache wirklich prinzipiell sicher.

Diese prinzipielle Sicherheit bedeutet allerdings noch lange nicht, dass 
es auch wie gewünscht funktioniert. Dazu muss natürlich dann auch noch 
der Rest des Programmes an den richtigen Stellen das Richtige tun.

Das heisst übrigens u.a.: Die ISR des Wakeup-Interrupts darf eigentlich 
nichts anderes machen, als eben diesen Interrupt zu deaktivieren. 
Abweichungen von diesem Grundsatz sind möglich, erfordern aber im 
Minimum ein vollständiges Verständnis des Sleep-Mechanismus und der zum 
Aufwachen benutzten Hardware.

Autor: Fritz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

nein, das habe ich nicht, muss mir ansehen, wie ich mir die Ausgabe in 
asm ansehen kann, mache ich gleich! Danke

Aber das Problem dürfte folgendes sein, ich muss einen Low Level 
Interrupt verwenden, da der Atmega32 mit einem falling Edge Interrupt 
nicht aufwachen kann.
Drücke ich nun meine Taste, geht er in den Sleep Modus, die Taste ist 
noch gedrückt, es kommt sofort ein Interrupt zum aufwachen, in der main 
sieht er aber, die Taste ist gedrückt, er legt sich gleich wieder 
schlafen, und das in einer Schleife...

Kann es sein, dass es mit einem Low Level Interrupt einfach nicht 
funktioniert, das heißt mit einem atmega32 in der Art nicht Möglich ist?

Autor: Planlos (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fritz schrieb:
> in der main
> sieht er aber, die Taste ist gedrückt, er legt sich gleich wieder
> schlafen,

Dann Ändere die Tastenabfrage in main, so dass sie nur auf Flanken 
Reagiert, üblich ist das Loslassen des Tasters.
Geht zusammen mit der Entprellung in Software sehr einfach.

Autor: Dieter F. (jim_quakenbush)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fritz schrieb:
> Nein, ich habe an PORTB 8 LEDs dran. Die 1. wird gefaded, alle anderen
> sollen nur zeigen, ob er aufgewacht ist.

Wie hast Du die denn angeschlossen? Welche Vorwiderstände?

Also das Coding funktioniert ohne die x LED's wunderbar auf meinem 
ATMega32 - mit dem Unterschied, dass ich PINB3 für die LED nutze - aber 
das kann es nicht sein.

: Bearbeitet durch User
Autor: Fritz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

läuft auf einem STK500, also low active LEDs.

Naja mehr oder weniger funktioniert es ja, aber wenn man eben im 
Interrupt die LEDs toggelt sieht man extrem, wie er in der Schleife 
läuft. Im Endeffekt kommt er zwar ins Sleep, aber finde es nicht so 
wirklich toll, wenn er ständig aufwächt, schlafen geht, solange bis ich 
von der Taste runtergehe.

Hast dus schonmal versucht in dem Interrupt LEDs toggeln zu lassen, oder 
einfach auf einem PIN ausgeben und mit Oszi ansehen? Ich denke bei dir 
wirds dann auch in einer Schleife toggeln, sonst wär das tatsächlich 
irgendwie komisch !?

Werde aber wahrscheinlich ohnehin auf einen neueren Atmega umsteigen, 
mit Pin Change Interrupts, da funktionierts besser ;).

Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fritz schrieb:
> aber finde es nicht so
> wirklich toll, wenn er ständig aufwächt, schlafen geht, solange bis ich
> von der Taste runtergehe.

Na dann geh eben erst in Power-Down, nachdem der Pin wieder high ist.

Autor: M. K. (sylaina)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
c-hater schrieb:
> Wenn dieser Schrottcompiler jetzt wirklich die schließende Klammer des
> Atomic-Blocks zu einer sei-Instruction übersetzt und das sleep_cpu() zu
> einer sleep-Instraction und nix weiter dazwischenballert, dann ist die
> Sache safe.

Was soll denn eine "sei-Instrucion" sein? sei() macht nix anderes als 
das asm-sei auch macht: Das Global Interrupt Flag setzen.
Probleme hat man eigentlich nur wenn z.B. die Tastatur kaputt ist und 
man statt GICR GIFR schreibt oder statt INT0 INTF0...Aber ich bin mir 
sicher, dann hat man auch in ASM ein Problem, nicht nur in C. Der 
Compiler kann dafür nix, der rät nicht was eigentlich damit gemeint war.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.