Forum: Mikrocontroller und Digitale Elektronik AtMega32 Sleep Mode


von Fritz (Gast)


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

von c-hater (Gast)


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.

von Dieter F. (Gast)


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

von Fritz (Gast)


Angehängte Dateien:

Lesenswert?

Hallo, und danke für die Rückmeldung.

hier im Anhang das Programm.
Danke :)

von c-hater (Gast)


Lesenswert?

Fritz schrieb:

> hier im Anhang das Programm.
1
void go_power_down( void )
2
{
3
  ATOMIC_BLOCK(ATOMIC_FORCEON){                 // = CLI
4
    LED0 = LED_OFF;        // switch off external loads
5
    TIMSK = 0;          // other interrupts off !
6
    
7
  //  GIMSK = 1<<PCIE;        // awake interrupt on
8
  GICR  |= 1<<INT1;
9
  
10
    set_sleep_mode( SLEEP_MODE_PWR_DOWN);       // prepare power down
11
    
12
  }                                             // = SEI
13
  #ifdef USE_SLEEP_MODE
14
  // use never sleep_mode()
15
  sleep_mode();                                 // under no circumstances
16
  
17
  // its always dangerous !!!
18
  #else
19
  
20
  sleep_cpu();          // do SLEEP instruction only !
21
  
22
  #endif
23
  TIMSK = 1<<TOIE0;                            // enable other interrupts again
24
}

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:
1
void go_power_down( void )
2
{
3
  ATOMIC_BLOCK(ATOMIC_FORCEON)
4
  {
5
    LED0 = LED_OFF;
6
    GICR |= 1<<INT1;
7
    set_sleep_mode( SLEEP_MODE_PWR_DOWN);
8
    GIFR = 1<<INTF1;
9
  }
10
  sleep_cpu();
11
}

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

von Dieter F. (Gast)


Lesenswert?

Fritz schrieb:
> Aber, wieso gehen die LEDs an?

Weil Du die "falsch" herum angeschlossen hast.

Was Du da bezweckst
1
  DDRB = 0xFF;
2
  PORTB |= 0x10;
3
  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
1
#define LED_OFF    1
2
#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.

von Fritz (Gast)


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.

von c-hater (Gast)


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.

von Fritz (Gast)


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?

von Planlos (Gast)


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.

von Dieter F. (Gast)


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.

von Fritz (Gast)


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

von Peter D. (peda)


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.

von M. K. (sylaina)


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.

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.