Was passiert in einem eingebetteten Prozessor, wenn die Ausführung diese endgültige return
Anweisung erreicht? Stromverbrauch etc, mit einem langen ewigen NOP am Himmel? oder werden NOPs fortlaufend ausgeführt oder wird ein Prozessor vollständig heruntergefahren?
Ich frage unter anderem, ob ein Prozessor ausgeschaltet werden muss, bevor die Ausführung abgeschlossen ist, und ob er die Ausführung jemals beendet, wenn er zuvor ausgeschaltet wurde.
Antworten:
Dies ist eine Frage, die mein Vater mir immer gestellt hat. " Warum durchläuft es nicht einfach alle Anweisungen und hört am Ende auf? "
Schauen wir uns ein pathologisches Beispiel an. Der folgende Code wurde im C18-Compiler von Microchip für den PIC18 kompiliert:
Es erzeugt die folgende Assembler-Ausgabe:
Wie Sie sehen, wird main () aufgerufen und enthält am Ende eine return-Anweisung, die wir jedoch nicht explizit angegeben haben. Wenn main zurückkehrt, führt die CPU den nächsten Befehl aus, der einfach ein GOTO ist, um zum Anfang des Codes zurückzukehren. main () wird einfach immer wieder aufgerufen.
Nun, nachdem wir das gesagt haben, ist dies nicht die Art und Weise, wie Menschen Dinge normalerweise tun würden. Ich habe noch nie einen eingebetteten Code geschrieben, mit dem main () so beendet werden kann. Meistens würde mein Code ungefähr so aussehen:
Daher würde ich main () normalerweise nie beenden.
"OK, ok" sagst du. All dies ist sehr interessant, da der Compiler sicherstellt, dass es nie eine letzte return-Anweisung gibt. Aber was passiert, wenn wir das Problem erzwingen? Was ist, wenn ich meinen Assembler mit der Hand codiere und keinen Sprung zurück zum Anfang mache?
Nun, offensichtlich würde die CPU einfach die nächsten Anweisungen ausführen. Diese würden ungefähr so aussehen:
Die nächste Speicheradresse nach der letzten Anweisung in main () ist leer. Auf einem Mikrocontroller mit FLASH-Speicher enthält eine leere Anweisung den Wert 0xFFFF. Zumindest auf einem PIC wird dieser Op-Code als 'nop' oder 'no operation' interpretiert. Es tut einfach nichts. Die CPU würde diese Nops bis zum Ende des Speichers weiter ausführen.
Was ist danach?
Bei der letzten Anweisung lautet der Anweisungszeiger der CPU 0x7FFe. Wenn die CPU 2 zu ihrem Befehlszeiger hinzufügt, erhält sie 0x8000, was als Überlauf auf einem PIC mit nur 32k FLASH angesehen wird, und springt so auf 0x0000 zurück, und die CPU setzt die Ausführung von Befehlen gerne am Anfang des Codes fort , als wäre es zurückgesetzt worden.
Sie haben auch gefragt, ob das Gerät ausgeschaltet werden muss. Grundsätzlich können Sie tun, was Sie wollen, und das hängt von Ihrer Anwendung ab.
Wenn Sie eine Anwendung hatten, die nach dem Einschalten nur eine Aktion ausführen musste, und dann nichts anderes tun, können Sie einfach eine Weile warten (1). am Ende von main (), damit die CPU nichts Auffälliges mehr tut.
Wenn die CPU aufgrund der Anwendung heruntergefahren werden musste, stehen je nach CPU möglicherweise verschiedene Energiesparmodi zur Verfügung. CPUs haben jedoch die Angewohnheit, wieder aufzuwachen, sodass Sie sicherstellen müssen, dass keine zeitliche Begrenzung für den Ruhezustand festgelegt wurde und kein Watch Dog Timer aktiv ist usw.
Sie könnten sogar einige externe Schaltkreise organisieren, die es der CPU ermöglichen würden, ihre eigene Stromversorgung vollständig zu unterbrechen, wenn sie fertig ist. Siehe diese Frage: Verwenden eines Tasters als einrastender Ein-Aus-Kippschalter .
quelle
Bei kompiliertem Code hängt dies vom Compiler ab. Der von mir verwendete Rowley CrossWorks gcc ARM-Compiler springt zum Code in der Datei crt0.s, die eine Endlosschleife enthält. Der Microchip C30-Compiler für die 16-Bit-Geräte dsPIC und PIC24 (ebenfalls auf gcc-Basis) setzt den Prozessor zurück.
Natürlich werden die meisten eingebetteten Programme niemals so beendet und führen Code kontinuierlich in einer Schleife aus.
quelle
Hier sind zwei Punkte zu beachten:
Das Konzept eines Programmabschlusses existiert normalerweise in einer eingebetteten Umgebung nicht. Auf einer niedrigen Ebene führt eine CPU Anweisungen aus, solange dies möglich ist. es gibt keine "final return statement". Eine CPU kann die Ausführung stoppen, wenn sie auf einen nicht behebbaren Fehler stößt oder explizit angehalten wird (in einen Ruhemodus, einen Energiesparmodus usw. versetzt). Beachten Sie jedoch, dass selbst Ruhemodi oder nicht behebbare Fehler im Allgemeinen nicht garantieren, dass kein Code mehr ausgeführt wird ausgeführt werden. Sie können aus dem Energiesparmodus aufwachen (so werden sie normalerweise verwendet), und sogar eine gesperrte CPU kann einen NMI-Handler ausführen (dies ist bei Cortex-M der Fall). Ein Watchdog wird auch weiterhin ausgeführt, und Sie können ihn möglicherweise auf einigen Mikrocontrollern nicht deaktivieren, sobald er aktiviert ist. Die Details variieren stark zwischen den Architekturen.
Bei Firmware, die in einer Sprache wie C oder C ++ geschrieben ist, wird das Beenden von main () durch den Startcode bestimmt. Hier ist zum Beispiel der relevante Teil des Startcodes aus der STM32 Standard Peripheral Library (für eine GNU-Toolchain sind meine Kommentare):
Dieser Code tritt in eine Endlosschleife ein, wenn main () zurückkehrt, allerdings auf nicht offensichtliche Weise (
bl main
wirdlr
mit der Adresse des nächsten Befehls geladen, was praktisch ein Sprung zu sich selbst ist). Es werden keine Versuche unternommen, die CPU anzuhalten oder in einen Energiesparmodus usw. zu versetzen. Wenn Sie dies in Ihrer Anwendung rechtmäßig benötigen, müssen Sie dies selbst tun.Beachten Sie, dass das Verbindungsregister gemäß ARMv7-M ARM A2.3.1 beim Zurücksetzen auf 0xFFFFFFFF gesetzt wird und eine Verzweigung zu dieser Adresse einen Fehler auslöst. Daher haben die Designer von Cortex-M beschlossen, eine Rückgabe des Reset-Handlers als abnormal zu behandeln, und es ist schwierig, mit ihnen zu streiten.
Apropos legitimer Bedarf, die CPU nach Abschluss der Firmware zu stoppen, ist kaum vorstellbar, dass ein Abschalten Ihres Geräts nicht besser funktioniert. (Wenn Sie Ihre CPU "für immer" deaktivieren, können Sie nur ein Aus- und Wiedereinschalten oder einen externen Hardware-Reset durchführen.) Sie können ein ENABLE-Signal für Ihren DC / DC-Wandler deaktivieren oder die Stromversorgung ausschalten auf andere Weise, wie es ein ATX-PC tut.
quelle
loop: b loop
. Ich frage mich, ob sie eigentlich eine Rückkehr vorhatten, aber vergessen hatten zu sparenlr
.Wenn Sie nachfragen
return
, denken Sie zu hoch. Der C-Code wird in Maschinencode übersetzt. Wenn Sie also stattdessen daran denken, dass der Prozessor Anweisungen blind aus dem Speicher zieht und ausführt, hat er keine Ahnung, welche die "endgültigen" sindreturn
. Prozessoren haben also kein inhärentes Ende, sondern es ist Sache des Programmierers, den Endfall zu behandeln. Wie Leon in seiner Antwort hervorhebt, haben Compiler ein Standardverhalten programmiert, aber oft möchte der Programmierer ihre eigene Sequenz zum Herunterfahren (ich habe verschiedene Dinge getan, wie in einen Energiesparmodus zu wechseln und anzuhalten oder auf das Anschließen eines USB-Kabels zu warten in und dann neu starten).Viele Mikroprozessoren verfügen über Stoppbefehle, mit denen der Prozessor gestoppt wird, ohne die Speicherkapazität zu beeinträchtigen. Andere Prozessoren können sich auf das "Anhalten" verlassen, indem sie einfach wiederholt zu derselben Adresse springen. Möglicherweise gibt es Optionen, aber es liegt am Programmierer, da der Prozessor einfach die Anweisungen aus dem Speicher liest, auch wenn dieser Speicher nicht als Anweisungen gedacht war.
quelle
Das Problem ist nicht eingebettet (ein eingebettetes System kann Linux oder sogar Windows ausführen), sondern eigenständig oder "Bare-Metal": Das (kompilierte) Anwendungsprogramm ist das einzige, was auf dem Computer ausgeführt wird (es spielt keine Rolle, ob es sich um ein handelt) Mikrocontroller oder Mikroprozessor).
Für die meisten Sprachen definiert die Sprache nicht, was passiert, wenn das Hauptprogramm beendet wird und es kein Betriebssystem gibt, zu dem zurückgekehrt werden kann. Für C hängt es davon ab, was sich in der Startdatei befindet (häufig crt0.s). In den meisten Fällen kann (oder muss) der Benutzer den Startcode eingeben. Die endgültige Antwort lautet also: Was Sie schreiben, ist der Startcode oder was zufällig in dem von Ihnen angegebenen Startcode enthalten ist.
In der Praxis gibt es 3 Ansätze:
Treffen Sie keine besonderen Maßnahmen. Was passiert, wenn die Hauptrückgabe undefiniert ist?
springe auf 0 oder benutze ein anderes Mittel, um die Anwendung neu zu starten.
Geben Sie eine enge Schleife ein (oder deaktivieren Sie Interrupts und führen Sie eine Halt-Anweisung aus), und sperren Sie den Prozessor für immer.
Was angemessen ist, hängt von der Anwendung ab. Eine Fur-Elise-Grußkarte und ein Bremssteuersystem (um nur zwei eingebettete Systeme zu nennen) sollten wahrscheinlich neu starten. Der Nachteil beim Neustart ist, dass das Problem möglicherweise unbemerkt bleibt.
quelle
Ich habe mir neulich einen zerlegten ATtiny45-Code (C ++, kompiliert von avr-gcc) angesehen, der am Ende des Codes auf 0x0000 springt. Grundsätzlich einen Reset / Neustart durchführen.
Wenn dieser letzte Sprung zu 0x0000 vom Compiler / Assembler ausgelassen wird, werden alle Bytes im Programmspeicher als 'gültiger' Maschinencode interpretiert und laufen den ganzen Weg, bis der Programmzähler auf 0x0000 wechselt.
Bei AVR ist ein 00-Byte (Standardwert, wenn eine Zelle leer ist) ein NOP = No Operation. Es läuft also sehr schnell und braucht nur etwas Zeit.
quelle
Im Allgemeinen wird der kompilierte
main
Code anschließend mit dem Startcode verknüpft (er kann in die vom Chiphersteller bereitgestellte, von Ihnen geschriebene Toolchain integriert werden usw.).Der Linker platziert dann den gesamten Anwendungs- und Startcode in Speichersegmenten. Die Beantwortung der Fragen hängt daher von folgenden Faktoren ab: 1. Code vom Start, da dies beispielsweise Folgendes kann:
bl lr
oderb .
), die "Programmende" ähnelt, aber zuvor aktivierte Interrupts und Peripheriegeräte funktionieren weiterhin,main
).ignoriere einfach "was als nächstes kommt" nach dem anruf an
main
return.main
Verhalten , hängt dies vom Linker (und / oder dem Linker-Skript, das während der Verknüpfung verwendet wird) ab.Wenn eine andere Funktion / Code nach Ihrer platziert
main
wird, wird sie mit ungültigen / undefinierten Argumentwerten ausgeführt.Wenn Watchdog aktiviert ist, wird die MCU trotz aller Endlosschleifen, in denen Sie sich befinden, zurückgesetzt (natürlich, wenn sie nicht erneut geladen wird).
quelle
Der beste Weg, ein eingebettetes Gerät zu stoppen, besteht darin, mit NOP-Anweisungen für immer zu warten.
Die zweite Möglichkeit besteht darin, das Gerät zu schließen, indem Sie das Gerät selbst verwenden. Wenn Sie ein Relais mit Ihren Anweisungen steuern können, müssen Sie nur den Schalter öffnen, der Ihr Embedded-Gerät mit Strom versorgt, und schon ist Ihr Embedded-Gerät stromlos .
quelle
Es wurde im Handbuch klar erklärt. Normalerweise wird von der CPU eine allgemeine Ausnahme ausgelöst, da sie auf einen Speicherort zugreift, der sich außerhalb des Stapelsegments befindet. [Speicherschutz Ausnahme].
Was hast du mit dem eingebetteten System gemeint? Mikroprozessor oder Mikrocontroller? Wie auch immer, es ist im Handbuch definiert.
In der x86-CPU schalten wir den Computer aus, indem wir den Befehl an den ACIP-Controller senden. Aufrufen des Systemverwaltungsmodus. Dieser Controller ist also ein E / A-Chip und muss nicht manuell ausgeschaltet werden.
Weitere Informationen finden Sie in der ACPI-Spezifikation.
quelle