Ich bin gerade dabei, batteriebetriebene Software mit den EFM Gekko-Controllern (http://energymicro.com/) zu entwickeln, und möchte, dass der Controller schläft, wenn es nichts Sinnvolles dafür gibt. Zu diesem Zweck wird der WFI-Befehl (Wait For Interrupt) verwendet. Dadurch wird der Prozessor in den Ruhezustand versetzt, bis ein Interrupt auftritt.
Wenn der Schlaf durch Speichern von etwas in Anspruch genommen würde, könnte man Lade- / Speicherexklusivoperationen verwenden, um etwas zu tun wie:
// dont_sleep wird immer dann mit 2 geladen, wenn etwas passiert // sollte die Hauptschleife zwingen, mindestens einmal zu zyklieren. Wenn ein Interrupt // tritt auf, wodurch es während der folgenden Anweisung auf 2 zurückgesetzt wird, // Verhalten wird so sein, als ob der Interrupt danach passiert wäre. store_exclusive (load_exclusive (dont_sleep) >> 1); while (! nicht schlafen) { // Wenn zwischen der nächsten Anweisung und store_exclusive ein Interrupt auftritt, schlafe nicht load_exclusive (SLEEP_TRIGGER); if (! dont_sleep) store_exclusive (SLEEP_TRIGGER); }
Wenn ein Interrupt zwischen den Operationen load_exclusive und store_exclusive auftritt, wird store_exclusive übersprungen, wodurch das System die Schleife erneut durchläuft (um festzustellen, ob der Interrupt dont_sleep gesetzt hat). Leider verwendet der Gekko einen WFI-Befehl anstelle einer Schreibadresse, um den Schlafmodus auszulösen. Schreiben von Code wie
if (! dont_sleep) WFI ();
Es besteht die Gefahr, dass ein Interrupt zwischen 'if' und 'wfi' auftritt und 'dont_sleep' gesetzt wird, aber die wfi wird trotzdem ausgeführt. Was ist das beste Muster, um das zu verhindern? Setzen Sie PRIMASK auf 1, um zu verhindern, dass Interrupts den Prozessor kurz vor der Ausführung der WFI unterbrechen, und löschen Sie sie sofort nach? Oder gibt es einen besseren Trick?
BEARBEITEN
Ich wundere mich über das Ereignis. Nach der allgemeinen Beschreibung wäre es für die Unterstützung mehrerer Prozessoren gedacht, aber ich habe mich gefragt, ob etwas wie das Folgende funktionieren könnte:
if (dont_sleep) SEV (); / * Löscht das Ereignis-Flag der folgenden WFE, ohne jedoch zu schlafen * / WFE ();
Jeder Interrupt, der "don't_sleep" setzt, sollte auch einen SEV-Befehl ausführen. Wenn der Interrupt also nach dem "if" -Test auftritt, löscht die WFE das Ereignis-Flag, geht aber nicht in den Ruhezustand. Klingt das nach einem guten Paradigma?