Welche Anweisung auf dem STM32 verbraucht am wenigsten Strom?

Das ADC-Modul des STM32 wird in meiner Anwendung verwendet, die sehr empfindlich auf den Stromverbrauch reagiert.

In dieser Anwendung muss der ADC nur mit 20 Abtastungen pro Sekunde arbeiten. Die Verwendung des DMA verbraucht mehr Strom als ich erwartet hatte. Ich entschied mich dafür, dass es im Single-Sample-Modus funktioniert, indem ich eine Aufgabe (FreeRTOS) eine Konvertierung auslösen und alle 50 ms darauf warten lasse, dass die Konvertierung durchgeführt wird.

Hier ist mein Code:

 u16 i;
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
 ADC_Cmd(ADC1, ENABLE);
 for(i=0;i<sizeof(ADC_Channel_Table)/sizeof(u8);i++)
 {
     ADC_RegularChannelConfig(ADC1, ADC_Channel_Table[i], 1, ADC_SampleTime_71Cycles5);
     ADC_SoftwareStartConvCmd(ADC1, ENABLE);
     while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
     {
     }
     ADCConvertedValue[i] = ADC_GetConversionValue(ADC1);
 }
 ADC_Cmd(ADC1, DISABLE);
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, DISABLE);

Wobei "sizeof(ADC_Channel_Table)" 5 ist, weil 5 Kanäle abgetastet werden.

Die Abtastzeit ist ADC_SampleTime_239Cycles5 (eigentlich 256 Zyklen, wobei die Konvertierungszeit enthalten ist). 5 Kanäle benötigen also etwa 1500 Zyklen. Der ADC-Takt beträgt 12 MHz und 1500 Zyklen sind etwa 120 µs.

Und schau dir den Code an:

while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
{
}

Das bedeutet, dass die CPU damit beschäftigt ist, auf die Konvertierung zu warten, und die Wartezeit insgesamt 120 µs beträgt.

120 µs sind groß, da die CPU so lange warten muss und dadurch Energie verschwendet wird, aber diese Zeit ist zu klein für das RTOS. Das RTOS kann eine so geringe Zeit nicht verbrauchen.

Ich möchte also einige "Energiespar"-Anweisungen in die Warteschleife einfügen.

Zum Beispiel:

while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
{
    __ASM("NOP");__ASM("NOP");__ASM("NOP");__ASM("NOP");
}

Aber NOP verbraucht genauso viel Strom wie jeder andere Befehl, den ich ausprobiert habe.

Welche Anweisung kann ich in meine While-Schleife einfügen, die am wenigsten Strom verbraucht?

Haben Sie darüber nachgedacht, das RTOS zu entsorgen?
Hoffentlich habe ich richtig interpretiert, was OP fragen wollte.
Ich denke, @AleksiTorhamo hat die richtige Antwort. Sie fragen ab, wann Sie schlafen sollten, und verwenden Interrupts, um sich selbst aufzuwecken. Dies würde Ihren dynamischen Stromverbrauch für Ihren Prozessor reduzieren.
Welcher Teil dieses Codes bietet eine Abtastrate von 50 ms?

Antworten (6)

Wenn Sie Strom sparen möchten, versetzen Sie die MCU in den Ruhezustand. Die relevanten Anweisungen sind WFI und WFE: Wait-for-Interrupt bzw. Wait-for-Event.

WFI ist irgendwie selbsterklärend: Es wacht auf, wenn Sie einen Interrupt erhalten. (Der Interrupt muss jedoch aktiviert sein!)

WFE könnte etwas mehr Erklärung verdienen. Um es zu verwenden, reicht es wahrscheinlich aus zu wissen, dass, wenn Sie SEVONPEND setzen, ein Interrupt, der im NVIC nicht aktiviert ist, als Ereignis qualifiziert wird. Wenn Sie also den ADC-Interrupt im Peripheriegerät, aber nicht im NVIC aktivieren, können Sie warten, bis er mit WFE abgeschlossen ist. Verwenden Sie weiterhin die Schleife mit der Flag-Prüfung, da möglicherweise andere Ereignisse die MCU aufwecken. (Ersetzen Sie einfach die NOPs durch ein WFE) Weitere Informationen finden Sie wie üblich im Referenzhandbuch.

Wahrscheinlich möchten Sie auch auswählen, in welchen Tiefschlaf Sie wechseln möchten, aber wie das geht, hängt möglicherweise von der spezifischen STM32-MCU ab, die Sie verwenden. Zumindest bei einem Modell waren die relevanten Flags PDDS, LPDS und SLEEPDEEP. Lesen Sie auf jeden Fall den entsprechenden Abschnitt des Referenzhandbuchs.

Wahrscheinlich wollen Sie immer noch die Schleife mit WFI sowie mit WFE, falls mehr als ein Interrupt aktiviert ist.
@ablight Sehr wahr!
Und wenn Sie die CPU in den Ruhezustand versetzen, wird ADC die Konvertierung fortsetzen? Nur neugierig...
@AliChen Im Allgemeinen hängt das vom Chip ab und davon, wie tief der ausgewählte Schlafmodus ist. Schlagen Sie im Zweifelsfall im Referenzhandbuch des von Ihnen verwendeten Chips nach. Auf allen Chips, an die ich mich erinnere, stoppt der leichteste Schlafmodus den Kern, lässt aber alle Peripheriegeräte laufen, es sei denn, Sie sagen es anders (z. B. durch Löschen des LPEN-Bits des relevanten Peripheriegeräts). In tieferen Schlafmodi werden die Peripheriegeräte im Allgemeinen auch gestoppt, aber alles hängt vom jeweiligen Chip und Peripheriegerät ab. Einige Peripheriegeräte auf einigen Chips können auch in tieferen Schlafmodi betrieben werden.
Das ist die Frage. Nicht generell, aber in dieser ganz besonderen MCU. Das OP fragt nicht, ob zwischen den Abtastungen 50 ms lang geschlafen werden soll oder nicht. Seine Frage ist, ob er während 120 us der ADC-Wandlungszeit etwas mehr Strom sparen kann, indem er etwas anderes tut, als sein Wandlungsende-Flag abzufragen.
@AliChen Und die Antwort war ja, wenn Sie sich tatsächlich die Mühe gemacht haben, meine Antwort oder meinen Kommentar zu lesen. Aber wie gesagt, es hängt von der jeweiligen MCU ab. Und das OP hat trotz Ihrer Behauptung keine bestimmte (oder "sehr bestimmte", wie Sie es ausdrücken) MCU erwähnt. Und ohne die genaue MCU zu kennen, kann ich keine genaue Antwort geben.
@AleksiTorhamo, dann sollten Sie sich vielleicht, vielleicht, anstatt eine triviale und offensichtliche Antwort zu geben, die Mühe machen und OP diese wichtigste Frage stellen. Wird ADC die Konvertierung fortsetzen, wenn Sie die MCU in den Ruhezustand versetzen?

Versuchen wir, die entgegengesetzte Frage zu beantworten, um zu erklären, warum NOPkeine Energie gespart wird. Der Cortex-M3 ist ein Prozessor, der klein und relativ einfach konzipiert ist – er verfügt nicht über viele der Schaltkreise, die für die Ausführung dedizierter Aufgaben ausgelegt sind (Caches, Fließkomma, Verzweigungsvorhersage), oder wo dies der Fall ist, sind sie auf Implementierungen beschränkt Holen Sie sich den größten Erfolg für die niedrigsten Kosten.

Die meisten Anweisungen durchlaufen die 3-Stufen-Pipe und erledigen ähnliche Arbeitsmengen. Befehlsabruf, Dekodierung und eine ALU-Operation. Um die Leistung zu erhöhen, könnten wir vielleicht eine Datenübertragung hinzufügen (die mehr Logik außerhalb des Kerns beleuchtet, aber dann höchstwahrscheinlich die gesamte Pipeline anhalten könnte, da der Kern in Ordnung ist). Vielleicht könnten wir die Ein-Zyklus-Teilung direkt nach einer Datenübertragung verwenden - dort könnten Sie möglicherweise zwei zusätzliche Teile der Aktivität gleichzeitig ausführen. Möglicherweise verringert dies jedoch die Aktivität der Registerdatei, sodass nicht alles dazu beiträgt, die Spitzenleistung zu erreichen.

Obwohl es einige Variationen von Anweisungen zu Anweisungen gibt (und eine Menge Designaufwand, um dies zu optimieren), hängt der Großteil der Wirkleistung nicht zu sehr von den Anweisungen ab. Sicher, wenn Sie die Pipe mit mehreren füllen, NOPwird jede Toggle-Aktivität gestoppt, aber die Pipe bewegt sich immer noch weiter. Das Anhalten der Pipe (für eine langsame Datenübertragung) wird viel mehr bewirken, aber der einzige klar definierte Zustand, auf den Sie sich verlassen können, um optimal zu sein, sind WFIund die verschiedenen Schlafzustände.

Größere Kerne haben viel mehr Spitze-zu-Mittelwert, da ein größerer Anteil ihres Siliziums in einer vorab abgerufenen und vorhergesagten Leerlaufschleife inaktiv ist (und wahrscheinlich mehr andere aktive Logik auf dem Chip, die oft auch takt- / leistungsgesteuert sein kann). )

Natürlich gibt es auch bei diesen Geräten viele Peripheriegeräte außerhalb der CPU, die Strom verbrauchen, von denen jedes über eine eigene Taktsteuerung verfügt.

Wenn Sie gerne alle 62,5 ms oder 31,25 ms (im Gegensatz zu 50 ms) Samples erhalten möchten, können Sie die RTC-Alarmfunktion verwenden, um den STM32 aufzuwecken und zwischen den Konvertierungen in den Standby-Modus zu versetzen. Dies spart massiv Strom, insbesondere wenn Sie den ADC so konfigurieren, dass er nach der Konvertierung in den Energiesparmodus wechselt (dies kann von der STM32-Serie abhängig sein). Wenn Sie eine Konvertierung starten, gehen Sie in den Standby/Stopp, sobald Sie aufwachen, ist die Konvertierung sowieso abgeschlossen. Dies fügt eine Latenz von einem Sample hinzu und erfordert, dass Sie das Sample verarbeiten, bevor Sie ein neues Sample starten, aber abhängig von Ihrer Anwendung kann dies machbar sein.

Fluss:

Starten Sie die ADC-Wandlung und aktivieren Sie den RTC-Alarm

Wechseln Sie in den Stoppmodus/Standby-Modus

Sobald RTC den Mikrocontroller aufgeweckt hat, holen Sie sich den ADC-Umwandlungswert

Probe verarbeiten (lagern/filtern etc.)

Vorgang erneut starten!

Stopp- und Standby-Modi verbrauchen sehr wenig Strom, daher kann dies je nach Ihrer Anwendung eine geeignete Methode sein.

Ich würde versuchen, einen Timer zu verwenden, um die Konvertierung zu starten, und einen Interrupt, um das Ergebnis zu sammeln.

Der CPU-Kern kann dann schlafen, bis Daten verfügbar sind.

Als Alternative zum Schlafen können Sie den Taktgenerator möglicherweise so konfigurieren, dass er dem Kern nur einen von 2, 4, 8 usw. Takten gibt, die in den Chip gehen. Wenn die CPU viele Operationen ausführen muss, die Code im Wert von sechs Zyklen erfordern, aber aufgrund externer Hardwareeinschränkungen nur einmal alle 64 Zyklen ausgelöst werden können, kann eine Verlangsamung der CPU auf 1/8 Geschwindigkeit genau das Richtige sein. Während die Verwendung eines Leerlaufmodus mit Interrupt-Aufwecken besser sein kann, als die CPU auf voller Geschwindigkeit zu belassen, muss die CPU möglicherweise viele Zyklen für jedes Ereignis aufwenden, um die Leerlauf-/Aufwach-Übergänge zu konfigurieren. Einige Controller haben Optionen, um die Geschwindigkeiten für die Hauptleitung und die Interrupt-Handler separat einzustellen, sodass selbst wenn die Hauptleitung die CPU auf 1/8-Geschwindigkeit verlangsamt, die Interrupt-Handler mit normaler Geschwindigkeit ausgeführt werden. Ich denke jedoch nicht, dass dies ein besonders häufiges Merkmal ist. Sonst bist du

  1. Stellen Sie einen Timer mit einem Intervall von 1/20 s ein, um eine Konvertierung zu starten
  2. Aktivieren Sie den ADC-Interrupt und behandeln Sie das Ergebnis dort

Oder wenn ein leichtes Zittern der Uhr kein Problem darstellt.

  1. Richten Sie einen 50-ms-FreeRTOS-Timer ein. Sie sind effizient
  2. Aktivieren Sie den ADC-Interrupt und behandeln Sie das Ergebnis dort

Um die MCU ansonsten in den Ruhezustand zu versetzen, setzen Sie einfach asm ("WFI") in die FreeRTOS-Leerlaufschleife.

Ich habe eine ähnliche Situation, aber ich habe gerade alles auf den 1-ms-Tick-Timer von FreeRTOS ausgerichtet.