Що знаходиться в різних типах пам'яті мікроконтролера?


25

Існують різні сегменти пам'яті, до яких вводяться різні типи даних із коду С після компіляції. Тобто: .text, .data, .bss, стек і купа. Я просто хочу знати, де кожен з цих сегментів знаходився б у пам'яті мікроконтролера. Тобто, які дані входять до того типу пам’яті, враховуючи типи пам’яті: ОЗУ, NVRAM, ROM, EEPROM, FLASH тощо.

Тут я знайшов відповіді на подібні запитання, але вони не змогли пояснити, який буде вміст кожного з різних типів пам'яті.

Будь-яка допомога високо цінується. Спасибі заздалегідь!


1
NVRAM, ROM, EEPROM та Flash - це майже різні назви для однієї і тієї ж речі: енергонезалежна пам'ять.
Лундін

Злегка дотичний до питання, але код може (у винятковому випадку) існувати в більшій частині будь-якого з них, особливо якщо врахувати використання виправлення або калібрування. Іноді він буде переміщений перед виконанням, іноді виконаний на місці.
Шон Хуліхане

@SeanHoulihane ОП запитує про мікроконтролери, які майже завжди виконуються з Flash (ви оцінили свій коментар виключно). Мікро процесори з МБ - х зовнішнього ОЗУ під управлінням Linux, наприклад, будуть копіювати свої програми в оперативну пам'ять , щоб виконати їх, можливо , від SD - карти , що діє в якості монтируемого обсягу.
tcrosley

@tcrosley Зараз є мікроконтролери з TCM, а іноді мікроконтролери є частиною більшого SoC. Я також підозрюю, що трапляються такі випадки, як пристрої eMMC, коли mcu завантажується сама з оперативної пам’яті з власної пам’яті (базується на пам’яті деяких телефонів, які важко затримати пару років тому). Я погоджуюсь, це не є прямою відповіддю, - але я вважаю дуже актуальним, що типові карти не є жодним чином жорсткими правилами.
Шон Хуліхане

1
немає правил для з'єднання однієї речі з іншою, переконайтеся, що лише ті елементи, які читаються, як текст і родата, в ідеалі хотіли б пройти спалахом, але .data та зміщення та розмір .bss також перейдуть туди (а потім скопіюйте код завантаження). ці терміни (.text тощо) не мають нічого спільного з мікроконтролерами. Це компілятор / інструментарій, що стосується всіх цілей компіляторів / ланцюжків інструментів. наприкінці дня програміст вирішує, куди подітись, та інформує ланцюжок інструментів зазвичай за допомогою сценарію лінкера.
old_timer

Відповіді:


38

.текст

Сегмент .text містить фактичний код і запрограмований у флеш-пам'ять для мікроконтролерів. При наявності декількох безперервних блоків Flash-пам’яті може бути більше одного сегмента тексту; наприклад, вектор запуску і перериваючі вектори, розташовані у верхній частині пам'яті, і код, починаючи з 0; або окремі розділи для завантажувальної програми та основної програми.

.bss та .data

Існує три типи даних, які можуть бути виділені зовнішньо до функції чи процедури; перший - неініціалізовані дані (історично називається .bss, який також включає 0 ініціалізованих даних), а другий - ініціалізований (non-bss), або .data. Назва "bss" історично походить від "Блоку, розпочатого символом", використовуваного в асемблері близько 60 років тому. Обидві ці області розташовані в оперативній пам'яті.

По мірі складання програми змінні будуть розподілятися на одну з цих двох загальних областей. Під час етапу зв’язування всі елементи даних будуть збиратися разом. Усі змінні, які потрібно ініціалізувати, матимуть частину пам'яті програми, відведену для зберігання початкових значень, і безпосередньо перед викликом main () змінні будуть ініціалізовані, як правило, модулем під назвою crt0. Розділ bss ініціалізується на всі нулі одним і тим же кодом запуску.

З кількома мікроконтролерами є короткі інструкції, які дозволяють отримати доступ до першої сторінки (перші 256 місць, колись називається сторінка 0) оперативної пам'яті. Компілятор для цих процесорів може зарезервувати ключове слово, як, наприклад, nearпризначити змінні для розміщення там. Аналогічно, є також мікроконтролери, які можуть посилатися на певні області лише через регістр вказівника (вимагаючи додаткових інструкцій), і такі змінні позначаються far. Нарешті, деякі процесори можуть адресувати розділ пам'яті по бітах, і компілятор матиме змогу вказати це (наприклад, ключове слово bit).

Таким чином, можуть бути додаткові сегменти, такі як .nearbss і .neardata тощо, де ці змінні зібрані.

.rodata

Третій тип даних, що є зовнішньою функцією або процедурою, схожий на ініціалізовані змінні, за винятком того, що він є лише для читання і не може бути змінений програмою. У мові С ці змінні позначаються за допомогою constключового слова. Зазвичай вони зберігаються як частина флеш-пам'яті програми. Іноді вони ідентифікуються як частина сегменту .rodata (лише для читання). Для мікроконтролерів, що використовують архітектуру Гарварду , компілятор повинен використовувати спеціальні інструкції для доступу до цих змінних.

стек і купа

Стек і купа обидва розміщуються в оперативній пам'яті. Залежно від архітектури процесора, стек може зростати чи наростати. Якщо вона виросте, вона буде розміщена внизу ОЗУ. Якщо він зростає вниз, він буде розміщений в кінці оперативної пам'яті. Купа використовує решту оперативної пам’яті, не виділену змінним, і зростатиме протилежний напрямок стека. Максимальний розмір стека та купи зазвичай можна вказати як параметри лінкера.

Змінні, розміщені в стеці, - це будь-які змінні, визначені у функції чи процедурі без ключового слова static. Колись їх називали автоматичними змінними ( autoключовими словами), але це ключове слово не потрібно. Історично autoіснує, оскільки вона була частиною мови B, яка передувала мові C, і там вона була потрібна. Параметри функції також розміщуються на стеку.

Ось типовий макет оперативної пам’яті (якщо немає спеціального розділу 0 розділу):

введіть тут опис зображення

EEPROM, ROM та NVRAM

Перед тим, як з'явилася флеш-пам'ять, EEPROM (програмована пам'ять, доступна лише для читання з електричним стиранням) використовувалася для зберігання програми та даних const (сегменти .text та .rodata). Зараз є лише невелика кількість (наприклад, від 2 КБ до 8 КБ байт) EEPROM, якщо вона взагалі є, і вона зазвичай використовується для зберігання даних конфігурації або інших невеликих обсягів даних, які потрібно зберегти під час вимкнення живлення цикл. Вони не декларуються як змінні в програмі, а натомість записуються до використання спеціальних регістрів мікроконтролера. EEPROM також може бути реалізований в окремій мікросхемі та доступ до неї через шину SPI або I²C.

ПЗУ по суті такий же, як Flash, за винятком того, що він запрограмований на заводі (не програмується користувачем). Він використовується лише для пристроїв дуже великого обсягу.

NVRAM (енергонезалежна оперативна пам'ять) є альтернативою EEPROM і зазвичай реалізується як зовнішня ІС. Регулярна оперативна пам’ять може вважатися енергонезалежним, якщо вона резервна; у цьому випадку не потрібні спеціальні методи доступу.

Хоча дані можуть бути збережені у Flash, флеш-пам’ять має обмежену кількість циклів стирання / програмування (від 1000 до 10000), тому вона насправді не призначена для цього. Він також вимагає одразу стерти блоки пам'яті, тому оновлювати лише кілька байтів незручно. Він призначений для змінних коду та лише для читання.

EEPROM має набагато більш високі межі циклів стирання / програмування (100 000 до 1 000 000), тому це набагато краще для цієї мети. Якщо на мікроконтролері є EEPROM і він досить великий, саме там ви хочете зберегти енергонезалежні дані. Однак перед тим, як записати, вам доведеться спочатку стерти блоки (зазвичай 4 КБ).

Якщо немає EEPROM або він занадто малий, тоді потрібна зовнішня мікросхема. 32 КБ EEPROM - це лише 66 ¢ і може бути стертий / записаний до 1 000 000 разів. NVRAM з однаковою кількістю операцій стирання / програмування значно дорожчий (x10) NVRAM, як правило, швидше для читання, ніж EEPROM, але повільніше для запису. Вони можуть записуватися по одному байту або по блоках.

Кращою альтернативою обом є FRAM (сегнетоелектрична оперативна пам'ять), яка по суті має нескінченний цикл запису (100 трлн) і не має затримок запису. Це приблизно така ж ціна, що і NVRAM, близько 5 доларів за 32 КБ.


Це була якась справжня корисна інформація. Чи можете ви надати посилання на своє пояснення? Як текстові книги чи журнали, на випадок, якщо я хочу прочитати більше про це ..?
Соджу Т Варгезе

ще одне питання, чи можете ви дати нам уявлення про переваги чи недоліки однієї пам'яті над іншою (EEPROM, NVRAM та FLASH)?
Soju T Varghese

Гарна відповідь. Я розмістив додатковий, акцентувавшись більш докладно на тому, що конкретно йде на мові С.
Лундін

1
@SojuTVarghese Я оновив свою відповідь і також включив деяку інформацію про FRAM.
tcrosley

@Lundin ми використовували однакові назви сегментів (наприклад, .rodata), тому відповіді чудово доповнюють одна одну.
tcrosley

21

Нормальна вбудована система:

Segment     Memory   Contents

.data       RAM      Explicitly initialized variables with static storage duration
.bss        RAM      Zero-initialized variables with static storage duration
.stack      RAM      Local variables and function call parameters
.heap       RAM      Dynamically allocated variables (usually not used in embedded systems)
.rodata     ROM      const variables with static storage duration. String literals.
.text       ROM      The program. Integer constants. Initializer lists.

Крім того, зазвичай існують окремі флеш-сегменти для запуску коду та векторів переривання.


Пояснення:

Змінна має статичну тривалість зберігання, якщо вона оголошена як staticабо якщо вона знаходиться в області файлу (іноді неохайно називається "глобальною"). C має правило, яке вказує, що всі статичні змінні тривалості зберігання, які програміст не ініціалізував явно, повинні бути ініціалізовані до нуля.

Кожна статична змінна тривалість зберігання, ініціалізована до нуля, неявно або явно, закінчується в .bss. У той час як ті, які явно ініціалізовані до нульового значення, закінчуються в .data.

Приклади:

static int a;                // .bss
static int b = 0;            // .bss      
int c;                       // .bss
static int d = 1;            // .data
int e = 1;                   // .data

void func (void)
{
  static int x;              // .bss
  static int y = 0;          // .bss
  static int z = 1;          // .data
  static int* ptr = NULL;    // .bss
}

Будь ласка, майте на увазі, що дуже поширеною нестандартною установкою для вбудованих систем є "мінімальний запуск", що означає, що програма буде пропускати всі ініціалізації об'єктів зі статичною тривалістю зберігання. Тому може бути розумним ніколи не писати програми, які покладаються на значення ініціалізації таких змінних, а натомість встановлюють їх у "час виконання" до їх першого використання.

Приклади інших сегментів:

const int a = 0;           // .rodata
const int b;               // .rodata (nonsense code but C allows it, unlike C++)
static const int c = 0;    // .rodata
static const int d = 1;    // .rodata

void func (int param)      // .stack
{
  int e;                   // .stack
  int f=0;                 // .stack
  int g=1;                 // .stack
  const int h=param;       // .stack
  static const int i=1;    // .rodata, static storage duration

  char* ptr;               // ptr goes to .stack
  ptr = malloc(1);         // pointed-at memory goes to .heap
}

Змінні, які можуть виходити на стек, часто можуть опинятися в регістрах процесора під час оптимізації. Як правило, будь-яка змінна, у якої немає взятої адреси, може бути розміщена в регістрі процесора.

Зауважте, що вказівники дещо складніші, ніж інші змінні, оскільки вони дозволяють використовувати два різних види const, залежно від того, чи слід вказати дані лише для читання або якщо має бути сам вказівник. Дуже важливо знати різницю, щоб ваші покажчики не опинилися в оперативній пам'яті випадково, коли ви хотіли, щоб вони були спалахом.

int* j=0;                  // .bss
const int* k=0;            // .bss, non-const pointer to const data
int* const l=0;            // .rodata, const pointer to non-const data
const int* const m=0;      // .rodata, const pointer to const data

void (*fptr1)(void);       // .bss
void (*const fptr2)(void); // .rodata
void (const* fptr3)(void); // invalid, doesn't make sense since functions can't be modified

У випадку цілих констант, списків ініціалізаторів, рядкових літералів тощо вони можуть знаходитись у .text або .rodata залежно від компілятора. Ймовірно, вони закінчуються як:

#define n 0                // .text
int o = 5;                 // 5 goes to .text (part of the instruction)
int p[] = {1,2,3};         // {1,2,3} goes to .text
char q[] = "hello";        // "hello" goes to .rodata

У вашому першому прикладі коду я не розумію, чому "static int b = 0;" переходить у .bss і чому "статичний int d = 1;" переходить у .дані ..? Наскільки я розумію, обидві є статичними змінними, які були ініціалізовані програмістом. Тоді, що має значення? @Lundin
Soju T Varghese

2
@SojuTVarghese Тому що .bss дані ініціалізуються до 0 як блок; специфічні значення, такі як d = 1, повинні зберігатися у спалах.
tcrosley

@SojuTVarghese Додав деякі пояснення.
Лундін

@Lundin Також з вашого останнього прикладу коду чи означає це, що всі ініціалізовані значення переходять у .text або .rodata, а їх відповідні змінні переходять у .bss чи .data? Якщо так, то як змінні та відповідні їм значення відображаються між собою (тобто між сегментами .bss / .data та .text / .rodata)?
Soju T Varghese

@SojuTVarghese Ні, .dataяк правило, має так звану адресу завантаження у спалах, де зберігаються початкові значення, і так звану віртуальну адресу (не дійсно віртуальну в мікроконтролері) в оперативній пам'яті, де змінна зберігається під час виконання. Перед mainзапуском початкові значення копіюються з адреси завантаження у віртуальну адресу. Вам не потрібно зберігати нулі, тому .bssне потрібно зберігати його початкові значення. sourceware.org/binutils/docs/ld/…
starblue

1

Хоча будь-які дані можуть потрапляти в будь-яку пам'ять, яку вибирає програміст, загалом система найкраще працює (і призначена для використання), де профіль використання даних узгоджується з профілями читання / запису пам'яті.

Наприклад, програмним кодом є WFRM (написати кілька прочитаних багато), і їх дуже багато. Це чудово підходить до FLASH. ПЗУ OTOH є W один раз RM.

Стек і купа невеликі, з читанням і записом. Це найкраще відповідатиме оперативної пам’яті.

EEPROM не підходить жодному з цих застосувань, але він відповідає профілю невеликих кількостей даних, що зберігаються під час роботи джерел живлення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.