В этом уроке мы изучим работу с режимами глубокого сна и источниками пробуждения в ESP32 с помощью ESP-IDF. Мы покажем, как перевести плату разработки ESP32 в режим глубокого сна. Кроме того, мы также обсудим различные источники пробуждения, с помощью которых ESP32 может переходить из спящего режима в обычный режим выполнения, такие как таймер, внешние события, сенсорные контакты и пробуждение сопроцессора ULP.

Также на нашем сайте вы можете прочитать статью про использование спящих режимов в ESP32 с помощью Arduino IDE.
Режим глубокого сна в ESP32
Режим глубокого сна в ESP32 помогает экономить заряд батареи и снижать энергопотребление. Модуль потребляет много энергии, обычно до 75 мА в обычном режиме, а при использовании Wi-Fi это потребление увеличивается до 240 мА. Чтобы уменьшить это дополнительное энергопотребление, мы можем легко перевести плату в режим глубокого сна, когда нам нужно выполнить какую-либо задачу после определенного промежутка времени. При успешной активации режима глубокого сна в ESP32 потребление тока будет находиться в диапазоне микроампер (мкА), а время работы батареи также увеличится.
В таблице ниже показаны периферийные устройства и модули, активные или неактивные в различных режимах работы ESP32. Обратите внимание, что в режиме глубокого сна включены только память RTC и периферийные устройства (контроллер RTC, быстрая память RTC, медленная память RTC) и сопроцессор ULP, остальные модули выключены, включая все цифровые периферийные устройства, большую часть ОЗУ и ЦП.
Для более полного понимания ситуации, ознакомьтесь с таблицей ниже, чтобы увидеть, как изменяется энергопотребление платы ESP32 в режиме глубокого сна по сравнению с другими режимами.
Теперь рассмотрим как настроить режимы пониженного энергопотребления.
Настройка режима глубокого сна
После настройки источников пробуждения плата ESP32 может перейти в режим глубокого сна с помощью следующего вызова функции.
|
1 |
esp_deep_sleep_start() |
Это API используется для перехода в режим глубокого сна. Если источник пробуждения еще не настроен, плата остается в режиме глубокого сна до тех пор, пока не будет нажата внешняя кнопка сброса.
После перехода платы ESP32 в режим глубокого сна контроллер RTC отключает цифровые периферийные устройства и процессоры. Кроме того, аппаратное обеспечение настраивается в соответствии с заданными источниками пробуждения.
Источники пробуждения ESP32
Для пробуждения ESP32 из глубокого сна можно использовать различные источники пробуждения. К ним относятся пробуждение по таймеру, пробуждение по контакту сенсора, внешнее пробуждение и пробуждение сопроцессора ULP. Эти источники пробуждения могут действовать по отдельности или даже комбинироваться таким образом, что при срабатывании любого из источников плата ESP32 просыпается. Эти источники настраиваются в коде до того, как плата ESP32 перейдет в режим глубокого сна. Для включения источника пробуждения используется следующий универсальный API:
|
1 |
esp_sleep_enable_X_wakeup() |
где 'X' — источник пробуждения, который может принимать одно из следующих значений:
- таймер;
- сенсорная панель;
- ext0;
- ext1;
- ulp.
Аналогичным образом, для отключения источника пробуждения используется следующий универсальный API:
|
1 |
esp_sleep_disable_wakeup_source() |
Пробуждение по таймеру
Пробуждение по таймеру — один из простейших способов пробуждения, использующий встроенный таймер контроллера реального времени (RTC). Плата ESP32 просыпается по истечении заданного времени таймера. Время таймера определяется в микросекундах, хотя точное разрешение зависит от источника тактовой частоты, выбранного для RTC SLOW_CLK. Хотя пробуждение по таймеру основано на встроенном таймере RTC, в этом режиме пробуждения нет необходимости оставлять периферийные устройства RTC/память RTC включенными во время сна.
Следующая функция используется для включения пробуждения в фазу глубокого сна с помощью таймера:
|
1 |
esp_sleep_enable_timer_wakeup() |
Сенсорная панель
Пробуждение с помощью сенсорной панели (или сенсорное пробуждение) — еще один способ вывести плату ESP32 из глубокого сна. Пробуждение произойдет, когда пользователь коснется одного из сенсорных контактов платы ESP32, что вызовет прерывание от сенсорного датчика.
Следующая функция используется для включения режима глубокого сна и пробуждения через сенсорную панель:
|
1 |
esp_sleep_enable_touchpad_wakeup() |
Контакты сенсорного датчика ESP32
ESP-WROOM-32 состоит из 10 встроенных емкостных сенсорных датчиков. Они полезны, поскольку работают как сенсоры, которые могут вызывать прерывание сенсорной панели при касании, обнаруживая любые электрические/магнитные волны вокруг себя. Вы можете посмотреть контакты сенсорных датчиков на плате ESP32:
- TOUCH0 – GPIO4
- TOUCH1 – GPIO0
- TOUCH2 – GPIO2
- TOUCH3 – GPIO15
- TOUCH4 – GPIO13
- TOUCH5 – GPIO12
- TOUCH6 – GPIO14
- TOUCH7 – GPIO27
- TOUCH8 – GPIO33
- TOUCH9 – GPIO32
Внешнее пробуждение
В качестве источника пробуждения также используется внешнее пробуждение, при котором изменение состояния контакта GPIO выводит плату ESP32 из глубокого сна. Источник пробуждения настраивается до перевода платы ESP32 в режим глубокого сна. Существует два типа внешнего пробуждения, которые можно настроить: ext0 и ext1. В случае ext0 один контакт GPIO настраивается как источник внешнего пробуждения. Однако, если используется несколько контактов GPIO, то вместо них используется ext1.
Важно отметить, что в качестве источника пробуждения для внешнего источника можно использовать только контакты GPIO RTC.
ESP32 DevKit V1-DOIT имеет 14 выводов GPIO для RTC, которые можно использовать для активации по внешнему прерыванию.
- RTC_GPIO0 : GPIO36
- RTC_GPIO3: GPIO39
- RTC_GPIO9: GPIO32
- RTC_GPIO8: GPIO33
- RTC_GPIO6: GPIO25
- RTC_GPIO7: GPIO26
- RTC_GPIO17: GPIO27
- RTC_GPIO16: GPIO14
- RTC_GPIO15: GPIO12
- RTC_GPIO14: GPIO13
- RTC_GPIO11: GPIO0
- RTC_GPIO13: GPIO15
- RTC_GPIO12: GPIO2
- RTC_GPIO10: GPIO4
Внешнее пробуждение – ext0
Как мы уже упоминали, ext0 используется, когда один из выводов GPIO RTC используется в качестве внешнего источника пробуждения. Для включения источника пробуждения ext0 мы используем следующий API:
|
1 |
esp_sleep_enable_ext0_wakeup() |
Модуль ввода-вывода RTC отвечает за запуск пробуждения ext0. Поскольку модуль ввода-вывода RTC является частью домена питания периферийных устройств RTC, периферийные устройства RTC должны быть включены во время режима глубокого сна, если ext0 используется в качестве источника пробуждения.
Как мы уже упоминали, можно комбинировать несколько источников пробуждения, при этом любой из них может инициировать пробуждение. Однако при использовании ext0 нельзя использовать одновременно источники пробуждения для тачпада или ULP. Они несовместимы с этим внешним источником пробуждения.
Внешнее пробуждение -ext1
Как мы уже упоминали, ext1 используется, когда несколько выводов GPIO RTC используются в качестве внешних источников пробуждения. Для включения источника пробуждения ext1 мы используем следующий API:
|
1 |
esp_sleep_enable_ext1_wakeup() |
Контроллер RTC отвечает за запуск пробуждения ext1. Поэтому периферийные устройства RTC могут быть выключены во время использования источников пробуждения ext1. Для запуска пробуждения с помощью ext1 можно использовать одну из двух логических функций: ESP_EXT1_WAKEUP_ANY_HIGH или ESP_EXT1_WAKEUP_ALL_LOW. В случае первой логической функции пробуждение запускается, когда любой из установленных выводов GPIO RTC находится в состоянии HIGH. В случае второй логической функции пробуждение запускается, когда все установленные выводы GPIO RTC находятся в состоянии LOW.
Пробуждение сопроцессора ULP
Наконец, рассмотрим пробуждение сопроцессора ULP. В этом случае пробуждение запускается при возникновении любого конкретного события, связанного с отслеживаемым сопроцессором ULP. Сопроцессор ULP включается, когда плата ESP32 находится в режиме глубокого сна, поэтому он может выступать в качестве источника пробуждения. При использовании сопроцессора ULP в качестве источника пробуждения будет включена медленная память RTC. Это связано с тем, что ULP является частью домена питания периферийных устройств RTC и отвечает за выполнение программы, хранящейся в медленной памяти RTC. Следовательно, когда ULP запускает программу, периферийные устройства RTC также включаются и отключаются после завершения работы ULP.
Для включения этого источника пробуждения мы используем следующий API:
|
1 |
esp_sleep_enable_ulp_wakeup() |
Пример глубокого сна ESP32 с помощью ESP-IDF
В этом разделе мы создадим и протестируем пример глубокого сна, предоставляемый ESP-IDF на вкладке system («Система»). Этот пример настраивает различные источники пробуждения, а затем переводит плату ESP32 в глубокий сон, используя API esp_sleep.h.
Создание примера проекта
Откройте VS Code и перейдите в меню View > Command Palette («Вид» > «Палитра команд»). Введите в строке поиска ESP-IDF: New Project и нажмите Enter.
Укажите название проекта и каталог. Мы назвали наш проект «ESP_IDF_DEEP_SLEEP». Для платы ESP-IDF мы выбрали опцию custom board («Пользовательская плата»). В качестве целевой платформы ESP-IDF мы выбрали модуль ESP32. Нажмите кнопку ‘Choose Template’ («Выбрать шаблон»), чтобы продолжить.
В разделе Extension («Расширение») выберите опцию ESP-IDF:
На вкладке system («Система») мы щелкнем по пункту «deep_sleep». Затем нажмем ‘Create project using template deep_sleep’ («Создать проект, используя шаблон deep_sleep»).

Вы получите уведомление о создании проекта. Чтобы открыть проект в новом окне, нажмите «Да».
Это откроет созданный нами проект ESP_IDF_DEEP_SLEEP во вкладке EXPLORER. Внутри папки проекта находится несколько папок. Это справедливо для всех проектов, которые вы будете создавать с помощью ESP-IDF Explorer.
Конфигурация проекта
Для начала перейдем в меню menuconfig. Щелкните значок, показанный ниже. Откроется редактор конфигурации ESP-IDF SDK.
Прокрутите вниз и откройте Example Configuration (пример конфигурации) для нашего проекта. Здесь вы можете включить источники пробуждения, которые хотите использовать в примере. По умолчанию включены пробуждение от касания, мониторинг температуры с помощью ULP и пробуждение от GPIO. Вы также можете отключить любую опцию по своему усмотрению.
Перейдём к файлу main.c. В папке main находится исходный код, поэтому файл main.c будет расположен именно там.
Теперь перейдите в файл main > deep_sleep_example_main.c и откройте его.
Ниже приведён фрагмент кода. Этот пример кода демонстрирует, как перевести ESP32 в режим глубокого сна и настроить четыре источника пробуждения, указанных ниже.
- Пробуждение по таймеру: встроенный таймер RTC запускает пробуждение ESP32 каждые 20 секунд.
- Внешнее пробуждение ext1: ext1 инициирует пробуждение с помощью ESP_EXT1_WAKEUP_ANY_HIGH. Это означает, что когда любой из выводов GPIO RTC находится в состоянии HIGH, плата ESP32 просыпается. В этом примере в качестве выводов GPIO RTC используются GPIO2 и GPIO4.
- Пробуждение сенсорной панели: пробуждение произойдет, когда пользователь коснется любого из контактов сенсорной панели: GPIO32 или GPIO33 для ESP32 и GPIO9 для ESP32-S2. Это вызовет прерывание от сенсорного датчика.
- Пробуждение с помощью сопроцессора ULP: п этом случае сопроцессор ULP непрерывно контролирует температуру микроконтроллера. Когда температура превышает 5 градусов Цельсия, запускается процесс пробуждения.
В этом примере скетча используются API, которые мы обсуждали ранее, для настройки источников пробуждения таймера, ext1, касания и ULP, а затем плата ESP32 переводится в режим глубокого сна.
Код для запуска глубокого сна на ESP32
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 |
/* Deep sleep wake up example This example code is in the Public Domain (or CC0 licensed, at your option.) Unless required by applicable law or agreed to in writing, this software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> #include <sys/time.h> #include "sdkconfig.h" #include "soc/soc_caps.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_sleep.h" #include "esp_log.h" #include "driver/adc.h" #include "driver/rtc_io.h" #include "soc/rtc.h" #if CONFIG_IDF_TARGET_ESP32 #include "esp32/ulp.h" #endif #if SOC_TOUCH_SENSOR_NUM > 0 #include "soc/sens_periph.h" #include "driver/touch_pad.h" #endif #ifdef CONFIG_IDF_TARGET_ESP32C3 #define DEFAULT_WAKEUP_PIN CONFIG_EXAMPLE_GPIO_WAKEUP_PIN #ifdef CONFIG_EXAMPLE_GPIO_WAKEUP_HIGH_LEVEL #define DEFAULT_WAKEUP_LEVEL ESP_GPIO_WAKEUP_GPIO_HIGH #else #define DEFAULT_WAKEUP_LEVEL ESP_GPIO_WAKEUP_GPIO_LOW #endif #endif static RTC_DATA_ATTR struct timeval sleep_enter_time; #ifdef CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP #if CONFIG_IDF_TARGET_ESP32 /* * Offset (in 32-bit words) in RTC Slow memory where the data is placed * by the ULP coprocessor. It can be chosen to be any value greater or equal * to ULP program size, and less than the CONFIG_ESP32_ULP_COPROC_RESERVE_MEM/4 - 6, * where 6 is the number of words used by the ULP coprocessor. */ #define ULP_DATA_OFFSET 36 _Static_assert(ULP_DATA_OFFSET < CONFIG_ESP32_ULP_COPROC_RESERVE_MEM/4 - 6, "ULP_DATA_OFFSET is set too high, or CONFIG_ESP32_ULP_COPROC_RESERVE_MEM is not sufficient"); /** * @brief Start ULP temperature monitoring program * * This function loads a program into the RTC Slow memory and starts up the ULP. * The program monitors on-chip temperature sensor and wakes up the SoC when * the temperature goes lower or higher than certain thresholds. */ static void start_ulp_temperature_monitoring(void); /** * @brief Utility function which reads data written by ULP program * * @param offset offset from ULP_DATA_OFFSET in RTC Slow memory, in words * @return lower 16-bit part of the word writable by the ULP */ static inline uint16_t ulp_data_read(size_t offset) { return RTC_SLOW_MEM[ULP_DATA_OFFSET + offset] & 0xffff; } /** * @brief Utility function which writes data to be ready by ULP program * * @param offset offset from ULP_DATA_OFFSET in RTC Slow memory, in words * @param value lower 16-bit part of the word to be stored */ static inline void ulp_data_write(size_t offset, uint16_t value) { RTC_SLOW_MEM[ULP_DATA_OFFSET + offset] = value; } #endif // CONFIG_IDF_TARGET_ESP32 #endif // CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP #ifdef CONFIG_EXAMPLE_TOUCH_WAKEUP #if CONFIG_IDF_TARGET_ESP32 #define TOUCH_THRESH_NO_USE 0 static void calibrate_touch_pad(touch_pad_t pad); #endif #endif void app_main(void) { struct timeval now; gettimeofday(&now, NULL); int sleep_time_ms = (now.tv_sec - sleep_enter_time.tv_sec) * 1000 + (now.tv_usec - sleep_enter_time.tv_usec) / 1000; switch (esp_sleep_get_wakeup_cause()) { #ifdef CONFIG_EXAMPLE_EXT1_WAKEUP case ESP_SLEEP_WAKEUP_EXT1: { uint64_t wakeup_pin_mask = esp_sleep_get_ext1_wakeup_status(); if (wakeup_pin_mask != 0) { int pin = __builtin_ffsll(wakeup_pin_mask) - 1; printf("Wake up from GPIO %d\n", pin); } else { printf("Wake up from GPIO\n"); } break; } #endif // CONFIG_EXAMPLE_EXT1_WAKEUP #if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP case ESP_SLEEP_WAKEUP_GPIO: { uint64_t wakeup_pin_mask = esp_sleep_get_gpio_wakeup_status(); if (wakeup_pin_mask != 0) { int pin = __builtin_ffsll(wakeup_pin_mask) - 1; printf("Wake up from GPIO %d\n", pin); } else { printf("Wake up from GPIO\n"); } break; } #endif //SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP case ESP_SLEEP_WAKEUP_TIMER: { printf("Wake up from timer. Time spent in deep sleep: %dms\n", sleep_time_ms); break; } #ifdef CONFIG_EXAMPLE_TOUCH_WAKEUP case ESP_SLEEP_WAKEUP_TOUCHPAD: { printf("Wake up from touch on pad %d\n", esp_sleep_get_touchpad_wakeup_status()); break; } #endif // CONFIG_EXAMPLE_TOUCH_WAKEUP #ifdef CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP #if CONFIG_IDF_TARGET_ESP32 case ESP_SLEEP_WAKEUP_ULP: { printf("Wake up from ULP\n"); int16_t diff_high = (int16_t) ulp_data_read(3); int16_t diff_low = (int16_t) ulp_data_read(4); if (diff_high < 0) { printf("High temperature alarm was triggered\n"); } else if (diff_low < 0) { printf("Low temperature alarm was triggered\n"); } else { assert(false && "temperature has stayed within limits, but got ULP wakeup\n"); } break; } #endif // CONFIG_IDF_TARGET_ESP32 #endif // CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP case ESP_SLEEP_WAKEUP_UNDEFINED: default: printf("Not a deep sleep reset\n"); } #ifdef CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP #if CONFIG_IDF_TARGET_ESP32 if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_UNDEFINED) { printf("ULP did %d temperature measurements in %d ms\n", ulp_data_read(1), sleep_time_ms); printf("Initial T=%d, latest T=%d\n", ulp_data_read(0), ulp_data_read(2)); } #endif // CONFIG_IDF_TARGET_ESP32 #endif // CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP vTaskDelay(1000 / portTICK_PERIOD_MS); const int wakeup_time_sec = 20; printf("Enabling timer wakeup, %ds\n", wakeup_time_sec); esp_sleep_enable_timer_wakeup(wakeup_time_sec * 1000000); #ifdef CONFIG_EXAMPLE_EXT1_WAKEUP const int ext_wakeup_pin_1 = 2; const uint64_t ext_wakeup_pin_1_mask = 1ULL << ext_wakeup_pin_1; const int ext_wakeup_pin_2 = 4; const uint64_t ext_wakeup_pin_2_mask = 1ULL << ext_wakeup_pin_2; printf("Enabling EXT1 wakeup on pins GPIO%d, GPIO%d\n", ext_wakeup_pin_1, ext_wakeup_pin_2); esp_sleep_enable_ext1_wakeup(ext_wakeup_pin_1_mask | ext_wakeup_pin_2_mask, ESP_EXT1_WAKEUP_ANY_HIGH); #endif // CONFIG_EXAMPLE_EXT1_WAKEUP #ifdef CONFIG_EXAMPLE_GPIO_WAKEUP const gpio_config_t config = { .pin_bit_mask = BIT(DEFAULT_WAKEUP_PIN), .mode = GPIO_MODE_INPUT, }; ESP_ERROR_CHECK(gpio_config(&config)); ESP_ERROR_CHECK(esp_deep_sleep_enable_gpio_wakeup(BIT(DEFAULT_WAKEUP_PIN), DEFAULT_WAKEUP_LEVEL)); printf("Enabling GPIO wakeup on pins GPIO%d\n", DEFAULT_WAKEUP_PIN); #endif #ifdef CONFIG_EXAMPLE_TOUCH_WAKEUP #if CONFIG_IDF_TARGET_ESP32 // Initialize touch pad peripheral. // The default fsm mode is software trigger mode. ESP_ERROR_CHECK(touch_pad_init()); // If use touch pad wake up, should set touch sensor FSM mode at 'TOUCH_FSM_MODE_TIMER'. touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); // Set reference voltage for charging/discharging // In this case, the high reference valtage will be 2.4V - 1V = 1.4V // The low reference voltage will be 0.5 // The larger the range, the larger the pulse count value. touch_pad_set_voltage(TOUCH_HVOLT_2V4, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_1V); //init RTC IO and mode for touch pad. touch_pad_config(TOUCH_PAD_NUM8, TOUCH_THRESH_NO_USE); touch_pad_config(TOUCH_PAD_NUM9, TOUCH_THRESH_NO_USE); calibrate_touch_pad(TOUCH_PAD_NUM8); calibrate_touch_pad(TOUCH_PAD_NUM9); #elif CONFIG_IDF_TARGET_ESP32S2 /* Initialize touch pad peripheral. */ touch_pad_init(); /* Only support one touch channel in sleep mode. */ touch_pad_config(TOUCH_PAD_NUM9); /* Denoise setting at TouchSensor 0. */ touch_pad_denoise_t denoise = { /* The bits to be cancelled are determined according to the noise level. */ .grade = TOUCH_PAD_DENOISE_BIT4, .cap_level = TOUCH_PAD_DENOISE_CAP_L4, }; touch_pad_denoise_set_config(&denoise); touch_pad_denoise_enable(); printf("Denoise function init\n"); /* Filter setting */ touch_filter_config_t filter_info = { .mode = TOUCH_PAD_FILTER_IIR_16, .debounce_cnt = 1, // 1 time count. .noise_thr = 0, // 50% .jitter_step = 4, // use for jitter mode. .smh_lvl = TOUCH_PAD_SMOOTH_IIR_2, }; touch_pad_filter_set_config(&filter_info); touch_pad_filter_enable(); printf("touch pad filter init %d\n", TOUCH_PAD_FILTER_IIR_8); /* Set sleep touch pad. */ touch_pad_sleep_channel_enable(TOUCH_PAD_NUM9, true); touch_pad_sleep_channel_enable_proximity(TOUCH_PAD_NUM9, false); /* Reducing the operating frequency can effectively reduce power consumption. */ touch_pad_sleep_channel_set_work_time(1000, TOUCH_PAD_MEASURE_CYCLE_DEFAULT); /* Enable touch sensor clock. Work mode is "timer trigger". */ touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); touch_pad_fsm_start(); vTaskDelay(100 / portTICK_RATE_MS); /* read sleep touch pad value */ uint32_t touch_value; touch_pad_sleep_channel_read_smooth(TOUCH_PAD_NUM9, &touch_value); touch_pad_sleep_set_threshold(TOUCH_PAD_NUM9, touch_value * 0.1); //10% printf("test init: touch pad [%d] slp %d, thresh %d\n", TOUCH_PAD_NUM9, touch_value, (uint32_t)(touch_value * 0.1)); #endif printf("Enabling touch pad wakeup\n"); esp_sleep_enable_touchpad_wakeup(); esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); #endif // CONFIG_EXAMPLE_TOUCH_WAKEUP #ifdef CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP #if CONFIG_IDF_TARGET_ESP32 printf("Enabling ULP wakeup\n"); esp_sleep_enable_ulp_wakeup(); #endif #endif #if CONFIG_IDF_TARGET_ESP32 // Isolate GPIO12 pin from external circuits. This is needed for modules // which have an external pull-up resistor on GPIO12 (such as ESP32-WROVER) // to minimize current consumption. rtc_gpio_isolate(GPIO_NUM_12); #endif printf("Entering deep sleep\n"); gettimeofday(&sleep_enter_time, NULL); #ifdef CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP #if CONFIG_IDF_TARGET_ESP32 start_ulp_temperature_monitoring(); #endif #endif esp_deep_sleep_start(); } #ifdef CONFIG_EXAMPLE_TOUCH_WAKEUP #if CONFIG_IDF_TARGET_ESP32 static void calibrate_touch_pad(touch_pad_t pad) { int avg = 0; const size_t calibration_count = 128; for (int i = 0; i < calibration_count; ++i) { uint16_t val; touch_pad_read(pad, &val); avg += val; } avg /= calibration_count; const int min_reading = 300; if (avg < min_reading) { printf("Touch pad #%d average reading is too low: %d (expecting at least %d). " "Not using for deep sleep wakeup.\n", pad, avg, min_reading); touch_pad_config(pad, 0); } else { int threshold = avg - 100; printf("Touch pad #%d average: %d, wakeup threshold set to %d.\n", pad, avg, threshold); touch_pad_config(pad, threshold); } } #endif #endif // CONFIG_EXAMPLE_TOUCH_WAKEUP #ifdef CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP #if CONFIG_IDF_TARGET_ESP32 static void start_ulp_temperature_monitoring(void) { /* * This ULP program monitors the on-chip temperature sensor and wakes the chip up when * the temperature goes outside of certain window. * When the program runs for the first time, it saves the temperature measurement, * it is considered initial temperature (T0). * * On each subsequent run, temperature measured and compared to T0. * If the measured value is higher than T0 + max_temp_diff or lower than T0 - max_temp_diff, * the chip is woken up from deep sleep. */ /* Temperature difference threshold which causes wakeup * With settings here (TSENS_CLK_DIV=2, 8000 cycles), * TSENS measurement is done in units of 0.73 degrees Celsius. * Therefore, max_temp_diff below is equivalent to ~2.2 degrees Celsius. */ const int16_t max_temp_diff = 3; // Number of measurements ULP should do per second const uint32_t measurements_per_sec = 5; // Allow TSENS to be controlled by the ULP SET_PERI_REG_BITS(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_CLK_DIV, 2, SENS_TSENS_CLK_DIV_S); SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 3, SENS_FORCE_XPD_SAR_S); CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP); CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_DUMP_OUT); CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP_FORCE); // Clear the part of RTC_SLOW_MEM reserved for the ULP. Makes debugging easier. memset(RTC_SLOW_MEM, 0, CONFIG_ESP32_ULP_COPROC_RESERVE_MEM); // The first word of memory (at data offset) is used to store the initial temperature (T0) // Zero it out here, then ULP will update it on the first run. ulp_data_write(0, 0); // The second word is used to store measurement count, zero it out as well. ulp_data_write(1, 0); const ulp_insn_t program[] = { // load data offset into R2 I_MOVI(R2, ULP_DATA_OFFSET), // load/increment/store measurement counter using R1 I_LD(R1, R2, 1), I_ADDI(R1, R1, 1), I_ST(R1, R2, 1), // enable temperature sensor I_WR_REG(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR_S, SENS_FORCE_XPD_SAR_S + 1, 3), // do temperature measurement and store result in R3 I_TSENS(R3, 8000), // disable temperature sensor I_WR_REG(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR_S, SENS_FORCE_XPD_SAR_S + 1, 0), // Save current measurement at offset+2 I_ST(R3, R2, 2), // load initial value into R0 I_LD(R0, R2, 0), // if threshold value >=1 (i.e. initialized), goto 1 M_BGE(1, 1), // otherwise, save the current value as initial (T0) I_MOVR(R0, R3), I_ST(R0, R2, 0), M_LABEL(1), // check if the temperature is greater or equal (T0 + max_temp_diff) // uses R1 as scratch register, difference is saved at offset + 3 I_ADDI(R1, R0, max_temp_diff - 1), I_SUBR(R1, R1, R3), I_ST(R1, R2, 3), M_BXF(2), // check if the temperature is less or equal (T0 - max_temp_diff) // uses R1 as scratch register, difference is saved at offset + 4 I_SUBI(R1, R0, max_temp_diff - 1), I_SUBR(R1, R3, R1), I_ST(R1, R2, 4), M_BXF(2), // temperature is within (T0 - max_temp_diff; T0 + max_temp_diff) // stop ULP until the program timer starts it again I_HALT(), M_LABEL(2), // temperature is out of bounds // disable ULP program timer I_WR_REG_BIT(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN_S, 0), // initiate wakeup of the SoC I_WAKE(), // stop the ULP program I_HALT() }; // Load ULP program into RTC_SLOW_MEM, at offset 0 size_t size = sizeof(program)/sizeof(ulp_insn_t); ESP_ERROR_CHECK( ulp_process_macros_and_load(0, program, &size) ); assert(size < ULP_DATA_OFFSET && "ULP_DATA_OFFSET needs to be greater or equal to the program size"); // Set ULP wakeup period const uint32_t sleep_cycles = rtc_clk_slow_freq_get_hz() / measurements_per_sec; REG_WRITE(SENS_ULP_CP_SLEEP_CYC0_REG, sleep_cycles); // Start ULP ESP_ERROR_CHECK( ulp_run(0) ); } #endif // CONFIG_IDF_TARGET_ESP32 #endif // CONFIG_EXAMPLE_ULP_TEMPERATURE_WAKEUP |
Компиляция скетча
Для прошивки микросхемы введите следующую команду в последовательном терминале. Не забудьте заменить COM-порт на тот, через который подключена ваша плата.
|
1 |
idf.py -p COMX flash monitor |
После успешной прошивки кода терминал ESP-ID отображает следующие сообщения. Это начальный запуск, поэтому он отображается сообщением ‘Not a deep sleep reset’ («Не выполнен сброс в режиме глубокого сна»). Таймер пробуждения включен на заданное время 20 секунд. Пробуждение ext1 настроено на GPIO2 и GPIO4. Для пробуждения тачпада были настроены GPIO33 и GPIO32, которые соответствуют тачпаду 8 и тачпаду 9 соответственно. Для обоих тачпадов выводится среднее значение показаний вместе с установленным порогом. Затем включается пробуждение тачпада и ULP. Наконец, плата ESP32 переходит в режим глубокого сна.
Это сообщения, которые мы получили в терминале, когда ESP32 вышел из глубокого сна. ESP32 снова загружается, но на этот раз терминал выводит сообщение о пробуждении и источник, вызвавший его. В нашем случае пробуждение произошло из-за ULP. После вывода всех сообщений, показывающих измерения температуры ULP и активацию источников пробуждения, ESP32 снова переходит в глубокий сон.
Для запуска пробуждения через ext1 сначала убедитесь, что контакты GPIO2 и GPIO4 ESP32 находятся в низком состоянии, чтобы избежать плавающих контактов, а затем подключите один из этих двух контактов к высокому состоянию. Аналогично, для запуска пробуждения с помощью тачпада подключите провод к контактам GPIO32 или GPIO33 и коснитесь их. Вы также можете подключить к этим контактам сенсоры касания. Без использования дополнительного оборудования будут работать только источники пробуждения по таймеру и ULP.
12 просмотров












