Данная статья представляет собой более-менее “читабельный” перевод раздела 4.5 ESP-IDF Programming Guide на конец ноября 2024 г.
Двухэтапный загрузчик ESP-IDF выполняет следующие функции:
- Минимальная начальная настройка внутренних модулей;
- Инициализация функций Flash Encryption и/или Secure Boot, если они задействованы;
- Выбор раздела приложения для загрузки на основе таблицы разделов и ota_data (если есть);
- Загрузка этого образа в оперативную память (IRAM и DRAM) и передача управления образу, который был только что загружен.
Процесс запуска выглядит следующим образом:
- Загрузчик первого этапа (который находится в ROM ESP32 (не flash)) загружает образ загрузчика второго этапа в ОЗУ (IRAM и DRAM) со смещения флэш-памяти 0x1000.
- Загрузчик второго этапа загружает таблицу разделов и образ основного приложения из флэш-памяти. Основное приложение включает в себя как сегменты ОЗУ, так и сегменты ReadOnly, сопоставленные через кэш флэш-памяти.
- Выполняется запуск приложения. В этот момент запускаются второе ядро ESP32 (если есть) и планировщик FreeRTOS, который затем запускает main_task, что приводит к выполнению app_main.
Совместимость загрузчиков разных версий
Рекомендуется своевременно обновлять ESP-IDF до новых версий, когда они выпускаются. Процесс обновления OTA (по воздуху) может прошивать новые приложения в рабочих условиях, но не может прошивать новый загрузчик. По этой причине загрузчик всегда поддерживает загрузку приложений, созданных из новых версий ESP-IDF. Но загрузчик не поддерживает загрузку приложений, созданных из старых версий ESP-IDF. При обновлении ESP-IDF вручную на существующем продукте, которому может потребоваться понижение версии приложения до более старой версии, продолжайте использовать также старый двоичный файл загрузчика ESP-IDF.
Примечание. При тестировании обновления OTA для существующего работающего продукта всегда тестируйте его с использованием того же двоичного файла загрузчика ESP-IDF, который был развернут на устройстве.
До ESP-IDF V2.1
Загрузчики, созданные на основе очень старых версий ESP-IDF (до ESP-IDF V2.1), выполняют меньше настроек оборудования, чем новые версии. При использовании загрузчика из этих ранних версий ESP-IDF и сборке нового приложения включите параметр конфигурации CONFIG_APP_COMPATIBLE_PRE_V2_1_BOOTLOADERS.
До ESP-IDF V3.1
Загрузчики, созданные на основе версий ESP-IDF до V3.1, не поддерживают контрольные суммы MD5 в двоичном файле таблицы разделов. При использовании загрузчика из этих версий ESP-IDF и сборке нового приложения включите параметр конфигурации CONFIG_APP_COMPATIBLE_PRE_V3_1_BOOTLOADERS.
До ESP-IDF V5.1
Загрузчики, созданные из версий ESP-IDF до V5.1, не поддерживают CONFIG_ESP_SYSTEM_ESP32_SRAM1_REGION_AS_IRAM. При использовании загрузчика из этих версий ESP-IDF и создании нового приложения не следует использовать эту опцию.
Конфигурация SPI Falsh
Каждый .bin файл приложения или загрузчика ESP-IDF содержит заголовок с параметрами CONFIG_ESPTOOLPY_FLASHMODE, CONFIG_ESPTOOLPY_FLASHFREQ, CONFIG_ESPTOOLPY_FLASHSIZE, встроенными в него. Они используются для настройки SPI флэш-памяти во время загрузки.
Загрузчик первой стадии (ПЗУ) считывает информацию заголовка загрузчика второй стадии из флэш-памяти и использует эту информацию для загрузки остальной части загрузчика второй стадии из флэш-памяти. Однако в это время тактовая частота системы может быть ниже нормальной, и поддерживаются не все режимы флэш-памяти.
Когда запускается загрузчик второй стадии, он перенастраивает флэш-память, используя значения, считанные из заголовка текущего выбранного двоичного файла приложения (а НЕ из заголовка загрузчика второй стадии). Это позволяет обновлению OTA изменять используемые настройки флэш-памяти SPI.
Загрузчики до ESP-IDF V4.0 использовали собственный заголовок загрузчика для настройки SPI flash, что означало, что эти значения не могли быть изменены в обновлении. Для поддержания совместимости со старыми загрузчиками приложение повторно инициализирует параметры flash во время запуска приложения, используя конфигурацию, найденную в заголовке приложения.
Log level
Уровень вывода отладочных сообщений для загрузчика по умолчанию — «Информация». Установив параметр CONFIG_BOOTLOADER_LOG_LEVEL, можно увеличить или уменьшить этот уровень. Этот log level не зависит от уровня журнала, используемого в приложении (см. ESP_LOG). Уменьшение детализации журнала загрузчика может немного улучшить общее время загрузки проекта и уменьшить размер образа.
Сброс к заводским настройкам
Иногда иметь возможность вернуться к заведомо исправному состоянию устройства в случае возникновения проблем с OTA-обновлением. Чтобы вернуться к исходной «заводской» конфигурации устройства и очистить все пользовательские настройки, настройте элемент конфигурации CONFIG_BOOTLOADER_FACTORY_RESET в загрузчике.
Механизм сброса настроек к заводским позволяет выполнить сброс настроек устройства двумя способами:
- Очистить один или несколько разделов данных. Параметр CONFIG_BOOTLOADER_DATA_FACTORY_RESET позволяет пользователям указать, какие разделы данных будут стерты при выполнении сброса настроек к заводским. Пользователи могут указать имена разделов в виде списка, разделенного запятыми, с дополнительными пробелами для удобства чтения. Например: nvs, phy_init, nvs_custom. Убедитесь, что имена разделов, указанные в данном параметре, совпадают с именами разделов, указанных в таблице разделов. Разделы типа «app» здесь указывать нельзя.
- Загрузка с раздела приложений «factory». Включение параметра CONFIG_BOOTLOADER_OTA_DATA_ERASE приведет к загрузке устройства с раздела «factory» по умолчанию после сброса к заводским настройкам. Если в таблице разделов нет раздела приложений «factory», вместо него будет выбран раздел приложений «ota» по умолчанию. Этот процесс сброса включает в себя очистку раздела данных OTA, который содержит текущий выбранный слот раздела OTA. Слот раздела приложений «factory» (если он существует) никогда не обновляется через OTA, поэтому сброс к нему позволяет вернуться к «известной исправной» прошивке. Один или оба этих параметра конфигурации могут быть включены независимо.
Кроме того, имеются дополнительные параметры конфигурации, которые управляют сбросом:
- CONFIG_BOOTLOADER_NUM_PIN_FACTORY_RESET — номер входного GPIO, используемый для запуска сброса к заводским настройкам. Этот GPIO должен быть переведен в низкий или высокий уровень (настраивается, см. ниже), чтобы запустить процесс сброса к заводским настройкам.
- CONFIG_BOOTLOADER_HOLD_TIME_GPIO — это время удержания GPIO для режима сброса/тестирования (по умолчанию 5 секунд). GPIO должен удерживаться непрерывно в течение этого периода времени после сброса, прежде чем будет выполнен сброс к заводским настройкам или загрузка тестового раздела (в зависимости от применимости)
- CONFIG_BOOTLOADER_FACTORY_RESET_PIN_LEVEL — настройте, должен ли сброс к заводским настройкам запускаться на высоком или низком уровне GPIO. Если у GPIO есть внутренняя подтяжка, то она включается до чтения вывода, см. техническое описание ESP32 для получения подробной информации о внутренних подтяжках выводов.
Если приложению необходимо знать, произошел ли сброс к заводским настройкам, пользователи могут вызвать функцию bootloader_common_get_rtc_retain_mem_factory_reset_state(). Если функция вернет true, то это указывает на то, что сброс к заводским настройкам произошел. Затем функция сбрасывает статус на false для последующего решения о сбросе к заводским настройкам. Если функция вернет false, то это указывает на то, что сброс к заводским настройкам не произошел, или память, в которой хранится этот статус, недействительна. Обратите внимание, что эта функция резервирует часть памяти RTC FAST (того же размера, что и функция CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP).
Тестовые прошивки
Можно написать специальное приложение прошивки для тестирования в production и загружать эту прошивку при необходимости. В таблице разделов проекта потребуется отдельная запись раздела приложения для этого тестового приложения, типа app и подтипа test (см. Таблицы разделов).
Реализация специальной прошивки тестового приложения требует создания совершенно отдельного проекта ESP-IDF, так как каждый проект в ESP-IDF собирает только одно приложение. Тестовое приложение можно разрабатывать и тестировать независимо от основного проекта, а затем интегрировать во время производства в виде предварительно скомпилированного файла .bin, который прошивается по адресу раздела тестового приложения основного проекта. Для поддержки этой функциональности в загрузчике основного проекта установите элемент конфигурации CONFIG_BOOTLOADER_APP_TEST и настройте следующие три элемента:
- CONFIG_BOOTLOADER_NUM_PIN_APP_TEST — номер GPIO для загрузки тестового раздела. Выбранный GPIO будет настроен как вход с включенным внутренним подтягиванием. Этот GPIO должен быть переведен в заранее заданный низкий или высокий уровень (настраивается, см. ниже) при сбросе, чтобы запустить этот процесс. После того, как вход GPIO будет освобожден и устройство будет перезагружено, последовательность загрузки будет снова переключена для загрузки заводского раздела или любого слота раздела приложения OTA по умолчанию.
- CONFIG_BOOTLOADER_HOLD_TIME_GPIO — это время удержания GPIO для режима тестирования (по умолчанию 5 секунд). GPIO должен удерживаться непрерывно в течение этого периода времени после сброса, прежде чем будет выполнен сброс к заводским настройкам или загрузка тестового раздела (в зависимости от применимости).
- CONFIG_BOOTLOADER_APP_TEST_PIN_LEVEL — настройте, должна ли загрузка тестового раздела запускаться на высоком или низком уровне GPIO. Если GPIO имеет внутреннюю подтяжку, то она включается до чтения данных контакта. Ознакомьтесь с техническим описанием ESP32 для получения подробной информации о внутренних подтяжках контактов.
Rollback
Функции отката неудачной прошивки и антиотката также должны быть настроены в загрузчике. Ознакомьтесь с разделами «Откат приложения» в справочном документе API OTA или на сайте.
Watchdog
Чипы ESP32 оснащены двумя группами сторожевых таймеров: главный системный сторожевой таймер MWDT_WDT и сторожевой таймер RTC RTC_WDT. Обе группы сторожевых таймеров автоматически запускаются при включении чипа. Однако в загрузчике они оба будут отключены.
Если установлено CONFIG_BOOTLOADER_WDT_ENABLE (что является поведением по умолчанию), RTC_WDT снова включается при выполнении загрузчика. Он отслеживает время с момента включения загрузчика до вызова основной функции пользователя. В этом сценарии RTC_WDT остается работоспособным и автоматически сбрасывает чип, если ни одно приложение не запустится успешно в течение 9 секунд. Эта функция особенно полезна для предотвращения зависаний, вызванных нестабильным источником питания во время запуска.
- Период ожидания можно отрегулировать, установив CONFIG_BOOTLOADER_WDT_TIME_MS и перекомпилировав загрузчик.
- RTC Watchdog можно отключить в загрузчике, отключив настройку CONFIG_BOOTLOADER_WDT_ENABLE и перекомпилировав загрузчик. Это не рекомендуется.
- См. раздел Аппаратные сторожевые таймеры, чтобы узнать, как RTC_WDT используется в приложении.
Размер загрузчика
При активации расширенных функций загрузчика, включая Flash Encryption или Secure Boot, и особенно при установке высокого уровня CONFIG_BOOTLOADER_LOG_LEVEL, важно следить за размером файла .bin загрузчика. При использовании значения CONFIG_PARTITION_TABLE_OFFSET по умолчанию 0x8000 ограничение по размеру составляет 0x8000 байт.
Если двоичный файл загрузчика слишком большой, то сборка загрузчика завершится с ошибкой «Размер двоичного файла загрузчика [..] слишком большой для смещения таблицы разделов». Если двоичный файл загрузчика уже прошит каким-либо образом, то ESP32 не загрузится — будут регистрироваться ошибки о недопустимой таблице разделов или недопустимой контрольной сумме загрузчика.
Варианты решения этой проблемы:
- Установите оптимизацию компилятора загрузчика обратно на «SIZE», если она была изменена с этого значения по умолчанию.
- Понизьте уровень журналирования загрузчика. Установка уровня журнала на WARNING, ERROR или NONE значительно уменьшает конечный размер двоичного файла (но может затруднить отладку).
- Установите CONFIG_PARTITION_TABLE_OFFSET на значение выше 0x8000, чтобы переразместить таблицу разделов во флэш-памяти. Это увеличивает пространство, доступное для загрузчика. Если файл CSV таблицы разделов содержит явные смещения разделов, их необходимо изменить, чтобы ни один раздел не имел смещения ниже, чем CONFIG_PARTITION_TABLE_OFFSET + 0x1000.
Когда включена опция Secure Boot V2, также существует абсолютный предел размера двоичного файла в 48 КБ (0xC000 байт) (исключая подпись 4 КБ), поскольку загрузчик сначала загружается в буфер фиксированного размера для проверки.
Быстрая загрузка из глубокого сна
Загрузчик имеет опцию CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP, которая позволяет сократить время выхода из глубокого сна (что полезно для снижения энергопотребления). Эта опция доступна, когда опция CONFIG_SECURE_BOOT отключена или включена CONFIG_SECURE_BOOT_INSECURE вместе с безопасной загрузкой. Сокращение времени достигается за счет игнорирования проверки образа.
Во время первой загрузки загрузчик сохраняет адрес запускаемого приложения в памяти RTC FAST. После выхода из глубокого сна этот адрес используется для повторной загрузки приложения без каких-либо проверок, что приводит к значительно более быстрой загрузке.
Пользовательский загрузчик
Текущая реализация загрузчика позволяет вашему проекту расширять или изменять его. Есть два способа сделать это: путем внедрения хуков или путем переопределения. Оба способа представлены в папке custom_bootloader в примерах ESP-IDF:
- custom_bootloader/bootloader_hooks показывает, как подключить некоторые хуки к инициализации загрузчика
- custom_bootloader/bootloader_override показывает, как переопределить реализацию загрузчика. В пространстве загрузчика вы не можете использовать драйверы и функции из других компонентов, если они явно не поддерживают запуск в загрузчике. При необходимости требуемую функциональность следует поместить в каталог bootloader_components проекта (обратите внимание, что это увеличит его размер). Примеры компонентов, которые можно использовать в загрузчике: storage/nvs_bootloader.
Если Ваш загрузчик станет слишком большим, он может не поместиться в таблице разделов, которая по умолчанию прошивается по смещению 0x8000. Увеличьте значение смещения таблицы разделов, чтобы перераспределить таблицу разделов на флэш-памяти. Это увеличит доступное пространство для загрузчика.
Пожалуйста, оцените статью: