Перейти к содержанию

Почему ESP32 после обновления по воздуху загружает старую прошивку?

Обновлено Редакция GAW

Обновление по воздуху (OTA) у ESP32 записывает новую прошивку в свободный слот — ota_0 или ota_1, — а раздел otadata отмечает, какой слот загружать. Если включена защита от неработающих обновлений, новой прошивке даётся одна попытка доказать, что она работает.

Жизненный цикл новой прошивки

ЭтапСостояние слотаКто ставит
Обновление записано, слот выбранESP_OTA_IMG_NEWesp_ota_set_boot_partition()
Первый запускESP_OTA_IMG_PENDING_VERIFYзагрузчик
Прошивка подтвердила себяESP_OTA_IMG_VALIDesp_ota_mark_app_valid_cancel_rollback()
Перезагрузка без подтвержденияESP_OTA_IMG_ABORTED, откатзагрузчик
Прошивка сама нашла ошибкуESP_OTA_IMG_INVALID, откатesp_ota_mark_app_invalid_rollback_and_reboot()

По ESP-IDF v6.1 (App Rollback), при включённом CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE.

Частые причины отката

  • Нет вызова подтверждения. Самая частая в ESP-IDF: прошивка работает, но после первой же перезагрузки возвращается старая версия.
  • Перезагрузка до подтверждения. Сторожевой таймер, исключение или пропадание питания между стартом и вызовом — Espressif поэтому советует проверять себя как можно быстрее.
  • Подтверждение после долгой операции. Если прошивка ждёт подключения к Wi-Fi или серверу, а оно не удалось и устройство перезагрузилось, — тоже откат. Это и есть задуманная защита (наш вывод).

Arduino-ESP32

В ядре Arduino подтверждение уже встроено. Функция initArduino() (cores/esp32/esp32-hal-misc.c) при включённом откате проверяет состояние слота и, если оно PENDING_VERIFY, вызывает слабую функцию verifyOta(): по умолчанию она возвращает true, и ядро само вызывает esp_ota_mark_app_valid_cancel_rollback() ещё до setup(). Если переопределить verifyRollbackLater() так, чтобы она возвращала true, проверка откладывается, и подтверждать прошивку должен скетч. Наш вывод: в Arduino откат по умолчанию случится, только если прошивка упала раньше initArduino() или вы сами отложили проверку и не подтвердили её.

Если отката не ждали

Без опции отката новый слот загружается всегда, и «старая прошивка» означает, что слот не был выбран: проверьте результат esp_ota_set_boot_partition(). Раздел otadata и два слота задаёт таблица разделов; в схемах Arduino-ESP32 No OTA и Huge APP второго слота нет, см. «Почему скетч ESP32 не помещается». Как устроены адреса разделов во флеш-памяти, рассказано в статье «Прошивка ESP32».

Похожие вопросы

Где в коде вызывать подтверждение?

В ESP-IDF — после самопроверки при первом запуске (в Arduino-ESP32 это по умолчанию делает ядро в initArduino()): ESP-IDF показывает пример, где приложение читает своё состояние через esp_ota_get_state_partition() и, если оно PENDING_VERIFY, проводит диагностику и вызывает esp_ota_mark_app_valid_cancel_rollback(). Самопроверку Espressif советует делать как можно быстрее, чтобы пропадание питания не привело к откату.

Откатится ли прошивка без опции отката?

Нет. По ESP-IDF без CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE состояния NEW и PENDING_VERIFY не используются, а функции подтверждения необязательны: загрузчик просто запускает слот, выбранный при обновлении. Если тогда загружается старая версия, значит, новый слот не был выбран — esp_ota_set_boot_partition() не вызвана или вернула ошибку (наш вывод).

Можно ли вернуться к прошивке, помеченной ABORTED?

Можно вручную: ESP-IDF допускает загрузку приложения в состоянии INVALID или ABORTED, если найти его раздел и передать в esp_ota_set_boot_partition() — это обновит otadata. Загрузчик сам такой слот больше не выберет.

Источники

  1. Espressif. ESP-IDF Programming Guide v6.1: Over The Air Updates (OTA), ESP32 — App Rollback: esp_ota_set_boot_partition() ставит новому приложению ESP_OTA_IMG_NEW; загрузчик при запуске меняет NEW на PENDING_VERIFY; без подтверждения при следующей загрузке PENDING_VERIFY превращается в ABORTED, и запускается предыдущее рабочее приложение; esp_ota_mark_app_valid_cancel_rollback() — VALID, esp_ota_mark_app_invalid_rollback_and_reboot() — INVALID и перезагрузка; у новой прошивки одна попытка; самопроверку советуют делать быстро, чтобы не откатиться из-за пропадания питания; без опции функции необязательны, состояния NEW и PENDING_VERIFY не используются
  2. Espressif. ESP-IDF Programming Guide v6.1: Partition Tables (ESP32) — для OTA нужны раздел otadata (0x2000) и минимум два слота ota_0 и ota_1; загрузчик выбирает слот по otadata
  3. Espressif. arduino-esp32, cores/esp32/esp32-hal-misc.c (ветка master, коммит 6b41cf6, 2026-10-26) — initArduino(): при CONFIG_APP_ROLLBACK_ENABLE, если verifyRollbackLater() вернула false, для слота в состоянии ESP_OTA_IMG_PENDING_VERIFY вызывается verifyOta(); true — esp_ota_mark_app_valid_cancel_rollback(), false — esp_ota_mark_app_invalid_rollback_and_reboot(); слабые реализации по умолчанию: verifyOta() — true, verifyRollbackLater() — false

Нашли ошибку?