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. Последовательность после пробуждения такая:
- Чип выполняет частичную инициализацию.
- Содержимое RTC fast memory проверяется по CRC. По описанию запуска ПЗУ читает регистр
RTC_CNTL_STORE6_REGс адресом точки входа иRTC_CNTL_STORE7_REGс CRC; если адрес не ноль и CRC верна, управление уходит по этому адресу. - Выполняется 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_CPU | RTC 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 рекомендует второй метод.
Источники
- 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 мс
- 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
Нашли ошибку? ·
Смотрите также
- Глубокий сон ESP32Режимы сна, токи, пробуждение по таймеру и выводам, RTC-память, расчёт батареи
- RTC-память ESP32 (FAST и SLOW)Две области по 8 КБ под питанием в глубоком сне: атрибуты RTC_DATA_ATTR, RTC_IRAM_ATTR, ULP
- Загрузчик второй ступени ESP-IDFbootloader.bin по адресу 0x1000: таблица разделов, выбор приложения, флеш, secure boot
- ULP-сопроцессорМаломощный сопроцессор ESP32 для работы в глубоком сне
- Light-sleep ESP32Лёгкий сон ESP32: процессор остановлен, пробуждение без перезагрузки
- Modem-sleep ESP32Процессор работает, радиочасть выключена: десятки миллиампер
- Код запускаТаблица векторов, Reset_Handler, .data и .bss, VTOR, FPU, .initN avr-libc