Ich bin ziemlich neu in der ARM-Architektur und arbeite mit einem Board, das einen STM32F0-Mikrocontroller und ein HF-Modem enthält, das jedes Mal, wenn es eine Nachricht empfängt, einen Interrupt sendet. Ich versuche, einen Schlafmodus in einem Mikrocontroller zu implementieren, um Strom zu sparen, aber ich verstehe nicht ganz, warum er sich so verhält, wie er es tut.
Begonnen habe ich mit einem einfachen Programm, das die CPU zu Beginn der Ausführung in den Schlafmodus versetzt. Dann wartet er auf den externen Interrupt, um ihn aufzuwecken, den Interrupt auszuführen und mit dem Hauptprogramm fortzufahren. In der ISR schalte ich jedes Mal, wenn die Routine aufgerufen wird, eine LED an Pin PA0 um, verwende dann aber Pin PA1 in der Hauptfunktion (), die mit einer kurzen Verzögerung ein- und ausschaltet und anzeigt, dass der Mikrocontroller den Schlafmodus verlassen hat.
Mein Code sieht im Grunde so aus:
int main()
{
periph_init();
modem_init();
HAL_PWR_EnterSLEEPMode(0,1);
while(1)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_1);
Delay();
}
}
Und der ISR für das EXTI
void EXTI0_1_IRQHandler(void)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0);
// Some other stuff
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
}
Das ARMv6-Architektur-Referenzhandbuch gibt Folgendes in Bezug auf Wait For Interrupt auf Seite B1-243 an:
Wenn ein Prozessor einen WFI-Befehl ausgibt, kann er die Ausführung aussetzen und in einen Niedrigleistungszustand eintreten. Es kann in diesem Zustand verbleiben, bis der Prozessor eines der folgenden WFI-Weckereignisse erkennt:
Eingestellt sind.
Eine asynchrone Ausnahme mit einer Priorität, die, wenn PRIMASK.PM auf 0 gesetzt wäre, alle derzeit aktiven Ausnahmen verdrängen würde.
Wenn Debug aktiviert ist, ein Debug-Ereignis.
Ein IMPLEMENTIERUNGSDEFINIERTES WFI-Weckereignis.
Wenn ich richtig verstehe, gilt in diesem Fall die zweite Zeile. Das bedeutet, dass der Aufruf eines beliebigen Interrupts unabhängig von seiner Priorität den Prozessor aufwecken würde, da der WFI von der Hauptleitung aus aufgerufen wurde. Zur Information werden alle implementierten Unterbrechungsprioritäten auf 0 gesetzt, mit Ausnahme von EXTI, das auf -1 gesetzt wird.
Das passiert nun tatsächlich. Die LED auf PA0 schaltet entsprechend um und zeigt an, dass die ISR tatsächlich ausgeführt wird. Aber die LED auf PA1 bleibt ausgeschaltet, was bedeutet, dass die CPU nach Abschluss der ISR in einem WFI bleibt. Dies wird sogar während des Debuggens bestätigt, indem ich einen Haltepunkt in die Interrupt-Service-Routine eingefügt habe. Nachdem der Code ausgeführt wurde, stoppt er erfolgreich am Haltepunkt. Wenn ich dann das Debuggen mit einer Schritt-für-Schritt-Funktion fortsetze, springt das Programm zum WFI-Befehl (wobei es weiter zum Hauptbildschirm geht, da das Debuggen dazu führen kann, dass der WFI beendet wird).
Meine Frage ist, warum kehrt die CPU zum WFI zurück, wenn der Interrupt eindeutig aufgerufen wird? Wenn sich die CPU in WFI befindet, sollte sie nach meinem Verständnis mit ihrem Betrieb dort fortfahren, wo sie aufgehört hat, sobald ein Interrupt aufgerufen wird.
Überprüfen Sie, ob das SLEEPONEXIT
Bit in SCB->SCR
gesetzt ist. Das Setzen auf 1 würde genau das bewirken, was Sie beschrieben haben:
Bit 1 SCHLAFAUSGANG
Konfiguriert Sleep-on-Exit bei der Rückkehr vom Handler-Modus in den Thread-Modus. Das Setzen dieses Bits auf 1 ermöglicht es einer Interrupt-gesteuerten Anwendung, die Rückkehr zu einer leeren Hauptanwendung zu vermeiden.
0: Nicht schlafen, wenn in den Thread-Modus zurückgekehrt wird.
1: Eintreten in Schlaf oder Tiefschlaf bei der Rückkehr von einer Interrupt-Service-Routine.
Scott Seidman
aljaz41
Scott Seidman
Bence Kaulics
void HAL_Delay(__IO uint32_t Delay)
Sean Houlihane