Что я могу сделать, если у меня заканчивается флэш-память или SRAM?

28

Согласно документации Arduino, ATmega328 имеет 32 КБ флэш-памяти для загрузчика + загруженный эскиз и только 2 КБ SRAM для данных времени выполнения. ATmega2560 имеет немного больше, общий объем 256 КБ и 8 КБ соответственно.

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

Что вы можете сделать, если у вас кончились? Например, если ваш эскиз слишком большой или вам нужно обрабатывать много данных (например, строк) во время выполнения? Есть ли способ расширить Flash или SRAM?

Питер Блумфилд
источник
Попробуйте использовать некоторые переменные оптимизации. Некоторые различные переменные обсуждаются здесь
TheDoctor
1
Используйте надлежащие области действия для ваших переменных, если это еще не сделано, компилятор оптимизирует использование оперативной памяти для вас, когда переменные не используются.
Джиппи
1
Вы можете использовать Teensy 3.2 (с программным обеспечением Teensyduino), которое будет сравнимо с Arduino. Учитывая, что у вас заканчивается RAM / PROGMEM, это также означает, что вы, скорее всего, пытаетесь подтолкнуть Arduino. Teensy 3.2 не намного дороже. но имеет: 32-битную, 72 МГц (wtf !?) флэш-память 256 КБ, 64 КБ ОЗУ и 3x UART. Не больше памяти программ, как у ATmega2560, но должно быть достаточно оперативной памяти и увеличения скорости.
Пол

Ответы:

30

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

С точки зрения сокращения использования программного пространства (Flash) размер кода может быть довольно трудно оптимизировать, если вы неопытны или более привыкли к программированию для настольных компьютеров, которые не склонны к этим навыкам. К сожалению, не существует подхода «волшебной пули», который будет работать во всех ситуациях, хотя он помогает, если вы серьезно задумаетесь над тем, что в действительности должен иметь ваш эскиз . Если функция не нужна, уберите ее.

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

Оптимизация данных времени выполнения (SRAM) имеет тенденцию быть немного легче, когда вы к этому привыкли. Очень распространенная ловушка для начинающих программистов - использование слишком большого количества глобальных данных. Все, что объявлено в глобальном масштабе, будет существовать в течение всего времени существования эскиза, и это не всегда необходимо. Если переменная используется только внутри одной функции, и она не должна сохраняться между вызовами, то сделайте ее локальной переменной. Если значение должно быть разделено между функциями, подумайте, можете ли вы передать его как параметр вместо того, чтобы делать его глобальным. Таким образом, вы будете использовать SRAM только для тех переменных, которые вам действительно нужны.

Еще одним убийцей использования SRAM является обработка текста (например, использование Stringкласса). Вообще говоря, вам следует избегать выполнения операций со строками, если это возможно. Они огромные боровы памяти. Например, если вы выводите много текста в последовательный порт, используйте несколько вызовов Serial.print()вместо вместо конкатенации строк. Также попытайтесь сократить количество строковых литералов в вашем коде, если это возможно.

Избегайте рекурсии, если это возможно. Каждый раз, когда выполняется рекурсивный вызов, стек поднимается на уровень глубже. Перефразируйте ваши рекурсивные функции, чтобы они стали итеративными.

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

Очевидно, что EEPROM довольно ограничен по размеру и скорости и имеет ограниченное количество циклов записи. Это не лучшее решение для ограничения данных, но этого может быть достаточно, чтобы облегчить нагрузку на Flash или SRAM. Также возможно взаимодействие с аналогичным внешним хранилищем, таким как SD-карта.

Расширение
Если вы исчерпали все остальные варианты, возможно, расширение возможно. К сожалению, расширение флэш-памяти для увеличения места в программе невозможно. Тем не менее, есть возможность расширить SRAM. Это означает, что вы сможете реорганизовать свой эскиз, чтобы уменьшить размер кода за счет увеличения размера данных.

Получить больше SRAM на самом деле довольно просто. Один из вариантов - использовать один или несколько чипов 23K256 . Доступ к ним осуществляется через SPI, и есть библиотека SpiRAM, которая поможет вам их использовать. Просто знайте, что они работают при 3,3 В, а не 5 В!

Если вы используете Mega, вы также можете получить щиты расширения SRAM от Lagrangian Point или Rugged Circuits .

Питер Блумфилд
источник
1
Вы также можете хранить постоянные данные в памяти программ, а не SRAM, если у вас есть проблемы с пространством SRAM и свободная память программ. Смотрите здесь или здесь
Коннор Вольф
1
Еще одна отличная альтернатива EEPROM - SD-карта. Это действительно занимает несколько портов ввода-вывода, но если вам нужен большой кусок пространства, например, для картографических данных или чего-то подобного, его можно легко заменить и отредактировать с помощью специальной программы на ПК.
Анонимный пингвин
1
Люди не должны поощряться к использованию SPI SRAM или расширений ОЗУ, если у них недостаточно памяти. Это просто трата денег. Выбор большего MCU будет дешевле. Кроме того, производительность может быть очень плохой. Сначала нужно сделать приблизительную оценку: если предполагаемое использование ОЗУ слишком близко к пределу, то вы выбираете неправильную плату / микроконтроллер / платформу разработки. Конечно, хорошее использование (хранение строк во флэш-памяти) и оптимизация (избегая использования некоторых библиотек) могут быть настоящими переменами в игре. Однако на данный момент я не вижу преимуществ от использования платформы Arduino Software.
следующий взлом
24

Когда вы загружаете свой код в Arduino, например, в Uno, он сообщит вам, сколько байтов он использует из доступных 32K. Вот сколько у вас флеш-памяти (вспомните жесткий диск компьютера). Пока ваша программа работает, она использует то, что называется SRAM, и этого гораздо меньше.

Иногда вы замечаете, что ваша программа ведет себя странно в тот момент, которого вы даже не трогали некоторое время. Может случиться так, что ваши последние изменения приводят к нехватке памяти (SRAM). Вот несколько советов о том, как освободить SRAM.

Хранение строк во Flash вместо SRAM.

Одна из самых распространенных вещей, которые я видел, - это нехватка памяти в чипе, потому что слишком много длинных строк.

Используйте эту F()функцию при использовании строк, чтобы они сохранялись во Flash, а не в SRAM, поскольку у вас их гораздо больше.

Serial.println(F("This string will be stored in flash memory"));

Используйте правильные типы данных

Вы можете сохранить байт, переключившись с int(2 байта) на byte(1 байт). Байт без знака даст вам 0-255, поэтому, если у вас есть числа, которые не превышают 255, сохраните байт!

Как я узнаю, что у меня заканчивается память?

Обычно вы наблюдаете, как ваша программа ведет себя странно, и удивляетесь, что пошло не так ... Вы ничего не изменили в коде рядом с точкой, в которой происходит сбой, так что дает? Недостаточно памяти.

Есть пара функций, чтобы сказать вам, сколько свободной памяти у вас есть.

Доступная память

sachleen
источник
Вы знаете F(), является ли эта функция специфичной для Arduino, или это в библиотеках AVR? Вы могли бы также упомянуть PROGMEM const ....
Джиппи
Также вы можете использовать битовые структуры для дальнейшего сокращения пространства, используемого вашими переменными (например, если вы имеете дело с большим количеством логических значений).
jfpoilpret
17

В дополнение к тому, что сказали другие (с чем я полностью согласен), я бы посоветовал прочитать эту статью о памяти; он хорошо написан, объясняет много вещей о памяти и дает советы о том, как ее оптимизировать.

В конце чтения, я думаю, вы получите довольно полный ответ на свой вопрос.

Подводя итог, у вас есть 2 возможных цели оптимизации (в зависимости от того, где у вас проблемы с памятью):

  • Flash (т.е. память программ); для этого вы можете:
    • удалить мертвый код (например, любой код, который включен, но не используется) и неиспользуемые переменные (этот также помогает с SRAM)
    • вычеркнуть дублированный код
    • полностью удалите загрузчик (вы можете получить от 0,5 КБ для UNO до 2 или 4 КБ для других моделей Arduino); это имеет некоторые недостатки, хотя
  • SRAM (т. Е. Стек, куча и статические данные); для этого вы можете:
    • удалить неиспользуемые переменные
    • оптимизировать размер каждой переменной (например, не использовать длинные -4 байта, если вам нужны только int-2 байта)
    • используйте правильную область видимости для ваших переменных (и, по возможности, предпочитайте стек статическим данным)
    • уменьшить размер буфера до строгого минимума
    • перенести постоянные данные в PROGMEM (т.е. ваши статические данные останутся во флэш-памяти и не будут скопированы в SRAM при запуске программы); это также относится к константным строкам, для которых вы можете использовать F()макрос)
    • избегать динамического выделения, если оно не является абсолютно необходимым; вы избежите фрагментированной кучи, которая может не сжиматься даже после освобождения памяти

Также описан дополнительный подход к сокращению использования SRAM (но он используется редко, поскольку он немного тяжел при кодировании и не очень эффективен), он заключается в использовании EEPROM для хранения данных, созданных вашей программой, но не используется до тех пор, пока в некоторых условиях происходят, когда данные могут быть загружены обратно из EEPROM.

jfpoilpret
источник
1
Удаление мертвого кода - компилятор действительно хорошо справляется с этим для вас - это не будет иметь никакого значения, если у вас много кода, который никогда не вызывался. Если вы случайно набрали код, который вам не нужен, то, конечно, он другой.
dethSwatch
9

Есть две вещи, которые нужно сделать, если у вас не хватает памяти:

  • Каким-то образом «оптимизировать» свой код, чтобы он занимал меньше места; или, по крайней мере, использует меньше определенного типа хранилища, из которого вы исчерпали (и использует больше хранилища, которого у вас еще много). Или,
  • Добавьте больше памяти.

В Интернете есть множество советов о том, как сделать первое (и для подавляющего большинства вещей, которые люди делают с Arduino, встроенной памяти более чем достаточно после «оптимизации»). Поэтому я сосредоточусь на втором:

Есть 3 вещи, которые используют флэш или SRAM; каждому нужен немного другой подход к добавлению хранилища:

  • хранилище переменных: можно расширить SRAM, как уже указывало sachleen. SRAM, FRAM и NVSRAM подходят для быстро меняющихся переменных. (Хотя в принципе вы можете использовать флэш-память для хранения переменных, вам придется беспокоиться о ее износе). SPI (последовательный протокол) проще всего подключить к Arduino. Библиотека SpiRAM работает с последовательным чипом SRAM Microchip 23K256 . Серийный чип FRAM Ramtron FM25W256 (теперь принадлежащий Cypress) также использует SPI. Cypress CY14B101 NVSRAM также использует SPI. И т.п.

  • постоянные данные, которые должны все еще быть в следующий раз при включении питания: это почти так же просто, как расширение SRAM. Существует много внешних устройств хранения EEPROM, FRAM, NVSRAM и FLASH . В настоящее время самая низкая стоимость за МБ - это флэш-карты SD (доступ к которым можно получить через SPI). Ramtron FM25W256 (см. Выше), Cypress CY14B101 (см. Выше) и т. Д. Также могут хранить постоянные данные. Многие экраны расширения включают в себя слот для SD-карт, а несколько библиотек и учебных пособий поддерживают чтение и запись на (флэш) SD-карты. (Мы не можем использовать SRAM для этого, потому что SRAM забывает все, когда отключается питание).

  • исполняемый код: К сожалению, расширение флэш-памяти Arduino для увеличения места в программе невозможно. Тем не менее, программист всегда может выполнить рефакторинг эскиза, чтобы уменьшить размер кода за счет увеличения размера данных и замедления его выполнения. (Теоретически, вы можете зайти так далеко, чтобы перевести весь ваш набросок на какой-то интерпретируемый язык, сохранить эту версию вашего наброска на SD-карте, а затем написать интерпретатор для этого языка, который работает на Arduino, для извлечения и выполнения инструкций из SD-карта - Forth on Arduino , BASIC-переводчик, переводчик Tom Napier Picaro, некоторые специфические для приложения языки и т. Д.).

Дэвид Кэри
источник