Почему ESP32 после обновления по воздуху загружает старую прошивку?
Обновлено Редакция GAW
Обновление по воздуху (OTA) у ESP32 записывает новую прошивку в свободный слот — ota_0 или ota_1, — а раздел otadata отмечает, какой слот загружать. Если включена защита от неработающих обновлений, новой прошивке даётся одна попытка доказать, что она работает.
Жизненный цикл новой прошивки
| Этап | Состояние слота | Кто ставит |
|---|---|---|
| Обновление записано, слот выбран | ESP_OTA_IMG_NEW | esp_ota_set_boot_partition() |
| Первый запуск | ESP_OTA_IMG_PENDING_VERIFY | загрузчик |
| Прошивка подтвердила себя | ESP_OTA_IMG_VALID | esp_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. Загрузчик сам такой слот больше не выберет.
Источники
- 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 не используются
- Espressif. ESP-IDF Programming Guide v6.1: Partition Tables (ESP32) — для OTA нужны раздел otadata (0x2000) и минимум два слота ota_0 и ota_1; загрузчик выбирает слот по otadata
- 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
Нашли ошибку?
Смотрите также
- OTA (обновление по воздуху)Обновление прошивки ESP32 из работающей программы по сети
- Таблица разделов ESP32Карта флеш-памяти ESP32: где приложение, NVS, OTA и данные
- Почему скетч ESP32 не помещается, хотя флеш-памяти 4 МБ?Предел — раздел app0, а не флеш; схемы Huge APP, No OTA, Minimal SPIFFS
- Прошивка ESP32Загрузчик ПЗУ, GPIO0 и автосброс, write-flash и адреса, ошибки esptool и питание