deep_sleep_example_main.c 17 KB

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