Es gibt verschiedene Speichersegmente, in die nach der Kompilierung verschiedene Datentypen aus C-Code eingefügt werden. Dh: .text
, .data
, .bss
, Stack und Heap. Ich möchte nur wissen, wo sich jedes dieser Segmente in einem Mikrocontroller-Speicher befinden würde. Das heißt, welche Daten gehen in welchen Speichertyp, vorausgesetzt, die Speichertypen sind RAM, NVRAM, ROM, EEPROM, FLASH usw.
Ich habe hier Antworten auf ähnliche Fragen gefunden, aber sie haben nicht erklärt, was der Inhalt jedes der verschiedenen Speichertypen sein würde.
Jede Art von Hilfe wird sehr geschätzt. Danke im Voraus!
microcontroller
c
embedded
memory
Soju T Varghese
quelle
quelle
Antworten:
.Text
Das .text-Segment enthält den eigentlichen Code und ist für Mikrocontroller in den Flash-Speicher programmiert. Es kann mehr als ein Textsegment geben, wenn mehrere, nicht zusammenhängende Flash-Speicherblöcke vorhanden sind. zB ein Startvektor und Interruptvektoren, die sich oben im Speicher befinden, und Code, der bei 0 beginnt; oder separate Abschnitte für einen Bootstrap und ein Hauptprogramm.
.bss und .data
Es gibt drei Arten von Daten, die einer Funktion oder Prozedur extern zugewiesen werden können. Das erste sind nicht initialisierte Daten (historisch .bss genannt, die auch die mit 0 initialisierten Daten enthalten), und das zweite ist initialisiert (nicht-bss) oder .data. Der Name "bss" kommt historisch von "Block Started by Symbol", der vor etwa 60 Jahren in einem Assembler verwendet wurde. Beide Bereiche befinden sich im RAM.
Beim Kompilieren eines Programms werden Variablen einem dieser beiden allgemeinen Bereiche zugewiesen. Während der Verknüpfungsphase werden alle Datenelemente zusammen erfasst. Für alle Variablen, die initialisiert werden müssen, wird ein Teil des Programmspeichers zur Aufbewahrung der Anfangswerte reserviert. Kurz bevor main () aufgerufen wird, werden die Variablen initialisiert, in der Regel von einem Modul mit dem Namen crt0. Der Abschnitt bss wird durch denselben Startcode mit allen Nullen initialisiert.
Bei einigen Mikrocontrollern gibt es kürzere Anweisungen, die den Zugriff auf die erste Seite (die ersten 256 Stellen, manchmal auch Seite 0 genannt) des RAM ermöglichen. Der Compiler für diese Prozessoren kann ein Schlüsselwort reservieren
near
, um Variablen zu bestimmen, die dort platziert werden sollen. In ähnlicher Weise gibt es auch Mikrocontroller, die nur über ein Zeigerregister auf bestimmte Bereiche verweisen können (was zusätzliche Anweisungen erfordert), und solche Variablen werden bezeichnetfar
. Schließlich können einige Prozessoren einen Abschnitt des Speichers Bit für Bit adressieren, und der Compiler kann dies angeben (z. B. das Schlüsselwortbit
).Es kann also zusätzliche Segmente wie .nearbss und .neardata usw. geben, in denen diese Variablen gesammelt werden.
.rodata
Der dritte Datentyp außerhalb einer Funktion oder Prozedur entspricht den initialisierten Variablen, ist jedoch schreibgeschützt und kann vom Programm nicht geändert werden. In der Sprache C werden diese Variablen mit dem
const
Schlüsselwort bezeichnet. Sie werden normalerweise als Teil des Programm-Flash-Speichers gespeichert. Manchmal werden sie als Teil eines .rodata-Segments (Nur-Lese-Daten) identifiziert. Bei Mikrocontrollern, die die Harvard-Architektur verwenden , muss der Compiler spezielle Anweisungen verwenden, um auf diese Variablen zuzugreifen.stapeln und haufen
Der Stack und der Heap befinden sich beide im RAM. Abhängig von der Architektur des Prozessors kann der Stapel größer oder kleiner werden. Wenn es wächst, wird es am unteren Rand des RAM platziert. Wenn es nachlässt, wird es am Ende des Arbeitsspeichers platziert. Der Heap verwendet den verbleibenden RAM, der nicht Variablen zugewiesen ist, und vergrößert die entgegengesetzte Richtung des Stapels. Die maximale Größe von Stack und Heap kann normalerweise als Linker-Parameter angegeben werden.
Variablen, die auf dem Stapel abgelegt werden, sind alle Variablen, die in einer Funktion oder Prozedur ohne das Schlüsselwort definiert sind
static
. Sie wurden einmal als automatische Variablen (auto
Schlüsselwort) bezeichnet, aber dieses Schlüsselwort wird nicht benötigt. Historisch gesehenauto
existiert es , weil es Teil der B-Sprache war, die C vorausging und dort gebraucht wurde. Funktionsparameter werden ebenfalls auf dem Stapel abgelegt.Hier ist ein typisches Layout für RAM (vorausgesetzt, es gibt keinen speziellen Abschnitt für Seite 0):
EEPROM, ROM und NVRAM
Vor der Einführung des Flash-Speichers wurde EEPROM (elektrisch löschbarer programmierbarer Nur-Lese-Speicher) zum Speichern der Programm- und Konstantendaten (.text- und .rodata-Segmente) verwendet. Jetzt ist nur noch eine kleine Menge (z. B. 2 KB bis 8 KB Bytes) EEPROM verfügbar, und es wird normalerweise zum Speichern von Konfigurationsdaten oder anderen kleinen Datenmengen verwendet, die beim Herunterfahren beibehalten werden müssen Zyklus. Diese werden im Programm nicht als Variablen deklariert, sondern über spezielle Register im Mikrocontroller beschrieben. EEPROM kann auch in einem separaten Chip implementiert und über einen SPI- oder I²C-Bus angesprochen werden.
Das ROM ist im Wesentlichen dasselbe wie Flash, außer dass es im Werk programmiert wurde (nicht vom Benutzer programmierbar). Es wird nur für Geräte mit sehr hoher Lautstärke verwendet.
NVRAM (nichtflüchtiger RAM) ist eine Alternative zum EEPROM und wird normalerweise als externer IC implementiert. Normaler RAM kann als nicht flüchtig betrachtet werden, wenn er batteriegepuffert ist. In diesem Fall sind keine speziellen Zugriffsmethoden erforderlich.
Obwohl Daten in Flash gespeichert werden können, hat der Flash-Speicher eine begrenzte Anzahl von Lösch- / Programmzyklen (1000 bis 10.000), sodass er nicht wirklich dafür ausgelegt ist. Außerdem müssen Speicherblöcke sofort gelöscht werden, sodass es unpraktisch ist, nur wenige Bytes zu aktualisieren. Es ist für Code- und Nur-Lese-Variablen vorgesehen.
EEPROM hat viel höhere Grenzen für Lösch- / Programmierzyklen (100.000 bis 1.000.000), daher ist es für diesen Zweck viel besser. Wenn auf dem Mikrocontroller ein EEPROM verfügbar und groß genug ist, möchten Sie dort nichtflüchtige Daten speichern. Sie müssen jedoch auch zuerst in Blöcken (normalerweise 4 KB) löschen, bevor Sie schreiben können.
Wenn kein EEPROM vorhanden oder zu klein ist, wird ein externer Chip benötigt. Ein 32-KB-EEPROM ist nur 66 ¢ groß und kann 1.000.000-mal gelöscht / beschrieben werden. Ein NVRAM mit der gleichen Anzahl von Lösch- / Programmiervorgängen ist viel teurer (x10). NVRAMs sind normalerweise schneller zum Lesen als EEPROMs, aber langsamer zum Schreiben. Sie können entweder byteweise oder blockweise geschrieben werden.
Eine bessere Alternative zu beiden ist FRAM (ferroelektrischer RAM), der im Wesentlichen unendliche Schreibzyklen (100 Billionen) und keine Schreibverzögerungen aufweist. Es ist ungefähr der gleiche Preis wie NVRAM, ungefähr 5 US-Dollar für 32 KB.
quelle
Normales eingebettetes System:
Außerdem gibt es normalerweise separate Flash-Segmente für Startcode- und Interrupt-Vektoren.
Erläuterung:
Eine Variable hat eine statische Speicherdauer, wenn sie
static
als "global" deklariert ist oder sich im Dateibereich befindet. C hat eine Regel, die besagt, dass alle statischen Speicherdauer-Variablen, die der Programmierer nicht explizit initialisiert hat, auf Null initialisiert werden müssen.Jede statische Speicherdauer-Variable, die implizit oder explizit mit Null initialisiert wird, endet in
.bss
. Während diejenigen, die explizit auf einen Wert ungleich Null initialisiert werden, in enden.data
.Beispiele:
Bitte beachten Sie, dass ein sehr häufiges nicht standardmäßiges Setup für eingebettete Systeme ein "minimaler Start" ist, was bedeutet, dass das Programm die gesamte Initialisierung von Objekten mit statischer Speicherdauer überspringt . Daher ist es möglicherweise ratsam, niemals Programme zu schreiben, die auf den Initialisierungswerten solcher Variablen basieren, sondern diese vor der ersten Verwendung auf "Laufzeit" zu setzen.
Beispiele für die anderen Segmente:
Variablen, die auf dem Stack gespeichert werden können, landen während der Optimierung häufig in CPU-Registern. Als Faustregel kann jede Variable, deren Adresse nicht vergeben ist, in ein CPU-Register eingetragen werden.
Beachten Sie, dass Zeiger etwas komplizierter sind als andere Variablen, da sie zwei verschiedene Arten von zulassen
const
, je nachdem, ob die Daten, auf die verwiesen wird, schreibgeschützt sein sollen oder ob der Zeiger selbst schreibgeschützt sein soll. Es ist sehr wichtig, den Unterschied zu kennen, damit Ihre Zeiger nicht versehentlich im RAM landen, wenn Sie wollten, dass sie im Flash sind.Im Fall von Ganzzahlkonstanten, Initialisierungslisten, Zeichenfolgenliteralen usw. können sie je nach Compiler entweder in .text oder .rodata enden. Wahrscheinlich enden sie als:
quelle
.data
normalerweise eine sogenannte Ladeadresse in Flash, wo die Anfangswerte gespeichert werden, und eine sogenannte virtuelle Adresse (nicht wirklich virtuell in einem Mikrocontroller) in RAM, wo die Variable während der Ausführung gespeichert wird. Vor demmain
Start werden die Anfangswerte von der Ladeadresse in die virtuelle Adresse kopiert. Sie müssen keine Nullen speichern und müssen daher.bss
auch keine Anfangswerte speichern. sourceware.org/binutils/docs/ld/…Während alle Daten in jeden vom Programmierer gewählten Speicher abgelegt werden können, funktioniert das System im Allgemeinen am besten (und ist für die Verwendung vorgesehen), wenn das Nutzungsprofil der Daten mit den Lese- / Schreibprofilen des Speichers übereinstimmt.
Zum Beispiel ist der Programmcode WFRM (schreibe wenige, lese viele) und es gibt eine Menge davon. Das passt gut zu FLASH. ROM OTOH ist W einmal RM.
Stapel und Haufen sind klein, mit vielen Lese- und Schreibvorgängen. Das würde am besten zu RAM passen.
EEPROM würde für keine dieser Verwendungen gut geeignet sein, passt jedoch zum Profil kleiner Datenmengen, die über die Startvorgänge hinweg vorhanden sind, also zu benutzerspezifischen Initialisierungsdaten und möglicherweise zu Protokollierungsergebnissen.
quelle