Istnieją różne segmenty pamięci, do których różne typy danych są wprowadzane z kodu C po kompilacji. Czyli: .text
, .data
, .bss
, stosu i sterty. Chcę tylko wiedzieć, gdzie każdy z tych segmentów znajdowałby się w pamięci mikrokontrolera. Oznacza to, które dane trafiają do jakiego rodzaju pamięci, biorąc pod uwagę typy pamięci RAM, NVRAM, ROM, EEPROM, FLASH itp.
Znalazłem tutaj odpowiedzi na podobne pytania, ale nie udało im się wyjaśnić, jaka byłaby zawartość każdego z różnych typów pamięci.
Każda pomoc jest bardzo ceniona. Z góry dziękuję!
microcontroller
c
embedded
memory
Soju T Varghese
źródło
źródło
Odpowiedzi:
.tekst
Segment .text zawiera rzeczywisty kod i jest zaprogramowany w pamięci Flash dla mikrokontrolerów. Może istnieć więcej niż jeden segment tekstowy, gdy istnieje wiele nieciągłych bloków pamięci Flash; np. wektor startowy i wektory przerwań umieszczone na górze pamięci i kod rozpoczynający się od 0; lub oddzielne sekcje dla programu ładującego i programu głównego.
.bss i .data
Istnieją trzy rodzaje danych, które można przypisać zewnętrznie do funkcji lub procedury; pierwszy to niezainicjowane dane (historycznie nazywane .bss, które obejmuje również 0 zainicjowanych danych), a drugi to inicjalizacja (nie bss) lub .data. Nazwa „bss” historycznie pochodzi od „Block Started by Symbol”, używanego w asemblerze około 60 lat temu. Oba te obszary znajdują się w pamięci RAM.
Podczas kompilacji programu zmienne zostaną przypisane do jednego z tych dwóch ogólnych obszarów. Podczas etapu łączenia wszystkie elementy danych będą zbierane razem. Wszystkie zmienne, które należy zainicjować, będą miały część pamięci programu przeznaczoną do przechowywania wartości początkowych, a tuż przed wywołaniem funkcji main () zmienne zostaną zainicjowane, zwykle przez moduł o nazwie crt0. Sekcja bss jest inicjalizowana do wszystkich zer przez ten sam kod startowy.
Z kilkoma mikrokontrolerami dostępne są krótsze instrukcje, które umożliwiają dostęp do pierwszej strony (pierwsze 256 lokalizacji, czasami nazywanej stroną 0) pamięci RAM. Kompilator dla tych procesorów może zarezerwować słowo kluczowe, takie jak
near
oznaczenie zmiennych, które mają zostać tam umieszczone. Podobnie istnieją również mikrokontrolery, które mogą odwoływać się tylko do niektórych obszarów za pośrednictwem rejestru wskaźników (wymagające dodatkowych instrukcji) i takie zmienne są oznaczonefar
. Wreszcie, niektóre procesory mogą adresować sekcję pamięci bit po bicie, a kompilator będzie w stanie to określić (na przykład słowo kluczowebit
).Mogą więc istnieć dodatkowe segmenty, takie jak .nearbss i .neardata itp., W których gromadzone są te zmienne.
.rodata
Trzeci typ danych zewnętrznych względem funkcji lub procedury przypomina zmienne zainicjowane, z tym że są one tylko do odczytu i nie mogą być modyfikowane przez program. W języku C zmienne te oznaczone są za pomocą
const
słowa kluczowego. Zazwyczaj są one przechowywane jako część pamięci flash programu. Czasami są one identyfikowane jako część segmentu .rodata (dane tylko do odczytu). Na mikrokontrolerach korzystających z architektury Harvarda kompilator musi użyć specjalnych instrukcji, aby uzyskać dostęp do tych zmiennych.stos i stos
Stos i stos są umieszczone w pamięci RAM. W zależności od architektury procesora stos może rosnąć lub rosnąć. Jeśli dorośnie, zostanie umieszczony na dole pamięci RAM. Jeśli wzrośnie, zostanie umieszczony na końcu pamięci RAM. Sterta wykorzysta pozostałą pamięć RAM nieprzydzieloną do zmiennych i będzie rosła w przeciwnym kierunku do stosu. Maksymalny rozmiar stosu i sterty można zwykle określić jako parametry linkera.
Zmienne umieszczone na stosie to dowolne zmienne zdefiniowane w funkcji lub procedurze bez słowa kluczowego
static
. Kiedyś nazywano je zmiennymi automatycznymi (auto
słowo kluczowe), ale to słowo kluczowe nie jest potrzebne. Historycznieauto
istnieje, ponieważ był częścią języka B poprzedzającego C i tam był potrzebny. Parametry funkcji są również umieszczane na stosie.Oto typowy układ pamięci RAM (przy założeniu braku specjalnej sekcji strony 0):
EEPROM, ROM i NVRAM
Zanim pojawiła się pamięć Flash, EEPROM (elektronicznie kasowalna programowalna pamięć tylko do odczytu) był używany do przechowywania programu i stałych danych (segmenty .text i .rodata). Teraz dostępna jest tylko niewielka ilość (np. 2 KB do 8 KB) pamięci EEPROM, o ile w ogóle jest dostępna, i jest zwykle używana do przechowywania danych konfiguracyjnych lub innych niewielkich ilości danych, które muszą zostać zachowane po wyłączeniu zasilania cykl. Nie są one deklarowane jako zmienne w programie, ale są zapisywane przy użyciu specjalnych rejestrów w mikrokontrolerze. EEPROM może być również zaimplementowany w osobnym układzie scalonym i dostępny za pośrednictwem magistrali SPI lub I²C.
Pamięć ROM jest zasadniczo taka sama jak Flash, tyle że jest programowana fabrycznie (nie programowalna przez użytkownika). Jest używany tylko w przypadku urządzeń o bardzo dużej głośności.
NVRAM (nieulotna pamięć RAM) jest alternatywą dla EEPROM i zwykle jest implementowana jako zewnętrzny układ scalony. Zwykła pamięć RAM może być uważana za nieulotną, jeśli jest zasilana z baterii; w takim przypadku nie są potrzebne żadne specjalne metody dostępu.
Chociaż dane można zapisywać we Flashu, pamięć Flash ma ograniczoną liczbę cykli kasowania / programów (od 1000 do 10 000), więc nie jest do tego specjalnie zaprojektowana. Wymaga również usunięcia bloków pamięci jednocześnie, więc aktualizowanie zaledwie kilku bajtów jest niewygodne. Jest przeznaczony do kodu i zmiennych tylko do odczytu.
EEPROM ma znacznie wyższe limity cykli kasowania / programów (od 100 000 do 1 000 000), więc jest znacznie lepszy w tym celu. Jeśli w mikrokontrolerze jest dostępna pamięć EEPROM i jest ona wystarczająco duża, tam właśnie chcesz zapisać nieulotne dane. Będziesz jednak musiał najpierw skasować bloki (zwykle 4KB) przed napisaniem.
Jeśli nie ma EEPROM lub jest za mały, potrzebny jest zewnętrzny układ. Pamięć EEPROM o pojemności 32 KB ma tylko 66 centów i można ją usunąć / zapisać do 1 000 000 razy. NVRAM z taką samą liczbą operacji kasowania / programu jest znacznie droższy (x10). NVRAM są zwykle szybsze do odczytu niż EEPROM, ale wolniejsze do zapisu. Mogą być zapisywane do jednego bajtu na raz lub blokami.
Lepszą alternatywą dla obu z nich jest FRAM (ferroelektryczna pamięć RAM), która ma zasadniczo nieskończone cykle zapisu (100 bilionów) i nie ma opóźnień zapisu. Ma mniej więcej tę samą cenę co NVRAM, około 5 USD za 32 KB.
źródło
Normalny system osadzony:
Ponadto zwykle istnieją oddzielne segmenty flash dla kodu startowego i wektorów przerwań.
Wyjaśnienie:
Zmienna ma statyczny czas przechowywania, jeśli jest zadeklarowana jako
static
lub znajduje się w zakresie pliku (czasami niedbale nazywana „globalną”). C ma regułę stwierdzającą, że wszystkie zmienne czasu trwania przechowywania statycznego, których programista nie zainicjował jawnie, muszą być inicjowane na zero.Każda zmienna czasu przechowywania statycznego, która jest inicjowana na zero, domyślnie lub jawnie, kończy się na
.bss
. Podczas gdy te, które są wyraźnie zainicjowane na niezerową wartość, kończą się w.data
.Przykłady:
Należy pamiętać, że bardzo powszechną niestandardową konfiguracją systemów osadzonych jest „minimalne uruchomienie”, co oznacza, że program pominie wszystkie inicjalizacje obiektów o statycznym czasie przechowywania. Dlatego może być mądre, aby nigdy nie pisać programów, które opierają się na wartościach inicjujących takich zmiennych, ale zamiast tego ustawiają je w „czasie wykonywania” przed ich pierwszym użyciem.
Przykłady innych segmentów:
Zmienne, które mogą wejść na stos, często kończą się w rejestrach procesora podczas optymalizacji. Zasadniczo każdą zmienną, która nie ma pobranego adresu, można umieścić w rejestrze procesora.
Zauważ, że wskaźniki są nieco bardziej skomplikowane niż inne zmienne, ponieważ pozwalają na dwa różne rodzaje
const
, w zależności od tego, czy wskazane dane powinny być tylko do odczytu, czy też sam wskaźnik powinien być. Bardzo ważne jest, aby znać różnicę, aby wskaźniki nie trafiły przypadkowo do pamięci RAM, gdy chcesz, aby były we flashu.W przypadku stałych całkowitych, list inicjalizujących, literałów łańcuchowych itp., Mogą one kończyć się w .text lub .rodata, w zależności od kompilatora. Prawdopodobnie kończą jako:
źródło
.data
zwykle ma tak zwany adres ładowania we flashu, w którym przechowywane są wartości początkowe, i tak zwany adres wirtualny (nie tak naprawdę wirtualny w mikrokontrolerze) w pamięci RAM, gdzie zmienna jest przechowywana podczas wykonywania. Przedmain
rozpoczęciem wartości początkowe są kopiowane z adresu ładowania na adres wirtualny. Nie musisz przechowywać zer, więc.bss
nie musisz przechowywać ich początkowych wartości. sourceware.org/binutils/docs/ld/…Chociaż dowolne dane mogą trafić do dowolnej pamięci wybranej przez programistę, ogólnie system działa najlepiej (i jest przeznaczony do użycia), gdy profil użytkowania danych jest dopasowany do profili odczytu / zapisu pamięci.
Na przykład kod programu to WFRM (napisz kilka, czytaj wiele), a jest ich dużo. Ładnie pasuje do FLASH. ROM OTOH jest W raz RM.
Stos i stos są małe, z dużą ilością odczytów i zapisów. To najlepiej pasowałoby do pamięci RAM.
Pamięć EEPROM nie pasuje dobrze do żadnego z tych zastosowań, ale pasuje do profilu niewielkich ilości danych trwających między uruchomieniami, więc dane inicjalizacji specyficzne dla użytkownika i być może rejestrowanie wyników.
źródło