Strom sparen mit AVRs

Nun macht die AD-Wandlung ja auch nur einen sehr kleinen Teil der Zeit aus, die aller meiste Zeit einen 200ms Zyklus wartet die CPU einfach. Mit 128kHz statt mit 9,6MHz zu „noppen“ hat ja schon mal einiges gebracht, aber eigentlich wollen wir in der Zeit lieber schlafen. Leider ist die Wahl der Schlafmodi ja recht begrenzt. Am liebsten wollen wir natürlich in den „Power-Down“ Modus, nur dann können wir nur noch durch einen externen Interrupt aufwachen (das ist z.B. super für Fernbedienungen!) – oder durch den Watchdog. Eigentlich soll der Watchdog ja die CPU resetten, wenn man ihn nicht oft genug zurücksetzt, um zu verhindern, dass sich die CPU aufhängen kann. Praktischerweise kann der Wachtdog aber auch einen Interrupt auslösen statt einem Reset, so dass man ihn noch ein bisschen als Timer missbrauchen kann. Und praktischerweise läuft der Watchdog in jedem Schlafmodus, also auch bei Power-Down. Können wir vielleicht den Watchdog als Wecker nutzen? Wir können!


//called after a wakeup from the watchdog
EMPTY_INTERRUPT(WDT_vect);

void delay_sleep()
{
wdt_reset();
WDTCR |= _BV(WDTIE); //enabled watchdog interrupt
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_mode();
//will wake up here after ~250ms
}

wdt_reset();
WDTCR |= (1<<WDCE) | (1<<WDE); //unlock watchdog registers (timed sequence!)
WDTCR = _BV(WDP2); //watchdog ~250ms timeout

Auch hier muss man wieder darauf achten, den Watchdog-Interrupt zumindest leer zu definiert. Außerdem muss man ihn auch aktivieren, und zwar jedes Mal, nach dem er ausgelöst wurde! Das ist ein Sicherheitsfeature, denn man kann den Watchdog so einstellen, dass er beim ersten „zubeißen“ den Interrupt auslöst, beim zweiten Mal dann aber einen Reset, sofern der Interrupt nicht wieder scharf geschaltet wurde. Auf diese Weise kann man den Watchdog als Timer benutzen, ohne die Sicherheitsfunktion großartig zu untergraben. Bleibt noch zu beachten, das man die Watchdog-Einstellungen nur in einer Timed-Sequence ändern darf, es muss erst WDCE und WDE im WDTCR Register gesetzt werden, danach hat man 5 Takte Zeit die Einstellungen anzupassen. Damit soll verhindert werden, das fehlerhafter Code den Watchdog versehentlich ausschaltet. Aber Achtung: Wir schaltet ihn gar nicht an! Der Interrupt funktioniert auch, wenn der Watchdog nicht „scharf“ ist, und so verhindern wir darauf achten zu müssen, ihn immer zurückzusetzen. Schlussendlich darf man nicht vergessen, dass man das Timeout des Watchdogs nicht ganz so flexibel einstellen kann, wie das eines normalen Timers, dafür kann man ihn aber bei den Mega’s weilweise auf bis zu 8s stellen, und das ist ja schon mal eine ordentliche Schlafzeit. Ich wollte ja eigentlich 200ms schlafen, die nächste Einstellung war da 250ms. Das passt.

Und der Stromverbrauch? Der ging auf 300µA zurück. Das ist ja schon mal ordentlich. Geht da noch mehr?

Es geht! Aktuell läuft ja der Analog-Digital-Wandler die ganze Zeit. Eigentlich können wir ihn während dir schlafen auch ausschalten. Das hat allerdings den Nebeneffekt, das die erste (und in diesem Fall meistens einzige) Wandlung kann eine „erweiterte“ ist, die zwei Takte (also bei meinem Prescaler 64 CPU-Takte) länger braucht. Das ist jetzt aber nicht so wirklich relevant für mich. Es hat aber auch einen positiven Nebeneffekt: Der tiny hat eine integrierte „Band-Gap“ Spannungsreferenz, die für den Analog-Komperator, den AD-Wandler und den Brown-Out-Detector gebraucht wird. Wenn man alle drei Module abschaltet (was wir je gerade tun), wird auch die Referenz ausgeschaltet (da hat jemand mitgedacht!). Also noch ein bisschen Code:


ADCSRA &= ~_BV(ADEN); //disable A/D converter to save power during sleep

//schlafen

ADCSRA |= _BV(ADEN);

Und siehe da: Jetzt sind wir bei 50-100µA und damit vermutlich auch ein bisschen am unteren Ende meines Multimeters angekommen. Verglichen mit den 6mA (aka 6000µA) ist das doch schon mal eine ordentliche Ersparnis. Und das, ohne auch nur ein bisschen der Funktionen zu opfern. Also: AVRs haben ein gewaltiges Potential zum Strom sparen, was gar nicht so schwer zu heben ist. Gerade die Mega’s haben da natürlich noch feine Möglichkeiten. Trotzdem war ich mal wieder erstaunt, was in dem kleinen ATtiny13 alles so drin steckt 😉

Zum Abschluss noch eine kleine Übersicht:

  • Normal: 6000µA
  • CPU Takt auf 128kHz, Schlafen während AD-Wandlung: 900µA
  • Analog-Komperator abschalten: 800µA
  • Power-Down Modus mit Watchdog zu Schlafen: 300µA
  • AD-Wandler und damit Band-Gap-Referenz während Schlafens abschalten: 50-100µA

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert