Как увеличить память arduino uno

Arduino.ru

Дополнительная flash-память

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

Столкнулся с проблемой нехватки flash-памяти — не хватает места для хранения скетча. Оптимизировал код как можно, а надо еще много всего добавить.

Есть ли внешнии модули, которые увеличивают flash-память? Или можно как-нибудь увеличить место для хранения скетча?

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

Замена микроконтроллера вам нужна, если действительно оптимизировали.

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

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

кстати ,вопрос к тем кто сюда заглянет : можно ли в среде ардуино настроить PROGMEM на работу с внешней энергонезаисимой памятью,по шине I2C или SPI?или как то по другому нативно расширить адресное пространство(не RAM,о примере ардуино на 512КБ ,знаком)

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

Progmem наврядли можно прям вот так с полтычка, иначе давно бы уже все еепромы по i2c в полный рост пользовали. А вот какой-нить драйвер можно, наверное, накатать. Только медленный он будет. Или с доп. буфером, как для SD-карты мутить.

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

EEPROM использовать вообще не проблема. А вот если скетч не влазит — оптимизация, или замена контроллера.

Вообще чистый СИ очень сильно снижает вес программы. Но, как сказал mixail844 , нужно определиться что там у вас за код, и что в нем используется. То что можно подгрузить — на флешку, а код перевести (хотя бы частично) в чистый СИ.

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

zzzzza , и RAM и PROGMEM находятся внутри адресного пространства процессора, а I2C или SPI — нет. Защищенного режима у AVR подобно как в 386+ тоже нет, значит программно прозрачная эмуляция тоже невозможна. Т.е. хранить константы где-то снаружи по I2C или SPI можно (написав для их добывания свои функции), а исполнять код из них — нет.

Могу порекомендовать Мегу 2560 — у нее и flash памяти побольше и при необходимости можно организовать внешнюю память в общем адресном пространстве.

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

Либо переходить на STM или ESP — вот там пямяти на много больше.

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

Спасибо за ответы!

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

Думал о меге, но у нее размер большой. Сейчас думаю между STM и Iskra JS. Больше в пользу Iskra JS, так как побаиваюсь, что памяти STM тоже может не хватить в будущем. Но придется переписывать все на JavaScript. Отсюда вопрос для тех кто сталкивался с микроконтроллерами с AVR процессорами, на которых установлен интерпретатор JavaScript: можно ли как-то писать код на Arduino Wiring?

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

Источник

Добавление внешней памяти EEPROM в Ардуино (24LC256)

Очень простой и эффективный способ хранения данных – это использовать внутреннюю память Ардуино. Но это подходит для хранения небольших объемов данных, поскольку в Ардуино встроенная EEPROM имеет размер всего 512 байт.

При работе с более крупными или более сложными проектами нам может потребоваться сохранять дополнительные данные. В связи с этим возникает необходимость использовать внешнюю память, например 24LC256.

Микросхема памяти 24LC256 имеет размер 256 Кбит, что на самом деле составляет 32 Кбайт (262 144 бит / 8 бит = 32 768 байт). Это в 62 раза больше встроенной памяти Ардуино!

Настройка оборудования

В этом примере мы будем использовать микросхему 24LC256 от Microchip. Если вы используете другую микросхему, убедитесь, что требования к выводам и питанию соответствующие, чтобы не повредить микросхему.

Микросхему Microchip 24LC256 можно приобрести в 8-контактном DIP-корпусе. Распиновка 24LC256 довольно проста:

  • вывод питания (8)
  • вывод GND (4)
  • вывод защиты от записи (7)
  • вывод SCL (6)
  • вывод SDA (5)
  • выводы адреса (1,2,3)

Прежде чем мы перейдем к программной части, давайте подключим микросхему 24LC256 к нашей Ардуино.

Используя вышеприведенный рисунок, давайте приступим к подключению микросхемы. Сначала подключите GND и VCC к контактам 4 и 8 соответственно. Далее подключите выводы данных к плате Ардуино. Поскольку мы используем I2C шину, мы будем использовать контакты A4 и A5. Подключите контакт SDA 24LC256 (контакт 5) к контакту A4 Ардуино. Затем подключите SCL (контакт 6) к контакту A5 на Ардуино. Дважды убедитесь, что все подключено правильно, иначе могут произойти странные вещи, если вы их перепутаете.

После того, как выводы данных и питание подключены, у 24LC256 осталось еще четыре неподключенных вывода: вывод WP и три вывода адреса.

Контакт WP обеспечивает защиту от записи. Это позволяет вам контролировать процесс записи данных в EEPROM. Если на этом выводе низкий логический уровень (0), то запись разрешена. Если же на выводе WP будет высокий логический уровень (1), то запись запрещена, но при этом чтение всегда доступно. В рамках этого руководства мы будем записывать в EEPROM, так что вывод WP подключим к GND.

Последние три контакта устанавливают адрес 24LC256, который позволяет идентифицировать конкретную микросхему на I2C шине. Микросхема 24LC256 поставляется с уже установленными четырьмя битами адреса (1010), которые нельзя изменить. Однако последние три бита адреса можно изменять, и это позволяет нам подключать до восьми микросхем 24LC256 на одну шину I2C. Давайте посмотрим на рисунок ниже, чтобы поподробнее разобраться, как формируется этот адрес:

Для простоты понимания как работает I2C адрес, мы можем игнорировать биты начала (Start) и подтверждения (Acknowledge). Шина I2C работает так: 7-битный адрес передается вместе с битом чтения / записи, который сообщает микросхеме, должна ли она записывать входящие данные или читать.

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

И теперь у нас остались семь средних битов, и, как упоминалось выше, первые четыре бита жестко запрограммированы, и мы не можем их изменить. Следующие три бита (A2, A1, A0) являются важными битами, которые мы можем изменять.

Итак, если мы соединим контакты 1, 2 и 3 микросхемы 24LC256 с GND, то микросхема будет иметь I2C адрес 0x50, а если все эти выводы подключить к Vcc, тогда микросхема будет иметь I2C адрес 0x57. Перебирая все комбинации, мы можем получить 8 адресов от 0x50 до 0x57.

Для упрощения просто соединим все контакты с GND, чтобы получился адрес 0x50.

После подключения адресных выводов аппаратная часть этого руководства завершена. Пора переходить к программному обеспечению!

Некоторые используют подтягивающие резисторы на выводах SCL и SDA Ардуино. Хотя это не повредит схеме, но в них нет необходимости, потому что при инициализации библиотеки Wire.h Ардуино знает, что выводы 4 и 5 будут использоваться для I2C, и в связи с этим активируются встроенные подтягивающие резисторы.

Скетч

Ниже приведен полный код работы с внешней памятью 24LC256. Далее рассмотрим его работу подробнее.

Чтобы использовать интерфейс I2C, нам необходимо подключить стандартную библиотеку Wire Ардуино, поэтому первым делом подключите Wire.h в верхней части скетча. Вы заметите, что сразу после подключения мы определяем переменную с именем disk1 и присваиваем ей шестнадцатеричное значение 0x50 – это адрес нашей памяти. Эта переменная не является обязательной, но она позволяет нам легко изменить адрес, к которому мы хотим получить доступ, не просматривая весь код и не заменяя значение.

Кроме того, если вы планируете добавить более одной микросхемы памяти, проще называть их disk1, disk2 и т. д., а не 0x50, 0x51… что может запутать.

Далее у нас есть функция setup() и функции loop(). В этом руководстве функция loop() оставлена ​​пустой, поэтому мы просто сосредоточимся на функции setup().

Сначала мы инициализируем последовательное соединение, а затем инициируем соединение I2C, вызывая Wire.begin(). Это активирует контакты 4 и 5 для I2C, а также подключает внутренние подтягивающие резисторы.

Затем мы создаем новую переменную для хранения адреса ячейки EEPROM, в которую мы хотим записать (не адрес самой микросхемы EEPROM, а адрес байта, который мы хотим считать / записать). Поскольку эта EEPROM имеет 32 Кбайт памяти, этот адрес может быть любым числом от 0 до 32 767. Мы начнем с адреса 0.

После того, как мы все инициализировали, мы переходим к нашим двум основными функциям: writeEEPROM и readEEPROM, которые фактически выполняют всю основную работу записи / чтения байтов данных.

Давайте сначала начнем с функции writeEEPROM. Эта функция принимает три аргумента: адрес устройства (переменная disk1), адрес памяти EEPROM и байт данных, которые мы хотим записать.

Первый аргумент — это адрес устройства, в память которого мы хотим выполнить запись, в нашем случае у нас только одно устройство (disk1), поэтому мы передаем его.

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

Пример: writeEEPROM (disk1, address, 123) будет записывать десятичное число 123 в «address» (который равен 0) на устройство disk1 (0x50).

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

Сначала мы вызываем функцию Wire.beginTransmission, которая отправляет адрес устройства, для того чтобы микросхема памяти знала, что мы хотим с ней связаться. Затем мы должны отправить адрес ячейки EEPROM, в которую мы хотим записать данные.

Поскольку наша микросхема EEPROM имеет 32 000 ячеек, мы используем два байта (16 бит) для хранения адреса. Но поскольку мы можем отправлять только один байт за раз, то мы должны разделить его.

Первая функция отправки принимает eeaddress и сдвигает биты вправо на восемь. Затем мы выполняем побитовое И, чтобы получить только последние восемь бит. Чтобы понять это рассмотрим это на примере:

Допустим, мы хотим записать в ячейку с адресом 20000 ( 0100 1110 0010 0000 в двоичном формате). Сначала нам нужно отправить MSB (старший бит), поэтому мы должны переместить наш адрес на восемь бит:

0100 1110 0010 0000 (eeaddress)
После сдвига на 8 бит вправо получаем
0100 1110

Теперь у нас есть первая половина адреса, пора получить вторую половину:

0100 1110 0010 0000 (eeaddress)
После побитового И 0xFF с eeaddress мы получаем
0010 0000

В результате этих операций микросхема 24LC256 получает адрес 1001 1100, а затем 0010 0000, который сообщает ей, что она должна сохранить следующий байт в ячейке с адресом 20000. Теперь, когда мы отправили адрес, мы отправляем данные, а затем завершаем процесс, вызывая функцию endTransmission.

Микросхема 24LC256 получит данные и запишет их по этому адресу. Чтобы завершить эту функцию, вы наверное заметили, что добавлена задержка в 5 миллисекунд. Это дает микросхеме время для завершения операции записи. Без этого, если вы попытаетесь выполнить последовательную запись, могут произойти странные вещи.

После того как мы научились сохранять наши данные в EEPROM, пора перейти к функции readEEPROM, которая позволяет считывать данные из микросхемы памяти.

ReadEEPROM принимает два аргумента и возвращает байт (данные). Аргументы, которые принимает ReadEEPROM — это те же первые два аргумента, что и у функции writeEEPROM, адрес устройства и адрес ячейки EEPROM, из которого следует считать данные.

Сначала мы объявляем переменную для хранения байта, который мы собираемся получить. Затем мы начинаем так же, как мы делали с функцией записи, запуская процесс beginTransmission, а затем отправляем адрес устройства, к которому мы хотим получить доступ (это работает точно так же, как функция записи).

Далее мы завершаем передачу. В итоге мы установили связь с 24LC256 с адресом, который нас интересует, так что теперь нам просто нужно запросить и прочитать данные.

Следующая функция requestFrom() отправляет этой микросхеме команду начать отправку данных по указанному выше адресу. Второй аргумент – сколько считать байтов (начиная с этого адреса). Мы запрашиваем только один. Наконец, мы проверяем, есть ли данные на шине I2C, и, если они есть, считываем их в переменную rdata. Возвращаем байт данных и все готово!

Это все, что вам действительно нужно знать, чтобы успешно использовать внешнюю память с Ардуино.

Источник

Работа с динамической памятью

Динамическая память

Чаще всего во время работы мы используем локальные и глобальные переменные: промежуточные вычисления делаем в локальных, объекты классов библиотек создаём глобально и пользуемся ими в программе и так далее. Не углубляясь в программу можно понять, в каком месте доступна конкретная переменная, где её область определения, т.е. где она существует. Если мы видим имя такой переменной в коде – мы с уверенностью можем сказать, что в данном месте программы эта переменная существует. Её значение находится в памяти и мы можем с ним работать напрямую, прочитать или изменить его, а также “измерить” вес этой переменной. Дело в том, что жизненный цикл таких переменных известен заранее, они не могут менять свой размер в процессе работы программы, не могут появиться или исчезнуть в другое время или в другом месте, работа с ними проста и понятна.

Но что делать, если нам нужно например принять данные неизвестного размера? Или нужно использовать несколько условных “библиотек” на глобальной области определения программы, но оперативной памяти для всех не хватит? На помощь приходит динамическая память: мы можем создавать переменные (выделять память) прямо в процессе работы программы и удалять их оттуда. В любое время, в любом месте, как душе угодно.

Распределение памяти

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

Память – это по сути большой массив, каждая ячейка которого имеет свой адрес, адрес растёт слева направо (по картинке выше). Первым идёт Flash, она же программная память, память, в ней хранится код программы. Во время работы программы этот код не меняется (есть способы сделать это, но это не относится к теме урока).

Сегодня нас интересует динамическая память, SRAM, которая на схеме представлена совокупностью синей, зелёной, розовой и оранжевой областей, а также белой областью со стрелочками между розовой и оранжевой. Рассмотрим подробнее:

  • Globals (синий и зелёный) – в этой области живут глобальные и статические переменные. Размер этой области известен на момент запуска программы и не меняется в процессе её выполнения, т.к. глобальные и статические переменные уже объявлены, их размер и количество известны.
  • Stack, он же стек (оранжевый) – в этой области живут локальные переменные и аргументы функций. Размер этой области меняется во время выполнения программы, стек растёт от конца области памяти в сторону уменьшения адресов, навстречу куче (см. стрелку на схеме). Переменные, которые тут живут, называются автоматическими: программа сама выделяет память (при создании локальной переменной) и сама эту память освобождает (локальная переменная удаляется при выходе из функции). Важно: процессор не контролирует размер стека, то есть во время работы стек может врезаться в кучу и перезаписать находящиеся там данные.
  • Heap (розовый), она же куча – из этой области мы можем самостоятельно выделить память под свои нужды. Размер этой области может меняться во время выполнения программы, куча “растёт” в сторону увеличения адресов, слева направо, что показано стрелкой на схеме. Эту память мы контролируем сами: сами выделяем и сами освобождаем. Важно: процессор не даст вам выделить область, если свободной памяти под неё недостаточно, т.е. наползание кучи на стек маловероятно.

Выделение памяти

Для выделения и освобождения динамической памяти “из кучи” у нас есть готовые инструменты. При выделении памяти мы получаем адрес на первый байт выделенной области и его нужно будет хранить в указателе (читайте предыдущий урок про адреса и указатели).

  • malloc(количество) – выделяет количество байт динамической памяти и возвращает адрес на первый байт выделенной области. Если свободной памяти недостаточно для выделения – возвращает “нулевой указатель” – NULL ( nullptr ).
  • free(ptr) – освобождает память, на которую указывает указатель ptr . Освободить можно только память, выделенную при помощи функций malloc() , realloc() или calloc() . В выделяемой области хранится размер этой области (+2 байта), и при освобождении функция free сама знает, какой размер освобождать.
  • new и delete – технически те же самые malloc() и free() , разница в применении (см. пример ниже)

Рассмотрим пример с выделением и освобождением памяти при помощи malloc/free и new/delete. Примеры абсолютно одинаковые с точки зрения происходящего, отличаются только синтаксисом:

malloc-free

Есть ещё две функции: calloc() и realloc() :

  • calloc(количество, размер) – выделяет память под количество элементов с размером размер каждый (в байтах). Тот же malloc, но чуть удобнее использовать: в примере выше мы умножали, чтобы получить нужное количество байт для хранения int malloc(20 * sizeof(int)) , а можно было вызвать calloc(20, sizeof(int)); – заменив знак умножения на запятую.
  • realloc(ptr, размер) – изменяет величину выделенной памяти, на которую указывает ptr, на новую величину, задаваемую параметром размер. Величина размер задается в байтах и может быть больше или меньше оригинала. Возвращается указатель на блок памяти, поскольку может возникнуть необходимость переместить блок при возрастании его размера. В таком случае содержимое старого блока копируется в новый блок и информация не теряется.

new-delete

Динамические объекты

Иногда бывает нужно использовать условную “библиотеку” на большой области определения, но делать это не на всём протяжении работы программы, т.е. иногда выделять объект из памяти, работать с ним, а затем удалять. Под библиотекой я в данном случае подразумеваю класс или структуру, т.к. 99.99% библиотек являются классами (читай урок про классы и объекты). С точки зрения программы, объект – это тоже переменная, просто “комплексная”. Мы всегда можем создать указатель на объект и использовать его динамически (не забываем, что оператор “точка” . превращается в “стрелочку” -> , см. урок про указатели). Абстрактный пример со стандартной библиотекой Servo, в которой объект создаётся динамически, а затем выгружается из памяти при повороте на заданный угол:

Фрагментация

Мы можем зарезервировать себе область памяти, можем её освободить. Что может пойти не так?

  1. Если последовательно несколько раз выделить память, участки будут располагаться друг за другом.
  2. Если освободить участок, выделенный раньше предыдущих – в памяти останется “дырка”: занятые области не сдвигаются на освободившееся место!
  3. Если продолжить выделять память, программа будет примерять новую область сначала на “дырки”, а затем уже на свободную область в куче.
  4. Если неаккуратно обращаться с динамической памятью – эта самая память может закончиться гораздо быстрее, чем ожидалось!

Потерял ключи

Как вы могли видеть из примеров выше – освобождение блока памяти производится по указателю, то есть мы указываем, с какого адреса нужно освобождать память. Это означает, что нам ни в коем случае нельзя терять указатель, иначе мы не сможем освободить память! Это как потерять ключи от дома =) Абстрактный пример:

Существует ли переменная?

Как определить, существует ли на данный момент выделенная переменная и можно ли с ней работать? Очень просто: у нас ведь есть указатель на неё. Если передать указатель в условие, то он покажет true , если адрес ненулевой (переменная существует в памяти), и false – если нулевой (переменная не существует в памяти, обращаться по указателю нельзя). Возвращаясь к примеру с Серво, можно поступить так:

То есть если объект существует (по указателю), то работаем с ним.

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

  • Локально созданный указатель может быть ненулевым. Если при создании указателя локально вы не выделяете память сразу, то лучше задать его нулём, приравняв к NULL или nullptr : int* val = nullptr;
  • При освобождении памяти указатель не сбрасывается в ноль! Делаем это вручную:

Вес динамической переменной

Если зачем-то понадобилось узнать вес динамической переменной, то нужно не перепутать, что измерять: мы работаем с указателем, а у указателя есть значение (тип), на которое он указывает. Например выделим байт памяти: byte* b = new byte;

  • Если измерить как sizeof(b) – результат будет 2 байта (AVR) и 4 байта (esp8266/esp32), потому что это – вес указателя, который зависит от разрядности адресного пространства микроконтроллера, т.е. результат не зависит от типа и веса данных!
  • Если измерить как sizeof(*b) – получим 1 байт, именно столько и весит байт, а мы измеряли размер данных по указателю.

Пакетное управление памятью

Итак, выделять и освобождать память мы научились, теперь рассмотрим несколько инструментов для удобной работы с динамической памятью:

  • memset(ptr, значение, количество) – заполняет область памяти, на которую указывает ptr, байтами значение, в количестве количество штук. Часто используется для задания начальных значений выделенной области памяти. Внимание! Заполняет только байтами, 0.. 255.
  • memcpy(ptr1, ptr2, количество) – переписывает байты из области ptr2 в ptr1 в количестве количество. Грубо говоря переписывает один массив в другой. Внимание! Работает с байтами!

Зачем?

Новичку работа с динамической памятью не понадобится, но знания будут полезны при изучении чужого кода. Также с динамической памятью мы сталкиваемся каждый раз, когда используем String-строки, которые являются динамическими массивами. Удобно, не правда ли?

Источник

Как увеличить память ардуино уно

Arduino.ru

Увеличение RAM memory Ардуины

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

Компутеры тоже десятками покупать предлагаете?

Собственно мне до лампочки у кого сколько денег и на что они тратятся. У меня и RPI есть и кубик 3 и дуня мега 2560 и мапле для экспериментов. Вот сделал контроллер cnc на нано3, думаю вот не переделать ли на мапле или оранж взять — можно будет сделать на 5-6 движков подключение, а то приходится выдумывать тут всякое извращение.

Да, 128 меги у меня тоже есть, одну даже спаял на плату разработки самодельную

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

1284 сейчас можно взять примерно за 510-530 руб. Согласен, не дешево. Но зато теперь уже родной AVR, а мне например STR32 нужно с 0 осваивать.

Нет ну я понимаю взять atmega128 по 50р, там на теже 128к флэш и «всего» 4к ram

Но брать 1284 по 500 ради +12к ram? В чем счастье?)

Кстати дешевле будет взять atmega128 и прилепить внешние 64 или даже 128к через имеющийся интерфейс ram, работать будет почти как родная память (доступ три такта вместо двух)

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

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

stm32 и есть арм)) имел в виду наверно avr

Не так уж и сложно переходить, даже интересно

у меня правда лень не победима, я для себя делаю библиотеку которая одинаково работает что с avr, что с stm8, чуть позже добавлю stm32. Вот сейчас связал через rs485 atmega с stm8s. На stm8s сразу bmp085, dht22, фоторезистор и термистор. Такая «метео» станция. Сам Мк стоит 16р. И в 8к прошивки еще 1.5к свободны

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

В рамках топика — проблема с нехваткой ОЗУ и более никаких «причин». Всё остальное предлагаю оставить «за кадром», а не мерятся длиной потраченного рубля или какой ещё. :)

Я поднял речь именно в сравнении УНО и пр. «недоМК», урезанных сознательно производителем с целью удешевления в конкретных конструкциях по отношению к «полному набору» Мега2560. Что ежели вам не хватает ОЗУ, то вполне можно взять модель постарше и/или воспользоваться x-bus шиной дабы прикрутить «сколько надо» к упрощенной модели ..

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

Собственно предложения «возьмите STM32 и будет вам щастье» .. как ни странно из той же самой оперы .. нежелания ВЫБИРАТЬ конкретного зверька под конкретные нужды .. там тоже ведь «свой зоопарк» не так ли? :)

По нехватке ОЗУ у Атмела: да, моя практика показала что размер встроенного ОЗУ сильно коррелирует с объемом тех задач управления, на которые и был рассчитан этот конкретный зверек. Что для Меги, что для УНЫ но .. памяти хватает на 90% задач.

/* Пробовал делать «слух» на наших микрофонах .. показалось что «вот точно не хватит» .. 8килов .. одна оцифровка даже в 10кгц затребует 10килов на 1 сек. записи .. ан нет! Вполне можно оцифровывать сэмплами в буфер 256 байт, иметь 4 буфера оцифровки для выравнивания скоростей и на лету сворачивать сэмпл в упрощенный БПФ в 20-40 байт и искать ключевые части фонем .. так и не доделал, но в целом решение увидел — даже это влезет! */ (вместо спойлера)

Плюс возможность прикрутить к некоторым зверькам внешнее ОЗУ — решает вопрос на 146%. :)

Переход на STM32 и ваще на 32-х разрядную архитектуру требует совсем ИНЫХ причин .. и вот когда они наступают, то да: такая рекомендация полезна. А все эти «дешевле/дороже» — исключительно для нищих.

Источник

Добавление внешней памяти EEPROM в Ардуино (24LC256)

Очень простой и эффективный способ хранения данных – это использовать внутреннюю память Ардуино. Но это подходит для хранения небольших объемов данных, поскольку в Ардуино встроенная EEPROM имеет размер всего 512 байт.

При работе с более крупными или более сложными проектами нам может потребоваться сохранять дополнительные данные. В связи с этим возникает необходимость использовать внешнюю память, например 24LC256.

Микросхема памяти 24LC256 имеет размер 256 Кбит, что на самом деле составляет 32 Кбайт (262 144 бит / 8 бит = 32 768 байт). Это в 62 раза больше встроенной памяти Ардуино!

Настройка оборудования

В этом примере мы будем использовать микросхему 24LC256 от Microchip. Если вы используете другую микросхему, убедитесь, что требования к выводам и питанию соответствующие, чтобы не повредить микросхему.

Микросхему Microchip 24LC256 можно приобрести в 8-контактном DIP-корпусе. Распиновка 24LC256 довольно проста:

  • вывод питания (8)
  • вывод GND (4)
  • вывод защиты от записи (7)
  • вывод SCL (6)
  • вывод SDA (5)
  • выводы адреса (1,2,3)

Прежде чем мы перейдем к программной части, давайте подключим микросхему 24LC256 к нашей Ардуино.

Используя вышеприведенный рисунок, давайте приступим к подключению микросхемы. Сначала подключите GND и VCC к контактам 4 и 8 соответственно. Далее подключите выводы данных к плате Ардуино. Поскольку мы используем I2C шину, мы будем использовать контакты A4 и A5. Подключите контакт SDA 24LC256 (контакт 5) к контакту A4 Ардуино. Затем подключите SCL (контакт 6) к контакту A5 на Ардуино. Дважды убедитесь, что все подключено правильно, иначе могут произойти странные вещи, если вы их перепутаете.

После того, как выводы данных и питание подключены, у 24LC256 осталось еще четыре неподключенных вывода: вывод WP и три вывода адреса.

Контакт WP обеспечивает защиту от записи. Это позволяет вам контролировать процесс записи данных в EEPROM. Если на этом выводе низкий логический уровень (0), то запись разрешена. Если же на выводе WP будет высокий логический уровень (1), то запись запрещена, но при этом чтение всегда доступно. В рамках этого руководства мы будем записывать в EEPROM, так что вывод WP подключим к GND.

Последние три контакта устанавливают адрес 24LC256, который позволяет идентифицировать конкретную микросхему на I2C шине. Микросхема 24LC256 поставляется с уже установленными четырьмя битами адреса (1010), которые нельзя изменить. Однако последние три бита адреса можно изменять, и это позволяет нам подключать до восьми микросхем 24LC256 на одну шину I2C. Давайте посмотрим на рисунок ниже, чтобы поподробнее разобраться, как формируется этот адрес:

Для простоты понимания как работает I2C адрес, мы можем игнорировать биты начала (Start) и подтверждения (Acknowledge). Шина I2C работает так: 7-битный адрес передается вместе с битом чтения / записи, который сообщает микросхеме, должна ли она записывать входящие данные или читать.

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

И теперь у нас остались семь средних битов, и, как упоминалось выше, первые четыре бита жестко запрограммированы, и мы не можем их изменить. Следующие три бита (A2, A1, A0) являются важными битами, которые мы можем изменять.

Итак, если мы соединим контакты 1, 2 и 3 микросхемы 24LC256 с GND, то микросхема будет иметь I2C адрес 0x50, а если все эти выводы подключить к Vcc, тогда микросхема будет иметь I2C адрес 0x57. Перебирая все комбинации, мы можем получить 8 адресов от 0x50 до 0x57.

Для упрощения просто соединим все контакты с GND, чтобы получился адрес 0x50.

После подключения адресных выводов аппаратная часть этого руководства завершена. Пора переходить к программному обеспечению!

Некоторые используют подтягивающие резисторы на выводах SCL и SDA Ардуино. Хотя это не повредит схеме, но в них нет необходимости, потому что при инициализации библиотеки Wire.h Ардуино знает, что выводы 4 и 5 будут использоваться для I2C, и в связи с этим активируются встроенные подтягивающие резисторы.

Скетч

Ниже приведен полный код работы с внешней памятью 24LC256. Далее рассмотрим его работу подробнее.

Чтобы использовать интерфейс I2C, нам необходимо подключить стандартную библиотеку Wire Ардуино, поэтому первым делом подключите Wire.h в верхней части скетча. Вы заметите, что сразу после подключения мы определяем переменную с именем disk1 и присваиваем ей шестнадцатеричное значение 0x50 – это адрес нашей памяти. Эта переменная не является обязательной, но она позволяет нам легко изменить адрес, к которому мы хотим получить доступ, не просматривая весь код и не заменяя значение.

Кроме того, если вы планируете добавить более одной микросхемы памяти, проще называть их disk1, disk2 и т. д., а не 0x50, 0x51… что может запутать.

Далее у нас есть функция setup() и функции loop(). В этом руководстве функция loop() оставлена ​​пустой, поэтому мы просто сосредоточимся на функции setup().

Сначала мы инициализируем последовательное соединение, а затем инициируем соединение I2C, вызывая Wire.begin(). Это активирует контакты 4 и 5 для I2C, а также подключает внутренние подтягивающие резисторы.

Затем мы создаем новую переменную для хранения адреса ячейки EEPROM, в которую мы хотим записать (не адрес самой микросхемы EEPROM, а адрес байта, который мы хотим считать / записать). Поскольку эта EEPROM имеет 32 Кбайт памяти, этот адрес может быть любым числом от 0 до 32 767. Мы начнем с адреса 0.

После того, как мы все инициализировали, мы переходим к нашим двум основными функциям: writeEEPROM и readEEPROM, которые фактически выполняют всю основную работу записи / чтения байтов данных.

Давайте сначала начнем с функции writeEEPROM. Эта функция принимает три аргумента: адрес устройства (переменная disk1), адрес памяти EEPROM и байт данных, которые мы хотим записать.

Первый аргумент — это адрес устройства, в память которого мы хотим выполнить запись, в нашем случае у нас только одно устройство (disk1), поэтому мы передаем его.

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

Пример: writeEEPROM (disk1, address, 123) будет записывать десятичное число 123 в «address» (который равен 0) на устройство disk1 (0x50).

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

Сначала мы вызываем функцию Wire.beginTransmission, которая отправляет адрес устройства, для того чтобы микросхема памяти знала, что мы хотим с ней связаться. Затем мы должны отправить адрес ячейки EEPROM, в которую мы хотим записать данные.

Поскольку наша микросхема EEPROM имеет 32 000 ячеек, мы используем два байта (16 бит) для хранения адреса. Но поскольку мы можем отправлять только один байт за раз, то мы должны разделить его.

Первая функция отправки принимает eeaddress и сдвигает биты вправо на восемь. Затем мы выполняем побитовое И, чтобы получить только последние восемь бит. Чтобы понять это рассмотрим это на примере:

Допустим, мы хотим записать в ячейку с адресом 20000 ( 0100 1110 0010 0000 в двоичном формате). Сначала нам нужно отправить MSB (старший бит), поэтому мы должны переместить наш адрес на восемь бит:

0100 1110 0010 0000 (eeaddress)
После сдвига на 8 бит вправо получаем
0100 1110

Теперь у нас есть первая половина адреса, пора получить вторую половину:

0100 1110 0010 0000 (eeaddress)
После побитового И 0xFF с eeaddress мы получаем
0010 0000

В результате этих операций микросхема 24LC256 получает адрес 1001 1100, а затем 0010 0000, который сообщает ей, что она должна сохранить следующий байт в ячейке с адресом 20000. Теперь, когда мы отправили адрес, мы отправляем данные, а затем завершаем процесс, вызывая функцию endTransmission.

Микросхема 24LC256 получит данные и запишет их по этому адресу. Чтобы завершить эту функцию, вы наверное заметили, что добавлена задержка в 5 миллисекунд. Это дает микросхеме время для завершения операции записи. Без этого, если вы попытаетесь выполнить последовательную запись, могут произойти странные вещи.

После того как мы научились сохранять наши данные в EEPROM, пора перейти к функции readEEPROM, которая позволяет считывать данные из микросхемы памяти.

ReadEEPROM принимает два аргумента и возвращает байт (данные). Аргументы, которые принимает ReadEEPROM — это те же первые два аргумента, что и у функции writeEEPROM, адрес устройства и адрес ячейки EEPROM, из которого следует считать данные.

Сначала мы объявляем переменную для хранения байта, который мы собираемся получить. Затем мы начинаем так же, как мы делали с функцией записи, запуская процесс beginTransmission, а затем отправляем адрес устройства, к которому мы хотим получить доступ (это работает точно так же, как функция записи).

Далее мы завершаем передачу. В итоге мы установили связь с 24LC256 с адресом, который нас интересует, так что теперь нам просто нужно запросить и прочитать данные.

Следующая функция requestFrom() отправляет этой микросхеме команду начать отправку данных по указанному выше адресу. Второй аргумент – сколько считать байтов (начиная с этого адреса). Мы запрашиваем только один. Наконец, мы проверяем, есть ли данные на шине I2C, и, если они есть, считываем их в переменную rdata. Возвращаем байт данных и все готово!

Это все, что вам действительно нужно знать, чтобы успешно использовать внешнюю память с Ардуино.

Источник

Arduino.ru

Дополнительная flash-память

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

Столкнулся с проблемой нехватки flash-памяти — не хватает места для хранения скетча. Оптимизировал код как можно, а надо еще много всего добавить.

Есть ли внешнии модули, которые увеличивают flash-память? Или можно как-нибудь увеличить место для хранения скетча?

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

Замена микроконтроллера вам нужна, если действительно оптимизировали.

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

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

кстати ,вопрос к тем кто сюда заглянет : можно ли в среде ардуино настроить PROGMEM на работу с внешней энергонезаисимой памятью,по шине I2C или SPI?или как то по другому нативно расширить адресное пространство(не RAM,о примере ардуино на 512КБ ,знаком)

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

Progmem наврядли можно прям вот так с полтычка, иначе давно бы уже все еепромы по i2c в полный рост пользовали. А вот какой-нить драйвер можно, наверное, накатать. Только медленный он будет. Или с доп. буфером, как для SD-карты мутить.

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

EEPROM использовать вообще не проблема. А вот если скетч не влазит — оптимизация, или замена контроллера.

Вообще чистый СИ очень сильно снижает вес программы. Но, как сказал mixail844 , нужно определиться что там у вас за код, и что в нем используется. То что можно подгрузить — на флешку, а код перевести (хотя бы частично) в чистый СИ.

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

zzzzza , и RAM и PROGMEM находятся внутри адресного пространства процессора, а I2C или SPI — нет. Защищенного режима у AVR подобно как в 386+ тоже нет, значит программно прозрачная эмуляция тоже невозможна. Т.е. хранить константы где-то снаружи по I2C или SPI можно (написав для их добывания свои функции), а исполнять код из них — нет.

Могу порекомендовать Мегу 2560 — у нее и flash памяти побольше и при необходимости можно организовать внешнюю память в общем адресном пространстве.

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

Либо переходить на STM или ESP — вот там пямяти на много больше.

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

Спасибо за ответы!

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

Думал о меге, но у нее размер большой. Сейчас думаю между STM и Iskra JS. Больше в пользу Iskra JS, так как побаиваюсь, что памяти STM тоже может не хватить в будущем. Но придется переписывать все на JavaScript. Отсюда вопрос для тех кто сталкивался с микроконтроллерами с AVR процессорами, на которых установлен интерпретатор JavaScript: можно ли как-то писать код на Arduino Wiring?

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

Источник

Adblock
detector