Программирование ARM ESP32-C3: минимизация размера двоичного кода Sun, November 10 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.


ESP32-C3: минимизация размера двоичного кода Печать
Добавил(а) microsin   

Система сборки ESP-IDF [3] компилирует все исходные коды проекта и компонентов ESP-IDF, однако в конечный двоичный файл исполняемой прошивки попадают только реально используемые объекты программы. В некоторых случаях необходимо уменьшить общий объем бинарника firmware (например, чтобы программа приложения поместилась в выделенный объем доступного размера flash).

Первый шаг для уменьшения общего размера бинарного кода firmware - определить, что в него входит, что увеличивает его размер.

[Определение статических размеров]

Чтобы оптимизировать как размер двоичного образа firmware, необходимо выяснить количество статически выделенной памяти RAM (под сегменты "data", "bss"), памяти кода (сегмент "text") и памяти данных только для чтения and ("rodata") в вашем проекте.

С помощью скрипта idf.py и его команд size, size-components и size-files можно узнать общую информацию по использованию памяти в проекте:

$ idf.py size
...
Total sizes:
 DRAM .data size:   11584 bytes
 DRAM .bss  size:   19624 bytes
Used static DRAM:       0 bytes (      0 available, nan% used)
Used static IRAM:       0 bytes (      0 available, nan% used)
Used stat D/IRAM:  136276 bytes ( 519084 available, 20.8% used)
      Flash code:  630508 bytes
    Flash rodata:  177048 bytes
Total image size:~ 924208 bytes (.bin may be padded larger)

Примечание: можно добавить -DOUTPUT_FORMAT=csv или -DOUTPUT_FORMAT=json, чтобы получить эту информацию в формате CSV или JSON.

Этот вывод разбивает размер всех всех статических регионов памяти бинарника firmware на секции:

DRAM .data size статически выделенное RAM, которое назначено для ненулевых значений в момент запуска программы (startup). Эта область использует как пространство RAM (DRAM) runtime, так и пространство в двоичном коде файла образа firmware (данные из образа во flash во время процесса startup копируются в область RAM).

DRAM .bss size статически выделенное RAM, которое обнуляется при startup. Эта область использует RAM (DRAM) runtime, но не занимает какое-либо пространство в двоичном коде файла образа firmware (код startup просто записывает в эту область RAM нули).

Used static DRAM, Used static IRAM - эти опции сохранены для совместимости с ESP32 target, и в настоящее время считываются как 0.

Used stat D/IRAM - это общее использование внутреннего RAM, сумма статических областей DRAM .data + .bss, и также статической памяти IRAM (Instruction RAM), используемой приложением для исполняемого кода. Доступный размер - это предполагаемый объем DRAM, который доступен runtime как память кучи (heap). Из-за того, что накладываются дополнительные накладные расходы на метаданные и ограничения реализации, и выделения кучи происходит кодом ESP-IDF в момент startup, актуальный свободный размер кучи будет меньше, чем этот доступный размер.

Flash code это общий размер выполняемого кода, который запускается из кэша flash (IROM). Это использует область в двоичном файле firmware.

Flash rodata это общий размер данных только для чтения, загружаемых из кэша flash (DROM). Это использует область в двоичном файле firmware.

Total image size оцененный общий размер двоичного файла firmware, в который входит сумма всех секций (типов областей) памяти, кроме секции .bss.

Команда idf.py size-components. Суммарный вывод занимаемой памяти команды idf.py size не позволяет определить, какой из компонентов больше всего расходует память. Для этой цели полезна команда size-components:

$ idf.py size-components
...
Total sizes:
 DRAM .data size:   14956 bytes
 DRAM .bss  size:   15808 bytes
Used static DRAM:   30764 bytes ( 149972 available, 17.0% used)
Used static IRAM:   83918 bytes (  47154 available, 64.0% used)
      Flash code:  559943 bytes
    Flash rodata:  176736 bytes
Total image size:~ 835553 bytes (.bin may be padded larger)
Per-archive contributions to ELF file:
            Archive File DRAM .data & .bss & other   IRAM   D/IRAM Flash code & rodata   Total
           libnet80211.a       1267   6044       0   5490        0     107445    18484  138730
               liblwip.a         21   3838       0      0        0      97465    16116  117440
            libmbedtls.a         60    524       0      0        0      27655    69907   98146
         libmbedcrypto.a         64     81       0     30        0      76645    11661   88481
                 libpp.a       2427   1292       0  20851        0      37208     4708   66486
                  libc.a          4      0       0      0        0      57056     6455   63515
                libphy.a       1439    715       0   7798        0      33074        0   43026
     libwpa_supplicant.a         12    848       0      0        0      35505     1446   37811
           libfreertos.a       3104    740       0  15711        0        367     4228   24150
          libnvs_flash.a          0     24       0      0        0      14347     2924   17295
          libspi_flash.a       1562    294       0   8851        0       1840     1913   14460
         libesp_system.a        245    206       0   3078        0       5990     3817   13336
            libesp-tls.a          0      4       0      0        0       5637     3524    9165
[... для сокращения списка некоторые строки были удалены ...]
            libesp_rom.a          0      0       0    112        0          0        0     112
                libcxx.a          0      0       0      0        0         47        0      47
                   (exe)          0      0       0      3        0          3       12      18
             libesp_pm.a          0      0       0      0        0          8        0       8
            libesp_eth.a          0      0       0      0        0          0        0       0
               libmesh.a          0      0       0      0        0          0        0       0

Первые строки этого вывода такие же, как и у команды idf.py size. После этого идет таблица "библиотека занимаемые_области_файла_ELF". Эта информация показывает, какую долю конечного двоичного файла занимает каждая библиотека (static library archive, статический библиотечный архив).

Обычно один статический библиотечный архив собирается для каждого компонента, хотя некоторые двочные библиотеки подключаются в определенный компонент (например, libnet80211.a включен в компонент esp_wifi). В этом списке можно также увидеть библиотеки тулчейна, такие как libc.a и libgcc.a, они предоставляют Standard C/C++ Library и встроенный в тулчейн функционал.

Если ваш проект простой, и в нем присутствует только компонент "main" component, то весь код проекта покзывается в libmain.a. Если ваш проект подключает свои собственные компоненты (см. [3]), то каждый из них будет показан в отдельной строке.

Отображенная таблица отсортирована в порядке убывания общего занимаемого размера в выходном двоичном файле (последний столбец flash_total). Столбцы таблицы:

DRAM .data, .bss и другие - содержат секции .data и .bss, такие же как и в общей показанной информации (статические инициализируемые данными и инициализируемые нулем переменные, которые уменьшают общее количество доступной runtime памяти RAM, но .bss не занимает место в файле образа firmware). "Другие" это любые пользовательские типы секций, которые также могут расходовать RAM.

IRAM0 - то же самое, что было в общей таблице (код, линкованный для выполнения из IRAM, использует место в двоичном файле и также уменьшает место DRAM, доступное runtime для кучи).

Flash code и rodata - то же самое, чтобы было в общей таблице, IROM и DROM доступны из кэша flash, и занимают место в двоичном файле.

Команда idf.py size-files. Для дополнительных подробностей запустите команду idf.py size-files, чтобы получить информацию о том, сколько места занимает код в каждом исходном файле. Каждая строка вывода соответствует одному файлу исходного кода.

$ idf.py size-files
...
Total sizes:
 DRAM .data size:   14956 bytes
 DRAM .bss  size:   15808 bytes
Used static DRAM:   30764 bytes ( 149972 available, 17.0% used)
Used static IRAM:   83918 bytes (  47154 available, 64.0% used)
      Flash code:  559943 bytes
    Flash rodata:  176736 bytes
Total image size:~ 835553 bytes (.bin may be padded larger)
Per-file contributions to ELF file:
             Object File DRAM .data & .bss & other   IRAM   D/IRAM Flash code & rodata   Total
     x509_crt_bundle.S.o          0      0       0      0        0          0    64212   64212
                wl_cnx.o          2   3183       0    221        0      13119     3286   19811
           phy_chip_v7.o        721    614       0   1642        0      16820        0   19797
       ieee80211_ioctl.o        740     96       0    437        0      15325     2627   19225
                    pp.o       1142     45       0   8871        0       5030      537   15625
      ieee80211_output.o          2     20       0   2118        0      11617      914   14671
         ieee80211_sta.o          1     41       0   1498        0      10858     2218   14616
        lib_a-vfprintf.o          0      0       0      0        0      13829      752   14581
       lib_a-svfprintf.o          0      0       0      0        0      13251      752   14003
             ssl_tls.c.o         60      0       0      0        0      12769      463   13292
             sockets.c.o          0    648       0      0        0      11096     1030   12774
                 nd6.c.o          8    932       0      0        0      11515      314   12769
       phy_chip_v7_cal.o        477     53       0   3499        0       8561        0   12590
                    pm.o         32    364       0   2673        0       7788      782   11639
        ieee80211_scan.o         18    288       0      0        0       8889     1921   11116
      lib_a-svfiprintf.o          0      0       0      0        0       9654     1206   10860
       lib_a-vfiprintf.o          0      0       0      0        0      10069      734   10803
          ieee80211_ht.o          0      4       0   1186        0       8628      898   10716
       phy_chip_v7_ana.o        241     48       0   2657        0       7677        0   10623
              bignum.c.o          0      4       0      0        0       9652      752   10408
              tcp_in.c.o          0     52       0      0        0       8750     1282   10084
                   trc.o        664     88       0   1726        0       6245     1108    9831
               tasks.c.o          8    704       0   7594        0          0     1475    9781
          ecp_curves.c.o         28      0       0      0        0       7384     2325    9737
                 ecp.c.o          0     64       0      0        0       8864      286    9214
      ieee80211_hostap.o          1     41       0      0        0       8578      585    9205
                  wdev.o        121    125       0   4499        0       3684      580    9009
             tcp_out.c.o          0      0       0      0        0       5686     2161    7847
                 tcp.c.o          2     26       0      0        0       6161     1617    7806
       ieee80211_input.o          0      0       0      0        0       6797      973    7770
                 wpa.c.o          0    656       0      0        0       6828       55    7539
[... дополнительные строки удалены ...]

После общей информации об используемых размерах печатается информация "объектный_файл занимаемые_области_файла_ELF".

Здесь столбцы те же самые, что были показаны в команде idf.py size-components, но на этот раз показанный занимаемый размер в двоичном файле показан строками, относящимися к конкретному объектному файлу.

Например, здесь мы видим, что x509_crt_bundle.S.o занимает 64212 байт от общего размера firmware, из которых все байты относятся к секции .rodata в памяти flash. Таким образом, мы можем определить, что это приложение использует функцию ESP x509 Certificate Bundle, и если этот функционал не использовать, то это позволит экономить существенную часть размера firmware.

Некоторые объектные файлы линкованы из двоичных библиотек, и поэтому их нельзя отнести к соответствующему исходному файлу. Чтобы найти, какому компоненту принадлежит исходный файл, обычно можно просмотреть дерево файлов исходного кода ESP-IDF, либо каталог build проекта, а также просмотреть содержимое Linker Map File, где будет показан полный путь.

Сравнение двух бинарников. Если были сделаны некоторые изменения, которые повлияли на размер двоичного файла, то можно использовать инструмент ESP-IDF, чтобы разобраться, какие стали различия по размеру. Эту операцию выполняет другая утилита idf_size.py.

Чтобы выполнить сравнение, сначала найдите в директории build файл карты памяти, сгенерирванный линкером (map-файл). Он носит имя PROJECTNAME.map. Утилита idf_size.py производит свой анализ на основ выходного map-файла линкера. Чтобы выполнить сравнение с другим бинарником, вам также понадобится его соответствующий map-файл, сохраненный из каталога build.

Например, чтобы сравнить две сборки, одну с настройкой оптимизации по умолчанию, когда опция CONFIG_COMPILER_OPTIMIZATION установлена в "Debug (-Og)", и другой сборки, где опция конфигурации установлена в "Optimize for size (-Os)":

$ $IDF_PATH/tools/idf_size.py --diff build_Og/https_request.map build_Os/https_request.map
< CURRENT> MAP file: build_Os/https_request.map
< REFERENCE> MAP file: build_Og/https_request.map
Difference is counted as < CURRENT> - < REFERENCE>, i.e. a positive number means that < CURRENT> is larger.
Total sizes of < CURRENT>:                               < REFERENCE> Difference
 DRAM .data size:   14516 bytes                                 14956       -440
 DRAM .bss  size:   15792 bytes                                 15808        -16
Used static DRAM:   30308 bytes (150428 available, 16.8% used)  30764       -456 ( +456 available, +0 total)
Used static IRAM:   78498 bytes ( 52574 available, 59.9% used)  83918      -5420 (+5420 available, +0 total)
      Flash code:  509183 bytes                                559943     -50760
    Flash rodata:  170592 bytes                                176736      -6144
Total image size:~ 772789 bytes (.bin may be padded larger)    835553     -62764

Мы здесь в столбце "Difference" мы можем увидеть, что изменение настройки позволило съэкономить более 60 килобайт памяти программ (строка "Total image size") и больше 5 кбайт RAM (строка Used static IRAM).

Также можно использовать режим "diff", чтобы вывести таблицу различий на уровне компонентов (static library archive):

$IDF_PATH/tools/idf_size.py --archives --diff build_Og/https_request.map build_Oshttps_request.map

И также на уровне отдельных исходных файлов:

$IDF_PATH/tools/idf_size.py --files --diff build_Og/https_request.map build_Oshttps_request.map

Примечание: чтобы получить результат вывода в формате JSON или CSV, используйте idf_size.py с опцией --format. Назначение других опций (наподобие записи в выходной файл) см. с помощью опции --help.

Как посмотреть размер, когда запуск линкера был неудачным. Если статической памяти использовалось слишком много, то линкер не сможет произвести генерацию двоичного файла из файлов объектного кода с выводом ошибки, что сегмент данных DRAM не помещается в доступную оперативную память, регион iram0_0_seg переполнился на 44 байта, или что-то подобное.

В этих случаях команда idf.py не сработает. Однако можно запустить idf_size.py вручную, чтобы просмотреть частичное использование статической памяти (использование памяти не будет показано для переменных, которые не удалось разместить в памяти, поэтому утилита покажет некоторое свободное пространство).

В качестве аргумента укажите map-файл, который находится в директории сборки (build/имяпроекта.map):

$IDF_PATH/tools/idf_size.py build/project_name.map

Также можно посмотреть вывод, эквивалентный командам size-components или size-files утилиты idf.py:

$IDF_PATH/tools/idf_size.py --archives build/project_name.map
$IDF_PATH/tools/idf_size.py --files build/project_name.map

Разбор содержимого карты памяти линкера (Linker Map File) весьма продвинутый метод анализа, и он может быть очень полезен. Пока что чтение этой врезки можно пропустить, перейдя напрямую к следующему разделу "Уменьшение общего размера", чтобы при необходимости вернуться к описанному здесь методу позже.

Утилита анализа idf.py size работает путем парсинга результата работы GNU binutils "linker map file", который является сводкой всего того, что делал линкер, когда создавал конечный двоичный файл образа firmware.

Map-файлы линкера сами по себе это простые текстовые файлы, которые можно просто прочитать и попытаться понять, что же было сделано линкером. Однако эти файлы обычно очень сложные и длинные - часто размером 100000 или больше строк!

Map-файл сам по себе разбит на части, и у каждой части есть заголовок. Эти части следующие:

· Библиотеки (archive), подключенные для удовлетворения ссылки из файла на символ. Это показывает вам: для каждого объектного файла, подключенного в процесс линковки, какой символ (функция или переменная) искал линкер, когда он подключил этот объектный файл. Если вам интересно, почему какой-то файл объекта, в частности, был включен в двоичный файл, эта часть может дать подсказку. Эта часть может использоваться вместе таблицей перекрестных ссылок (Cross Reference Table), находящейся в конце файла. Обратите внимание, что не каждый объектный файл, показанный в этом списке, подключается в конечный двоичный файл, некоторые вместо этого попадают в список отбрасываемых входных секций (Discarded input sections).

· Allocating common symbols - это список (некоторых) глобальных переменных вместе с их размерами. Общие символы (common symbols) имеют особое значение в двоичных файлах ELF, однако ESP-IDF их не очень использует.

· Discarded input sections - эти секции были прочитаны линкером как часть объектного файла, который должен быть связан с конечным двоичным файлом, но на эти объекты (функции, переменные) нигде не было ссылок, поэтому они были выброшены из конечного двоичного файла. Для системы программирования ESP-IDF этот список может быть очень длинным, поскольку компилируется каждая функция и статическая переменная в уникальную секцию, чтобы минимизировать размер конечного двоичного файла (в частности, ESP-IDF использует опции компилятора -ffunction-sections, -fdata-sections, и опцию линкера --gc-sections). Элементы, упомянутые в этом списке, не занимают место в конечном двоичном файле.

· Memory Configuration, Linker script and memory map. Эти две части идут вместе. Некоторые выходные данные поступают напрямую из командной строки линкера и файла настроек линкера (Linker Script), и то, и другое предоставляется системой сборки [3]. Linker Script частично генерируется из проекта ESP-IDF, с использованием функционала Linker Script Generation.

По мере просмотра выходных данных Linker Script и части карты памяти (memory map) вы можете увидеть каждый символ (функцию или статическую переменную), которые были линкованы в конечный двоичный файл, вместе с его адресом (в виде HEX-значения из 16 цифр), его длиной (также в HEX), а также библиотекой и объектным файлом, откуда они были взяты (по этой последней информации можно определить компонент и исходный файл).

После всех выходных секций, которые занимают место в конечном файле .bin, карта памяти (memory map) также включает некоторые секции в ELF-файле, которые используются только для отладки (ELF-секции .debug_*, и т. п.). Они не занимают место в конечном двоичном файле. Вы можете заметить, что адрес этих символов очень низкий (начинается от 0x0000000000000000 и растет вверх).

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

Примечание: к сожалению, Cross Reference Table включает не только символы, которые попали в конечный бинарник. Она также включает символы, которые были в отброшенных секциях. Поэтому если здесь что-то показано, то это не означает, что оно было включено в конечный бинарник - это нужно проверять отдельно.

Файл карты памяти линкера (Linker Map File) генерируется линкером GNU binutils "ld", не системой ESP-IDF. Дополнительную информацию по формату map-файла линкера вы можете найти в Интернете. Это краткое резюме было составлено, в частности, с точки системы сборки ESP-IDF.

[Уменьшение общего размера]

Следующие опции конфигурации уменьшат размер конечного бинарника в любом проекте ESP-IDF:

· Установка CONFIG_COMPILER_OPTIMIZATION в "Optimize for size (-Os)". Во многих случаях "Optimize for performance (-O2)" также уменьшит размер бинарника в сравнении с настройкой по умолчанию. Имейте в виду, что если код C или C++ содержит области с неопределенной заранее последовательностью действий (C/C++ Undefined Behaviour), то повышение уровня оптимизации компилятора поможет выявить баги, которые иначе не проявляются.

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

· Установка CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL в "Silent". Это отключает компиляцию выделенных строк assert и имена исходных файлов, где они использовались, чтобы показать, где мог сработать каждый assert. В этом случае мы лишаемся удобства быстрого нахождения места ошибки в коде, где сработал assert, однако все еще остается возможность найти ошибку assert в коде путем анализа адреса памяти, где сработал assert (место в исходном коде можно найти с помощью этого абсолютного адреса, если просмотреть выходной map-файл линкера).

· Помимо опции CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL, вы можете запретить или сделать тихими срабатывания assert для компонента HAL отдельно, путем установки CONFIG_HAL_DEFAULT_ASSERTION_LEVEL. Следует отметить, что ESP-IDF понижает уровень вывода HAL assert в загрузчике (bootloader), чтобы его сообщения assert не выводились, даже если CONFIG_HAL_DEFAULT_ASSERTION_LEVEL установлена на полный вывод сообщений assert. Это сделано для уменьшения размера загрузчика.

· Установка CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT. Это удалит специальные сообщения об ошибках для определенных внутренних ESP-IDF макросов проверки ошибок. Установка этой опции может затруднить поиск ошибок в некоторых ситуациях при чтении вывода лога.

· Если бинарник должен работать только в определенной ревизии (ревизиях) кристалла ESP32-C3, то повышение CONFIG_ESP32C3_REV_MIN, чтобы она совпадала с определенными ревизиями, может привести к уменьшению размера бинарника. Это верно, в частности, если установить для ESP32-C3 минимальную ревизию 3 и использовать Wi-Fi, поскольку некотороя часть функционала была перемещена в код ROM.

Замечание: ревизию используемого кристалла можно узнать по маркировке чипа (см. даташит), а также из UART-вывода загрузчика первого уровня (ROM bootloader), когда запускается команда idf.py flash:

esptool.py v3.3-dev
Serial port /dev/ttyUSB0
Connecting....
Chip is ESP32-C3 (revision 3)
Features: Wi-Fi
Crystal is 40MHz
MAC: 7c:df:a1:b3:8f:04
Uploading stub...

· Не разрешайте опции CONFIG_COMPILER_CXX_EXCEPTIONS, CONFIG_COMPILER_CXX_RTTI, или установите CONFIG_COMPILER_STACK_CHECK_MODE в Overall. Все эти опции по умолчанию запрещены, однако они сильно влияют на размер бинарника.

· Запрет CONFIG_ESP_ERR_TO_NAME_LOOKUP удалит таблицу поиска (lookup table), применяемую для трансляции значений ошибок в удобочитаемые имена (см. описание обработки ошибок ESP-IDF [4]) в файлах лога, и т. п. Это несколько сократит размер бинарника, однако теперь значения ошибок будут печататься только как целые числа.

· Установка CONFIG_ESP_SYSTEM_PANIC в "Silent reboot" немного сократит бинарник, однако это рекомендуется только если вывод UART для отладки не используется.

· Установка CONFIG_COMPILER_SAVE_RESTORE_LIBCALLS для уменьшения размера бинарника путем замены inline прологов/эпилогов с библиотечными вызовами.

· Если бинарник приложения использует одну версию безопасности компонента protocomm, то поддержка других версий может быть запрещена, чем может быть уменьшен размер кода. Поддержка может быть запрещена через опции CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0, CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1 или CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2 соответственно.

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

[Целевые оптимизации]

Следующие оптимизации размера бинарника применимы к определенному компоненту или функционалу.

Wi-Fi

· Запрет CONFIG_ESP_WIFI_ENABLE_WPA3_SAE уменьшит размер бинарника, если не нужна поддержка WPA3 (имейте в виду, что наличие WPA3 обязательно для сертификации новых устройств Wi-Fi).

· Запрет CONFIG_ESP_WIFI_SOFTAP_SUPPORT уменьшит размер бинарника, если не нужна поддержка точки доступа (soft-AP).

Bluetooth NimBLE. Если используется NimBLE Bluetooth Host, то следующие модификации могут уменьшить размер бинарника:

· Установка в 1 опции CONFIG_BT_NIMBLE_MAX_CONNECTIONS, если нужно поддерживать только одно соединение BLE.

· Запрет либо CONFIG_BT_NIMBLE_ROLE_CENTRAL (главное устройство сети BLE), либо CONFIG_BT_NIMBLE_ROLE_OBSERVER (обозреватель сети BLE), если эти роли не нужны.

· Уменьшение CONFIG_BT_NIMBLE_LOG_LEVEL может уменьшить размер бинарника. Обратите внимание, что если был уменьшено общий уровень лога, как это было описано выше, то это также уменьшит уровень лога NimBLE.

lwIP IPv6

· Установка CONFIG_LWIP_IPV6 в false уменьшит размер стека lwIP TCP/IP ценой того, что будет оставлена только поддержка IPv4.

Примечание: IPv6 требуется некоторым компонентам, таким как coap и ASIO. Эти компоненты будут недоступны, если IPV6 запрещен.

lwIP IPv4

· Если соединения IPv4 не нужны, то установка CONFIG_LWIP_IPV4 в false уменьшит размер стека lwIP, оставив в нем только поддержку стека IPv6 TCP/IP.

Примечание: перед запретом поддержки IPv4 учтите, что IPv6 работает не применяются повсеместно, и это должно поддерживаться в локальной сети, т. е. к примеру вашим провайдером Интернета, или при использовании ограниченных параметров локальной сети.

Форматирование Newlib nano. По умолчанию ESP-IDF использует newlib "full" форматирование для ввода/вывода (printf, scanf, и т. д.).

Разрешение опции конфигурации CONFIG_NEWLIB_NANO_FORMAT переключит newlib проекта на режим форматирования "nano". Это уменьшит размер кода, и большая часть кода форматирования будет использоваться из ESP32-C3 ROM.

Точная экономия зависит от функций, которые использует firmware, но обычно код уменьшается на 25 .. 50 килобайт.

Разрешение форматирования Nano уменьшает использование стека каждой функцией, которая вызывает printf() или другие функции форматирования строки, см. раздел "Reducing Stack Sizes" статьи [5].

Форматирование Nano не поддерживает 64-битные целые числа или возможности форматирования C99. Для полного списка ограничений см. --enable-newlib-nano-formatted-io в файле Newlib README [6].

Функции mbedTLS. В menuconfig разделе Component Config -> mbedTLS есть несколько опций по настройке функционала mbedTLS, которые по умолчанию разрешены, однако могут быть запрещены для экономии места под код. Вот эти опции:

· CONFIG_MBEDTLS_HAVE_TIME.
· CONFIG_MBEDTLS_ECDSA_DETERMINISTIC.
· CONFIG_MBEDTLS_SHA512_C.
· CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS.
· CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS.
· CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION.
· CONFIG_MBEDTLS_SSL_ALPN.
· CONFIG_MBEDTLS_SSL_RENEGOTIATION.
· CONFIG_MBEDTLS_CCM_C.
· CONFIG_MBEDTLS_GCM_C.
· CONFIG_MBEDTLS_ECP_C (альтернатива: оставьте эту опцию разрешенной, но запретите при этом некоторые эллиптические кривые, перечисленные в подменю).
· Поменяйте CONFIG_MBEDTLS_TLS_MODE, если не нужна функциональность и сервера, и клиента.
· Рассмотрите запрет некоторых вариантов шифрования (cipher suites), перечисленных в подменю "TLS Key Exchange Methods" (например CONFIG_MBEDTLS_KEY_EXCHANGE_RSA).

Текст подсказки по каждой опции даст больше информации для конфигурирования.

Важное замечание: настоятельно не рекомендуется запрещать все эти опции mbedTLS. Запрещайте только опции, функционал которых четко понимаете, и при этом уверены, что они не нужны в приложении. В частности:

· Убедитесь, что все серверы TLS, к которым устройство подключается, по-прежнему могут использоваться. Если сервер управляется сторонней организацией или облачным сервисом, то рекомендуется обеспечить, чтобы firmware поддерживало как минимум 2 поддерживаемых метода шифрования (cipher suites) для случая, когда при будущем обновлении один из методов будет запрещен.

· Убедитесь, что любой клиент TLS, который подключается к устройству, все еще может подключаться через поддерживаемые/рекомендуемые cipher suites. Обратите внимание, что будущие версии операционных систем клиента могут удалить поддержку некторых функций, так что для надежности рекомендуется оставить поддержку нескольких cipher suites или алгоритмов.

В зависимости от сторонних клиентов или серверов всегда уделяйте внимание оповещениям о будущих изменениях в поддерживаемых функциях TLS. Иначе устройство ESP32-C3 может оказаться недоступным, если поддержка TLS поменяется.

Примечание: не все комбинации опций конфигурации mbedTLS времени компиляции были протестированы в ESP-IDF. Если вы обнаружите, что какая-то комбинация настроек не компилируется, или работает как ожидалось, то выложите об этом багрепорт на GitHub.

VFS. Виртуальная файловая система в ESP-IDF [7] позволяет нескольким драйверам файловой системы и драйверам периферийных устройств, которые могут работать в режиме файла, быть доступными для стандартных функций ввода/вывода (open, read, write, и т. д.) и библиотечных функций C (fopen, fread, fwrite, и т. д.). Когда файловая система или драйвер периферийного устройства, работающий как файл, не используется в приложении, то этот функционал может быть запрещен полностью или частично. Компонент VFS предоставляет следующие опции конфигурации:

· CONFIG_VFS_SUPPORT_TERMIOS — может быть запрещена, если приложение не использует семейство функций termios. В настоящее время эти функции реализованы только для драйвера UART VFS. Большинство приложений могут запретить эту опцию, что уменьшит размер кода примерно на 1.8 килобайт.

· CONFIG_VFS_SUPPORT_SELECT — может быть запрещена, если приложению не нужно использовать функцию select с дескрипторами файла. В настоящий момент только драйверы UART и eventfd VFS реализуют поддежку select. Обратите внимание, что когда эта опция запрещена, select все еще может использоваться для дескрипторов файла socket. Запрет этой опции уменьшит размер кода примерно на 2.7 килобайт.

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

· CONFIG_VFS_SUPPORT_IO — может быть запрещена, если приложение не использует фаловые системы или драйверы периферийных устройств, работающие как файлы. Это полностью запретит весь функционал VFS, включая три упомянутые выше опции. Когда эта опция запрещена консоль использовать не получится. Обратите внимание, что приложение все еще может использовать функции стандартного ввода/вывода с дескрипторами файла socket, когда эта опция запрещена. В сравнении с конфигурацией по умолчанию, запрет этой опции уменьшит размер кода примерно на 9.4 килобайт.

[Размер загрузчика]

Этот документ затрагивает только описание оптимизации размера бинаника приложения ESP-IDF, но не загрузчика второго уровня (ESP-IDF Second stage bootloader).

Подробнее про процесс запуска приложения и для описания, что влияет на размер загрузчика, см. [8, 9].

[Размер двоичного кода IRAM]

Если размер секции IRAM бинарника слишком велика, то эту проблему можено решить путем уменьшения использования памяти под инструкции в оперативной памяти (IRAM). См. раздел "Optimizing IRAM Usage" документации [5].

[Ссылки]

1. ESP-IDF Minimizing Binary Size site:espressif.com.
2. ESP32-C3: оптимизация скорости работы.
3. ESP-IDF Build System.
4. ESP-IDF Error Handling site:espressif.com.
5. ESP-IDF Minimizing RAM Usage site:espressif.com.
6. README for newlib release site:sourceware.org.
7. ESP VFS: виртуальная файловая система.
8. ESP32: процесс запуска приложения.
9. ESP32 Bootloader.

 

Добавить комментарий


Защитный код
Обновить

Top of Page