Hallo Habr!
Es gibt viele Artikel im Netzwerk über den Betrieb von STM32-Mikrocontrollern in energieeffizienten Geräten - normalerweise batteriebetriebenen Geräten -, darunter ist es bedauerlich, dass sie dieses Thema außerhalb der Liste der Energiesparmodi und der SPL / HAL-Befehle, die sie enthalten, nicht verstehen (es gilt jedoch der gleiche Anspruch zu der überwiegenden Mehrheit der Artikel über die Arbeit mit STM32).
In der Zwischenzeit gewinnt das Thema aufgrund der rasanten Entwicklung von Smart Homes und allen Arten von IoT zunehmend an Bedeutung. In solchen Systemen sind viele Komponenten batteriebetrieben, und von ihnen wird ein jahrelanger Dauerbetrieb erwartet.
Wir werden diese Lücke am Beispiel des STM32L1 schließen - eines sehr beliebten Controllers, der recht sparsam ist und gleichzeitig einige spezifische Probleme für diese Serie aufweist. Fast alle der oben genannten Punkte gelten auch für STM32L0 und STM32L4 sowie in Bezug auf allgemeine Probleme und Ansätze für andere Steuerungen, die auf Cortex-M-Kernen basieren.

Das praktische Ergebnis sollte ungefähr so aussehen wie auf dem Foto oben (und ja, wir werden auch über die Anwendbarkeit von Multimetern und anderen Messinstrumenten auf ähnliche Aufgaben sprechen).
Energiesparmodi in STM32L1
Die Grundlagen des Batteriesparens sind die wichtigsten Energiesparmodi des Prozessors. Jeder Hersteller und jede Serie von Controllern hat ihre eigenen (ein spezifischer Satz ist eine Herstellererweiterung der Standard-Cortex-M-Kernmodi mit verschiedenen Nuancen in Bezug auf Peripherie, Versorgungsspannungen usw.).
Insbesondere der STM32L1, der zur wirtschaftlichen Reihe von Steuerungen gehört und in dieser Hinsicht unter anderem einen erweiterten Satz von Leistungseinstellungen erhalten hat, hat Folgendes:
- Ausführen - normaler Modus. All inclusive, alle Peripheriegeräte verfügbar, Frequenz bis 32 MHz.
- Low Power Run (LP Run) - ein spezieller Modus mit einer Betriebsfrequenz innerhalb von 131 kHz und einem maximalen Verbrauch unter Berücksichtigung der gesamten Peripherie von 200 μA. Im LP-Run-Modus wechselt der Prozessorleistungsregler in einen besonders wirtschaftlichen Modus, der bis zu fünfzig Mikroampere spart, während im Run-Modus mit derselben Frequenz gearbeitet wird.
- Schlaf - Suspendierung des Kernels, jedoch unter Beibehaltung aller Taktfrequenzen. Die Prozessorperipheriegeräte können weiterarbeiten, wenn der Kernel sie nicht benötigt, sie können jedoch automatisch ausgeschaltet werden.
- Low Power Sleep (LP Sleep) - eine Kombination aus Sleep mit dem Übergang des Stabilisators in den Economy-Modus. Die Taktfrequenz ist nicht höher als 131 kHz, der Gesamtverbrauch ist nicht höher als 200 μA.
- Stopp - ein vollständiger Stopp aller Taktfrequenzen mit Ausnahme des externen oder internen Taktgenerators 32768 Hz. Im Fall von STM32L1 arbeitet in diesem Modus nur die Echtzeituhr weiter, alles andere stoppt vollständig. In neueren Prozessoren können einige Peripheriegeräte mit niedrigen Frequenzen getaktet werden. Fast alle Prozessorbeine behalten ihren Zustand. Der Inhalt des RAM wird gespeichert, externe Interrupts funktionieren weiterhin.
- Standby - ein vollständiges Herunterfahren des Prozessorkerns, des Arbeitsspeichers und aller Peripheriegeräte mit Ausnahme von Echtzeituhren. RAM wird nicht gespeichert (d. H. Aus Sicht der Software ist das Verlassen im Standby fast das Gleiche wie Leistungsverzerrung - von vorne beginnen), die RTC tickt weiter. Externe Interrupts funktionieren nicht, mit Ausnahme von drei speziellen WKUPx-Beinen, deren Umschaltung von 0 auf 1 den Prozessor weckt.
Das Aufrufen der einzelnen Modi ist recht einfach: Sie müssen die Flags in drei bis fünf Registern setzen. Danach rufen Sie (für den Schlafmodus) den WFI- oder WFE-Befehl auf. Dies ist der Standard-Cortex-M-Befehl und bedeutet „Auf Unterbrechung warten“ und „Auf Ereignis warten“. . Abhängig von den Flags (sie sind im Referenzhandbuch des Prozessors beschrieben, für STM32L1 ist es
RM0038 )
fällt der Prozessor selbst mit diesem Befehl in diesen Modus.
Außerdem wäre es schön, Interrupts zu verbieten (dies hat keinen Einfluss auf die Fähigkeit externer und interner Ereignisse, den Prozessor aus dem Ruhezustand zu erwecken) und darauf zu warten, dass die Daten aus den Registern im Speicher gespeichert werden, wenn dies plötzlich mit dem DSB-Befehl geschieht.
So sieht es beispielsweise aus, wenn Sie in den Stoppmodus wechseln:
PWR->CR &= ~(PWR_CR_PDDS); PWR->CR |= PWR_CR_CWUF; PWR->CR |= PWR_CR_LPSDSR; PWR->CR |= PWR_CR_ULP; SCB->SCR |= (SCB_SCR_SLEEPDEEP_Msk); unsigned state = irq_disable(); __DSB(); __WFI(); init_clk(); irq_restore(state);
WFI ist eine Blockierungsanweisung.
Daraufhin geht der Prozessor in den Tiefschlaf und verlässt ihn erst, wenn eine Unterbrechung auftritt. Ja, ich wiederhole, obwohl wir Interrupts explizit deaktiviert haben, reagiert der Prozessor auf sie und wacht auf - aber die Verarbeitung beginnt erst, nachdem wir sie wieder eingeschaltet haben. Und das hat eine tiefe Bedeutung.
Im obigen Code geht nach WFI eine Art Neuinitialisierung der Betriebsfrequenzen nicht einfach so vor - Tatsache ist, dass L1 den Tiefschlaf immer bei einer Frequenz von 4,2 MHz und mit dem internen MSI-Generator als Quelle dieser Frequenz verlässt. In vielen Situationen möchten Sie natürlich nicht, dass der Interrupt-Handler, der den Prozessor aufweckt, mit dieser Frequenz startet - zum Beispiel, weil die Frequenzen aller Timer, UARTs und anderer Busse abfliegen. Daher stellen wir zuerst die Betriebsfrequenzen wieder her (oder berechnen die erforderlichen Busse unter 4,2 MHz neu, wenn wir auf MSI bleiben möchten) und tauchen dann in Interrupts ein.
In der Praxis sind die beiden am häufigsten verwendeten Modi Ausführen und Stoppen. Tatsache ist, dass LP Run schmerzhaft langsam ist und keinen Sinn ergibt, wenn der Prozessor einige Berechnungen durchführen und nicht nur auf externe Ereignisse warten muss, und Sleep und LP Sleep nicht zu wirtschaftlich sind (Verbrauch bis zu 2 mA) und bei Bedarf benötigt werden Sparen Sie mindestens ein wenig, lassen Sie aber gleichzeitig die funktionierenden Peripheriegeräte und / oder sorgen Sie für die schnellstmögliche Reaktion des Prozessors auf Ereignisse. Solche Anforderungen existieren zwar, aber insgesamt nicht sehr oft.
Der Standby-Modus wird normalerweise nicht verwendet, da es nach dem Nullsetzen des Arbeitsspeichers nicht möglich ist, an der Stelle fortzufahren, an der Sie aufgehört haben. Außerdem treten einige Probleme mit externen Geräten auf, die im Folgenden erläutert werden und Hardwarelösungen erfordern. Wenn das Gerät jedoch unter diesem Gesichtspunkt entwickelt wurde, kann der Standby-Modus beispielsweise während der Langzeitspeicherung dieses Geräts als "Aus" -Modus verwendet werden.
Tatsächlich brechen die meisten Handbücher bei der Präsentation normalerweise triumphierend ab.
Das Problem ist, dass Sie, wenn Sie ihnen folgen, traurige 100-200 μA tatsächlichen Verbrauchs anstelle der versprochenen 1,4 μA in Stop mit den Arbeitsstunden erhalten - selbst beim Nucleo-Referenz-Debugging, das keine externen Chips, Sensoren usw. enthält. dem es zugeschrieben werden könnte.
Und nein, Ihr Prozessor funktioniert, es gibt nichts in Errata und Sie haben alles richtig gemacht.
Nur nicht bis zum Ende.
Restless-Legs-Syndrom
Das erste Problem STM32L1, über das
einige Artikel sprechen, das sich aber oft nur in Foren erinnern, wenn am dritten Diskussionstag, woher die 100-200 μA kamen, sich jemand an die Existenz von
AN3430 erinnert und Seite 19 darin erreicht - dies Beine Zustand standardmäßig.
Ich stelle fest, dass sich sogar STMicro selbst auf das Problem durch die Hüllen bezieht und in den meisten Dokumenten, in denen die Optimierung des Energieverbrauchs in Betracht gezogen wird, auf ein oder zwei Sätze beschränkt ist, mit dem Rat, nicht verwendete Beine zu Boden zu ziehen oder in den analogen Eingabemodus zu versetzen, ohne die Gründe zu erläutern.
Das Traurige ist, dass standardmäßig alle Beine als digitale Eingänge konfiguriert sind (0x00 im GPIOx_MODER-Register). Ein Schmitt-Trigger befindet sich immer am digitalen Eingang, wodurch die Störfestigkeit dieses Eingangs verbessert wird, während er völlig unabhängig ist - es ist ein einfaches Logikelement, ein Puffer mit Hysterese, der keine externe Taktung erfordert.
In unserem Fall bedeutet dies, dass wir die Uhr im Stoppmodus ausgeschaltet haben und die Schmitt-Trigger weiter funktionierten, als wäre nichts passiert - je nach Pegel des Eingangssignals schalten sie ihre Ausgänge auf 0 und 1.
Gleichzeitig hängt ein Teil der Prozessorschenkel in einem typischen Schaltkreis in der Luft - das heißt, es ist kein verständliches Signal auf ihnen. Es wäre falsch zu glauben, dass das Fehlen eines klaren Signals bedeutet, dass auf diesen Beinen 0 aufgrund ihrer hohen Eingangsimpedanz kein zufälliges Rauschen eines unbestimmten Werts von Tonabnehmern und Strom von benachbarten Spuren zum ersten Fernsehkanal fließt. Wenn der Fuß lang genug ist, um als Antenne zu dienen (analoge Fernsehgeräte in Russland werden jedoch bald ausgeschaltet, was zu einer gewissen Reduzierung des Stromverbrauchs falsch konfigurierter Mikrocontroller führen sollte).
In Übereinstimmung mit diesen Schwankungen schaltet der Zweig auf zufällige Weise zwischen 0 und 1 um. Die CMOS-Logik verbraucht beim Schalten Strom. Das heißt, ein
in der Luft hängender Prozessorabschnitt, der im digitalen Eingabemodus konfiguriert ist, verbraucht an sich einen spürbaren Strom .
Der Ausweg ist einfach: Wenn Sie das Programm starten, müssen Sie alle Beine auf den Status des Analogeingangs konfigurieren. STM32 hat es formal für alle Beine ohne Ausnahme, unabhängig davon, ob sie an den ADC angeschlossen sind oder nicht, und unterscheidet sich vom digitalen Eingang nur, wenn kein Schmitt-Trigger am Eingang vorhanden ist.

Dazu reicht es aus, den Wert 0xFF ... FF in alle GPIOx_MODER-Register zu schreiben. Dies ist, wie oben erwähnt, am einfachsten gleich zu Beginn, und dann werden Sie im Verlauf des Spiels die einzelnen Beine nach Bedarf in diesem Gerät neu konfigurieren.
Hier tritt jedoch ein Problem zweiter Ordnung auf - es ist gut, wenn Ihre Firmware auf einem bestimmten Controller funktioniert und Sie daher immer wissen, was
x in GPIOx ist. Schlimmer noch, wenn die Firmware universell ist - der STM32 kann
bis zu 8 Ports haben, aber kleiner sein; Wenn Sie versuchen, auf einen Port zu schreiben, der in diesem Modell des Controllers nicht vorhanden ist, wird ein Hard Fault angezeigt, d. h. Kernel-Absturz.
Selbst dieser Fall kann umgangen werden. Mit Cortex-M können Sie die Adressen auf ihre Gültigkeit überprüfen. Im Fall von M3 und M4 ist die Überprüfung im Allgemeinen recht trivial, erfordert jedoch bei M0 etwas Magie, ist aber realisierbar (
Details können hier gelesen werden , wir werden diesen Artikel nicht fächern )
Das heißt, im Allgemeinen hat der Prozessor gestartet, die Frequenzen eingestellt - und sofort alle verfügbaren GPIO-Ports durchlaufen und in MODER-Ports geschrieben (der folgende Code ist für RIOT OS geschrieben, aber im Allgemeinen ist er kommentarlos klar und kann auf drei Minuten übertragen werden jede andere Plattform).
#if defined(CPU_FAM_STM32L1) GPIO_TypeDef *port; uint32_t ahb_gpio_clocks = RCC->AHBENR & 0xFF; periph_clk_en(AHB, 0xFF); for (uint8_t i = 0; i < 8; i++) { port = (GPIO_TypeDef *)(GPIOA_BASE + i*(GPIOB_BASE - GPIOA_BASE)); if (cpu_check_address((char *)port)) { port->MODER = 0xffffffff; } else { break; } } /* restore GPIO clock */ uint32_t tmpreg = RCC->AHBENR; tmpreg &= ~((uint32_t)0xFF); tmpreg |= ahb_gpio_clocks; periph_clk_en(AHB, tmpreg); #endif
Ich stelle fest, dass dies nur für die L1-Serie gilt. In L0 und L4 wurde die Erfahrung berücksichtigt, und sie konfigurieren standardmäßig alle Ports beim Start als analoge Eingänge.
Nachdem Sie alle diese Verfahren sorgfältig durchgeführt haben, füllen Sie die Firmware in das fertige Gerät ... und erhalten 150 uA im Stoppmodus des Prozessors und aller externen Chips, die ausgeschaltet sind, obwohl Ihre Schätzungen die pessimistischsten sind, die aus den Datenblättern für alles stammen, was Sie auf die Platine gelötet haben Geben Sie nicht mehr als 10 μA.
Außerdem versuchen Sie dann, den Prozessor anstelle von Stop in den Standby-Modus zu versetzen, d. H. Schalten Sie es einfach fast vollständig aus - und anstatt zu fallen, verdreifacht sich der Stromverbrauch und nähert sich fast einem halben Milliampere!
Kein Grund zur Panik. Wie Sie vielleicht erraten haben, haben Sie alles richtig gemacht. Aber nicht bis zum Ende.
Restless Leg Syndrom - 2
Das nächste Problem besteht aus zwei Teilen.
Das erste liegt auf der Hand: Wenn Ihr Gerät nicht aus einem Mikrocontroller besteht, ist es wichtig, nicht zu vergessen, dass externe Chips auch Eingangssignale haben, an denen Schmitt-Trigger hängen und die darüber hinaus die interne Logik des Chips wecken können. Beispielsweise versucht ein Chip, der vom UART-Team aus dem Ruhezustand gezogen und aus dem Ruhezustand entfernt wird, bei jeder Bewegung auf diesem Bus Daten daraus zu lesen.
Wenn all diese Beine in der Luft hängen, bekommen wir dementsprechend nichts Gutes.
Unter welchen Bedingungen landen sie in der Luft?
Erstens, wenn der Controller in den Standby-Modus wechselt, werden alle GPIOs mit hohem Widerstand in den High-Z-Zustand versetzt - das heißt, die an sie angeschlossenen externen Chips befinden sich in der Luft. Es ist unmöglich, dies programmgesteuert in STM32L1 zu beheben (bei anderen Serien und anderen Controllern geschieht dies auf unterschiedliche Weise). Der einzige Ausweg besteht daher in einem System, das den Standby-Modus verwendet. Die Eingänge externer Chips müssen gegen Masse gezogen oder von externen Widerständen gespeist werden.
Eine bestimmte Ebene wird so gewählt, dass die Linie aus Sicht des Chips inaktiv ist:
- 1 für UART TX
- 0 für SPI MOSI
- 0 für SPI CLK im SPI-Modus 0 oder 1
- 1 für SPI CLK mit SPI-Modus 2 oder 3
- 1 für SPI CS
Zweitens kann auf STM32
bei Verwendung des Stoppmodus (sic!)
Der Status der GPIOs, die mit den internen Hardwareblöcken der Schnittstellen verbunden sind, unterschiedlich sein. Das heißt, dieselbe SPI-Schnittstelle, wenn sie in Stop konfiguriert ist, stellt sich plötzlich entweder als digitaler Eingang oder im Allgemeinen als High-Z heraus - mit den entsprechenden Konsequenzen für externe Chips, die daran hängen. Während die Dokumentation besagt, dass die Beine in gutem Zustand sind, können Sie sich a priori nur darauf verlassen, wenn Sie Ihre Beine als reguläre GPIOs verwenden.
Sie können es nicht verstehen und verzeihen, aber Sie können es sich merken und beheben: Für Schnittstellen, die sich auf diese Weise verhalten, müssen Sie in der Schlafpflegefunktion ein erzwungenes Umschalten auf normales GPIO mit Pegeln hinzufügen, die inaktiven Ebenen dieser Schnittstelle entsprechen. Nach dem Aufstehen können die Schnittstellen wiederhergestellt werden.
Zum Beispiel das gleiche SPI vor dem Einschlafen (der Einfachheit halber nehme ich den Code aus dem RIOT-Betriebssystem, es ist klar, dass das gleiche einfach in Registern zu implementieren ist):
for (i = 0; i < SPI_NUMOF; i++) { if (is_periph_clk(spi_config[i].apbbus, spi_config[i].rccmask) == 1) { if (spi_config[i].dev->CR1 & (1<<1)) { gpio_init(spi_config[i].sclk_pin, GPIO_IN_PU); } else { gpio_init(spi_config[i].sclk_pin, GPIO_IN_PD); } gpio_init(spi_config[i].mosi_pin, GPIO_IN_PD); gpio_init(spi_config[i].miso_pin, GPIO_AIN); } }
Bitte beachten Sie, dass die Ausgänge hier nicht als GPIO_OUT mit Stufe 0 oder 1 konfiguriert sind, sondern als Eingänge mit einem Pull-up bis 0 oder 1 - dies ist kein grundlegender Punkt, bietet jedoch zusätzliche Sicherheit, wenn Sie einen Fehler machen und versuchen, Pull-Push mit einer Art von zu spielen Ein externer Chip zieht dieses Bein in die andere Richtung. Mit GPIO_OUT können Sie einen Kurzschluss arrangieren, mit GPIO_IN mit einem Pull-up - niemals.
Darüber hinaus ist das SPI-CS-Signal nicht betroffen - in diesem Fall wird es programmgesteuert generiert, dh von einem normalen GPIO, und es behält seinen Zustand sicher in einem Traum.
Um den Zustand des Beins beim Verlassen des Schlafes wiederherzustellen, reicht es aus, die Werte der Register, die geändert werden sollen (MODER, PUPDR, OTYPER, OSPEEDR - siehe die Situation in einem bestimmten Fall), am Eingang in Variablen zu schreiben und sie beim Verlassen des Schlafes in Register zurückzusetzen .
Und jetzt ... ta daaam! Titelbild. Eineinhalb Mikroampere.
Aber es ist zu früh zum Feiern. Damit haben wir die
statische Optimierung des Energieverbrauchs abgeschlossen und liegen vor uns
dynamisch .
Achilles gegen Schildkröte
Was ist besser - mehr essen und schneller laufen oder weniger essen, aber langsamer laufen? Bei Mikrocontrollern ist die Antwort auf diese Frage zweimal nicht trivial.
Erstens können die Betriebsfrequenzen in einem sehr weiten Bereich geändert werden - von 65 kHz (LP Run) bis 32 MHz im Normalmodus. Wie jeder CMOS-Chip hat STM32 zwei Komponenten im Stromverbrauch - statisch und dynamisch; die zweite hängt von der Frequenz ab, die erste ist konstant. Infolgedessen sinkt der Energieverbrauch nicht so schnell wie die Betriebsfrequenz und Produktivität, und je nach Aufgabe kann sich die aus Sicht der Energieeffizienz optimale Frequenz als unterschiedlich herausstellen - wenn Sie auf ein Ereignis warten müssen, aber aus irgendeinem Grund nicht einschlafen können, wird dies der Fall sein Niedrige Frequenzen sind effektiv, wenn Sie nur Zahlen dreschen müssen - hoch. Bei typischen "Krankenhausdurchschnitt" -Aufgaben ist es normalerweise nicht sinnvoll, unter 2-4 MHz zu fallen.
Zweitens, und dies ist ein weniger trivialer Moment, hängt die Geschwindigkeit, mit der Sie aus dem Schlaf kommen, von der Arbeitsfrequenz und der Art und Weise ab, wie sie empfangen wird.
Der schlimmste Fall ist, mit einer Frequenz von 32 MHz von einem externen Quarz aus dem Schlaf zu kommen (ich möchte Sie daran erinnern, dass STM32L1 mit einem internen 4-MHz-Oszillator aufwacht), da er aus drei Stufen besteht:
- Eigentlich wacht der Prozessor aus dem Schlaf auf
- Stabilisierung der Quarzerzeugung (1-24 MHz)
- Stabilisierung der PLL-Erzeugung (32 MHz)
Tatsächlich ist es das kleinste Problem, den Prozessor hier aus dem Ruhezustand zu bringen. Bei einer Frequenz von 4,2 MHz dauert es ungefähr 10 μs. Die Stabilisierung von Quarz kann jedoch bis zu 1 ms dauern (obwohl sie bei Hochgeschwindigkeitsresonatoren normalerweise noch schneller ist, in der Größenordnung von mehreren hundert Mikrosekunden), beträgt der Zugriff auf den PLL-Modus weitere 160 μs.
Diese Verzögerungen sind unter dem Gesichtspunkt des Energieverbrauchs für ein System, das selten aufwacht (nicht mehr als einmal pro Sekunde), möglicherweise nicht signifikant. Wenn jedoch die Zeitspanne zwischen den Aufweckvorgängen mehrere zehn Millisekunden und weniger beträgt und die Aufweckvorgänge selbst kurz sind, beginnt der Overhead sogar eine bereits messbare Addition unter Berücksichtigung, dass der Prozessor beim Aufwachen einen relativ kleinen Strom verbraucht.
Was kann man damit machen? Im Allgemeinen liegt die Antwort auf der Hand: Vermeiden Sie die Verwendung von externem Quarz. Beispielsweise kann ein Programm, in dem es seltene schwere Unteraufgaben gibt, die eine genaue Taktung erfordern (z. B. die trivialen - UART-Datenaustausch), und häufige einfache Unteraufgaben bei jedem Erwachen selbst entscheiden, ob es notwendig ist, zu gehen externer Quarz, oder es ist einfacher (und schneller!), die aktuelle Aufgabe auf dem MSI-Generator auszuführen, auf dem der Prozessor bereits aufgewacht ist, ohne viel Zeit für die Initialisierung der Frequenzen aufzuwenden.
In diesem Fall kann es jedoch erforderlich sein, die Taktfrequenzen der Peripherie sowie die Zugriffsmodi auf den Flash-Speicher (die Anzahl der Verzögerungszyklen), die Spannung des Prozessorkerns (in STM32L1 wird aus drei möglichen Werten ausgewählt) usw. anzupassen. In Bezug auf die Kernel- und Speicherbetriebsarten ist es jedoch häufig möglich, diese durch Auswahl der für die maximal verwendete Frequenz empfohlenen zu optimieren, da ein nicht optimaler Betrieb des Kerns bei niedrigeren Frequenzen aufgrund des geringen Aufgabenvolumens bei diesen Frequenzen keine signifikante Änderung der praktischen Leistung und des Stromverbrauchs bewirkt durchgeführt.
Obwohl alle diese Maßnahmen bereits für die Feinabstimmung von Modi gelten (und zum Beispiel die meisten Betriebssysteme und Bibliotheken nicht einmal etwas in der Nähe der Box wissen), können sie in einigen Fällen den Durchschnittsverbrauch auf einer Skala von Prozenteinheiten und manchmal sogar noch mehr senken. Stellen Sie sich zum Beispiel einen Wasserzähler vor, der alle 50 ms die Kontakte eines Reed-Schalters abfragt, während die eigentliche Vermessung mehrere zehn Mikrosekunden dauert. Möchten Sie bis zu diesem Zeitpunkt ~ 500 μs hinzufügen, um den Controller aufzuwecken?
Unerträglich lange Sekunde
Ein weiteres Problem, das nicht direkt mit der Energieeinsparung zusammenhängt, sondern unvermeidlich damit zusammenhängt - wie werden Zeitintervalle von weniger als 1 Sekunde gezählt?
Tatsache ist, dass es auf dem STM32L1 nur einen Timer gibt, der im Stoppmodus arbeitet - dies ist RTC, die Standardeinheit für 1 Sekunde. Gleichzeitig gibt es in den Programmen ständig Zeitintervalle von Einheiten, zehn und hundert Millisekunden, um mindestens denselben Wasserzähler zu nehmen.
Wie man ist Auf Prozessoren mit LPTIM-Timern laufen, die mit 32768 Hz getaktet sind? Eine gute Option, aber nicht immer notwendig. Es ist ohne es möglich.
Nicht bei allen STM32L1, aber beginnend mit Cat. In 2 (dies sind die Prozessoren STM32L151CB-A, STM32L151CC und neuer) wurde der RTC-Block durch ein neues Register ergänzt - SSR, SubSeconds Register. Genauer gesagt wurde es nicht so sehr ergänzt, als dass es für den Benutzer sichtbar gemacht wurde, und die Subsekundenalarme ALRMASSR und ALRMBSSR wurden hinzugefügt.
Dieses Register enthält keine verständlichen Zeiteinheiten, es wurde von einem technischen internen Zähler erstellt. In STM32L1 durchläuft ein Takt, der mit 32768 Hz tickt, zwei Teilerzähler, asynchron und synchron, die ihn normalerweise durch 32768 teilen, um einen Tick von 1 Sekunde für den Takt zu erhalten. SSR ist also nur der aktuelle Wert des zweiten Zählers.
Obwohl die SSR nicht in Millisekunden, sondern in ihren Einheiten zählt, kann die Dimension dieser Einheiten geändert werden, indem das Verhältnis der Teiler des synchronen und asynchronen Zählers geändert wird, während ihr Gesamtkoeffizient gleich 32768 gehalten wird, um die Standard-1-Sekunde am RTC-Eingang zu erhalten. Wenn wir diese Koeffizienten kennen, können wir den Preis einer SSR-Division in Millisekunden berechnen und von hier aus mit der Programmierung von Alarmen im Sekundentakt fortfahren.
Es ist anzumerken, dass ein asynchroner Vorzähler wirtschaftlicher ist als ein synchroner SSR, und daher ist es energetisch nachteilig, ihn auf 1 zu setzen und die Eingangsfrequenz bereits durch 32768 in SSR zu teilen, nachdem er nur 30 μs gezählt hat. Für uns haben wir den optimalen Wert für den vorläufigen Teiler 7 für synchron - 4095 ((7 + 1) * (4095 + 1) = 32768) bestimmt. Mit einer weiteren Abnahme des vorläufigen Teilers beginnt der Energieverbrauch von RTC messbar zu wachsen - um einen Bruchteil einer Mikroampere, aber da wir dies mit der „Referenz“ 1,4 μA im Stoppmodus vergleichen, sind sogar die Fraktionen von Bedeutung. Standardmäßig sind diese Werte für STM32L1 127 und 255, d. H. Der Referenzpreis beträgt ca. 4 ms, was etwas rau ist.
Wenn Sie tiefer in den Code eintauchen möchten, haben wir zu gegebener Zeit
den Standard-RTC-Treiber von RIOT OS fertiggestellt, um RTC_SSR- und Millisekundenintervalle zu unterstützen. Seitdem verwenden wir es buchstäblich bei jedem Schritt (und da wir im Betriebssystem arbeiten, hängt auch ein Dienst darüber, mit dem Sie fast eine beliebige Anzahl von Aufgaben mit beliebigen Zeiträumen mit einem Handgriff an einen Hardware-Timer hängen können).
Der gleiche Ansatz wird auf die Steuerungen STM32L0 und STM32L4 übertragen, deren Modelle alle das Register RTC_SSR haben. Dadurch werden keine LPTIM-Timer mehr benötigt und der Code für verschiedene Plattformen wird vereinheitlicht.
Wie man versteht, dass ein Multimeter lügt
Nach all den Optimierungen stellt sich natürlich die berechtigte Frage: Was haben wir tatsächlich erreicht?
Ohne die Antwort darauf zu kennen, könnte man sich vollständig auf ein WFE mit korrekt konfigurierten Flags beschränken, schlafen gehen und 200-500 μA erhalten.Die traditionellste Methode zur Strommessung ist natürlich ein Multimeter. Zu verstehen, dass es mit seinem dynamischen Verbrauch wie ein Mikrocontroller auf einer Last liegt, ist sehr einfach - wenn es eingeschaltet ist, liegt es.Dies bedeutet jedoch nicht, dass das Multimeter in dieser Angelegenheit unbrauchbar ist. Sie müssen es nur anwenden können.Erstens ist ein Multimeter eine sehr langsame Sache, eine typische Zeit für eine Zählung ist eine zweite Skala, eine typische Zeit für die Änderung des Zustands eines Mikrocontrollers ist eine Mikrosekunden-Skala. In einem System, das seinen Verbrauch in diesem Tempo ändert, zeigt das Multimeter einfach zufällige Werte an.Eine der für uns nicht zufälligen Variablen ist jedoch der Verbrauch des Mikrocontrollers im Schlafmodus. Wenn es den auf Datenblättern geschätzten Wert deutlich überschreitet, stimmt eindeutig etwas nicht. Dies ist der Verbrauch eines statischen Systems , dh er kann mit einem Multimeter gemessen werden.Die trivialste Methode, die auf dem Titelfoto gezeigt wird, ist ein Multimeter im Mikroammetermodus, das jetzt in den meisten Modellen mit mittlerer Reichweite verwendet wird und eine gute Genauigkeit und hervorragende Auflösung aufweist. UT120C hat eine Auflösung von 0,1 μA mit einer zertifizierten Genauigkeit von ± 1% ± 3 Entladungen, was für uns ausreicht.Bei diesem Modus gibt es nur ein Problem: Die darin enthaltenen Multimeter haben einen großen Serienwiderstand mit einer Skalierung von Hunderten von Ohm. Im normalen Modus startet der Mikrocontroller mit einem solchen Multimeter im Stromkreis einfach nicht. Glücklicherweise befinden sich die Positionen von "mA" und "uA" in fast allen Instrumenten auf der Waage in der Nähe. Die Buchsen für die Messung in beiden Bereichen sind gleich, sodass Sie den Controller sicher an der Grenze von "mA" starten können. Wenn er in den Ruhezustand wechselt, klicken Sie auf "uA" "- Dies geschieht schnell genug, damit der Controller keine Zeit hat, die Stromversorgung zu verlieren und neu zu starten.Bitte beachten Sie, dass diese Methode nicht anwendbar ist, wenn der Controller Aktivitätsspitzen aufweist. Beispielsweise wird der Watchdog-Timer in der Firmware des Geräts alle 15 Sekunden zurückgesetzt. In diesen Momenten zeigt das Multimeter etwas im Bereich von 27 μA an, was natürlich nichts mit dem Wetter auf dem Mars zu tun hat. Wenn auf Ihrem System öfter als einmal alle 5-10 Sekunden etwas willkürlich Kurzes auftritt, liegt das Multimeter einfach.Eine andere Möglichkeit, statische Aufladung zu messen(Ich hebe dieses Wort direkt hervor) Der Verbrauch durch ein Multimeter ist ein Maß für den Sturz auf einen externen Shunt. Wenn Sie ultrakleine Ströme im Maßstab von einigen zehn Mikroampere messen möchten, müssen Sie einen großen Shunt (z. B. 1 kOhm) parallel dazu schalten - eine Schottky-Diode in direkter Verbindung. Wenn der Shunt mehr als 0,3 V abfällt, öffnet die Diode und begrenzt den Spannungsabfall. Bis zu 0,3 V können Sie den Abfall sicher mit einem Multimeter im Millivoltbereich von 1 mV = 1 μA messen.Leider wird es nicht funktionieren, einen Abfall an einem Shunt mit niedriger Impedanz mit einem typischen Multimeter zu messen - Geräte der Mittelklasse sind in diesem Bereich unglücklich, selbst wenn sie etwas unter 100 μV anzeigen. Wenn Sie ein gutes Desktop-Gerät haben, das 1 UV anzeigen kann, brauchen Sie meinen Rat nicht mehr.Die Statik ist zwar gut, aber was ist mit der Dynamik? Wie kann der gleiche Effekt verschiedener Frequenzen auf den durchschnittlichen Stromverbrauch bewertet werden?Hier ist alles kompliziert.Schreiben wir die Grundvoraussetzungen auf:- Strombereich von mindestens 1 μA - 100 mA (10 ^ 5)
- Messdauer nicht mehr als 10 μs
- Spannungsabfall nicht höher als 100 mV
- Messdauer - unbegrenzt
Wenn wir dies einfach direkt in Zahlen übersetzen, erhalten wir einen relativ schnellen und nicht weniger als 18-Bit-ADC mit einer Eingangsvorspannung von weniger als 30 μV, ein analoges Front-End, das Spannungen von 1 μV messen kann, und eine schnelle Schnittstelle zum Computer, über die wir all dies übertragen können und speichern.Und das alles für einen einzigen Gebrauch.Sie sehen, ja, warum liegen solche Dinge nicht an jeder Ecke von zehn Dollar? Keysight N6705C erfüllt in erster Näherung unsere Anforderungen, kostet jedoch nur 7960 US-Dollar.Bei Budgetlösungen beispielsweise integriert SiLabs die aktuelle Messung in seine Debugs. Die Eigenschaften des Advanced Energy Monitoring (AEM) -Systems hängen vom jeweiligen Debugging-Modell ab und sie haben das größte Problem mit der Messgeschwindigkeit. In den alten „Starter-Kits“ beträgt der STK3300 / 3400 nur 100 Hz, in den neueren Debugs der STK3700 / 3800 (leicht erkennbar an schwarzem Textolith) - 6,25 kHz, und in älteren Debug-Modellen der DK-Serie kann er bis zu 10 kHz erreichen, kostet aber auch Sie sind bereits $ 300 +. Für ernsthafte Aufgaben empfiehlt SiLabs offiziell die oben genannte Keysight.Im Prinzip kann ein solches Gerät von Ihnen selbst entworfen werden - zunächst benötigen Sie sehr gute Operationsverstärker mit minimaler Eingangsvorspannung wie OPA2335. Solche Operationsverstärker werden auf den gleichen Shunt von 2-3 Teilen mit unterschiedlichen Verstärkungsfaktoren gelegt, alle werden auf unterschiedliche ADC-Eingänge gewickelt (bei diesem Ansatz ist es durchaus möglich, den eingebauten Mikrocontroller zu verwenden), und dann wird bei jeder Datenerfassung programmgesteuert bestimmt, welcher der Operationsverstärker in einem bestimmten Bereich vorhanden ist Wenn der Moment nicht überlastet ist, werden die Messwerte gezählt.Das Problem der Geschwindigkeit der Datenübertragung auf einen Computer ist ganz einfach zu lösen - da wir aus praktischen Gründen in erster Linie am durchschnittlichen Verbrauch des Systems im realen Leben interessiert sind, können Mikrosekundenwerte im integrierten Mikrocontroller des Messgeräts erfasst und der arithmetische Durchschnitt für einen angemessenen Millisekundenmaßstab gesendet werden.Darüber hinaus ist es, wie die Praxis zeigt, sehr nützlich, einen Zählerlogger zu haben, der zwar einfach und nicht zu genau ist, aber immer zur Hand ist, um keine Überraschungen mit einer durch Energiesparen unterbrochenen Firmware-Änderung zu erhalten.Zum Beispiel haben wir einen in unseren Standard-USB-Adapter UMDK-RF eingebaut, der beim Debuggen der Firmware ständig verwendet wird. Er verfügt bereits über einen SWD-Programmierer mit Unterstützung für das DAPLink-Protokoll, eine USB-UART-Brücke und eine Energieverwaltungslogik. Er verfügt über eine Verbrauchsanzeige fast kostenlos. Das Messgerät selbst ist ein 1-Ohm-Shunt und ein INA213-Verstärker (50-fache Verstärkung, typischer Nullpunktversatz 5 μV): Der
Verstärker wird direkt an den Eingang des ADC des Mikrocontrollers (STM32F042F6P6) angeschlossen, der ADC verarbeitet über einen Hardware-Timer mit einer Dauer von 10 μs und über USB gemittelte Daten werden für ein Intervall von 100 ms ausgegeben. Wenn Sie also etwas an der Firmware-Logik ändern, können Sie einfach rauchen oder Kaffee trinken, das Gerät auf dem Tisch lassen und zurückkehren. Sehen Sie sich einen Zeitplan wie diesen an:
Die Genauigkeit eines solchen „freien“ Geräts ist natürlich nicht hoch - mit einem 12-Bit-ADC und einem Verstärker beträgt das Mindestquantum 16 μA, aber es ist äußerst nützlich für eine schnelle und regelmäßige Bewertung des Verhaltens von debuggten Geräten unter dem Gesichtspunkt des Energieverbrauchs. Wenn Sie am Ende etwas an der Firmware oder dem Gerät falsch machen, können Sie mit einer sehr hohen Garantie mindestens Hunderte von Mikroampere-Einheiten verlassen, was deutlich sichtbar ist.
Ein weiterer netter Bonus ist, dass Sie, da die Daten in Textform (Werte in Mikroampere) an den virtuellen COM-Port gesendet werden, das Terminalfenster neben dem Fenster mit der Gerätekonsole positionieren und gleichzeitig mit den Debug-Meldungen den Stromverbrauch anzeigen können.Ich prahle aus einem bestimmten Grund damit, aber um jedem anzubieten, der diesen minimalen (und sehr billigen!) Debugger-Programmierer in seinen eigenen Projekten verwenden möchte.Sie können das Diagramm hier zeichnen ( Quelle in DipTrace ), die Firmware hier herausziehen (umdk-rf-Brunch, wenn das Ziel UMDK-RF ist, basierend auf dem dap42- Projekt ). Das Diagramm ist chaotisch gezeichnet, aber ich hoffe, die Hauptpunkte sind klar, die Firmware wird mit libopencm3 in C geschrieben und mit dem üblichen arm-none-eabi-gcc zusammengesetzt. Als zusätzliche Funktionen verfügt die Firmware über eine Energieverwaltung, die Signale über Überlastung von Steuertasten abfängt und den mit ihr verbundenen Controller per langem Drücken eines Knopfdrucks in ihren nativen Bootloader eingibt.NB: Wenn Sie möchten, dass die Boot-Schaltfläche den eigenen Controller des Programmierers regelmäßig in den Bootloader bringt, muss die Polarität der Verbindung geändert, die Optionsbytes-Bearbeitung des Controllers beim ersten Start und die Programmeingabe für den Bootloader entfernt und die Interrupt-Polarität für den regulären Bootloader entfernt werden Funktionen dieser Taste. Hier (Seite 9)können Sie sehen, wie der Strom an einem Operationsverstärkerpaar mit unterschiedlichen Verstärkungsfaktoren gemessen wird (z. B. um den oben für Ihre Aufgaben beschriebenen Debugger zu verbessern). Dies ist eine traditionellere alternative Option - mit einem Operationsverstärker und einem teuren 24-Bit-ADC - TI hat es (EnergyTrace auf Seite 5).PS Bitte beachten Sie, dass beim Debuggen mit einem angeschlossenen UART oder JTAG / SWD auch ein kleiner Strom durch die Beine fließen kann, der während des tatsächlichen Betriebs des Geräts nicht auftritt. Bei UMDK-RF treten also etwa 15 μA in die SWD aus (und daher werden auf dem Header-Foto Messungen mit einem Multimeter an der alten Version der Platine ohne SWD durchgeführt), und bei der STM32 Nucleo gab es Fälle mit einem Störstrom durch die SWD von etwa 200 μA . Die für die Messung verwendeten Debug-Karten müssen auf solche Funktionen überprüft werden - entweder durch Trennen ihrer Schnittstellenleitungen, wenn dies möglich ist, oder durch Vergleichen der Ergebnisse mit dem gemessenen Verbrauch des Geräts, ohne es zum Debuggen zu installieren, z. B. mit einem Multimeter im statischen Modus.Anstelle einer Schlussfolgerung
Ich hoffe, Sie haben bereits verstanden, welchen Fehler Sie gemacht haben, als Sie die Mikrocontroller-Programmierung als Ihre Hauptspezialität gewählt haben.