Sleep verhält sich auf verschiedenen ATMega328p unterschiedlich

OP #7175428
Lesenswert?

Hallo, ich habe bei einem Projekt ein recht eigenartiges Verhalten von 
verschiedenen AtMega328P's. Bei Atmega A funktioniert der Beispiel 
Sketch von unten wie geplant und ohne Probleme. Jedoch funktioniert das 
Programm bei einem anderen nicht bzw. nur sehr sporadisch. z.B. Watchdog 
löst nach 3x loop aus (mal mehr, mal weniger),  nach dem in Power Down 
(genauer in sleep_cpu) wahrscheinlich nicht mehr in die Interrupt 
Funktion gewechselt wird und der wdt nicht mehr resetted wird.

Prinzipiell sollte es so funktionieren:
1. WDT aktivieren um nach uC zu resetten wenn er durch irgendwas 
blockiert wird
2. Jedoch sollte zwischen den Messungen immer kurz in den sleep Modus 
gewechselt werden
3. WDT wieder auf 8s setzen um zu resetten wenn nötig

Schritt 2 macht mir teilweise bei manchen AtMega328P's Probleme.
Verwende für den Sleep Modus die LowPower Library 
https://github.com/rocketscream/Low-Power
1
#include <Arduino.h>
2
#include "LowPower.h"
3
#include <avr/wdt.h>
4

5

6
void setup() {
7
    bool _WDRF = ((1 << WDRF) & MCUSR);     // Watchdog Reset
8

9
    if (_WDRF) {
10
        cli();
11
        MCUSR &= ~(1 << WDRF);
12
        WDTCSR |= (1<<WDCE) | (1<<WDE);
13
        WDTCSR = 0;
14
        sei();
15
    }
16

17
    bool _BORF = ((1 << BORF) & MCUSR);     // BrownOut Reset
18
    bool _EXTRF = ((1 << EXTRF) & MCUSR);    // External Reset
19
    bool _PORF = ((1 << PORF) & MCUSR);     // Power-Off Reset
20
    MCUSR = 0;
21

22
    
23
        Serial.begin(4800);
24

25
    if (_WDRF)
26
        Serial.println("WDT Triggered");
27
    Serial.println(F("Start Setup"));
28

29

30
    WDTCSR |= (1 << WDIE) | (1 << WDE); //Watchdog  Mode = Interrupt Mode && System Reset Mode
31
    wdt_enable(WDTO_8S);
32
    wdt_reset();
33
}
34

35
void loop() {
36
    wdt_reset();
37

38
    // eventuell blockiert
39

40
    LowPower.powerDown(ENERGY_MANAGEMENT_SLEEP_INTERVAL, adc_t::ADC_ON, bod_t::BOD_ON);
41

42

43
    WDTCSR |= (1 << WDIE) | (1 << WDE); //Watchdog  Mode = Interrupt Mode && System Reset Mode
44
    wdt_enable(WDTO_8S);
45
    wdt_reset();
46
}
Wenn der uC neugestartet wird, passiert das bei sleep_cpu(); in 
LowPower.cpp
1
#define  lowPowerBodOn(mode)  \
2
do {             \
3
      set_sleep_mode(mode); \
4
      cli();        \
5
      sleep_enable();    \
6
      sei();        \
7
      sleep_cpu();      \
8
      sleep_disable();    \
9
      sei();        \
10
} while (0);

Vielleicht hat jemand eine Idee was das Problem sein könnte.

PS:
1
    "efuse": "0xFF",
2
    "file": "atmega/ATmegaBOOT_168_atmega328_pro_8MHz.hex",
3
    "hfuse": "0xD9",
4
    "lock_bits": "0xFF",
5
    "lfuse": "0x62",
6
    "unlock_bits": "0xFF"
f_cpu = 1MHz
Gast #7175616
Lesenswert?

Mathias schrieb:
> wahrscheinlich nicht mehr in die Interrupt
> Funktion gewechselt wird

Überprüfe das. Du könntest dazu in der Interrupt-Funktion einen Ausgang 
toggeln.

Warum rufst du innerhalb der loop wdt_enable() auf? Das scheint mir 
unnötig.

Bist du sicher, dass die Brown-Out Schwelle 4,3V OK ist? Bei USB kann 
man durchaus mal darunter fallen, das müssen USB Geräte tolerieren.

Offenbar soll der ADC den Mikrocontroller aufwecken, aber ich sehe keine 
Code dazu. Die Interrupt-Funktion hast du auch nicht gezeigt. Mit so 
wenig Infos kann man dir kaum helfen.
#7175624
Lesenswert?

Die LowPower-Bibliothek, die du verwendest, scheint auch was mit dem 
Watchdog zu machen, und hat mehrere Stellen, die den umkonfigurieren.

Hab jetzt nicht im Detail geprüft, ob das mit deiner eigenen 
WDT-Verwendung kollidiert, könnte aber sehr gut sein.

Insbesondere wird dort der Watchdog zum Aufwachen aus dem Sleep 
verwendet, was mit deiner Intention, den µC per Watchdog zu resetten, 
nicht ganz kompatibel ist.

Den Sleep mode "zu Fuß" selber zu implementieren ist vmtl. einfacher als 
zu versuchen deinen Code mit dieser Low-Power-Library in Einklang zu 
bringen.

Steve schrieb:
> Warum rufst du innerhalb der loop wdt_enable() auf? Das scheint mir
> unnötig.

Weil die Library folgendes enthält:
1
ISR (WDT_vect)
2
{
3
  // WDIE & WDIF is cleared in hardware upon entering this ISR
4
  wdt_disable();
5
}

d.H. der Watchdog schaltet sich damit immer selber aus...
#7175630
Lesenswert?

Um sleep zu benutzen, brauchst Du einen Interrupt, der die CPU wieder 
aufweckt. Der fehlt aber.

Die Reihenfolge ist falsch. MCUSR muß gelöscht werden, bevor man den 
Wachhund disabled.

wdt_enable(WDTO_8S); gehört nicht in die Loop. Einmal im Init reicht 
völlig, die CPU ist ja nicht vergeßlich.
Ebenso ist des doppelte sei() im Macro überflüssig, einmal reicht.
#7175641
Lesenswert?

Peter D. schrieb:
> Um sleep zu benutzen, brauchst Du einen Interrupt, der die CPU wieder
> aufweckt. Der fehlt aber.

Läuft bei Arduino nicht sowieso immer ein Timer mit, um die millis() 
hochzuzählen?

Ansonsten wärs der Watchdog-Irq...

Peter D. schrieb:
> wdt_enable(WDTO_8S); gehört nicht in die Loop. Einmal im Init reicht
> völlig, die CPU ist ja nicht vergeßlich.

Dafür sorgt die Rundum-Glücklich-Lowpower-Library :)

@ribisl:

tl;dr:

Entweder du kontrollierst den Watchdog in deinem Code, oder 
rocketscream/Low-Power tut es. Dann lässt du aber auch die Finger davon.
#7175656
Lesenswert?

Εrnst B. schrieb:
> Dafür sorgt die Rundum-Glücklich-Lowpower-Library :)

Mit Sicherheit macht sie das Programm extrem undurchschaubar. Ich hab da 
keine Lust mich durchzukämpfen. Sie scheint mir nicht gerade foolproof 
zu sein.

Εrnst B. schrieb:
> Entweder du kontrollierst den Watchdog in deinem Code, oder
> rocketscream/Low-Power tut es. Dann lässt du aber auch die Finger davon.

So wirds sein. Ich sehe auch keinen rechten Nutzen in der Lib.
Ich würde sie komplett in die Tonne treten und alles selber ordentlich 
machen. Sleepmode ist nämlich recht tricky und enthält einige 
Race-Conditions.

Daß ich sleep_disable(); für Bullshit halte, hab ich ja schon mehrfach 
gesagt.
Ohne das sleep_disable(); reicht es völlig, das sleep_enable(); nur im 
Init zu machen und dann ist man schonmal eine Race-Condition los.
OP #7175668
Lesenswert?

Steve schrieb:
> Warum rufst du innerhalb der loop wdt_enable() auf? Das scheint mir
> unnötig.

Nach dem Sleep Modus soll der Watchdog wieder auf 8s gesetzt werden, 
damit er nicht nach 250ms wieder resetted.

Steve schrieb:
> Bist du sicher, dass die Brown-Out Schwelle 4,3V OK ist? Bei USB kann
> man durchaus mal darunter fallen, das müssen USB Geräte tolerieren.

Ja, AtMega läuft auf 3.3V und BrownOut wird nie ausgelöst

Steve schrieb:
> Offenbar soll der ADC den Mikrocontroller aufwecken, aber ich sehe keine
> Code dazu.

Verstehe nicht ganz wie du drauf kommst, dass der ADC den uC aufweckt?

Steve schrieb:
> Die Interrupt-Funktion hast du auch nicht gezeigt.
1
ISR (WDT_vect)
2
{
3
  // WDIE & WDIF is cleared in hardware upon entering this ISR
4
  wdt_disable();
5
}

Das eigenartige ist halt, dass bei einigen ATMegas alles ohne Probleme 
funktioniert, und bei manchen nach wenigen loops resetted wird.

Werde jetzt mal versuchen den sleep Teil selbst zu machen.

Peter D. schrieb:
> Daß ich sleep_disable(); für Bullshit halte, hab ich ja schon mehrfach
> gesagt.

Könntest du es kurz nocheinmal erklären? :)
#7175677
Lesenswert?

Mathias schrieb:
> Könntest du es kurz nocheinmal erklären? :)
1
sleep_enable(); 
2
sleep_cpu();    
3
sleep_disable();
In dieser Sequenz ist sleep_disable(); vollkommen überflüssig, da ja vor 
jedem Sleep das sleep_enable(); ausgeführt wird.
Daher reicht sleep_enable(); einmal im Init und sleep_disable(); fällt 
ersatzlos weg.
Übrig bleibt in der Loop nur das:
sleep_cpu();
#7175681
Lesenswert?

Eine Race-Condition wäre möglich wenn im Interrupt das SMCR angefaßt 
wird.

Der Interrupt ändert aber das WDTCSR. Ob dadurch auch eine 
Race-Condition möglich ist, müßte man bei jeder Funktion prüfen, die im 
Main das WDTCSR ändert. Am besten vorsorglich alle diese Funktionen 
atomar kapseln.
#7175768
Lesenswert?

Mathias schrieb:
> Das eigenartige ist halt, dass bei einigen ATMegas alles ohne Probleme
> funktioniert, und bei manchen nach wenigen loops resetted wird.

Das ist das Fiese an so Race-Conditions, besonders wenn sie von zwei 
voneinander unabhängigen Clock-Sources abhängen...
Die Watchdog-Clock ist sehr ungenau, temperaturabhängig, und streut 
stark mit den Exemplaren. Da kann es schon sein, dass ein Chip bei 
Raumtemperatur lange problemlos läuft, und der nächste praktisch ständig 
ins Fettnäpfchen tritt.
Kannst ja mal probieren, deine Crash-Kandidaten etwas zu erwärmen oder 
zu kühlen, oder anderweitig das Timing beeinflussen, z.B. durch ein paar 
extra delay() in der loop().
Aber: das ist natürlich keine Lösung, nur ein evtl. interessantes 
Experiment, falls du der Sache auf den Grund gehen möchtest.
OP #7175846
Lesenswert?

Habs jetzt mal so umgeschrieben
1
#include <Arduino.h>
2
#include <avr/sleep.h>
3
#include <avr/wdt.h>
4

5
inline void sleep()
6
{
7
    cli();
8
    wdt_reset();
9
    WDTCSR |= (1 << WDCE) | (1 << WDE);
10
    WDTCSR = (1 << WDIE) | (1 << WDP2) | (1 << WDP0); // Interrupt and 0.5s
11
    sei();
12
    
13
    SMCR = (1 << SE) | (1 << SM1);  // Sleep Enable and Power-Down Sleep Mode
14
    sleep_cpu();                    // goto sleep
15
}
16

17
ISR(WDT_vect)
18
{
19
    SMCR = 0;
20
}
21

22
void setup()
23
{
24
    bool _WDRF = ((1 << WDRF) & MCUSR); // Watchdog Reset
25
    if (_WDRF)
26
    {
27
        cli();
28
        MCUSR &= ~(1 << WDRF);
29
        WDTCSR |= (1 << WDCE) | (1 << WDE);
30
        WDTCSR = 0;
31
        sei();
32
    }
33
    bool _BORF = ((1 << BORF) & MCUSR);   // BrownOut Reset
34
    bool _EXTRF = ((1 << EXTRF) & MCUSR); // External Reset
35
    bool _PORF = ((1 << PORF) & MCUSR);   // Power-Off Reset
36
    MCUSR = 0;
37

38
    pinMode(6, OUTPUT);
39

40
    Serial.begin(4800);
41
    if (_WDRF)
42
        Serial.println("WDT Triggered");
43
    Serial.println(F("Start Setup"));
44
    delay(3000);
45

46
    cli();
47
    WDTCSR |= (1 << WDIE) | (1 << WDE); // Watchdog  Mode = Interrupt Mode && System Reset Mode
48
    wdt_enable(WDTO_8S);
49
    wdt_reset();
50
    sei();
51
}
52
void loop()
53
{
54
    static int x = 0;
55
    wdt_reset();
56
    digitalWrite(6,x++%2==0);
57
    delay(500);
58
    sleep();
59

60
    cli();
61
    wdt_reset();
62
    WDTCSR = (1 << WDCE) | (1 << WDIE) | (1 << WDE);   // Watchdog  Mode = Interrupt Mode && System Reset Mode // do not put this in ISR
63
    WDTCSR |= (1 << WDIE) | (1 << WDP3) | (1 << WDP0); // Interrupt and 0.5s
64
    wdt_reset();
65
    sei();
66
}

Funktioniert schon etwas besser aber immer noch nicht prefekt
OP #7176034
Lesenswert?

Peter D. schrieb:
> Was soll das ganze Konstrukt eigentlich bewirken.

Es sollte eine Messung durchgeführt werden und periodisch auch etwas auf 
eine SD Karte geschrieben werden. Nach der Messung sollte für 500ms 
geschlafen werden. Nun kam es manchmal dazu, dass der uC komplett 
blockiert wurde und nichts mehr ging. Deshalb wollte ich den WDT so 
umkonfigurieren, dass wenn der blockierte Fall eintritt nach 8s resetted 
wird.
1
void loop(){
2
  wdt_reset();
3
  
4
  // Messung oder SD Karte beschreiben, könnte blockieren
5
  
6
  sleepFor500MS();
7

8
  // setze WDT auf 8s und System Reset Modus
9
}

Ich hoffe das ganze ist jetzt etwas klarer.
#7176061
Lesenswert?

Mathias schrieb:
> Deshalb wollte ich den WDT so
> umkonfigurieren, dass wenn der blockierte Fall eintritt nach 8s resetted
> wird.

Was nicht funktioniert hat, weil das "LowPower-Sleep" den Watchdog zum 
Aufwachen nach den 500ms umkonfiguriert hat, also auf kürzeren Timeout 
und auf Interrupt statt Reset.

=> wenn der Watchdog zuverlässig immer zuschlagen können soll, darf 
dein sleep den nicht mal zwischendurch zum Wiederaufwachen verwenden.
Also: andere Aufwach-Zeitquelle verwenden, auch wenn dann der 
Schlafmodus nicht ganz so stromsparend ausfallen kann.

Timer2 im Async-Mode mit 32kHz Uhrenquarz wäre eine Möglichkeit, der 
läuft im Power-Save Modus weiter, und kann die CPU wieder aufwecken.
Stomverbrauch müsstest du nachmessen.
OP #7176079
Lesenswert?

Εrnst B. schrieb:
> Was nicht funktioniert hat, weil das "LowPower-Sleep" den Watchdog zum
> Aufwachen nach den 500ms umkonfiguriert hat, also auf kürzeren Timeout
> und auf Interrupt statt Reset.

Hab jetzt die LowPower Library rausgeschmissen und was anderes probiert.

Εrnst B. schrieb:
> wenn der Watchdog zuverlässig immer zuschlagen können soll, darf
> dein sleep den nicht mal zwischendurch zum Wiederaufwachen verwenden.

Verstehe nicht ganz warum das nicht geht soll? WDT umkonfigurieren um 
nach 500ms sleep aufzuwachen, nach dem Aufwachen wieder so 
umkonfigurieren damit er nach 8s keinem wdt_reset() den uC resetted. 
Klingt für mich nicht ganz unlogisch aber ich kann mich auch irren.
#7176127
Lesenswert?

Mathias schrieb:
> Bzw warum passiert der Absturz genau
> an der Stelle?

ich hab keine große Freude daran, diese LowPower-Bibliothek zu debuggen. 
Das darf gerne jemand anderes machen.
Auf den ersten Blick: an den beiden markierten Stellen könnte die 
Watchdog-ISR ausgeführt werden, und ein "wdt_disable()" reinmogeln.

Führt das zum Absturz? Zum sleep ohne wakeup? Keine Ahnung. Möglich.
Angehängte Dateien:
Gast #7176149
Lesenswert?

Ich finde es nicht so schlau, den Watchdog Timer wechselweise als 
Watchdog und zum Aufwachen zu benutzen. Immer wenn der Mikrocontroller 
schläft, ist der Watchdog deaktiviert. Wenn er sich dabei aufhängt, 
bleibt er für immer hängen.

Εrnst B. schrieb:
> Also: andere Aufwach-Zeitquelle verwenden, auch wenn dann der
> Schlafmodus nicht ganz so stromsparend ausfallen kann.
OP #7176154
Lesenswert?

Εrnst B. schrieb:
> Watchdog-ISR ausgeführt werden, und ein "wdt_disable()" reinmogeln.

wenn ich hier ein wdt_disable() einbauen würde, dann würde ja nie mehr 
aufgewacht werden oder?

Steve schrieb:
> Immer wenn der Mikrocontroller
> schläft, ist der Watchdog deaktiviert.

sollte er eigentlich nicht sein, wenn der uC schläft ist der WDT auf 
500ms und Interrupt eingestellt?
#7176193
Lesenswert?

Mathias schrieb:
> Εrnst B. schrieb:
>> Watchdog-ISR ausgeführt werden, und ein "wdt_disable()" reinmogeln.
>
> wenn ich hier ein wdt_disable() einbauen würde, dann würde ja nie mehr
> aufgewacht werden oder?

Genau das könnte bei deinen Abstürzen passiert sein. Nur dass das 
"wdt_disable()" natürlich nicht direkt an der Stelle steht, sondern in 
der ISR (WDT_vect)

Das ist exakt eine der Sachen, die man beachten muss, und die die 
Autoren der LowPower-Lib vermasselt haben:
ISRs können den Programmfluss immer unterbrechen, solange nicht per CLI 
verboten, und dann an den ungünstigsten Stellen ausgeführt werden.
Gast #7176208
Lesenswert?

Mathias schrieb:
>> Immer wenn der Mikrocontroller
>> schläft, ist der Watchdog deaktiviert.

> sollte er eigentlich nicht sein,

Aber im Sleep macht der Watchdog nur einen Interrupt, keinen Reset. Wenn 
der µC hängt, führt er den Interrupt mit einer gewissen 
Wahrscheinlichkeit auch nicht mehr aus.
OP #7176236
Lesenswert?

Εrnst B. schrieb:
> Genau das könnte bei deinen Abstürzen passiert sein. Nur dass das
> "wdt_disable()" natürlich nicht direkt an der Stelle steht, sondern in
> der ISR (WDT_vect)

hab jetzt mal versucht, das ist mein Ergebnis:
1
#include <Arduino.h>
2
#include <avr/sleep.h>
3
#include <avr/wdt.h>
4

5
inline void sleep()
6
{
7
    cli();
8
    wdt_reset();
9
    WDTCSR |= (1 << WDCE) | (1 << WDE);
10
    WDTCSR = (1 << WDIE) | (1 << WDP2) | (1 << WDP0) | (0 << WDE); // Interrupt and 0.5s
11
    wdt_reset();
12
    
13
    Serial.println("1");
14
    Serial.flush();
15

16
    SMCR &= ~0x0e;
17
    SMCR |= 0x01 | 0x04; // SE + SM1 (power-down)
18
    sei();
19
    sleep_cpu();
20

21
    Serial.println("2");
22
    Serial.flush();
23

24
    cli();
25
    wdt_reset();
26
    WDTCSR |= (1 << WDCE) | (1 << WDIE) | (1 << WDE); // Watchdog  Mode = Interrupt Mode && System Reset Mode // do not put this in ISR
27
    WDTCSR = (1 << WDE) | (1 << WDP3) | (1 << WDP0);     // Interrupt and 8s
28
    sei();
29
}
30

31
ISR(WDT_vect)
32
{
33
    wdt_disable();
34
    Serial.println("ISR");
35
    Serial.flush();
36
}
37

38
void setup()
39
{
40
    bool _WDRF = ((1 << WDRF) & MCUSR); // Watchdog Reset
41
    if (_WDRF)
42
    {
43
        cli();
44
        MCUSR &= ~(1 << WDRF);
45
        WDTCSR |= (1 << WDCE) | (1 << WDE);
46
        WDTCSR = 0;
47
        sei();
48
    }
49
    bool _BORF = ((1 << BORF) & MCUSR);   // BrownOut Reset
50
    bool _EXTRF = ((1 << EXTRF) & MCUSR); // External Reset
51
    bool _PORF = ((1 << PORF) & MCUSR);   // Power-Off Reset
52
    MCUSR = 0;
53

54
    pinMode(6, OUTPUT);
55

56
    Serial.begin(4800);
57
    if (_WDRF)
58
        Serial.println("WDT Triggered");
59
    Serial.println(F("Start Setup"));
60
    delay(3000);
61

62
    cli();
63
    WDTCSR |= (1 << WDIE) | (1 << WDE); // Watchdog  Mode = Interrupt Mode && System Reset Mode
64
    wdt_enable(WDTO_8S);
65
    wdt_reset();
66
    sei();
67
}
68
void loop()
69
{
70
    static int x = 0;
71
    wdt_reset();
72
    digitalWrite(6, x++ % 2 == 0);
73
    sleep();
74
}

Mit der seriellen Ausgabe hab ich herausgefunden, dass er nach "1" 
manchmal in den Setup wechselt.
Was auch relativ eigenartig ist, dass er fast sofort in nach "1" 
wechselt, also ohne die 8s abzuwarten
1
15:27:47.970 > ISR
2
15:27:47.980 > 2
3
15:27:47.988 > 1
4
15:27:48.527 > Start Setup
5
15:27:49.018 > ISR

PS das selbe Verhalten ist auch ohne Seriellen Monitor sichtbar. Und es 
kommt auch die WDT Triggered Nachricht nicht!
Gast #7176248
Lesenswert?

> Serial.println("ISR");

Das funktioniert nur mit Glück. Wenn der Sendepuffer gerade voll ist, 
hängt sich der µC auf. Denn dann wartet println() für immer, dass der 
Puffer frei wird, wird er aber nie.

Und zwar deswegen nicht, weil der AVR nicht gleichzeitig die ISR vom 
seriellen port ausführen kann, welche den Puffer senden und somit Platz 
schaffen würde.
#7176262
Lesenswert?

Mathias schrieb:
> Und es
> kommt auch die WDT Triggered Nachricht nicht!

Das Auslesen von MCUSR in der setup() zum herausfinden der Reset-Quelle 
muss nicht klappen. Da läuft vorher noch der Bootloader und 
Arduino-code, die das Register u.U. schon gelöscht haben.
Hab ich nicht geprüft --> selber nachschauen.

Warum verwendest du nicht die sleep_enable() und 
set_sleep_mode(SLEEP_MODE_PWR_DOWN)
aus der avr/sleep.h?

und welchen Sinn siehst du im wdt_disable() in deiner ISR?
#7176269
Lesenswert?

Steve schrieb:
> Ich finde es nicht so schlau, den Watchdog Timer wechselweise als
> Watchdog und zum Aufwachen zu benutzen.

Es sollte schon gehen.
Einfach vor dem sleep_cpu(); den Watchdog auf 500ms, Interrupt setzen.
Und danach, also wenn er aufgewacht ist, den Watchdog auf 8s, Reset 
setzen. Der Interrupt bleibt leer:
EMPTY_INTERRUPT(WDT_vect);

Zum Testen kann man per Pinabfrage die Loop irgendwo anhalten d.h. in 
eine Endlosschleife gehen. Nur dann darf ein Reset erfolgen (nach 8,5s).

Ein wdt_disable(); darf nirgends stehen!

Und Sleepmode einstellen erfolgt nur einmalig im Setup, d.h. da dreht 
man nicht mehr ständig dran rum. Bzw. nur, wenn man definitiv nicht mehr 
schlafen will.
OP #7176270
Lesenswert?

Εrnst B. schrieb:
> Das Auslesen von MCUSR in der setup() zum herausfinden der Reset-Quelle
> muss nicht klappen. Da läuft vorher noch der Bootloader und
> Arduino-code, die das Register u.U. schon gelöscht haben.
> Hab ich nicht geprüft --> selber nachschauen.

ist nicht der Fall, wenn ich im LOOP ein +8s delay hineingebe, erscheint 
die wdt triggered Nachricht und der Reset Modus wird auch angezeigt.

Εrnst B. schrieb:
> Warum verwendest du nicht die sleep_enable() und
> set_sleep_mode(SLEEP_MODE_PWR_DOWN)
> aus der avr/sleep.h?

Weil es keinen Unterschied macht.

Εrnst B. schrieb:
> und welchen Sinn siehst du im wdt_disable() in deiner ISR?

Ich dachte mir da ich den WDT eh danach wieder direkt aktiviere kann ich 
ihn hier deaktivieren. Sollte die ISR leer bleiben?
OP #7176279
Lesenswert?

Peter D. schrieb:
> Es sollte schon gehen.
> Einfach vor dem sleep_cpu(); den Watchdog auf 500ms, Interrupt setzen.
> Und danach, also wenn er aufgewacht ist, den Watchdog auf 8s, Reset
> setzen. Der Interrupt bleibt leer:
> EMPTY_INTERRUPT(WDT_vect);

Sollte dann so ja prinzipiell stimmen oder?
1
inline void sleep()
2
{
3
    cli();
4
    wdt_reset();
5
    WDTCSR |= (1 << WDCE) | (1 << WDE);
6
    WDTCSR = (1 << WDIE) | (1 << WDP2) | (1 << WDP0) | (0 << WDE); // Interrupt and 0.5s
7
    wdt_reset();
8

9
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
10
    sleep_enable();
11
    sei();
12
    sleep_cpu();
13

14
    cli();
15
    wdt_reset();
16
    WDTCSR |= (1 << WDCE) | (1 << WDIE) | (1 << WDE); // Watchdog  Mode = Interrupt Mode && System Reset Mode // do not put this in ISR
17
    WDTCSR = (1 << WDE) | (1 << WDP3) | (1 << WDP0);     // Interrupt and 8s
18
    sei();
19
}
20

21
EMPTY_INTERRUPT(WDT_vect);

    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();
*sollten nur im setup sein()

Peter D. schrieb:
> Mathias schrieb:
>> Und es
>> kommt auch die WDT Triggered Nachricht nicht!
>
> Im Power-Down macht die UART ja auch nichts.

Die WDT Triggered Nachricht kommt ja auch erst wieder im Setup nach dem 
das WDRF Bit gesetzt wurde
Gast #7176878
Lesenswert?

> da 32kHz zu langsam

Der Controller läuft dann natürlich mit dem internen RC-Oszillator, also 
z.B. mit 8 MHz. Die 32 KiHz sind nur für den asynchronen Timer2.

> gerne auf die Weise schaffen möchte

Okay - ich lese interessiert mit.
#7176952
Lesenswert?

S. Landolt schrieb:
> Ist bekannt, dass der ATmega328P im Modus Power-save mit einem 32
> KiHz-Quarz so um ein uA herum, je nach Ucc, benötigt?

Hast du das Nachgemessen? Im Datenblatt hab ich nur Angaben zum WDT 
gefunden, der den Stromverbrauch je nach VCC um so 6µA hochtreibt.

Εrnst B. schrieb:
> Timer2 im Async-Mode mit 32kHz Uhrenquarz wäre eine Möglichkeit, der
> läuft im Power-Save Modus weiter, und kann die CPU wieder aufwecken.
> Stomverbrauch müsstest du nachmessen.

Damit wäre ja für Low-Power/Batterie-Anwendungen ein Betrieb ohne WDT 
aber mit Uhrenquarz besser.
OP #7176979
Lesenswert?

Peter D. schrieb:
> Ist denn überhaupt Batteriebetrieb vorgesehen?

Ja Batteriebetrieb ist vorgesehen!

Habe jetzt auch herausgefunden, dass wenn ich den Mikrocontroller etwas 
erhitze das ganze sehr stabil läuft. Läuft jetzt seit einer Stunde ohne 
einen einzigen Reset.
Natürlich könnte es jetzt ein anderes Hardware Problem sein, deshalb 
habe ich mal einen "problematischen" uC mit einem neuen augetauscht und 
es läuft mit dem neuen auch ohne Probleme.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren