Was verursacht diese Leistungsspitze im STM32-Energiesparmodus?

7

Ich verwende einen STM32L073RZ auf einem bloßen Board mit nur der CPU und den Entkopplungskappen. Ich versorge das Board direkt über einen Otii Arc mit Strom und messe den Stromverbrauch. Ich verwende MbedOS 5.11.2.

Wenn ich die sleep()Funktion aufrufe, wechselt die CPU in einen Energiesparmodus mit einem gelegentlichen Anstieg des Stromverbrauchs um 5 mA ungefähr jede Sekunde (siehe Abbildung unten):

Derzeitiger Verbrauch

Was ist die Ursache dafür? Ich versuche, die CPU bei laufender RTC in den STOP-Modus zu versetzen - dies sollte laut Datenblatt einen Strom von 1 µA ziehen.

Wie kann ich außerdem feststellen, welchen Energiesparmodus die sleep()Funktion gewählt hat? Ich versuche, mich von der HAL fernzuhalten, weil ich viele Probleme beim Konfigurieren von Interrupts und dergleichen hatte.

Der Vollständigkeit halber ist hier der Code, der auf der Platine ausgeführt wird:

#include "mbed.h"

int main() {
    sleep();
}
Amitchone
quelle
1
Ich würde vermuten, dass Ihr mcu aus irgendeinem Grund einmal pro Sekunde aufwacht
Colin
2
Es erscheint durchaus plausibel, dass die RTC einmal pro Sekunde einen Interrupt generiert. Setzen Sie einen Haltepunkt auf den RTC-Interrupt-Handler.
Jeremy
@ Jeremy danke für den Vorschlag, scheint kein RTC-Interrupt zu sein, da der Handler nicht auslöst, wenn ich ihn einbinde.
Amitchone
1
@Adam - Selbst wenn der Interrupt maskiert ist, kann die RTC bei aktivem RTC ohnehin Elemente aus dem Energiesparmodus bringen.
Jeremy
@ Jeremy das ist ein fairer Vorschlag. Ich denke, ich muss mich mit der HAL auseinandersetzen, damit ich absolut sicher sein kann, welche Timer laufen, in welchem ​​Energiemodus sich die CPU befindet usw. Danke!
Amitchone

Antworten:

10

Ich kann nicht speziell über mbed sprechen, aber die allgemeine Idee ist, sleep()dass die Ausführung des aktuellen Prozesses für einige Sekunden angehalten wird oder auf unbestimmte Zeit, wenn kein Argument (entspricht einem Argument von 0) angegeben wird.

In einer Multiprozessumgebung bedeutet dies, dass die CPU einfach anderen Prozessen übergeben wird. Wenn keine anderen Prozesse zur Ausführung bereit sind, kann das Betriebssystem die CPU in einen Energiesparmodus versetzen oder nicht, während auf Interrupts gewartet wird - dies hängt davon ab, wie die idle()Aufgabe geschrieben wird. Dies ist jedoch im Allgemeinen nicht der Zustand mit der niedrigsten Leistung, der auf der CPU verfügbar ist, da diese bei Auftreten von Interrupts schnell aktiviert werden soll.

In Ihrem Fall scheint es einmal pro Sekunde aufzuwachen, um den System-Timer-Tick zu verarbeiten.

Wenn Sie wirklich in einen Zustand mit geringerer Leistung gelangen möchten, gibt es im Allgemeinen plattformspezifische Aufrufe dafür, und genau dafür ist die HAL gedacht. Du solltest es nicht vermeiden, du solltest es lernen .


Nach einer kurzen Suche stellte ich fest, dass die Dokumentation hier: APIs - Power Management dies speziell beschreibt.

Dave Tweed
quelle
Vielen Dank für Ihre Antwort, sehr nützlich. In Mbed sleep()soll die CPU in einen Energiesparmodus versetzt werden, aber keine Dokumentation, die ich finden kann, erklärt diese Logik. Ich habe den SysTick IRQ im NVIC ohne Erfolg deaktiviert. Ich schätze, ich werde Timer / Zähler so lange ausschalten, bis er verschwindet.
Amitchone
1
@AdamMitchell - Wahrscheinlicher ist, dass Sie tatsächlich den Mbed-Code lesen müssen (es ist Open Source, auch wenn standardmäßig eine Binärversion davon verknüpft ist) und herausfinden, was sie tun, und dann entscheiden, ob dies gebracht werden kann in Übereinstimmung mit Ihren Zielen, oder wenn ihre Ziele einfach zu unterschiedlich sind.
Chris Stratton
2

Wie in der Dokumentation erläutert , können die folgenden Treiber Tiefschlaf verhindern:

  • Ticker
  • Auszeit
  • Timer
  • SPI
  • I2C
  • KANN
  • SerialBase

Wenn Sie herausfinden müssen, was den Tiefschlaf blockiert, können Sie über die Befehlszeile erstellen und das ausführliche Debuggen aktivieren - auch wenn Sie in Ihrem Beispiel anscheinend keine haben.

Sie können auch die tickless Dokumentation überprüfen . Ich glaube, dieser Modus ist relativ neu, daher ist es möglich, dass Ihre Plattform einige Probleme in der HAL hat.

Sean Houlihane
quelle
2

Wenn Sie den tickless-Modus (via MBED_TICKLESS=1) aktivieren und den Thread (via wait_ms(10000)) einfach anhalten, werden keine Spitzen angezeigt, und die MCU bleibt im Stop-Modus (zumindest auf meiner STM32F4-Karte).

Jan Jongboom
quelle
1

Also habe ich es geschafft, das herauszufinden; Die Antworten von Sean, Dave und Jan waren äußerst hilfreich und zeigten mir die richtige Richtung (ebenso wie die Kommentare).

Wie bereits erwähnt, habe ich MbedOS 5.11.2 verwendet. Dies beinhaltete dieses Problem, bei dem die CPU aus dem Tiefschlafmodus ausgeschlossen wurde und keine Timer / Ticker usw. deaktivierte. Durch die Aktualisierung auf Version 5.11.4 wurde dieses Problem behoben und das Gerät konnte in den von mir angenommenen STOP-Modus wechseln.

Ich konnte dann die HAL verwenden und in den STANDBY-Modus wechseln. Die resultierende Endstromaufnahme meiner Leerlaufschleife betrug ~ 550 nA. So versetze ich das Gerät in den STANDBY-Modus:

#include "mbed.h"

int main()
{
    HAL_Init();

    __HAL_RCC_PWR_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();
    __HAL_RCC_GPIOH_CLK_ENABLE();
    __HAL_RCC_GPIOE_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.Pin = GPIO_PIN_All;
    GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStructure.Pull = GPIO_NOPULL;

    HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); 
    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
    HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
    HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
    HAL_GPIO_Init(GPIOH, &GPIO_InitStructure);
    HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);

    /* Disable GPIOs clock */
    __HAL_RCC_GPIOA_CLK_DISABLE();
    __HAL_RCC_GPIOB_CLK_DISABLE();
    __HAL_RCC_GPIOC_CLK_DISABLE();
    __HAL_RCC_GPIOD_CLK_DISABLE();
    __HAL_RCC_GPIOH_CLK_DISABLE();
    __HAL_RCC_GPIOE_CLK_DISABLE();

    /* Enable Ultra low power mode */
    HAL_PWREx_EnableUltraLowPower();

    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
    HAL_PWR_EnterSTANDBYMode();
}
Amitchone
quelle
Zu Ihrer Information, ich habe eine Bibliothek für den Standby-Modus auf STM32 mit Mbed: github.com/janjongboom/stm32-standby-rtc-wakeup
Jan Jongboom