Was passiert, wenn Mikrocontroller keinen RAM mehr haben?


12

Es mag nur ein Zufall sein, aber ich habe festgestellt, dass die von mir verwendeten Mikrocontroller neu gestartet wurden, als ihnen der Arbeitsspeicher ausgegangen war (Atmega 328, wenn hardwarespezifisch). Ist es das, was Mikrocontroller tun, wenn ihnen der Speicher ausgeht? Wenn nicht, was passiert dann?

Warum wie? Der Stapelzeiger wird zwar blind auf einen nicht zugewiesenen Speicherbereich erhöht (oder überschrieben), aber was passiert dann: Gibt es einen Schutz, der einen Neustart bewirkt, oder ist dies (unter anderem) das Ergebnis des Überschreibens von Kritisch Daten (von denen ich annehme, dass sie sich von dem Code unterscheiden, von dem ich denke, dass er direkt von Flash ausgeführt wird)?

Ich bin mir nicht sicher, ob dies hier oder auf Stack Overflow sein soll. Bitte teilen Sie mir mit, ob dies verschoben werden soll, obwohl ich mir ziemlich sicher bin, dass Hardware eine Rolle dabei spielt.

Aktualisieren

Ich möchte darauf hinweisen, dass mich der eigentliche Mechanismus der Speicherbeschädigung besonders interessiert (ist er das Ergebnis des SP-Rollover -> hängt das von der Speicherzuordnung in den USA ab usw.).


8
Einige Mikros werden zurückgesetzt, wenn Sie versuchen, auf ungültige Adressen zuzugreifen. Es ist eine wertvolle Funktion, die in Hardware implementiert ist. In anderen Fällen kann es vorkommen, dass der Sprung zu einer beliebigen Stelle erfolgt (beispielsweise, wenn Sie die Absenderadresse für einen ISR überlastet haben), Daten ausgeführt werden und nicht der Code, wenn die Architektur dies zulässt, und möglicherweise eine Schleife durchlaufen wird, die der Watchdog hervorbringt von.
Spehro Pefhany

2
Einem Prozessor kann der Arbeitsspeicher nicht ausgehen. Es gibt keine Anweisung, die bewirkt, dass ihm der Arbeitsspeicher ausgeht. Der RAM-Speicher ist ein reines Softwarekonzept.
user253751

Antworten:


14

In der Regel stoßen Stapel und Haufen zusammen. An diesem Punkt wird alles chaotisch.

Abhängig von der MCU kann (oder wird) eines von mehreren Dingen passieren.

  1. Variablen werden beschädigt
  2. Der Stapel wird beschädigt
  3. Das Programm wird beschädigt

Wenn etwas passiert, wird es merkwürdig - Dinge, die nicht das tun, was sie sollten. Wenn 2 passiert, bricht die Hölle los. Wenn die Rücksendeadresse auf dem Stapel (falls vorhanden) beschädigt ist, kann niemand raten, wohin der aktuelle Anruf zurückkehren wird. Zu diesem Zeitpunkt wird die MCU im Grunde genommen anfangen, zufällige Dinge zu tun. Wenn 3 wieder passiert, wer weiß schon, was passieren würde. Dies geschieht nur, wenn Sie Code außerhalb des Arbeitsspeichers ausführen.

Wenn der Stapel beschädigt wird, ist er im Allgemeinen vorbei. Was passiert, hängt von der MCU ab.

Möglicherweise schlägt der Versuch, den Speicher zuzuweisen, fehl, sodass die Beschädigung nicht auftritt. In diesem Fall kann die MCU eine Ausnahme auslösen. Wenn kein Ausnahmehandler installiert ist, wird die MCU in den meisten Fällen einfach angehalten (entspricht while (1);. Wenn ein Handler installiert ist, wird sie möglicherweise sauber neu gestartet.

Wenn die Speicherzuweisung fortgesetzt wird oder wenn sie versucht, fehlschlägt und einfach ohne zugewiesenen Speicher fortgesetzt wird, befinden Sie sich im Bereich "Wer weiß?". Die MCU startet sich möglicherweise durch die richtige Kombination von Ereignissen neu (Unterbrechungen, die dazu geführt haben, dass der Chip zurückgesetzt wurde usw.), aber es gibt keine Garantie dafür, dass dies geschieht.

Normalerweise besteht eine hohe Wahrscheinlichkeit, dass ein Fehler auftritt. Ist dies jedoch aktiviert, läuft der interne Watchdog-Timer (sofern vorhanden) ab und startet den Chip neu. Wenn das Programm durch diese Art von Absturz vollständig ABGELAUFEN ist, werden die Anweisungen zum Zurücksetzen des Timers im Allgemeinen nicht ausgeführt, sodass eine Zeitüberschreitung und ein Zurücksetzen auftreten.


Vielen Dank für Ihre Antwort, es ist eine hervorragende Zusammenfassung der Auswirkungen. Vielleicht hätte ich aber spezifizieren sollen, dass ich mehr Details über den tatsächlichen Mechanismus dieser Verfälschungen haben möchte: Ist der gesamte RAM für Stapel und Heap reserviert, so dass der Stapelzeiger frühere Variablen / Adressen überschreibt und überschreibt? Oder ist das weniger abhängig von der Speicherzuordnung der einzelnen Mikros? Optional (es ist wahrscheinlich ein Thema für sich) würde ich gerne erfahren, wie diese Hardware-Handler implementiert werden.
Herr Mystère

1
Dies hängt hauptsächlich vom Compiler und der verwendeten Standard-C-Bibliothek ab. Es hängt auch manchmal davon ab, wie der Compiler konfiguriert ist (Linkerskripte usw.).
Majenko

Könnten Sie das vielleicht mit ein paar Beispielen erweitern?
Mister Mystère

Nicht wirklich, nein. Einige Systeme weisen unterschiedlichen Segmenten endlichen Platz zu, andere nicht. Einige verwenden Linker-Skripte, um Segmente zu definieren, andere nicht. Suchen Sie sich einen Mikrocontroller aus, der Sie interessiert, und untersuchen Sie, wie die Speicherzuweisungen funktionieren.,
Majenko

12

Eine alternative Sichtweise: Mikrocontrollern geht der Speicher nicht aus.

Zumindest nicht, wenn es richtig programmiert ist. Das Programmieren eines Mikrocontrollers ist nicht mit dem Programmieren für allgemeine Zwecke vergleichbar. Um dies richtig zu tun, müssen Sie sich seiner Einschränkungen bewusst sein und entsprechend programmieren. Dafür gibt es Tools. Suchen Sie sie heraus und lernen Sie sie - zumindest, wie Sie Linker-Skripte und Warnungen lesen.

Wie Majenko und andere sagen, kann ein schlecht programmierter Mikrocontroller zu wenig Speicher haben und dann irgendetwas tun, einschließlich einer Endlosschleife (die dem Watchdog-Timer zumindest die Möglichkeit gibt, ihn zurückzusetzen. Sie haben den Watchdog-Timer aktiviert, nicht wahr? )

Gemeinsame Programmierregeln für Mikrocontroller vermeiden dies: Beispielsweise wird der gesamte Speicher entweder auf dem Stapel oder statisch (global) zugewiesen. "new" oder "malloc" sind verboten. Dies gilt auch für die Rekursion, sodass die maximale Tiefe der Unterprogrammverschachtelung analysiert und so angezeigt werden kann, dass sie in den verfügbaren Stapel passt.

Auf diese Weise kann der maximal erforderliche Speicherplatz berechnet werden, wenn das Programm kompiliert oder verknüpft wird, und mit der Speichergröße (häufig im Linker-Skript codiert) für den bestimmten Prozessor verglichen werden, den Sie als Ziel festlegen.

Der Mikrocontroller verfügt dann möglicherweise nicht über genügend Arbeitsspeicher, Ihr Programm jedoch möglicherweise. Und in diesem Fall kommen Sie zu

  • schreiben Sie es um, kleiner, oder
  • Wählen Sie einen größeren Prozessor (diese sind häufig mit unterschiedlichen Speichergrößen erhältlich).

Ein allgemeines Regelwerk für die Mikrocontroller-Programmierung ist MISRA-C , das von der Automobilindustrie übernommen wurde.

Aus meiner Sicht wird empfohlen, die Teilmenge SPARK-2014 von Ada zu verwenden. Ada zielt tatsächlich ziemlich gut auf kleine Steuerungen wie AVR, MSP430 und ARM Cortex ab und bietet von Natur aus ein besseres Modell für die Mikrocontroller-Programmierung als C. SPARK fügt dem Programm jedoch Anmerkungen in Form von Kommentaren hinzu, die beschreiben, was das Programm tut.

Jetzt analysieren die SPARK-Tools das Programm, einschließlich dieser Anmerkungen, und beweisen Eigenschaften darüber (oder melden potenzielle Fehler). Sie müssen weder Zeit noch Codeplatz für fehlerhafte Speicherzugriffe oder Integer-Überläufe verschwenden, da sich herausgestellt hat, dass dies niemals der Fall ist.

Obwohl SPARK mehr Vorarbeit leistet, kann es erfahrungsgemäß schneller und billiger zu einem Produkt kommen, da Sie keine Zeit damit verbringen, mysteriöse Neustarts und andere seltsame Verhaltensweisen zu verfolgen.

Ein Vergleich von MISRA-C und SPARK


3
+1 dies. Das Portieren malloc()(und es ist C ++ - Begleiter new) auf den AVR ist eines der schlimmsten Dinge, die die Arduino-Leute hätten tun können, und hat zu vielen, vielen sehr verwirrten Programmierern mit kaputten Codes sowohl in ihrem Forum als auch beim Austausch von Arduino-Stapeln geführt. Es gibt sehr, sehr wenige Situationen, in denen die Verwendung malloceines ATmega von Vorteil ist.
Connor Wolf

3
+1 für Philosophie, -1 für Realismus. Wenn das Zeug richtig programmiert wäre, gäbe es keine Notwendigkeit für diese Frage. Die Frage war, was passiert, wenn Mikrocontroller keinen Speicher mehr haben. Eine andere Frage ist, wie verhindert werden kann, dass ihnen der Speicher ausgeht. Andererseits ist die Rekursion ein leistungsfähiges Werkzeug, um Probleme zu lösen und den Stapel zu schließen.
PkP

2
@ Brian, da ich kein Idiot bin, stimme ich dir offensichtlich zu. Ich denke nur gerne in umgekehrter Richtung darüber nach. Ich hoffe, dass Sie nach Möglichkeiten suchen, um dies zu verhindern, wenn Sie die schrecklichen Folgen eines Speichermangels (Stack) erkennen. Auf diese Weise haben Sie einen echten Anreiz, gute Programmierpraktiken zu finden, anstatt nur gute Programmierempfehlungen zu befolgen ... und wenn Sie die Speichergrenze erreichen, werden Sie die guten Praktiken mit größerer Wahrscheinlichkeit auch auf Kosten der Benutzerfreundlichkeit durchsetzen. Es ist nur eine Ansicht ...
PkP

2
@PkP: Höre dich laut und deutlich. Ich habe dies als alternative Sichtweise bezeichnet - weil sie die Frage nicht wirklich beantwortet!
Brian Drummond

2
@ MisterMystère: Mikrocontroller haben im Allgemeinen nicht genügend Speicher. Ein Mikrocontroller, der beim ersten Einschalten 4096 Bytes RAM hat, hat für immer 4096 Bytes. Es ist möglich, dass Code fälschlicherweise versucht, auf nicht vorhandene Adressen zuzugreifen, oder erwartet, dass zwei verschiedene Methoden zum Berechnen von Adressen auf unterschiedlichen Speicher zugreifen, wenn dies nicht der Fall ist, aber der Controller selbst führt einfach die angegebenen Anweisungen aus.
Superkatze

6

Majenkos Antwort gefällt mir sehr gut und ich habe sie selbst getippt. Aber ich möchte das auf den Punkt bringen:

Alles kann passieren, wenn ein Mikrocontroller keinen Speicher mehr hat.

Man kann sich wirklich nicht auf irgendetwas verlassen, wenn es passiert. Wenn der Stapelspeicher des Computers knapp wird, wird der Stapel höchstwahrscheinlich beschädigt. Und so kann alles passieren. Variable Werte, Überläufe und temporäre Register werden alle beschädigt und stören den Programmfluss. If / then / elses kann falsch auswerten. Rücksprungadressen sind verstümmelt und das Programm springt zu zufälligen Adressen. Jeder Code, den Sie in das Programm geschrieben haben, kann ausgeführt werden. (Betrachten Sie Code wie: "if [condition] then {fire_all_missiles ();}"). Auch eine ganze Reihe von Anweisungen, die Sie nicht geschrieben haben , können ausgeführt werden, wenn der Core an einen nicht verbundenen Speicherort springt. Alle Wetten sind aus.


2
Vielen Dank für den Nachtrag, mir hat besonders die Zeile fire_all_missiles () gefallen.
Herr Mystère

1

AVR hat den Vektor auf die Adresse Null zurückgesetzt. Wenn Sie den Stapel mit zufälligem Müll überschreiben, werden Sie eventuell eine Schleife durchführen und eine Rücksprungadresse überschreiben, die auf "nirgendwo" verweist. Wenn Sie dann von einer Unterroutine zu diesem Nirgendwo zurückkehren, führt die Ausführung eine Schleife zur Adresse 0 durch, wo sich normalerweise ein Sprung zum Zurücksetzen des Handlers befindet.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.