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

Wake stub (заглушка пробуждения из глубокого сна ESP32)

Проснуться, проверить один вывод и снова уснуть — для этого не обязательно ждать загрузчик, инициализацию флеш и FreeRTOS. ESP-IDF позволяет выполнить короткий код прямо из RTC-памяти в первые миллисекунды после пробуждения.

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

Wake stub (deep-sleep wake stub, заглушка пробуждения) — функция, которую ESP32 выполняет сразу после выхода из глубокого сна, ещё до загрузчика второй ступени и любого кода ESP-IDF. Она живёт в RTC FAST memory, которая не обесточивается во сне, поэтому может стартовать без загрузки из флеш. Типичное применение — быстро проверить условие и, если ничего не случилось, уйти обратно в сон, не тратя время и ток на полную загрузку.

Как это работает

По ESP-IDF пробуждение из Deep-sleep дольше, чем из light-sleep и modem-sleep: ПЗУ и RAM были обесточены, и процессору нужно грузить код по SPI. Последовательность после пробуждения такая:

  1. Чип выполняет частичную инициализацию.
  2. Содержимое RTC fast memory проверяется по CRC. По описанию запуска ПЗУ читает регистр RTC_CNTL_STORE6_REG с адресом точки входа и RTC_CNTL_STORE7_REG с CRC; если адрес не ноль и CRC верна, управление уходит по этому адресу.
  3. Выполняется wake stub. Если он возвращается (или CRC не сошлась), загрузка идёт как после включения питания: ПЗУ грузит загрузчик, тот — приложение, как описано в статье о коде запуска.

В ESP-IDF стаб — это функция esp_wake_deep_sleep(). Она слабо слинкована с esp_default_wake_deep_sleep(): если в проекте есть своя функция с таким именем, она подменяет стандартную. Первым действием своя версия должна вызвать esp_default_wake_deep_sleep(). Писать стаб не обязательно — он нужен только для поведения «сразу после пробуждения». Сменить стаб во время работы можно функцией esp_set_deep_sleep_wake_stub(); все объявления — в esp_sleep.h.

Ограничения

ЧтоПочему
Только функции из ПЗУ или из RTC fast memoryпериферия в сбросе, SPI-флеш ещё не отображена
Размер стаба ограничен RTC fast memoryпо даташиту ESP32 это 8 КБ
Остальная RAM — случайные данныегодится как временный буфер, но содержимое перезапишется при возврате в сон или старте ESP-IDF
Строки — массивами с RTC_RODATA_ATTRиначе компилятор положит их во флеш
Данные стаба — RTC_DATA_ATTR / RTC_RODATA_ATTRинициализируются при каждом старте, кроме пробуждения из Deep-sleep
RTC_FAST_ATTR — только PRO_CPURTC fast memory доступна одному ядру

Два способа разместить код в RTC fast memory: атрибут RTC_IRAM_ATTR у функции — для коротких фрагментов; файл с именем вида rtc_wake_stub*.c — компоновщик целиком отправит его в RTC-память, что удобнее для длинного кода и строк. По умолчанию данные RTC_DATA_ATTR лежат в RTC SLOW; опция CONFIG_ESP32_RTCDATA_IN_FAST_MEM переносит их в RTC FAST и освобождает медленную память под программы ULP, но требует одноядерной сборки.

RTC_DATA_ATTR int wake_count;

void RTC_IRAM_ATTR esp_wake_deep_sleep(void) {
    esp_default_wake_deep_sleep();
    static RTC_RODATA_ATTR const char fmt_str[] = "Wake count %d\n";
    esp_rom_printf(fmt_str, wake_count++);
}

Время пробуждения

ESP-IDF предлагает два способа измерить задержку от пробуждения до стаба. По счётчику тактов процессора в примере system/deep_sleep_wake_stub лог ESP32-C3 показывает «wakeup cost 12734 us», но оценка захватывает часть инициализации. По логическому анализатору — один GPIO будит чип, другой стаб поднимает первым действием — документация показывает 2,657 мс. Если стаб не нужен, а важна скорость полной загрузки, есть опция CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP: загрузчик сохраняет адрес приложения в RTC FAST memory и после пробуждения не проверяет образ (доступно без secure boot или с CONFIG_SECURE_BOOT_INSECURE).

Частые вопросы

Что можно и что нельзя делать в wake stub?

По ESP-IDF в момент выполнения стаба периферия находится в состоянии сброса, а SPI-флеш ещё не отображена в адресное пространство, поэтому вызывать можно только функции из ПЗУ или код, размещённый в RTC fast memory. Остальная оперативная память содержит случайные данные; использовать её как временный буфер можно, но содержимое пропадёт при возврате в сон или при старте ESP-IDF. Строковые константы нужно объявлять массивами с RTC_RODATA_ATTR, иначе они окажутся во флеш.

Как добавить свой wake stub в проект?

Определить функцию esp_wake_deep_sleep() с атрибутом RTC_IRAM_ATTR: она слабо слинкована с esp_default_wake_deep_sleep() и заменит её. Первой строкой ESP-IDF требует вызвать esp_default_wake_deep_sleep(). Для длинного кода удобнее положить функцию в файл с именем, начинающимся на rtc_wake_stub, — компоновщик сам отправит его в RTC fast memory. Переменные для стаба объявляют с RTC_DATA_ATTR, а переключить стаб на лету можно функцией esp_set_deep_sleep_wake_stub().

Сколько времени проходит от пробуждения до wake stub?

Зависит от чипа и способа измерения. ESP-IDF приводит два метода: по счётчику тактов процессора в примере system/deep_sleep_wake_stub лог ESP32-C3 показывает «wakeup cost 12734 us», но эта оценка захватывает часть инициализации; по логическому анализатору между фронтом вывода пробуждения и выводом, который стаб поднимает сам, документация показывает 2,657 мс. Для точных цифр Espressif рекомендует второй метод.

Источники

  1. Espressif. ESP-IDF Programming Guide v6.1, ESP32: Deep-sleep Wake Stubs — Introduction: пробуждение из Deep-sleep дольше, чем из Light-sleep и Modem-sleep, так как ПЗУ и RAM обесточены и нужна загрузка по SPI; wake stub выполняется сразу после пробуждения, до загрузчика и кода ESP-IDF; после пробуждения частичная инициализация, RTC fast memory проверяется по CRC, затем выполняется стаб; периферия в сбросе, SPI-флеш не отображена — можно вызывать только функции из ПЗУ или из RTC fast memory; размер ограничен RTC fast memory; код — в RTC fast, данные — в RTC fast или slow; Implement wake stub: функция esp_wake_deep_sleep() слабо слинкована с esp_default_wake_deep_sleep(), своя версия её переопределяет; первым делом вызывать esp_default_wake_deep_sleep(); esp_set_deep_sleep_wake_stub() переключает стабы во время работы; остальная RAM содержит случайные данные, её содержимое перезапишется при возврате в сон или старте ESP-IDF; способы размещения — атрибут RTC_IRAM_ATTR или файлы с именем rtc_wake_stub*; строки — массивами с RTC_RODATA_ATTR; данные — RTC_DATA_ATTR и RTC_RODATA_ATTR; данные в RTC-памяти инициализируются при каждом старте, кроме пробуждения из Deep-sleep; CONFIG_ESP32_RTCDATA_IN_FAST_MEM; RTC_FAST_ATTR только для PRO_CPU; объявления в esp_hw_support/include/esp_sleep.h; CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP сокращает время пробуждения; пример system/deep_sleep_wake_stub; измерение: по счётчику тактов в примере wakeup cost 12734 us (лог ESP32-C3), по логическому анализатору 2,657 мс
  2. Espressif. ESP-IDF Programming Guide v6.1, ESP32: Application Startup Flow; Bootloader — First stage (ROM) bootloader: при сбросе из глубокого сна, если RTC_CNTL_STORE6_REG не ноль и CRC RTC-памяти в RTC_CNTL_STORE7_REG верна, ПЗУ переходит по адресу из RTC_CNTL_STORE6_REG; если ноль, CRC неверна или код вернулся — загрузка продолжается как после включения питания; Bootloader: при CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP адрес приложения хранится в RTC FAST memory и после пробуждения образ не проверяется; доступно без secure boot или с CONFIG_SECURE_BOOT_INSECURE
Страница помогла?

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