ATmega — использование памяти


Иногда, бывает полезно узнать, сколько памяти использует Ваш скетч.

Иногда, это очень важно, например, когда Вы достигаете предела. Потому что, могут происходить странные и совершенно непредсказуемые вещи, при достижении программой границ памяти (out of memory).

Выхода кода за границы памяти легко избежать, так Arduino IDE скажет вам точно, сколько используется памяти после каждой компиляции/загрузки:


Отследить выход за границы памяти EEPROM сложнее, но это обычно не является проблемой, поскольку очень немногие скетчи используют значительные объемы EEPROM.

Достижение границы RAM — крайне неприятная проблема. Потому что это может произойти в любое время; не обязательно при запуске, и быть совершенно непредсказуемым, потому что, например, проблемы может вызывать функция-обработчик прерываний.

В оперативной памяти (RAM), есть три области:
* статических данных, в ней хранятся глобальные переменные и массивы … и строки!
* «куча»(heap), используется, если вы вызываете malloc() и free()
* «cтек»(stack), используется, когда одна функция вызывает другую

Куча растёт вверх, и используется довольно непредсказуемым образом. Если вы освобождаете области памяти, то они становятся неиспользованными пробелами в куче, которые могут повторно использоваться новым вызовом malloc(), если запрошенный блок вписывается в эти пробелы.

В любой момент времени, существует высокая точка в оперативной памяти (RAM), занимаемая кучей. Это значение может быть найдено в системной переменной, которая называется __brkval.

Стек расположен в конце оперативной памяти(RAM), и расширяется вниз, по направлению к области кучи. Область стека расширяется и освобождается при необходимости вызова других функций. В нём же хранятся локальные переменные.

т.о. стек растёт навстречу данным! Если он разрастётся, то может достигнуть области данных и записать свои данные вместо ваших значений переменных. Возможна и обратная ситуация — данные разрослись и переписали данные стека. Оба случая крайне неприятны и сложно детектируемы.

Весь фокус в том, чтобы использовать минимальное количесво оперативной памяти(RAM), потому что это дефицитный ресурс: ATmega имеет всего 2048 байт RAM.

похоже, имеется в виду ATmega328, у Atmega8/Atmega168 ОЗУ ещё меньше — всего 1024 байта

Вот небольшая функция функция, которая определяет, сколько оперативной памяти в настоящее время не используется:

int freeRam () {
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

И вот скетч, который вызывает данную функцию:

void setup () {
    Serial.begin(57600);
    Serial.println("\n[memCheck]");
    Serial.println(freeRam());
}

void loop () {}

Результат выполнения:

[memCheck]
1846

Итак, у нас есть около 1.8 Kb доступного ОЗУ в этом крошечном скетче, который почти ничего не делает. Более точно: скетч использует 2048 — 1846 = 202 байта для внутренних нужд и прочего (кстати, 128 байт, используются для входного буфера последовательного порта).

Когда это значение упадёт до 0, ваш скетч рухнет. Это может выглядеть, как бесконечный цикл, странные расчеты или выход, или постоянная перезагрузка. Не ожидайте, понятных сообщений об ошибке!

Давайте внесём в скетч незначительные изменения:

Serial.println("\n[memCheck2]");

Результат:

[memCheck2]
1844

А?

Первое — это объясняется тем, что все C-строки также хранятся в оперативной памяти! Это объясняет, почему добавление одного символа в строчке приводит к уменьшению объема доступной памяти.

Второе — флэш-память организована в слова. Поэтому, иногда, когда вы ожидаете однобайтовый эффект, то можете получить округление из-за того, что объект хранится во флэш-памяти(flash).

И третье — все C-строки также хранятся во флэш-памяти. Дело в том, что содержимое оперативной памяти не определено при включении питания, поэтому одна из задач, выполняемых при запуске С-кода, состоит в том чтобы скопировать все строки из флэш-памяти в оперативную память.

Мораль: будьте очень осторожны, когда что-нибудь делаете со строками на ATmega, потому что вы можете обнаружить, что очень быстро достигли границы памяти. Добавление большого количества подробных отладочных сообщений может вызвать больше проблем, чем вы думаете!

На сайте avr-libc отыскалась замечательная картинка, иллюстрирующая AVR RAM:

Ссылки
ATmega memory use
PROGMEM
avr/pgmspace.h
Optimizing SRAM
PROGMEM BASICS

По теме
Хаки Arduino — Экономим RAM
AVR. Учебный Курс. Работа с памятью


0 комментариев на «“ATmega — использование памяти”»

  1. в связи с этим реквестируется статья об использовании внешней памяти на avr :))

    ну или как альтернативу можно использовать полностью совместимую подделку под ардуино на арме — там и частота в разы выше и памяти в десятки раз больше:)

    • Внешняя память возможна лишь на некоторых камнях, например ATmega640/1280/2560.
      Там можно просто взять и подключить 64кбайт внешней оперативки. и активировать ее парой когнфигурационных байтов.
      В датащите есть даже схема подключения, так как порт данных совмещен с нижним байтом адреса.

Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Android Arduino Bluetooth CraftDuino DIY IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение