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

Глубокий сон ESP32: как спать на 10 мкА и просыпаться по делу

В глубоком сне ESP32 по даташиту потребляет около 10 мкА — в тысячи раз меньше, чем в работе. Но просыпается он почти как после сброса, Wi-Fi при этом отключается, а лишние токи через подтяжки легко съедают выигрыш. Разбираем по даташиту Espressif и руководству ESP-IDF режимы сна, источники пробуждения и что делать, чтобы плата действительно жила от батареи.

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

У ESP32 пять режимов питания, и по даташиту Espressif они различаются тем, что остаётся включённым. Глубокий сон (deep sleep) — самый ходовой экономный режим: работают только часы реального времени и маленькая память RTC, а ток падает до 10 мкА. Это основа любого датчика на батарейках: проснулся, измерил, отправил, уснул.

Режимы и токи

По таблице 4-2 даташита ESP32:

РежимЧто работаетТок
Activeпроцессор и радиоWi-Fi: передача до 240 мА, приём 95–100 мА
Modem-sleepпроцессор, радио выключено20–68 мА в зависимости от частоты 80–240 МГц
Light-sleepпроцессор остановлен, RTC и ULP работают0,8 мА
Deep-sleep с ULPпамять и периферия RTC, сопроцессор ULP150 мкА
Deep-sleep, ULP по расписанию 1 %то же, ULP измеряет периодически100 мкА
Deep-sleepтаймер RTC и память RTC10 мкА
Hibernationтолько таймер RTC и некоторые RTC GPIO5 мкА
ВыключенCHIP_PU в нуле1 мкА

Цифры относятся к самому чипу. Всё остальное на плате — стабилизатор, преобразователь USB–UART, светодиод питания, внешние подтяжки — потребляет дополнительно, и на отладочной плате ток сна может быть намного больше табличного. Для батарейного устройства его измеряют на своей плате.

Что сохраняется во сне

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

Отсюда главное отличие от привычного «сна» микроконтроллера: после пробуждения ESP32 не продолжает программу с места остановки. ESP-IDF описывает это так: при пробуждении выполняется короткий код wake stub, а затем загружается приложение — фактически программа стартует заново, и setup() в Arduino выполняется снова. Данные, которые нужно пронести через сон — счётчик пробуждений, последнее измерение, — объявляют с атрибутом RTC_DATA_ATTR: они лежат в памяти RTC SLOW, и ESP-IDF по умолчанию оставляет её включённой, если там есть переменные.

Wi-Fi и Bluetooth во сне выключены, и соединения не сохраняются. После пробуждения устройство подключается к сети заново, а радио по даташиту потребляет 95–240 мА — время подключения и стоит сокращать.

Источники пробуждения

ESP-IDF перечисляет для ESP32 такие источники; их можно включать одновременно, и чип проснётся от любого:

ИсточникКак работаетФункция ESP-IDF
Таймер RTCчерез заданное время, задаётся в микросекундахesp_sleep_enable_timer_wakeup
ext0один RTC GPIO на заданном уровне; периферия RTC во сне остаётся включённойesp_sleep_enable_ext0_wakeup
ext1несколько RTC GPIO: любой в единице или все в нулеesp_sleep_enable_ext1_wakeup_io
Касаниепрерывание сенсора касанияesp_sleep_enable_touchpad_wakeup
ULPпрограмма сопроцессора решает, когда будитьesp_sleep_enable_ulp_wakeup

Для внешнего пробуждения годятся только выводы RTC. По даташиту ESP32 это RTC_GPIO0–RTC_GPIO17: GPIO36, 37, 38, 39, 34, 35, 25, 26, 33, 32, 4, 0, 2, 15, 13, 12, 14 и 27. Подтяжку для кнопки включают функциями rtc_gpio_pullup_en и rtc_gpio_pulldown_en до входа в сон. У ext1 есть ограничение: если выводов несколько, уровень пробуждения у всех один. После пробуждения вывод остаётся в режиме RTC, и чтобы снова использовать его как обычный GPIO, ESP-IDF требует вызвать rtc_gpio_deinit.

Причину пробуждения возвращает esp_sleep_get_wakeup_cause(), а для ext1 и касания отдельные функции сообщают, какой именно вывод сработал. Если не включить ни одного источника, чип по ESP-IDF будет спать до внешнего сброса.

Режим Light-sleep будит ещё и любой GPIO, а также UART, но там и ток другой — 0,8 мА против 10 мкА.

Где теряются микроамперы

  • Подтяжки на выводах. ESP-IDF приводит пример: на модуле ESP32-WROVER вывод GPIO12 подтянут вверх снаружи и вниз внутри чипа, и через эту пару резисторов во сне течёт ток. Его убирают вызовом rtc_gpio_isolate(GPIO_NUM_12) перед esp_deep_sleep_start(). Так же изолируют другие выводы, к которым во сне подключена внешняя схема.
  • ext0 и ULP держат периферию RTC. С ext0 и с работающим ULP периферия RTC остаётся включённой, и ток выше, чем с одним таймером: по даташиту 150 мкА с ULP против 10 мкА.
  • Флеш-память. По ESP-IDF esp_deep_sleep_start() всегда выключает внешнюю SPI-флеш, так что о ней в глубоком сне можно не думать. В Light-sleep она по умолчанию остаётся включённой и тратит по ESP-IDF около 10–30 мкА.
  • Плата. Стабилизатор с большим собственным током, преобразователь USB–UART и светодиод питания потребляют больше самого чипа — для батарей их отключают или выбирают плату без них.

Пример: сколько проработает батарея

Устройство раз в минуту просыпается на 1 с, измеряет датчик без Wi-Fi на 80 МГц и снова засыпает. По даташиту в работе без радио это 20–31 мА, возьмём 25 мА, во сне — 10 мкА. Средний ток:

Iср=25 мА⋅160+0,01 мА⋅5960≈0,43 мА.I_\text{ср} = 25\ \text{мА} \cdot \frac{1}{60} + 0{,}01\ \text{мА} \cdot \frac{59}{60} \approx 0{,}43\ \text{мА}.

Батарея ёмкостью 2000 мА·ч при таком токе проработает около 4700 часов — больше полугода, если ток самой платы во сне действительно близок к табличному. Если же каждое пробуждение с подключением к Wi-Fi длится несколько секунд при сотне миллиампер, средний ток вырастет в разы — поэтому данные копят в RTC-памяти и отправляют пачкой.

Измерять напряжение батареи во сне умеет сопроцессор ULP, а о точности измерения — статья «АЦП ESP32». Какие выводы влияют на загрузку после пробуждения — strapping-выводы, остальные чипы Espressif — в разделе ESP32.

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

Сколько потребляет ESP32 в глубоком сне?

По даташиту Espressif — 10 мкА, когда работают только таймер RTC и RTC-память; с работающим сопроцессором ULP — 150 мкА, в режиме Hibernation — 5 мкА. Это ток самого чипа. Отладочная плата со стабилизатором, преобразователем USB–UART и светодиодом питания потребляет во сне больше, поэтому для батарейного устройства ток меряют на своей плате.

Как разбудить ESP32 кнопкой?

Через внешнее пробуждение ext0 или ext1 по одному из выводов RTC_GPIO: у ESP32 это GPIO0, 2, 4, 12–15, 25–27 и 32–39. Для ext0 задают один вывод и уровень, для ext1 — несколько выводов и условие: любой в единице или все в нуле. Подтяжку для кнопки включают функциями rtc_gpio_pullup_en или rtc_gpio_pulldown_en, как описано в ESP-IDF.

Почему после глубокого сна программа начинается сначала?

Потому что в глубоком сне процессоры и почти вся оперативная память выключены. По ESP-IDF после пробуждения выполняется короткий код wake stub, а затем загружается приложение — как после сброса. Переменные, которые нужно сохранить, помечают атрибутом RTC_DATA_ATTR: они хранятся в памяти RTC SLOW, которая во сне остаётся под питанием.

Сохраняется ли подключение к Wi-Fi в глубоком сне?

Нет. По ESP-IDF в режимах Deep-sleep и Light-sleep радио выключено, и соединения Wi-Fi и Bluetooth не сохраняются. После пробуждения устройство подключается заново. Если связь нужно держать, используют Modem-sleep и автоматический Light-sleep: драйвер Wi-Fi сам будит чип для приёма.

Источники

  1. Espressif. ESP32 Series Datasheet, v5.3 — разд. 4.3.1 — режимы Active, Modem-sleep, Light-sleep, Deep-sleep, Hibernation и что в них работает; табл. 4-2 — Modem-sleep 20–68 мА в зависимости от частоты, Light-sleep 0,8 мА, Deep-sleep 150 мкА с ULP, 100 мкА в режиме ULP-наблюдения при 1 %, 10 мкА с таймером RTC и RTC-памятью, Hibernation 5 мкА, выключение по CHIP_PU 1 мкА; табл. 5-4 — передача Wi-Fi до 240 мА, приём 95–100 мА; разд. 2 — выводы RTC_GPIO0–RTC_GPIO17
  2. Espressif. ESP-IDF Programming Guide (stable), ESP32: Sleep Modes — в Deep-sleep работают контроллер RTC, ULP и память RTC FAST и SLOW, процессоры, большая часть ОЗУ и цифровая периферия выключены; Wi-Fi и Bluetooth во сне не сохраняются; источники пробуждения: таймер, касание, ext0 (один RTC GPIO, RTC-периферия остаётся включённой), ext1 (несколько RTC GPIO, любой в единице или все в нуле, уровни одинаковые), ULP, GPIO в Light-sleep, UART в Light-sleep; esp_sleep_get_wakeup_cause; переменные RTC_DATA_ATTR в памяти RTC SLOW; после пробуждения выполняется wake stub и загружается приложение; esp_deep_sleep_start всегда выключает SPI-флеш; на ESP32-WROVER GPIO12 подтянут внешне вверх и внутри вниз — rtc_gpio_isolate(GPIO_NUM_12); без источников пробуждения чип спит до внешнего сброса

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