
Управление памятью в маломощных встраиваемых системах
Энергопотребление для разработчиков мобильных систем стало первостепенной задачей наряду с производительностью и дизайном. Как правило, процессоры с самым низким энергопотреблением — это 4-разрядные или 32 кГц процессоры с чрезвычайно низкими циклами питания. Перемещение памяти между программой и SRAM на Arduino или, например, между ядром процессора и Icache в других системах, от 50 до 80% нестабильности мощности во время выполнения может быть связано с трафиком памяти, вызванным переносами между внешней и встроенной памятью.
Чтобы уменьшить влияние передачи памяти, важно с самого начала сосредоточиться на стратегиях, которые отслеживают и сокращают трафик памяти и энергопотребление. Некоторые из таких стратегий включают в себя:
- Размер кэша
- Циклические преобразования
В Arduino, например, стратегия уменьшения передачи памяти должна также включать в себя правильное управление памятью. Arduino Uno имеет 32 КБ Progmem (флэш-память, из которых 0,5 КБ используется для загрузчика), 2 КБ SRAM и 1 КБ памяти EEPROM. Если вам не хватает памяти, программа может неожиданно завершить работу или вести себя странно. Эти проблемы трудно диагностировать без мониторинга. Начиная с Arduino 1.0 макрос F стал доступен.
WString.h:#define F(string_literal) (reinterpret_cast(PSTR(string_literal)))
Макрос F сохраняет строки в стиле C в памяти программы и во время выполнения перемещает эти строки в SRAM по мере необходимости. Вот коммит, который я недавно сделал для библиотеки Adafruit NFCShield, чтобы преобразовать их строки в стиле Serial C (массивы символов) в строки Progmem:
Переписывание библиотеки Adafruit NFCShield для использования макроса F
Проблема с этим подходом заключается в том, что для этого преобразования требуются дополнительные циклы; и эти дополнительные циклы потребляют много энергии. За один раз в SRAM копируется один байт данных. Лучшим подходом является разгрузка как можно большего количества вычислений, ответов и отображаемых значений на удаленный сервер.
Каждый символ представляет собой байт, а завершающий символ '\0', который добавляется к каждой строке в стиле C, является дополнительным байтом. Эта простая строка занимает 19 байт SRAM. Имея всего 2048 байт, вы быстро израсходуете всю доступную SRAM.
char message[] = “This is a message.”;
Существуют важные соображения относительно использования Progmem для строк. Например, Progmem и EEPROM являются энергонезависимыми (информация сохраняется после отключения питания). SRAM является энергозависимой (память будет потеряна при отключении питания); поэтому, если вам нужно, чтобы данные сохранялись между циклами питания, данные должны иметь выделение памяти и адрес памяти Progmem или EEPROM. Кроме того, в Programmem строки не могут быть изменены; однако при копировании в SRAM строки можно изменить.
Во-вторых, знакомство с размерами памяти типов данных и использование наименьшего типа данных может уменьшить трафик памяти. Например, int занимает два байта, а byte использует только один (но хранит меньший диапазон значений). Уменьшение слишком больших переменных может дать ряд преимуществ в производительности. Вот список размеров переменных в байтах:
- логическое значение 1
- символ 1
- беззнаковый символ, байт, uint8_t 1
- инт, короткое 2
- беззнаковое целое, слово, uint16_t 2
- длинный 4
- беззнаковый длинный, uint32_t 4
- поплавок, двойной 4
Оптимизация SRAM
В-третьих, используйте различные транзисторы, чтобы снизить энергопотребление без потери производительности. Регулировка мощности позволяет некоторым спящим транзисторам отключать целые блоки схемы, когда они не используются.
Размер спящего транзистора
В-четвертых, циклические преобразования могут позволить двум массивам совместно использовать одно и то же пространство памяти, уменьшая трафик памяти и экономя циклы энергопотребления за счет выделения памяти. Возьмем массив c[] и массив w[]; при обмене циклами количество чтений памяти будет уменьшено, потому что массив c[] и массив w[] могут совместно использовать пространство памяти.
Циклические преобразования
В-пятых, вычисления с учетом энергопотребления включают снижение активности переключения шины данных Icache между ядром процессора и Icache. Примеры регистров следует использовать для записи частот переходов между метками регистров (кодировками) инструкций, выполняемых в последовательных циклах. ОС поддерживает таблицу преобразований виртуальных адресов в физические адреса.
malloc: выделяет заданное количество байтов и возвращает указатель на них. Возвращает нулевой указатель, если недостаточно памяти.
free: принимает указатель на сегмент памяти, выделенный malloc, и возвращает его для последующего использования программой или операционной системой.
- Оптимизация компилятора для систем с низким энергопотреблением
- Проектирование и исследование памяти для встраиваемых систем с низким энергопотреблением
Удачного кодирования.