Forum: Compiler & IDEs CPU verweigert den Schlaf


von ceberus (Gast)


Lesenswert?

Ok. Ich weiss ich bin jetzt besoffen und das ist auch gut so, darum mag 
man mir die Tippfehler verzeihen. Ich bastle seit Wochen an meinem Board 
rum um den CAN128 in den Schlaf zu versetzen, was mich inzwischen 3 oder 
mehr Wochenenden gekostet hat.
Das Ziel: Die CPU soll schlafen und sich aus einer kleinen Knopfzelle 
nähren wenn an PINE,PE7 ein Lowlevel anliegt und soll aus dem Schlaf 
zurückkehren, wenn PINE,PE7 wieder Spannung hat (High - Level), 
Natürlich soll dan noch immer die Uhrzeit stimmen. Es ist ein 32?Xde 
irgendwas am Port und das ASSR Register ist entsprechend eingestellt.

  // Oszillatoren einstellen
    setbit(ASSR,AS2);                  // 2. Oszillator für TOSC 
aktivieren
  // Clocktimer aktivieren
    TCCR2A = 0x05;                    // Prescaler Timer 2 = 128, extern 
32kHz Clock
    setbit(TIMSK2,OCIE2A);                // Interrupt enable Timer 2
  while(checkbit(ASSR,TCN2UB) || checkbit(ASSR,OCR2UB) || 
checkbit(ASSR,TCR2UB)) asm("NOP");

und ausgewertet wird auch ganz artig

SIGNAL(SIG_OUTPUT_COMPARE2)
  {
  setbit(GPIOR2,GPIOR01); // Sekundenbit
  }
wird gesetzt und die Uhrroutine arbeitet es ab, wenn Zeit dafür ist.
Ich habe zig Anleitungen und natürlich das vermaledeite Handbuch des CAN 
128 gelesen,  den Befehl asm(sleep) habe ich natürlich nirgendwo 
gefunden sondern bin in dem Programmbeispiel des Butterfly darüber 
gestolpert.
Da der Stromverbrauch im Sleep-Modus noch immer bei 10 - 12 mA lag hatte 
ich schon die Hardware in Verdacht... Heute dann die Ernüchterung.

Bei einem Codeschnipsel, der etwa diesem hier
clearbit(EIMSK,INT7);
  cli();
  SMCR = 0x0c;
  sleep_enable();
    sei();
  sleep_cpu();
  while(!checkbit(PINE,PE7)) {totzeitx++; asm volatile ("sleep");}

  sleep_disable();

  sei();

ähnlich gewesen sein könnte war totzeitx nach 3 Sekunden bei einer 
5stelligen Zahl. Es sollte dieses räudige 64beinige Mistvieh doch 
schlafen?! und nur jede Sekunde erwachen, wenn 
SIGNAL(SIG_OUTPUT_COMPARE2) klingelt. Wie kann es sich da in 3 Sekunden 
auf 27?x? hochschrauben?
Ergo. Die Sau schläft nicht. Ich bin mir nicht sicher ob ich überhaupt 
noch wissen will, warum das elende Mistvieh nicht schläft, aber 
vieleicht hat jemand eine Routine für mich wie ich den Hund zum schlafen 
bringe.
Prosit!

von Peter D. (peda)


Lesenswert?

ceberus wrote:
> Ergo. Die Sau schläft nicht.

Ja, der Powerdown Mode ist ziemlich tückisch.
Man muß eine bestimmte Abfolge einhalten und besonders auf die 
Interrupts achten.

Die WINAVR-Funktionen tragen auch das ihre zur Verwirrung bei, da sie 
nicht interruptfest sind.
Da steht zwar im "sleep.h" schön versteckt wichtiger Text, aber wer 
liest das schon so gründlich.

Am besten fährt man, wenn man sie daher nicht benutzt und alles selber 
macht.

Hier mal ein funktionierendes Beispiel auf nem ATtiny45:

http://www.mikrocontroller.net/attachment/33635/SLEEP.C


Peter

von ceberus (Gast)


Lesenswert?

Ach Peter, es ist ja nicht so, dass ich Deine Hilfen und Erklärungen 
nicht zu schätzen wüsste, auch wenn ich mir dabie immer vorkomme wie 
Alice im Wunderland.
Das Beispiel sieht ja auch schick aus, aber ???
Wie und wann kommt Dein Tiny aus der For-Schleife am Ende wieder raus? 
Und wo lässt man die Uhr?
Und wo ist jetzt eigentlich der elementare Fehler in meinem 
Geschriebsel? Macht es einen Unterscheid, ob ich das Register so SMCR = 
0x0c; oder MCUCR = 1<<SE^1<<SM1; beschreibe? wenn die 0 gesetzten Bits 
ohnehin nicht belegt sind?

von Peter D. (peda)


Lesenswert?

ceberus wrote:

> Wie und wann kommt Dein Tiny aus der For-Schleife am Ende wieder raus?

Garnicht, das ist die Mainloop, da kommt nie ein MC raus.
Sie ist hier leer (außer dem Sleep), aber das ist ja nur ein 
Grundgerüst.


> Und wo lässt man die Uhr?

Im T2-Interrupt oder in der Mainloop.
Ganz wo Du willst.


> Und wo ist jetzt eigentlich der elementare Fehler in meinem
> Geschriebsel?

Daß es nur zusammenhanglose Codefetzen sind.


> Macht es einen Unterscheid, ob ich das Register so SMCR =
> 0x0c; oder MCUCR = 1<<SE^1<<SM1; beschreibe?

Ja, das letzte ist lesbarer.


Das Beispiel soll zeigen, daß es am sinnvollsten ist, die entsprechenden 
Sleepmodi in nem Interrupt zu setzen.
Dann muß das Main nur noch das eigentliche Sleep machen, wenn es alle 
Tasks fertig hat.
Wichtig ist, nur das nackte SLEEP, nicht das sleep_mode !!!

Es ergibt IMHO keinerlei Sinn, das Sleepenable separat von den 
Sleepmodis zu setzen. Entweder man will schlafen oder nicht.

Damit gibt es keine Konflikte mehr.


Peter

von cerberus (Gast)


Lesenswert?

Nun ja, ich hatte mir die Sache aus dem sleep.h zusammengeklaubt. 
Geholfen hat es nix. Warum das Sleep_enable immer separat gesetzt wurde, 
kann ich auch nicht sagen, ich habe es überall so gefunden und weil es 
bei mir nicht wirklich funktionierte, wenn ich es gleich mit geschrieben 
habe, habe ich es eben mal so herum probiert. Sleep im Interrupt, sleep 
ohne interrupt, sleep in der Endlosschleife, ... langsam gehen mir die 
Ideen aus...  Vermutlich muss ich es noch einmal ganz von Vorne anfangen 
und die komplette Software um das Sleep-Modul herumschreiben ...

von Peter D. (peda)


Lesenswert?

cerberus wrote:

> Vermutlich muss ich es noch einmal ganz von Vorne anfangen
> und die komplette Software um das Sleep-Modul herumschreiben ...

Eigentlich nicht.
Man sollte erst die Funktionalität fertig stellen und das Sleep ganz zum 
Schluß dazubasteln.

Dazu braucht es nur eine Stelle im Main, wo man denkt, grad nichts mehr 
zu tun zu haben und dann das Sleep dahin setzen.
Das Sleep Mode einstellen machen dann die Interrupts oder das Main unter 
Interruptsperre.

Die Mainloop darf natürlich keine Delayschleifen enthalten, das würde ja 
einem Sleep zuwider laufen.
Also immer schön in Sleep gehen und Timerinterrupts aufsetzen für die 
Delays.


Peter

von cerberus (Gast)


Lesenswert?

Ich komme aus der SPS-Programmierung ;-) bei mir gibt es keine delays 
;-), wird alles über Merker gesteuert.
Das sleep in der Main-schleife und die Initialisierung in der ISR hatte 
ich gestern auch schon, hat aber auch nicht geholfen ...
Ich muss noch mal schauen, was passiert, wenn ich vorher alle Interrupts 
kille, bevor ich den Kollegen schlafen lege. Irgend wo da war ich 
gestern nicht mehr aufnahmefähig ... Ich weiss, dass er dann nicht mehr 
aufwacht, gerade das will ich ja wissen, oder ob er dann einfach 
sang-und Klanglos weitermacht.

Was denkst zu zu einem Main in der Form

int main( void )
{

// Initialisierung und vorgeplänkel

  while(1)
  {
   if(!checkbit(PINE,PE7))
     {
     totzeitx++;
     asm volatile ("sleep");
     }
   else
     {
// Hauptprogramm
     }
  }

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.