CraftDuino v2.0
  • - это CraftDuino - наш вариант полностью Arduino-совместимой платы.
  • CraftDuino - настоящий конструктор, для очень быстрого прототипирования и реализации идей.
  • Любая возможность автоматизировать что-то с лёгкостью реализуется с CraftDuino!
Просто добавьте CraftDuino!

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. Учебный Курс. Работа с памятью
  • +2
  • 27 мая 2011, 08:17
  • noonv

Комментарии (3)

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

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

xtile

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

Radiolok

  • 27 мая 2011, 10:56
+
0
есичо, я вот это имел в виду
www.digilentinc.com/Products/Detail.cfm?NavPath=2,719,895&Prod=CHIPKIT-MAX32
avatar

xtile

  • 28 мая 2011, 17:36

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.