Forum: Mikrocontroller und Digitale Elektronik attiny25 reset nach power down


von Vlad T. (vlad_tepesch)


Lesenswert?

Hi,
ich will etwas bauen, dass statt ausgeshcalten zu werden in den power 
down geht und mit einem pin change dann wieder aufwacht, dann jedoch 
einen Reset durchführt.

in einem Anderen Projekt hab ich das schonmal mit int0 gemacht.
da ich im Programm den Interupt aber nicht brauchte (und Platzmangel 
war) hab ich die ISR einfach weggelassen. Das hat funktioniert.


den PCINT, den ich benutzen möchte benötige ich jetzt jedoch im 
Programm.

Bei AVR bin ich auf etwas gestoßen mit dem WDT.
http://support.atmel.no/bin/customer?=&action=viewKbEntry&id=21
Das scheint nur leider nicht zu funktionieren.


Das ist der code:
1
static inline void powerDown(void)
2
{
3
  set_sleep_mode( SLEEP_MODE_PWR_DOWN);
4
  TCCR0B = 0;
5
  TCCR1 = 0;
6
7
  sleep_enable();
8
  sei();    // enable because called from timer ISR
9
  sleep_cpu();
10
11
  /* bis hier hin funktionierts */
12
13
  /*reset*/
14
  wdt_enable(WDTO_30MS);
15
  while(1) {};
16
}

die CPU legt sich schlafen, wacht auch wieder auf (getestet mit 
led-gewackel nach dem sleep_cpu() , aber der reset klappt nicht.

Jemand von euch ne idee?

von Vlad T. (vlad_tepesch)


Lesenswert?

hat niemand einen Hinweis, wie man einen Software-rest auslöst.

von Gast 57 (Gast)


Lesenswert?

Software-Reset:

Auslösen mit Watch-Dog? -> Braucht halt die WD-Time
Jump to Reset bzw. Programm-Beginn. (Dann alle Regs initialisieren!)

Nicht elegant, aber wirkungsvoll

von Vlad T. (vlad_tepesch)


Lesenswert?

mit dem WD das schlägt ja atmel vor mit folgendem Codebispiel:
1
  /*reset*/
2
  wdt_enable(WDTO_30MS);
3
  while(1) {};

Allerdings passiert dabei gar nix.
Er scheint danach in der Whileschleife zuhängen.

von holger (Gast)


Lesenswert?

>Er scheint danach in der Whileschleife zuhängen.

Dann aktiviere den Watchdog doch mal.

von Hc Z. (mizch)


Lesenswert?

Wenn's nur um den Sprung zum Reset-Vektor geht und nicht um das Löschen 
von Registern etc., was ein Hardware-Reset ja zusätzlich macht:
1
asm volatile ( "jmp 0x0" )

von R. M. (rmax)


Lesenswert?

Vlad Tepesch schrieb:

> Allerdings passiert dabei gar nix.
> Er scheint danach in der Whileschleife zuhängen.

Kannst Du mal noch den Anfang von main() posten? Evtl. hängt er nicht in 
der Schleife, sondern führt einen Reset nach dem anderen aus, weil Du 
den Watchdog nach dem Reset nicht oder zu spät abschaltest.

Alternativ könntest Du die Taste zum ein- und ausschalten an den 
Reset-Pin hängen und in main() unterscheiden, ob der Reset aus dem Wach- 
oder Schlafzustand ausgelöst wurde.

von Timmo H. (masterfx)


Lesenswert?

Erstmal WDTCR[WDE] auf 1 bevor hier weiter rumgerätselt wird

von R. M. (rmax)


Lesenswert?

Timmo H. schrieb:
> Erstmal WDTCR[WDE] auf 1 bevor hier weiter rumgerätselt wird

wdt_enable() tut genau das.

von Vlad T. (vlad_tepesch)


Lesenswert?

R. Max schrieb:
> Vlad Tepesch schrieb:
>
>> Allerdings passiert dabei gar nix.
>> Er scheint danach in der Whileschleife zuhängen.
>
> Kannst Du mal noch den Anfang von main() posten? Evtl. hängt er nicht in
> der Schleife, sondern führt einen Reset nach dem anderen aus, weil Du
> den Watchdog nach dem Reset nicht oder zu spät abschaltest.
Kann ich heut abend noch mal schauen, ich bin mir aber fast sicher, dass 
ich vordichtshalber eine Routine eingebaut hatte, die noch vor der 
runtime-Initialisierung läuft und den wdt abschaltet.
In der Atmel Appnote steht davon ja aber auch nix.

>
> Alternativ könntest Du die Taste zum ein- und ausschalten an den
> Reset-Pin hängen und in main() unterscheiden, ob der Reset aus dem Wach-
> oder Schlafzustand ausgelöst wurde.

hab keinen taster dafür.
Hab nen primitven bewegungssenso gebaut, der wenn er bewegt wird gegen 
Masse schaltet.

wurde das gerät eine Weile nicht bewegt, dann wird alles abgeschalteten.
Wird das ding wieder bewegt soll alles wieder an gehen - mit einem 
kompletten neustart, was gegen einen Sprung nach 0 spricht.

>asm volatile ( "jmp 0x0" )
hatte ich übrigens auch probiert, der meckert der assembler, dass der 
atmega25 diesen opcode nicht hat. Laut reference kann der nur relative 
sprünge.

von Timmo H. (masterfx)


Lesenswert?

Ahh, stimmt
1
(_BV(_WD_CHANGE_BIT) | _BV(WDE)
sagt der name ja auch schon. Hatte angenommen, dass da so nur der Timer 
angefasst wird. Dann sollte es aber ja eigentlich auch funzen

von Peter D. (peda)


Lesenswert?

Ich würde ja zu einer ordentlichen Entprellung raten, damit ist 
Power-Down ein Kinderspiel:

http://www.avrfreaks.net/index.php?module=Freaks%20Academy&func=viewItem&item_type=project&item_id=2265


Und ein Reset ist immer ein Dirty Hack.
Mach besser einfach in das Main noch ne äußere Loop, die nach dem 
Power-Down durchlaufen wird und die Initialisierung + innere Loop neu 
startet.


Peter

von Vlad T. (vlad_tepesch)


Lesenswert?

Vlad Tepesch schrieb:
>>asm volatile ( "jmp 0x0" )
> hatte ich übrigens auch probiert, der meckert der assembler, dass der
> atmega25 diesen opcode nicht hat. Laut reference kann der nur relative
> sprünge.
meine natürlich attiny25

von Vlad T. (vlad_tepesch)


Lesenswert?

Peter Dannegger schrieb:
> Ich würde ja zu einer ordentlichen Entprellung raten, damit ist
> Power-Down ein Kinderspiel:
>
> 
http://www.avrfreaks.net/index.php?module=Freaks%20Academy&func=viewItem&item_type=project&item_id=2265


Zitat:
>wurde das gerät eine Weile nicht bewegt, dann wird alles abgeschalteten.
wenn etwas nicht geschaltet wird, brauchs auch nicht entprellt werden

>
>
> Und ein Reset ist immer ein Dirty Hack.
> Mach besser einfach in das Main noch ne äußere Loop, die nach dem
> Power-Down durchlaufen wird und die Initialisierung + innere Loop neu
> startet.
>
>
> Peter

Was ist ein dirty hack daran, wenn ein System ausgeschalten wird und vor 
weiteren Gebrauch mit der Standard-Prozedur neu startet?

eine weitere äußere Loop ist für mich der dirty hack, da hier 
zusätzliche kommunikation zwischen ISR und main benötigt wird und das 
System länger arbeitet, als es sollte.

von R. M. (rmax)


Lesenswert?

Vlad Tepesch schrieb:

> In der Atmel Appnote steht davon ja aber auch nix.

Ich weiß nicht, welche Appnote Du meinst, aber im Manual zum 
ATtiny25/45/85 sind im Kapitel 8.4.2 auf Seite 45 Beispiele in Assembler 
und C zum Abschalten des Watchdog. Wichtig ist, daß man das MCUSR zuerst 
nullt, sonst schaltet sich der WDT nicht ab.

Falls Du die Ursache für den Reset später nochmal brauchst, findest Du 
in avr/wdt.h ein Beispiel, wie man das in Verbindung mit wdt_disable() 
macht.

> wurde das gerät eine Weile nicht bewegt, dann wird alles abgeschalteten.
> Wird das ding wieder bewegt soll alles wieder an gehen - mit einem
> kompletten neustart, was gegen einen Sprung nach 0 spricht.

Kannst Du den Spieß nicht umdrehen und gleich den Watchdog-Reset als 
Timeout zum Abschalten nehmen? Im Tiny25 kann der immerhin bis zu 8 
Sekunden. Im Reset schaltest Du dann als erstes den Watchgog aus und 
schickst den Tiny in den Power-Down. Wenn er durch den PCINT wieder 
aufwacht, ist die CPU immer noch im "gerade resetteten" Zustand, und Du 
kannst die Initialisierung fortsetzen.

Falls Deine "Weile" bis zum Abschalten länger als 8 Sekunden dauern 
soll, kannst Du den WDT auch erstmal einen Iterrupt statt eines Resets 
auslösen lassen und nach einer bestimmten Anzahl von Interrupts auf 
Reset umschalten.

Andererseits: Ist dierer komplette Neustart wirklich nötig? Kann das 
Programm nicht einfach da weitermachen, wo es sich vorher schlafengelegt 
hat?

>>asm volatile ( "jmp 0x0" )
> hatte ich übrigens auch probiert, der meckert der assembler, dass der
> atmega25 diesen opcode nicht hat. Laut reference kann der nur relative
> sprünge.

Er hat auch einen absoluten Sprung (IJMP), nur kann die Zieladresse halt 
nicht unmittelbar im Code stehen, sondern muß vorher ins Z-Register 
geladen werden.

von Vlad T. (vlad_tepesch)


Lesenswert?

R. Max schrieb:
> Vlad Tepesch schrieb:
>
>> In der Atmel Appnote steht davon ja aber auch nix.
>
> Ich weiß nicht, welche Appnote Du meinst,
siehe eingangspost
ok, ist keine Appnote, ist ein FAQ-Eintrag

> Falls Du die Ursache für den Reset später nochmal brauchst>> wurde das gerät eine Weile nicht bewegt, dann wird alles abgeschalteten.
>> Wird das ding wieder bewegt soll alles wieder an gehen - mit einem
>> kompletten neustart, was gegen einen Sprung nach 0 spricht.
>
> Kannst Du den Spieß nicht umdrehen und gleich den Watchdog-Reset als
> Timeout zum Abschalten nehmen? Im Tiny25 kann der immerhin bis zu 8
> Sekunden. Im Reset schaltest Du dann als erstes den Watchgog aus und
> schickst den Tiny in den Power-Down. Wenn er durch den PCINT wieder
> aufwacht, ist die CPU immer noch im "gerade resetteten" Zustand, und Du
> kannst die Initialisierung fortsetzen.
>
> Falls Deine "Weile" bis zum Abschalten länger als 8 Sekunden dauern
> soll, kannst Du den WDT auch erstmal einen Iterrupt statt eines Resets
> auslösen lassen und nach einer bestimmten Anzahl von Interrupts auf
> Reset umschalten.


wär eine Möglichkeit, man würde sich den timer sparen, das eigendliche 
Problem, behebt es nicht.
Das ist ja momentan, dassd er WD nicht zu funktionieren scheint und 
scheinbar kein reset auslöst.


>
> Andererseits: Ist dierer komplette Neustart wirklich nötig? Kann das
> Programm nicht einfach da weitermachen, wo es sich vorher schlafengelegt
> hat?
es soll neu gestartet werden.

>
>>>asm volatile ( "jmp 0x0" )
>> hatte ich übrigens auch probiert, der meckert der assembler, dass der
>> atmega25 diesen opcode nicht hat. Laut reference kann der nur relative
>> sprünge.
>
> Er hat auch einen absoluten Sprung (IJMP), nur kann die Zieladresse halt
> nicht unmittelbar im Code stehen, sondern muß vorher ins Z-Register
> geladen werden.
Ach stimmt, das hatte ich dannach gelesen, aber wieder verworfen,
weil ich mir nicht sicher war, was bei einem sprungnach 0 passiert.
werden die register und der vor allem der stack von der runtime 
intialisiert?

von Peter D. (peda)


Lesenswert?

Vlad Tepesch schrieb:
> wenn etwas nicht geschaltet wird, brauchs auch nicht entprellt werden

Das ist ein Irrtum.
Entprellen ist auch beim Einschalten äußerst nützlich. Man will ja 
nicht, daß Geräte sofort durch irgendwelche Störimpulse von alleine 
angehen (Handy, Staubsauger einschalten, gehen mit Gummisohlen usw.).


> Was ist ein dirty hack daran, wenn ein System ausgeschalten wird und vor
> weiteren Gebrauch mit der Standard-Prozedur neu startet?

Ein Gerät, welches einen Resettaster benötigt oder sich selbst resettet, 
hinterläßt immer das ungute Gefühl, in der Software wurde gepfuscht.

Du weißt ja, in welchem Zustand alle Register und Pins nach einem 
Aufwachen sind, nämlich in genau dem Zustand vor dem Power-Down. Warum 
also unnötige Aktionen durchführen?

Einen PC möchte man ja auch nicht neu booten müssen, nur weil zum 
Stromsparen nach ner Weile Bildschirm und Festplatte abschalten.
Man möchte dort weitermachen, wo man aufgehört hat.

Ein Reset ohne Not ist ein Dirty Hack, da man damit zugibt, die 
Kontrolle über sein Programm verloren zu haben.
Es ist unsauberer Programmierstil. Wenn Deine Programme mal größer und 
komplexer werden, wirst Du das schnell selber merken, es wird Dir 
irgendwann auf die Füße fallen.


Peter

von R. M. (rmax)


Lesenswert?

Vlad Tepesch schrieb:

> ok, ist keine Appnote, ist ein FAQ-Eintrag

Da heißt es "Example Code (GCC) Resetting the AVR every 30mS:", Du 
willst ihn aber nicht alle 30ms resetten, sondern nur einmal, also musst 
Du den Watchdog nach dem Reset innerhalb von 30ms wieder abschalten.

>> Kannst Du den Spieß nicht umdrehen und gleich den Watchdog-Reset als
>> Timeout zum Abschalten nehmen?
>
> wär eine Möglichkeit, man würde sich den timer sparen, das eigendliche
> Problem, behebt es nicht.
> Das ist ja momentan, dassd er WD nicht zu funktionieren scheint und
> scheinbar kein reset auslöst.

Also wenn Dein Exemplar nicht gerade einen Hau hat, dann gibt es keinen 
Grund, warum der WDT mit dem Code, den Du gepostet hast, nicht 
funktionieren sollte. Das Problem dürfte also woanders liegen, als da, 
wo Du es vermutest. Ohne mehr von Deinem Code gesehen zu haben, sehe ich 
leider keine Möglichkeit, Dir weiter zu helfen.

> werden die register und der vor allem der stack von der runtime
> intialisiert?

Der Stack und die Variablen werden von der Runtime initialisiert. Ob die 
auch von definierten Registerinhalten ausgeht oder einen undefinierten 
Zustand annimmt, weiß ich nicht auswendig. Ich wollte ja auch nicht die 
JMP-Variante propagieren, sondern nur festhalten, daß es durchaus einen 
absoluten Sprung gibt.

von Vlad T. (vlad_tepesch)


Lesenswert?

R. Max schrieb:
> Vlad Tepesch schrieb:
>
>> ok, ist keine Appnote, ist ein FAQ-Eintrag
>
> Da heißt es "Example Code (GCC) Resetting the AVR every 30mS:", Du
> willst ihn aber nicht alle 30ms resetten, sondern nur einmal, also musst
> Du den Watchdog nach dem Reset innerhalb von 30ms wieder abschalten.

das der alle 30ms resettet liegt ja aber eher da ran, dass nach dem 
reset in der main gleich wieder der timer gestartet wird.

>
>>> Kannst Du den Spieß nicht umdrehen und gleich den Watchdog-Reset als
>>> Timeout zum Abschalten nehmen?
>>
>> wär eine Möglichkeit, man würde sich den timer sparen, das eigendliche
>> Problem, behebt es nicht.
>> Das ist ja momentan, dassd er WD nicht zu funktionieren scheint und
>> scheinbar kein reset auslöst.
>
> Also wenn Dein Exemplar nicht gerade einen Hau hat, dann gibt es keinen
> Grund, warum der WDT mit dem Code, den Du gepostet hast, nicht
> funktionieren sollte. Das Problem dürfte also woanders liegen, als da,
> wo Du es vermutest. Ohne mehr von Deinem Code gesehen zu haben, sehe ich
> leider keine Möglichkeit, Dir weiter zu helfen.

naja, ich wollte euch den Code nicht zumuten.
Habs jetzt aber so gelöst, wie peda es vorgeschalgen hatte, ohne reset, 
mit ner großen schleife ums gesammte programm.

Ist zwar nicht sehr befriedigend, die Ursache des Problems mit dem nicht 
funktionierneden reset nicht gefunden zu haben, aber ich hab keine Zeit 
und Lust mich ewig damit aufzuhalten.

Ich werd das bei gelegenheit nochmal mit nem frischen tiny und nem 
leeren Minimal-Programm testen.

Danke euch allen nochmal.

von R. M. (rmax)


Lesenswert?

So habe ich das kürzlich (auch mit einem Tiny25) gemacht, um das Gerät 
mit Watchdog-Reset und dem Pin-Change-Interrupt an PB0 ein- und 
auszuschalten. Die Entprellung und den Code für die eigentliche Funktion 
(simuliertes Kerzenflackern an PB1..PB4) habe ich der Übersichtlichkeit 
halber weggelassen.
1
#include <avr/io.h>
2
#include <avr/sleep.h>
3
#include <avr/wdt.h>
4
#include <avr/interrupt.h>
5
#define F_CPU 8000000UL
6
#include <util/delay.h>
7
8
#define BUTTON (!(PINB & 1<<PB0))
9
10
EMPTY_INTERRUPT(PCINT0_vect);
11
12
int main(void)
13
{
14
    MCUSR = 0;
15
    wdt_disable();
16
17
    PORTB |= 1<<PB0; // Pullup on PB0
18
19
    // Pin change interrupt on PB0
20
    GIMSK = 1<<PCIE;
21
    PCMSK = 1<<PCINT0;
22
23
    while(BUTTON);
24
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
25
    sleep_enable();
26
    sei();
27
    sleep_cpu();
28
    sleep_disable();
29
    cli();
30
    while(BUTTON);
31
32
    for (;;) {
33
        if (BUTTON) {
34
            wdt_enable(WDTO_500MS);
35
            while(BUTTON);
36
            wdt_disable();
37
        }
38
    }
39
}

Nach dem Reset schaltet der AVR den Watchdog-Timer aus, den PCINT ein, 
wartet ggf. bis der Taster losgelassen wird und geht in den Power-Down. 
Beim Erwachen wartet er wieder auf den Taster und geht dann in die 
Hauptschleife.

Dort wird der Watchdog beim Drücken des Tasters ein- und nach dem 
Loslassen wieder abgeschaltet. Ein Halten der Taste über den 
Watchdog-Timeout hinaus löst den Reset aus und führt zur Abschaltung.

Falls Du Dich über den langen Timeout wunderst: Im vollständigen 
Programm schaltet ein kurzer Tastendruck zwischen verschiedenen 
Betriebsmodi um. Das war auch der Grund, warum ich zum Abschalten den 
Watchdog genommen habe.

von Vlad T. (vlad_tepesch)


Lesenswert?

so hab ichs in dem adneren Projekt gemacht, einen PCInt ohne ISR.
das geht hier nicht, da ich den PCINT im Programm brauche.

habs jetz aber wie gesagt anders gelöst.

das
    MCUSR = 0;
    wdt_disable();

sollt eaber in code der direkt nach dem start ausgeführt wird.
Wobei das bei deinem großen timeout unkritisch ist.

von R. M. (rmax)


Lesenswert?

Vlad Tepesch schrieb:
> so hab ichs in dem adneren Projekt gemacht, einen PCInt ohne ISR.
> das geht hier nicht, da ich den PCINT im Programm brauche.

Es spricht ja nichts dagegen, den PCINT mit ISR auch zum Aufwecken zu 
benutzen, ggf. halt mit einem zusätzlichen Flag, an dem die ISR erkennen 
kann, ob die CPU gerade aufgewacht ist oder sich im normalen Betrieb 
befindet.

> sollt eaber in code der direkt nach dem start ausgeführt wird.
> Wobei das bei deinem großen timeout unkritisch ist.

Klar, bei extrem kurzen Timeouts kann es in main() schon zu spät sein.

von Vlad T. (vlad_tepesch)


Lesenswert?

Ich hab das
EMPTY_INTERRUPT(PCINT0_vect);
missverstanden, ich dachte das markiert einen Interupt der nicht 
implementiert ist, wodurch ein reset (jmp 0) ausgelöst wird.

aber das wär quatsch.

Aber wie gesagt, mein Problem ist erst mal auf dem pragmatischen weg 
gelöst.

Ob das mit dem wdt-reset in einem Minimalbeispiel klappt, oder mit dem 
selbe COde auf einem anderen Tiny25, probier ishc ein anderes Mal.

Nochmal Danke,
Vlad

von R. M. (rmax)


Lesenswert?

Vlad Tepesch schrieb:
> Ich hab das
> EMPTY_INTERRUPT(PCINT0_vect);
> missverstanden, ich dachte das markiert einen Interupt der nicht
> implementiert ist, wodurch ein reset (jmp 0) ausgelöst wird.

Nein, jmp 0 bekommt man, wenn man gar keine ISR definiert. 
EMPTY_INTERRUPT() baut eine ISR, die nur aus RETI besteht, wobei ich 
mich frage, warum gcc bzw. avr-libc das RETI nicht gleich in die 
Interrupt-Tabelle setzen, sondern zuerst noch einen jmp machen.

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.