Arduino сколько памяти осталось

Обновлено: 05.07.2024

Программирование Arduino, оживление микроэвм Электроника МК-90, аппаратный хакинг.

05.04.2009

+1К свободной памяти для Arduino

Как известно, в Arduino используется bootloader - специальная подпрограмма, которая постоянно находится в самом конце памяти программ. После сброса она получает управление и через последовательный интерфейс (SPI, пины Rx и Tx) зашивает новую микропрограмму (sketch) в верхние адреса памяти, а затем и вовсе отдает ей управление.

Строго говоря, bootloader необязателен. В готовом изделии можно одним легким движением поставить FUSE-бит BOOTRST в 1 , и управление после сброса будет передаваться непосредственно программе, по адресу 0x0000 (именно так я и сделал с ATmega в светодиодном индикаторе).

Испокон веков ;) размер bootloader-а Arduino был 2048. Конечно, реально-то он был чуть меньше, но размер bootloader-а кодируется двумя FUSE-битами BOOTSZ1 и BOOTSZ0 . Таким образом, для ATmega168P есть четыре фиксированных размера: 256, 512, 1024 и 2048 байт. Для ATmega328P тоже четыре размера, но поскольку памяти программ у него в два раза больше, то разработчики чипа "сдвинули" размеры bootloader-а в сторону увеличения: 512, 1024, 2048, 4096.

Те, кто писал программы на ассемблере, обычно загадочно улыбаются в ответ на мою фразу "скетч занял пять килобайт в памяти программ". Оно и понятно - при программировании на C память программ съедается стремительно, зато и сама программа пишется значительно быстрее. Именно поэтому ATmega328P заменил на боевом посту ATmega168 - в некоторых случаях просто не хватало 16К памяти программ.

Стоп-стоп, не 16, а 14-ти ( минус 2К на бутлоадер ). После замены процессора становится свободно 30К:


Но что делать, если скетч занял 30936 байт? Переходить на ассемблер?

  1. Берется новый исходник bootloader-а, компиляется в .hex
  2. Результат зашивается в память ATmega, корректируются fuse-биты
  3. Чтобы ArduinoIDE поняла, что у нее стало больше памяти для результата компиляции, правится boards.txt.

Итак, вот мой результат компиляции: bootloader_1k_0015.zip. Его надо распаковать в каталог с Arduino IDE 0015, при этом изменятся две секции в списке плат, станет так: "Arduino Duemilanove w/ ATmega 328P 1k" и "Arduino Diecemila or Duemilanove w/ ATmega 168 1K". Выбирайте нужную, затем можно прошить новый bootloader через Arduino IDE, дальше - как обычно.

Сами понимаете, что если прошить 1К-bootloader, то даже немодифицированная Arduino IDE будет замечательно работать, но не наоборот :(

Более правильно было бы добавить секции, но тогда Arduino IDE не сможет корректно отобразить в своем окне информацию об ошибках, сославшись на длинную цепочку исключений java - согласитесь, это не очень удобно.

Я скомпилировал bootloader-ы для тех процессоров, для которых смог 100%-но убедиться в работоспособности - с трудом, но нашел таки ATmega168P :) Во всех моих Arduino сейчас работает ATmega328P - выписал целую упаковку из-за границы, и, как всегда, раздаю остатки через "молоток".

[Как определить, сколько осталось свободной оперативной памяти (RAM)]

Это может оказаться полезным, когда скетч работает некорректно, и трудно определить причину ошибки. Ниже на примере показано, как определить количество свободной памяти RAM вызовом функции memoryFree.

Пользовательская функция memoryFree использует системные переменные для вычисления количества свободной оперативной памяти RAM. Обычно системные переменные невидимы - они создаются компилятором для собственного использования (для управления внутренними ресурсами).

Количество свободной памяти может меняться с течением времени, пока работает Ваша программа. Очень важно удостовериться, что Вы не тратите больше памяти, чем имеется в наличии у системы.

Вот несколько основных причин потребления памяти RAM:

• Когда Вы инициализируете константы:

• Когда Вы декларируете глобальные переменные:

• Когда делаете вызов функции:

• Когда динамически выделяете память:

Объект String системы Arduino использует динамическое выделение памяти для строк. Вы можете проверить это, если добавите в начало кода примера определение строки String s = "\n";, и затем добавите в код loop перед задержкой строки:

После запуска этого варианта скетча Вы увидите, что количество памяти уменьшается, потому что каждая прокрутка цикла loop увеличивает размер строки. В какой-то момент память переполнится, и программа перестанет работать. Поэтому не увеличивайте размер строк сверх необходимого, и следите за их размером. Также будьте особенно внимательны с кодом, который использует динамическое выделение памяти. Не пишите код, который динамически создает разное количество переменных в зависимости от некоторых параметров во время своей работы, потому что очень сложно бывает найти ошибки во время выполнения кода, связанные с переполнением памяти.

Также в библиотеках часто объявляются константы и глобальные переменные, о которых Вы можете не знать, но они также расходуют RAM. У библиотеки Serial, например, есть глобальный массив из 128 байт, который используется как буфер для приходящих последовательных данных. Только это использует одну восьмую от общего объема памяти старого Arduino на микроконтроллере ATmega168.

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

Иногда, это очень важно, например, когда Вы достигаете предела. Потому что, могут происходить странные и совершенно непредсказуемые вещи, при достижении программой границ памяти (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 байта

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

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


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

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

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

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

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


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

Здравствуйте!
Возникли подозрения, что не хватает оперативной памяти.

В документации на ардуино написано, что ОЗУ и стек располагаются рядом. ОЗУ заполнятся слева направо, стек справа налево. Могут возникать ситуации наезда ОЗУ на стек или наоборот.

Возможно ли через «Serial.print()» или каким либо другим образом оперативно выводить, сколько использовано ОЗУ или сколько осталось свободной и наезжает ли ОЗУ на стек?

И не могу найти информацию, сколько ОЗУ занимает char и String.
Например «char st2[0]="00 01 02 03 04 05 06 07"» и «String st2[0]="00 01 02 03 04 05 06 07»?

Перессылка массива данных из одного места ОЗУ в другое место ОЗУ
Есть ли какой-нибудь примерчик программки, которая выполняет пересылку массива данных размерностью.

Что будет если в 1 слот поставить 2 ОЗУ. Получится ли задублировать ОЗУ?
В теории. Например две одинаковые планки? Зачем? Любопытство, ну и есть кое какие мысли по этому).

Какой эффект будет если к ПК с 1024 мб ОЗУ, процессор одноядерный добавить 1-2 гб ОЗУ
Какой эффект будет если к ПК с 1024 мб ОЗУ, 2.1гц, Ram 512, проц.(одноядерный) добавить 1-2 гб.

Перестали работать вместе озу. Все слоты рабочие, проверял другой озу
Проблемы с 2-мя плашками по 4gb, которые начали отказывать работать вместе. Есть подозрения на биос.

массив из 0 элементов
пишешь в чужую память
вот так попробуй

Неверно поставил вопрос.
Пишу «char * st2[20];», компилирую, замеряю размер скетча.
Дописываю «st2[0]="00 01 02 03 04 05 06 07";» - размер скетча увеличился на 32 байта, а по идее должен увеличиться на 23 байта.

Делаю тоже самое, только со «String st2[20];». Размер скетча увеличивается на 36 байт!
Но у меня строки массива задаются НЕ заранее, а определяются в момент выполнения программы.
С размером массива до 7 все работает, но мне нужен массив из 20 строк (каждая до 23х байт).
Вот я и хочу посмотреть, что твориться в оперативной памяти.

Сергей 190, Указывайте компилятор
Из исходных данных для моего IAR я проблем не вижу, но другие компиляторы могут .

Витальич навел меня на мысль. Я пользовался версией «1.5.2». После компиляции выводился только размер скетча.
Скачал версию «1.6.4». Появилась информация об ОЗУ.
Показало, что глобальные переменные занимают 1 891 байт, осталось 157.
Объявленных переменных не так уж и много, стал разбираться.

Выяснилось, следующее:
Serial.print(переменная) увеличивает только размер скетча на 12 байт.
Serial.print("текст") увеличивает и размер скетча, и место в оперативной памяти.

Serial.print("текст") у меня многовато и съели больше половины ОЗУ.
Решил вызывать нужные тексты из файла на SD карте.

Вызов процедуры Print(P,znak); где znak – номер строки из файла, которую нужно вывести на экран и если P==1 перевести на следующую строку.

Первый вызов процедуры увеличил размер скетча на 1224 байта и ОЗУ на 12 байт.
Последующие вызовы увеличивает только размер скетча на 16 байт.

Написал в лоб. Может, кто подскажет более красивое решение?

Но эта информация ДО выполнения программы.
Вопрос «можно ли оперативно выводить, сколько использовано ОЗУ в каждый момент во время выполнения программы?» остаётся актуальным.

в IAR которым пользуется Витальич есть отладчик. в моем компиляторе есть отладчик. в них можно посмотреть сколько памяти занято, где занято. мой компилятор при переполнении памяти выдает ошибку.
а ардуино похоже пофигу. вот что будет если файл на SD превысит объем ОЗУ? Вызов процедуры Print(P,znak); где znak – номер строки из файла, тебе же это только для отладки нужно. сделай Print(znak); а на листе бумаги напиши, что каждый знак обозначает. при ошибке можеш число с минусом выводить(так удобней).
можно ли оперативно выводить, сколько использовано ОЗУ ИМХО, нельзя. МК не любят динамические переменные(динамически изменяемые массивы). размер занятой ОЗУ определяется при компиляции.
размер стека меняется. на ассемблере можно посмотреть последний адрес в стека. и записать туда чего нибуть и программа зависнет. 1. Для С++
Классический компилятор создаст в ОЗУ переменные int P и int Ns, что вызовет увеличении размера ОЗУ
Создаст указатели на эти переменные.
Посмотрите, что меньше "съест" ОЗУ
ИМХО: для восьмибитника скорей всего будет по барабану.
2. А Вам так важно использовать int, я стараюсь брать тип как можно меньшей размерности если данные гарантировано не превысят размерности типа.
Вопрос «можно ли оперативно выводить, сколько использовано ОЗУ в каждый момент во время выполнения программы? не знаю как у Вас, но в IAR можно посмотреть таблицу размещения переменных в памяти, а также задавать размер стека. По динамическим переменным, согласен с уважаемым Grey.
Также попробуйте поиграться настройками оптимизации.
P.S. Насколько помню (давно не попадал в такие ситуации), IAR не отслеживает ошибки связанные с переполнением ОЗУ и обнаружить её можно только во время отладки. в IAR которым пользуется Витальич есть отладчик. в моем компиляторе есть отладчик Витальич, у Вас какой компилятор? Grey, а Вы каким пользуетесь?
И вообще, что такое отладчик? Где его брать и как им пользоваться?
в IAR можно посмотреть таблицу размещения переменных в памяти, а также задавать размер стека Нельзя ли поподробнее. Может ссылки какие, что бы почитать.
Я пользуюсь IAR (яры есть почти под все платформы МК, что позволяет с минимальным переучиванием переходить на разные контроллеры). Но Вам это не поможет, выбрав ардуину, которая по сути является программно аппаратным законченным решением, Вы только этой средой и можете пользоваться, можно еще взять Atmel Studio, но там для новичка еще печальней всё выглядит.
Это программный или программно-аппаратный модуль, который позволяет просмотреть внутреннее состояние МК (контекст МК) в любой момент времени. Моменты времени выбираются заданными точками останова или пошаговым выполнением программы.
Можно, но знания по IAR (самая не любимая среда большинства программистов МК, да еще при этом и самая дорогая ) Вам не помогут, он слишком сильно отличается от ардуины, а ардуиной я вообще не занимался так что извините.
К примеру вот так в IAR выглядит отладчик (окно напихал от фонаря, обычно столько не нужно) Algorithm Builder 5.44
довольно удобный. если умееш строить алгоритмы, то и очень понятный.
в сети можно найти примеры кодов к нему. но готовых библиотек в нём нету.
и это всё таки ассемблер.
так, что не советую. симулятор, отладчик в AB. там ещё много чего можно открыть. однако, в комплекте Arduino IDE уже идёт WinAVR (\hardware\tools\avr\), поэтому можно воспользоваться им. в WinAVR был отладчик. но в ардуино(по крайне мере последней версии) WinAVR не полностью, не весь комплект программ. но можно попробовать востановить.

Я когда-то давно писал для себя функцию, выводящую на печать фрилист ардуиновского маллока. С помощью него вполне можно узнать сколько оперативки занято динамически. Те числа, которые приводит ардуино - это исключительно статически занятая память.

Добавлено через 8 минут
Ардуиновский String в оперативной памяти занимает 2байта на указатель, 2байта на размер зарезервированной области, 2байта на размер данных, 2байта на предзаголовок блока пвыделеленной памяти и плюс сами данные с терминирующим нулем.

Добавлено через 2 минуты
Для решения проблемы хранения строк в оперативной памяти, ардуиновские либы обучены работать с флеш строками. Можно использовать их.

Добавлено через 4 минуты
Самый простой, но малоточный способ оценки имеющийся памяти состоит в сравнении текущий вершины кучи __brkval (не помню, как то так он называется) и указателя стека (SP).

Игры используют только 1 плашку озу,то есть загружают под 50 % озу а 2 плашка отдыхает
Тип ЦП QuadCore Intel Core i5-7500, 3600 MHz (36 x 100) Системная плата Asus H110M-R (2 PCI-E x1.

Не запускается виндовс после установки второй планки озу 1333mhz к озу 1600mhz (ddr3)
После установки 2й планки памяти ddd3 1333mhz к ddr3 1600mhz (обе по 4гб, обе good ram) комп выдал.

Комп не работает с ОЗУ, раньше работал. ОЗУ рабочая
Дело было так. На компе стоит 8Гб озу(2 планки по 4Гб). Раньше комп работал без изъянов. Утром.

ОЗУ 800Mhz не работает с ОЗУ 667Mhz, зависает комп
ОЗУ 1Gb 800Mhz не работает с ОЗУ 1Gb 667Mhz, зависает комп, сказали что надо в биосе что то.

Читайте также: