Code einmal im Leben eines eingebetteten C-Programms ausführen

Wie kann ich dafür sorgen, dass ein Code-Snippet nur einmal in der Lebensdauer eines Programms ausgeführt wird? Es kann viele Male aus- und eingeschaltet werden. Die einzige Möglichkeit, das Code-Snippet erneut auszuführen, muss das Board erneut flashen.

Der Code ist ein Kalibrierungsabschnitt, den ich nicht erneut ausführen möchte. Wenn ich EEPROM oder Flash verwende, setzen wir ein Flag auf „true“ oder „false“. Wenn wir also diesen Speicherort zum ersten Mal lesen, was wäre der Zufallswert in diesem Speicherbereich?

Was ist die beste Methode, um dies in eingebettetem C zu implementieren?

Möchten Sie nur einmal ausführen? Sollte dieser Code jedes Mal, wenn Sie ihn aus- und wieder einschalten, nur einmal ausgeführt werden und dann bis zu einem erneuten Neustart nichts tun? Oder suchen Sie nach etwas wie Code-Leseschutz?
Verwenden Sie ein Flag und speichern Sie dieses Flag im Eeprom (oder im Flash). Lesen Sie in jedem Augenblick die Flagge vom Eeprom. Beim allerersten Mal des Augenblicks zwingt der Wert des Flags die Ausführung der Funktion. Danach können Sie den Wert des Flags ändern und erneut im Eeprom speichern. In allen anderen Fällen erzwingt der Wert des Flags nicht die Ausführung der Funktion.
unklar, was Sie fragen.
@dwelch: Ich würde vermuten, dass das OP möchte, dass das Gerät erkennen kann, ob es "jungfräulich" ist, damit es beim ersten Lauf etwas anderes tun kann als bei allen nachfolgenden Läufen (z. B. Durchführen einer Kalibrierung usw.).
Richtig, aber das ist nur eine Vermutung, könnte eine Klärung gebrauchen. und wenn das die Frage ist, dann bewegt sie sich von der unklaren Kategorie in die zu breite Kategorie, da die Implementierung für diesen Mikrocontroller spezifisch ist.
Was ist Ihre Motivation, um zu verhindern, dass der Code ein zweites Mal ausgeführt wird? Ist es wichtig, dass der Code nicht rückentwickelt werden kann, in welchem ​​Fall das Setzen eines Flags zur Umgehung möglicherweise nicht sicher genug ist? Würde ein zweites Ausführen des Codes die Hardware beschädigen? Handelt es sich um eine UX-Sache, z. B. um eine Tutorial-Nachricht anzuzeigen, wenn das System zum ersten Mal verwendet wird, in welchem ​​​​Fall es wünschenswert sein könnte, dass die Funktion "Factory Reset" (falls vorhanden) den Code erneut auslöst?
@MichealJohnson Es ist ein Kalibrierungsabschnitt, den ich nicht erneut ausführen möchte. Wenn ich EEPROM oder Flash verwende, setzen wir ein Flag auf wahr oder falsch. Wenn wir also diesen Speicherort zum ersten Mal lesen, was wäre der zufällige Wert in diesem Speicher Bereich.
Im Allgemeinen ist es eine gute Idee, eine Neukalibrierung zuzulassen, falls etwas beim ersten Mal durcheinander gerät oder das System für ein anderes Setup neu kalibriert werden muss oder um die Alterung der Hardware usw. auszugleichen. Ich zum Beispiel neige dazu, die Kalibrierung durcheinander zu bringen das erste Mal, weil ich nicht weiß, was ich tun soll.
Wie wäre es, wenn Sie den Code so einrichten, dass es eine Möglichkeit gibt, ihn zum Ausführen zu befehlen (dh etwas über eine serielle Schnittstelle einzusenden). So müssen Sie sich nicht um nichtflüchtige Speicher kümmern und können die Kalibrierung kontrolliert während der Produktion auslösen.
Sie haben wiederholt gefragt: "Was wäre der Zufallswert in diesem [EEPROM/FLASH]-Speicherbereich?" Die Antwort - es hängt von Ihrem Mikrocontroller ab. Es wird wahrscheinlich alles 0 oder 1 sein, aber wir wissen es nicht. Testen Sie dies ... und passen Sie dann den Code an, um diesen Zustand zu erkennen. Wenn "gleich", führen Sie eine Kalibrierung durch und drehen Sie das Bit um. Hinweis: Ich würde mich nicht darauf verlassen, dass dieser Zustand über Geräterevisionen und Toolchains hinweg unverändert bleibt.

Antworten (4)

Ihr Mikrocontroller verfügt möglicherweise über EEPROM, OTP-Speicher und Benutzersicherungsbits, in denen Sie ein Flag setzen können.

Es gibt keine "beste Methode in Embedded C", das Schreiben von nichtflüchtigem Speicher ist in jedem Mikrocontroller anders.

bearbeiten:

BLITZ

Der Inhalt des Flash-Speichers wird während der Programmierung des Geräts gelöscht. Nach der Programmierung enthalten alle nicht geschriebenen Bytes 0xFF. Konsultieren Sie das Datenblatt, um einen Bereich zu finden, der innerhalb der laufenden Firmware sicher programmiert werden kann.

EEPROM

Obwohl dies in den Datenblättern nicht garantiert wird, enthielten alle EEPROMs, die ich bisher gesehen habe, 0xFF:s, wenn sie ab Werk versendet wurden (außer denen, die mit einer eindeutigen MAC-Adresse vorprogrammiert sind, aber das ist ausdrücklich dokumentiert). Einige Programmiergeräte/Software sind auch in der Lage, EEPROM-Inhalte zu löschen oder zu programmieren. Einige können dauerhaft oder reversibel schreibgeschützt werden.

OTP

Einmal programmierbarer Speicher enthält immer gut definierte Anfangswerte, die im Datenblatt dokumentiert sind.

Es ist immer eine gute Idee, eine gute Prüfsumme wie CRC32 in die geschriebenen Daten aufzunehmen, um sich vor Datenverfälschung durch defekte Teile, Übertragungsfehler, kosmische Strahlung usw. zu schützen.

Wenn ich EEPROM oder Flash verwende, setzen wir ein Flag auf true oder False. Also, wenn wir diesen Speicherplatz zum ersten Mal lesen, was wäre der zufällige Wert in diesem Speicherbereich.
Setzen Sie während der Herstellung das EEPROM zurück (entweder mit einem Programmierer, wenn möglich, oder indem Sie ein dummes kleines Wischerprogramm erstellen, das flashen, es für ein paar Sekunden normal einschalten und dann Ihr Produktionsprogramm laden).

Du sagtest:

Die einzige Möglichkeit, diesen Code auszuführen, muss das Board erneut blinken.

Andere haben gesagt, EEPROM zu verwenden, um ein Flag zu speichern, um anzuzeigen, wann die Funktion run_once() ausgeführt wurde. Dies hat jedoch einen Nachteil: Wenn Sie den Mikrocontroller neu flashen, wurde das ran_it_once-Flag im EEPROM bereits gesetzt und die Funktion run_once() wird nicht ausgeführt. Wenn Ihr Mikrocontroller über ein eingebettetes EEPROM verfügt, ist es möglicherweise möglich, das ran_it_once-Flag zu löschen, wenn Sie den Mikrocontroller neu flashen, sofern der Programmierer dies unterstützt.

Ein besserer Weg ist, Versionsnummern sowohl im EEPROM als auch im Code zu haben. Wenn der Code nach dem Einschalten ausgeführt wird, sollte er die Versionsnummer aus dem EEPROM lesen und mit der im Code gespeicherten Versionsnummer vergleichen. Wenn sie nicht übereinstimmen, wird die Funktion run_once() aufgerufen, und der letzte Akt des Codes run_once() besteht darin, die Firmware-Versionsnummer in das EEPROM zu schreiben. Jedes Mal, wenn Sie den Quellcode der Firmware ändern, müssen Sie die darin eingebettete Versionsnummer erhöhen.

Dies hätte tatsächlich das gleiche Problem wie ein boolesches Flag, wenn der Benutzer lediglich den Mikrocontroller neu flashen würde und er (in diesem Szenario) erneut ausgeführt werden müsste. Es würde das Problem definitiv lösen, wenn die Firmware aktualisiert würde und erneut ausgeführt werden müsste.

Wählen Sie einen Mikrocontroller, der seinen eigenen Programmspeicher schreiben/löschen kann. Nachdem Sie den betreffenden Code ausgeführt haben, lassen Sie den letzten Teil des Codes die erste Anweisung durch einen Sprung ersetzen, der ihn umgeht. Optional können Sie auch den Rest löschen (vielleicht durch nop ersetzen), sodass die Wahrscheinlichkeit, dass er jemals wieder ausgeführt wird, absolut null ist.

Diese Nachricht wird sich in 5..4 selbst zerstören...

So schlau diese Antwort auch sein mag, ich denke, sie ist unnötig komplex. Vielleicht könnte es einen Hinweis verwenden, der angibt, dass es wahrscheinlich nur verwendet werden sollte, wenn persistenter Speicher außerhalb des Codespeichers nicht verfügbar ist?
Auch wenn andere Lösungen möglich sind, denke ich, dass dies einfacher zu verstehen ist als andere.
Selbst wenn andere Lösungen möglich wären, wäre dies meiner Meinung nach auf Quellcodeebene sehr schwer zu verstehen.
Die meisten PICs haben nur 35 Anweisungen ... was könnte schief gehen? ;)

Da Sie diesen Code für die Kalibrierung verwenden, wäre mein Vorschlag, einen Sprengprozess zu erstellen, der den Kalibrierungscode als erste Stufe ausführt und ihn nicht einmal auf der fertigen Produktionsversion der Platine hat. Dies ähnelt der Antwort von Apalopohapa, unterscheidet sich jedoch in dem Sinne, dass Sie zwei separate Programmladungen haben würden: Haben Sie einen Sprengprozess, der die erste Programmladung flasht, die alle Kalibrierungen ausführt und die Daten daraus ausspuckt. Nehmen Sie dann diese Daten und integrieren Sie sie in die Daten des zweiten Programmladevorgangs.

Ein Vorteil dieses Ansatzes besteht darin, dass Sie den benötigten Speicherplatz absolut minimieren – Sie müssen nicht Ihren einmaligen Code speichern, sondern nur die Daten, die er generiert. Indem Sie einen Blast-Prozess haben, der zwei separate Programme lädt, isolieren Sie sich auch ein wenig von Fehlern im Initialisierungscode, die sonst herumliegen könnten. Sie haben auch eine gewisse zusätzliche Flexibilität, wenn Sie Ihren Kalibrierungscode erneut ausführen möchten: Anstatt zusätzlichen Code schreiben zu müssen, um das Bit zu löschen, das anzeigt, dass Ihr Code ausgeführt wurde (was versehentlich bereits gelöscht werden könnte), führen Sie einfach Ihren erneut aus Sprengvorgang.