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
staticinlinevoidpowerDown(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?
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
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.
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.
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
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.
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.
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
nö
>> 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?
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
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.
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.
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
intmain(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.
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.
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.
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
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.