ATmega328p timer2 sleep mode zu kurz

OP #4869156
Hallo Zusammen,

ich möchte meinen ATMega328p in den Schlafmodus versetzen.  Durch den 
Timer2 soll dieser wieder aufwachen.

dazu verwende ich folgenden Code:
1
set_sleep_mode(SLEEP_MODE_PWR_SAVE);
2
  
3
  sei();
4
}
5
 
6
void loop(){
7
  
8
  
9
  // Timer 2 Konfigurieren
10
  TCCR2B = (1<<CS22)|(1<<CS21)|(1<<CS20); // Prescaler 1024
11
    
12
  // Overflow Interrupt erlauben
13
  TIMSK2 |= (1<<TOIE0);
14
  
15
  sleep_enable();
16
  for (int i=0; i<1000; i++)
17
  {
18

19
    TCNT2 &= 0; //Timer resetten
20
    sleep_cpu();
21
  }
22
  sleep_disable();
23
  
24
  digitalWrite(ledPin, HIGH);
25
  delay(1000);
26
  digitalWrite(ledPin, LOW);
27
  
28
}
29

30
ISR(TIMER2_OVF_vect){  
31
}

meiner Meinung nach müsste der MCU dann für ca. 16 s im Schlafmodus 
bleiben:
256*1024*1000/16000000 (Der MCU läuft mit 16 MHz Takt)
Es zeigt sich jedoch, dass die LED genauso lang an, wie aus ist. Also 
etwa 1 Sekunde.
Wo ist mein Fehler?
#4869245
Zeig mal den vollständigen Code.

Power-Save geht nur mit T2 im asynchronen Mode, d.h. am 32kHz Quarz.
Und dann muß vor dem Sleep gewartet werden, bis der Zugriff beendet 
wurde (Löschen des Interruptflags ist ein Zugriff), d.h. die nächste 
32kHz Flanke erfolgte.
Ansonsten laufen die Timer nur bei Idle weiter.
Gast #4869525
> Power-Save geht nur mit T2 im asynchronen Mode, d.h. am 32kHz Quarz.
Das lese ich im Datenblatt anders.

Das Programm, zumindest was von ihm zu sehen ist, sollte funktionieren. 
Unklar ist mir der Sinn von
> TCNT2 &= 0; //Timer resetten

Und
> TIMSK2 |= (1<<TOIE0)
klappt nur dank etwas Glück.
#4869569
S. Landolt schrieb:
>> Power-Save geht nur mit T2 im asynchronen Mode, d.h. am 32kHz Quarz.
> Das lese ich im Datenblatt anders.

2. If Timer/Counter2 is running in asynchronous mode.

Die Fußnote DB bezieht sich auf den Timer Oszillator. Der einzige Takt, 
der im Power Save aktiv ist und somit, neben dem Watchdog Timer, die 
einzige Möglichkeit des Controllers, sich selbst aufzuwecken. 
Nachzulesen im DB unter Sleep Modes.

S. Landolt schrieb:
> Unklar ist mir der Sinn von

Mir auch.

S. Landolt schrieb:
> klappt nur dank etwas Glück.

Warum braucht man dazu Glück?
OP #4869575
Vielen Dank für eure Antworten!

S. Landolt schrieb:
> Unklar ist mir der Sinn von
>> TCNT2 &= 0; //Timer resetten
>

hier setze ich den Timer zurück, damit er bei 0 zu zählen anfängt. Da 
war ich mich auch nicht sicher, ob das nötig ist. Aber der Timer läuft 
ja schon vorher oder? Das heißt, es könnte sein, dass er bei einem 
höheren Wert anfängt.

>
> Und
>> TIMSK2 |= (1<<TOIE0)
> klappt nur dank etwas Glück.
Könntest du das bitte etwas genauer erklären! Warum klappt das nicht 
immer?

Hier noch der volle Code:
1
#include <Arduino.h>
2
#include <avr/interrupt.h>
3
#include <avr/sleep.h>
4

5
int ledPin = 8;
6

7
 
8
void setup(){
9
  
10
  pinMode(ledPin,OUTPUT);
11
  digitalWrite(ledPin,LOW);
12
  
13
  
14
  set_sleep_mode(SLEEP_MODE_PWR_SAVE);
15
  
16
  sei();
17
}
18
 
19
void loop(){
20
  
21
  
22
  // Timer 2 Konfigurieren
23
  TCCR2B = (1<<CS22)|(1<<CS21)|(1<<CS20); // Prescaler 1024
24
    
25
  // Overflow Interrupt erlauben
26
  TIMSK2 |= (1<<TOIE0);
27
  
28
  sleep_enable();
29
  for (int i=0; i<1000; i++)
30
  {
31

32
    TCNT2 &= 0;
33
    sleep_cpu();
34
  }
35
  sleep_disable();
36
  
37
  digitalWrite(ledPin, HIGH);
38
  delay(5000);
39
  digitalWrite(ledPin, LOW);
40
  
41
}
42

43
ISR(TIMER2_OVF_vect){  
44
}
#4869604
Ich würd mal das ganze Init-Zeugs aus der Loop nehmen:
1
void setup( void )
2
{
3
  pinMode(ledPin,OUTPUT);
4
  digitalWrite(ledPin,LOW);
5
  TCCR2B = (1<<CS22)|(1<<CS21)|(1<<CS20); // Prescaler 1024
6
  TIMSK0 = 0; // no other Interrupts
7
  TIMSK1 = 0; // no other Interrupts
8
  TIMSK2 = (1<<TOIE2);
9
  set_sleep_mode(SLEEP_MODE_PWR_SAVE);
10
  sleep_enable();
11
  sei();
12
}
13
 
14
void loop( void )
15
{
16
  for (int i=0; i<1000; i++)
17
  {
18
    sleep_cpu();
19
  }
20
  digitalWrite(ledPin, HIGH);
21
  delay(5000);
22
  digitalWrite(ledPin, LOW);
23
}
24

25
ISR(TIMER2_OVF_vect)
26
{  
27
}
Gast #4870466
> genauso lang an, wie aus ist. Also etwa 1 Sekunde.
Bei einer Schleife mit 1000 Durchläufen.

  Und irgendwo stand mal, "In Arduino, Timer0 is already set up to 
generate a millisecond interrupt to update the millisecond counter for 
millis()" oder so ähnlich.
  So würde also das sleep-cpu nach jeweils 1 ms unterbrochen werden 
zusätzlich zu den berechneten 16.384 ms = 256*1024/16000000 ms von 
Timer2.
#4871622
Peter D. schrieb:
> S. Landolt schrieb:
>> zusätzlich zu den berechneten 16.384 ms = 256*1024/16000000 ms von
>> Timer2.
>
> Da er T2 nach jedem Sleep rücksetzt, würde der nie ablaufen. Es sind
> also ausschließlich die T0 Interrupts.

In "PowerSave" läuft der Timer0 aber gar nicht!
Atmel dazu: "2.If Timer/Counter2 is running in asynchronous mode"

Vermutlich schläft der auch nicht "PowerSave", weil die Arduino-RT den 
Wert von der Initialisierung nicht stehen läst. Die möchte nämlich 
Timer0 sehen.

Dann paßt auch das Verhalten:
LED an, 1000x1ms Schlafen,
LED aus, 1s delay

Ich kenne sleep eher als:
Set sleep mode
Enable sleep
Sleep
Disable sleep
#4871645
Carl D. schrieb:
> In "PowerSave" läuft der Timer0 aber gar nicht!

Wie ja schon festgestellt wurde, kann im Gegensatz zum ATmega8 beim 
ATmega328 der T2 im Power-Save auch synchron laufen.
Das impliziert, daß der CPU-Taktgeber und CPU-Prescaler aktiv bleiben 
müssen.
Grob gesagt mutiert das Power-Save bei synchronem T2 zum Idle.
Das Datenblatt schweigt sich allerdings zu Details aus. Und probiert hat 
das warscheinlich auch noch niemand.
Gast #4871762
Vergessen zu schreiben:
Wie Carl Drexler betonte, läuft Timer0 in power-save tatsächlich nicht. 
Bleibt also die Frage, was Arduino aus dem Ganzen macht.
Gast #4871843
S. Landolt schrieb:
> Wie erklärt sich dann aber das eingangs beschriebene Verhalten?

Wie sich das erklärt?
KA!
Interessiert mich auch nicht wirklich.

Natürlich löst Timer0, in der Arduino Welt, dauernd Interrupts aus.
Den Timer sollte man in den leichten Schlafmodi schon stilllegen.
Ansonsten, kann ich nur sagen, dass meine Arduinos nicht einfach so 
aufwachen.

Von der Arduino IDE werden typischer weise folgende ISR etabliert:
1. Timer0 (wenn setup() und loop() vorhanden)
2. UART (wenn setup() und loop() vorhanden)
3. I2C (wenn Wire genutzt wird)

Solange noch SendeDaten in der UART FIFO stecken ....(kann man sich ja 
denken)


Der Code im Eingangspost ist unvollständig. Und damit untestbar. 
Irgendwie macht sowas auf mich immer den Eindruck, als wolle man gar 
nicht, das man das Problem findet und löst.
Vermutlich wurde mal wieder vergessen das Wichtigste zu zeigen...

Wenn ich sowas lese, dann blättere ich einfach weiter:
> TIMSK2 |= (1<<TOIE0);
OK, mag sein, dass das funktioniert, aber falsch ist es trotzdem.


Der Code von  Multi __ macht sei(); . Das ist flüssiger, als Wasser, 
überflüssig. Den Rest habe ich mir dann gar nicht mehr angesehen.


Peter Dannegger vergisst den Clear des SE Bit nach dem sleep.
Habe ich noch nicht getestet, ob das dann funktioniert.
Meine Erinnerung sagt aber, dass man das unbedingt tun sollte.

Das Gcc Manual sagt, dass es so auszusehen hat:
1
#include <avr/interrupt.h>
2
#include <avr/sleep.h>
3
...
4
  set_sleep_mode(<mode>);
5
  cli();
6
  if (some_condition)
7
  {
8
    sleep_enable();
9
    sei();
10
    sleep_cpu();
11
    sleep_disable();
12
  }
13
  sei();
Ich sehe nicht ein, warum man davon abweichen sollte....
Freiwillig, ohne Not...
Es sei denn, es wurde die Doku nicht gelesen..


-----------

Arduino sagt dazu: 
http://playground.arduino.cc/Learning/ArduinoSleepCode

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 9 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.