Was kann ich tun, wenn mir der Flash-Speicher oder der SRAM ausgeht?


28

Gemäß der Arduino-Dokumentation verfügt der ATmega328 über 32 KB Flash-Speicher für den Bootloader + hochgeladene Skizze und nur 2 KB SRAM für Laufzeitdaten. Der ATmega2560 hat mit 256 KB bzw. 8 KB einiges mehr.

In beiden Fällen scheinen diese Grenzwerte eher gering zu sein, insbesondere im Vergleich zu Konsumgeräten ähnlicher Größe wie Smartphones.

Was können Sie tun, wenn Sie ausgehen? Ist Ihre Skizze beispielsweise zu groß oder müssen Sie zur Laufzeit viele Daten (z. B. Zeichenfolgen) verarbeiten? Gibt es eine Möglichkeit, den Flash- oder SRAM-Speicher zu erweitern?


Versuchen Sie es mit einer Variablenoptimierung. Einige andere Variablen werden hier
TheDoctor

1
Verwenden Sie geeignete Bereiche für Ihre Variablen, wenn dies noch nicht geschehen ist. Der Compiler optimiert die RAM-Nutzung für Sie, wenn Variablen nicht verwendet werden.
jippie

1
Sie könnten tatsächlich einen Teensy 3.2 (mit Teensyduino-Software) verwenden, der mit einem Arduino vergleichbar wäre. Vorausgesetzt, dass Ihnen RAM / PROGMEM ausgeht, bedeutet dies, dass Sie wahrscheinlich auch versuchen, Ihr Arduino voranzutreiben. Ein Teensy 3.2 ist nicht viel teurer. hat aber: 32bit, 72MHz (wtf !?) 256KB FLASH und 64KB RAM und 3x UART. Nicht mehr Programmspeicher als beim ATmega2560, sondern RAM und Geschwindigkeitserhöhung sollten ausreichen.
Paul

Antworten:


30

Optimierung Die
einfache Programmierung für eingebettete Systeme unterscheidet sich erheblich von der Programmierung für Allzweckgeräte wie Computer und Mobiltelefone. Effizienz (in Bezug auf Geschwindigkeit und Platz) ist weitaus wichtiger, da Ressourcen knapp werden. Das bedeutet, dass Sie als Erstes prüfen müssen, welche Teile Ihres Codes Sie optimieren können, wenn Ihnen der Speicherplatz ausgeht.

In Bezug auf die Reduzierung des Programmspeichers (Flash) kann es schwierig sein, die Codegröße zu optimieren, wenn Sie unerfahren sind oder wenn Sie eher daran gewöhnt sind, für Desktop-Computer zu programmieren, für die diese Fähigkeiten normalerweise nicht erforderlich sind. Leider gibt es keinen "Magic Bullet" -Ansatz, der in allen Situationen funktioniert, obwohl es hilfreich ist, wenn Sie sich ernsthaft überlegen, was Ihre Skizze wirklich braucht . Wenn eine Funktion nicht benötigt wird, nehmen Sie sie heraus.

Manchmal ist es auch hilfreich zu identifizieren, wo mehrere Teile Ihres Codes gleich (oder sehr ähnlich) sind. Möglicherweise können Sie sie zu wiederverwendbaren Funktionen zusammenfassen, die von mehreren Stellen aus aufgerufen werden können. Beachten Sie jedoch, dass der Versuch, Code zu wiederverwendbar zu machen, manchmal tatsächlich dazu führt, dass er ausführlicher wird. Es ist eine schwierige Balance, die mit Übung einhergeht. Ein Blick auf die Auswirkungen von Codeänderungen auf die Compiler-Ausgabe kann hilfreich sein.

Die Optimierung von Laufzeitdaten (Runtime Data, SRAM) ist in der Regel etwas einfacher, wenn Sie daran gewöhnt sind. Eine sehr häufige Gefahr für Programmieranfänger ist die Verwendung zu vieler globaler Daten. Alles, was im globalen Rahmen deklariert wurde, bleibt während der gesamten Lebensdauer der Skizze bestehen. Dies ist nicht immer erforderlich. Wenn eine Variable nur innerhalb einer Funktion verwendet wird und nicht zwischen den Aufrufen bestehen bleiben muss, machen Sie sie zu einer lokalen Variablen. Wenn ein Wert zwischen Funktionen geteilt werden muss, prüfen Sie, ob Sie ihn als Parameter übergeben können, anstatt ihn global zu machen. Auf diese Weise verwenden Sie SRAM nur dann für diese Variablen, wenn Sie es tatsächlich benötigen.

Ein weiterer Killer für die SRAM-Nutzung ist die Textverarbeitung (z. B. mit der StringKlasse). Im Allgemeinen sollten Sie Zeichenfolgenoperationen nach Möglichkeit vermeiden. Sie sind massive Erinnerungsfresser. Wenn Sie beispielsweise viel Text seriell ausgeben, verwenden Sie mehrere Aufrufe, Serial.print()anstatt die Zeichenfolgenverkettung zu verwenden. Versuchen Sie außerdem, die Anzahl der Zeichenfolgenliterale in Ihrem Code zu verringern, wenn dies möglich ist.

Vermeiden Sie nach Möglichkeit auch eine Rekursion. Jedes Mal, wenn ein rekursiver Aufruf erfolgt, wird der Stapel um eine Stufe tiefer gelegt. Korrigieren Sie Ihre rekursiven Funktionen so, dass sie stattdessen iterativ sind.

EEPROM verwenden
EEPROM wird zur langfristigen Speicherung von Dingen verwendet, die sich nur gelegentlich ändern. Wenn Sie große Listen oder Nachschlagetabellen mit festen Daten verwenden müssen, sollten Sie diese im Voraus im EEPROM speichern und nur dann herausziehen, wenn dies erforderlich ist.

Offensichtlich ist das EEPROM jedoch in Größe und Geschwindigkeit ziemlich begrenzt und weist eine begrenzte Anzahl von Schreibzyklen auf. Es ist keine großartige Lösung für Datenbeschränkungen, aber es könnte ausreichen, um Flash oder SRAM zu entlasten. Es ist auch durchaus möglich, eine Schnittstelle zu einem ähnlichen externen Speicher wie einer SD-Karte herzustellen.

Erweiterung
Wenn Sie alle anderen Optionen ausgeschöpft haben, ist möglicherweise eine Erweiterung möglich. Das Erweitern des Flash-Speichers zur Erhöhung des Programmspeichers ist leider nicht möglich. Es ist jedoch möglich, SRAM zu erweitern. Dies bedeutet, dass Sie Ihre Skizze möglicherweise überarbeiten können, um die Codegröße auf Kosten der Erhöhung der Datengröße zu verringern.

Es ist eigentlich ziemlich einfach, mehr SRAM zu bekommen. Eine Möglichkeit besteht darin, einen oder mehrere 23K256- Chips zu verwenden. Sie werden über SPI abgerufen, und die SpiRAM-Bibliothek hilft Ihnen bei der Verwendung. Achten Sie nur darauf, dass sie mit 3,3 V und nicht mit 5 V betrieben werden!

Wenn Sie das Mega verwenden, können Sie alternativ SRAM-Erweiterungsschilde von Lagrangian Point oder Rugged Circuits erhalten .


1
Sie können auch konstante Daten im Programmspeicher speichern, anstatt im SRAM, wenn Sie Probleme mit dem SRAM-Speicherplatz haben und freien Programmspeicher haben. Sehen Sie hier oder hier
Connor Wolf

1
Eine weitere großartige Alternative zum EEPROM ist eine SD-Karte. Es nimmt zwar einige E / A-Ports in Anspruch, aber wenn Sie beispielsweise für Kartendaten oder ähnliches viel Speicherplatz benötigen, können Sie diese problemlos mit einem benutzerdefinierten Programm auf einem PC austauschen und bearbeiten.
Anonym Pinguin

1
Es sollte nicht empfohlen werden, SPI-SRAMs oder RAM-Erweiterungen zu verwenden, wenn der Arbeitsspeicher knapp wird. Das ist nur eine Verschwendung von Geld. Die Wahl einer größeren MCU wäre günstiger. Außerdem könnte die Leistung sehr schlecht sein. Man sollte zuerst eine Schätzung des Baseballstadions vornehmen: Wenn die geschätzte RAM-Auslastung zu nahe am Limit liegt, wählen Sie die falsche Karte / Mikrocontroller / Entwicklungsplattform. Sicher, eine gute Verwendung (Speichern von Strings in Flash) und Optimierung (Vermeidung einiger Bibliotheken) können wahre Spielveränderer sein. Zu diesem Zeitpunkt sehe ich jedoch keine Vorteile bei der Verwendung der Arduino Software-Plattform.
Next-Hack

24

Wenn Sie Ihren Code auf Ihr Arduino hochladen, beispielsweise ein Uno, werden Sie darüber informiert, wie viele Bytes von den verfügbaren 32K verwendet werden. Das ist, wie viel Flash-Speicher Sie haben (denken Sie Computer-Festplatte). Während Ihr Programm ausgeführt wird, verwendet es das, was als SRAM bezeichnet wird, und es ist viel weniger davon verfügbar.

Manchmal werden Sie bemerken, dass sich Ihr Programm an einem Punkt merkwürdig verhält, den Sie eine Weile nicht mehr berührt haben. Es kann sein, dass aufgrund Ihrer letzten Änderungen nicht mehr genügend Arbeitsspeicher (SRAM) zur Verfügung steht. Hier finden Sie einige Tipps zum Freigeben von SRAM.

Speichern von Strings in Flash anstelle von SRAM.

Eines der häufigsten Dinge, die ich gesehen habe, ist, dass dem Chip der Speicherplatz ausgeht, weil zu viele lange Zeichenfolgen vorhanden sind.

Verwenden Sie die F()Funktion, wenn Sie Zeichenfolgen verwenden, damit diese in Flash anstelle von SRAM gespeichert werden, da Ihnen viel mehr davon zur Verfügung steht.

Serial.println(F("This string will be stored in flash memory"));

Verwenden Sie die richtigen Datentypen

Sie können ein Byte speichern, indem Sie von einem int(2 Byte) zu einem byte(1 Byte) wechseln . Ein Byte ohne Vorzeichen gibt Ihnen 0-255. Wenn Sie also Zahlen haben, die nicht höher als 255 sind, speichern Sie ein Byte!

Woher weiß ich, dass mir der Speicher ausgeht?

Normalerweise beobachten Sie, wie sich Ihr Programm seltsam verhält, und fragen sich, was schief gelaufen ist. Sie haben an dem Code an der Stelle, an der er durcheinander gerät, nichts geändert. Was gibt es also? Der Speicher geht zur Neige.

Es gibt einige Funktionen, mit denen Sie feststellen können, wie viel Speicher Sie zur Verfügung haben.

Verfügbare Erinnerung


Wissen Sie, ob das F()Ding eine Arduino-spezifische Funktion ist oder in den AVR-Bibliotheken? Sie könnten erwägen, auch zu erwähnen PROGMEM const ....
Jippie

Sie können auch Bitstrukturen verwenden, um den von Ihren Variablen belegten Platz weiter zu reduzieren (z. B., wenn Sie mit vielen booleschen Werten arbeiten).
jfpoilpret

17

Zusätzlich zu dem, was andere gesagt haben (dem ich voll und ganz zustimme), würde ich raten, diesen adafruit-Artikel über das Gedächtnis zu lesen . Es ist gut geschrieben, erklärt eine Menge Dinge über das Gedächtnis und gibt Hinweise, wie es optimiert werden kann.

Am Ende der Lektüre, denke ich, würden Sie eine ziemlich vollständige Antwort auf Ihre Frage bekommen.

Zusammenfassend haben Sie 2 mögliche Optimierungsziele (je nachdem, wo sich Ihre Speicherprobleme befinden):

  • Flash (dh Programmspeicher); Dafür können Sie:
    • Entfernen Sie toten Code (z. B. Code, der enthalten ist, aber nicht verwendet wird) und nicht verwendete Variablen (dieser hilft auch bei SRAM).
    • doppelten Code herausrechnen
    • Entfernen Sie den Bootloader insgesamt (Sie können zwischen 0,5 KB für eine UNO und 2 oder 4 KB für andere Arduino-Modelle gewinnen). Dies hat jedoch einige Nachteile
  • SRAM (dh Stack-, Heap- und statische Daten); Dafür können Sie:
    • Entfernen Sie nicht verwendete Variablen
    • Optimieren Sie die Größe jeder Variablen (verwenden Sie z. B. keine langen -4 Bytes, wenn Sie nur int -2 Bytes benötigen).
    • Nutze den richtigen Bereich für deine Variablen (und bevorzuge Stack gegenüber statischen Daten, wenn möglich)
    • Reduzieren Sie die Puffergröße auf das strikte Minimum
    • Verschieben Sie konstante Daten nach PROGMEM (dh Ihre statischen Daten bleiben im Flash-Speicher und werden beim Programmstart nicht in SRAM kopiert). Dies gilt auch für konstante Zeichenfolgen, für die Sie ein F()Makro verwenden können.
    • Vermeiden Sie dynamische Zuweisungen, wenn dies nicht unbedingt erforderlich ist. Sie vermeiden einen fragmentierten Heap , der möglicherweise auch nach dem Freigeben von Speicher nicht verkleinert wird

Es wird auch ein zusätzlicher Ansatz zur Reduzierung der SRAM-Nutzung beschrieben (der jedoch nur selten verwendet wird, da er beim Codieren etwas umfangreich und wenig effizient ist). Er besteht darin, EEPROM zum Speichern von Daten zu verwenden, die von Ihrem Programm erstellt wurden, wird jedoch unter bestimmten Bedingungen erst später verwendet auftreten, wenn Daten aus dem EEPROM zurückgeladen werden können.


1
Entfernen von totem Code - der Compiler ist wirklich gut darin, dies für Sie zu handhaben - es macht keinen Unterschied, ob Sie viele Codes haben, die noch nie aufgerufen wurden. Wenn Sie versehentlich Code aufrufen, den Sie nicht benötigen, ist das natürlich anders.
dethSwatch

9

Wenn der Speicherplatz knapp wird, gibt es zwei Möglichkeiten:

  • Optimieren Sie irgendwie Ihren Code, sodass er weniger Speicherplatz benötigt. oder verwendet zumindest weniger von der bestimmten Art von Speicher, der Ihnen ausging (und verwendet mehr von der Art von Speicher, über die Sie immer noch reichlich verfügen). Oder,
  • Fügen Sie mehr Speicher hinzu.

Es gibt viele Tipps online, wie man das erste macht (und für die allermeisten Dinge, die Leute mit dem Arduino machen, ist der eingebaute Speicher nach dem "Optimieren" mehr als genug). Also werde ich mich auf die Sekunde konzentrieren:

Es gibt 3 Dinge, die Flash oder SRAM verbrauchen. Jeder benötigt einen etwas anderen Ansatz für das Hinzufügen von Speicher:

  • Variable Lagerung: Wie Sachleen bereits betont hat, ist es möglich, SRAM zu erweitern. SRAM, FRAM und NVSRAM eignen sich alle für sich schnell ändernde Variablen. (Während Sie prinzipiell Flash zum Speichern von Variablen verwenden könnten, müssen Sie sich um die Abnutzung des Flashs sorgen). SPI (ein serielles Protokoll) ist die einfachste Verbindung zum Arduino. Die SpiRAM-Bibliothek arbeitet mit dem seriellen SRAM-Chip Microchip 23K256 . Der serielle FRAM- Chip Ramtron FM25W256 (jetzt im Besitz von Cypress) verwendet ebenfalls SPI. Der Cypress CY14B101 NVSRAM verwendet ebenfalls SPI. Etc.

  • Konstante Daten, die beim nächsten Einschalten noch vorhanden sein müssen: Dies ist fast so einfach wie das Erweitern von SRAM. Es stehen viele externe EEPROM-, FRAM-, NVSRAM- und FLASH- Speichergeräte zur Verfügung. Derzeit sind die niedrigsten Kosten pro MB SD-Flashkarten (auf die über SPI zugegriffen werden kann). Der Ramtron FM25W256 (siehe oben), der Cypress CY14B101 (siehe oben) usw. können ebenfalls konstante Daten speichern. Viele Erweiterungsschilder verfügen über einen SD-Kartensteckplatz und verschiedene Bibliotheken und Lernprogramme unterstützen das Lesen und Beschreiben von (Flash-) SD-Karten. (Wir können SRAM dafür nicht verwenden, da SRAM alles vergisst, wenn die Stromversorgung ausfällt.)

  • ausführbarer Code: Leider ist es nicht möglich, den Flash-Speicher eines Arduino zu erweitern, um den Programmspeicher zu vergrößern. Ein Programmierer kann jedoch jederzeit eine Skizze überarbeiten, um die Codegröße zu verringern, wobei die Datengröße erhöht und die Ausführung etwas verlangsamt wird. (Theoretisch könnten Sie so weit gehen, dass Sie Ihre gesamte Skizze in eine interpretierte Sprache übersetzen, diese Version Ihrer Skizze auf einer SD-Karte speichern und dann einen Interpreter für diese Sprache schreiben, der auf dem Arduino ausgeführt wird, um Anweisungen vom abzurufen und auszuführen SD-Karte - Weiter geht es mit Arduino , einem BASIC-Interpreter, einem Tom Napier Picaro-Interpreter, einer anwendungsspezifischen Sprache usw.).

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.