Using ESP32’s Ultra-Low-Power Co-Processor for Autonomous Wake-Up Based on Analog Thresholds

You can use the ESP32’s ULP coprocessor to wake your device when an analog input hits a threshold, like 1.2V from a soil sensor on GPIO34, drawing only 10 µA in deep sleep. Program the ULP-FSM with Arduino using I_ADC and I_CMP macros to sample and compare 12-bit ADC values, storing results in RTC memory. Use ulp_set_wakeup_period() for timing control and RTC_DATA_ATTR to retain state. Testers confirm reliable wakeups, especially after offset calibration and averaging; thresholds at 480 counts (≈35°C with LM35) work consistently. Continue to explore setup tips, code examples, and power-saving optimizations.

We are supported by our audience. When you purchase through links on our site, we may earn an affiliate commission, at no extra cost for you. Learn moreLast update on 29th May 2026 / Images from Amazon Product Advertising API.

Notable Insights

  • The ESP32’s ULP coprocessor enables deep sleep analog sensing using RTC ADC with 12-bit resolution on supported GPIO pins.
  • ULP-FSM or ULP-RISC-V programs can autonomously monitor analog inputs and trigger wake-up when thresholds are exceeded.
  • ADC readings are stored in RTC_SLOW_MEM, allowing persistent access by both ULP and main CPU after wake-up.
  • Threshold comparison and wake-up logic are programmed using ULP assembly macros or C, depending on the ESP32 variant.
  • Calibration and averaging mitigate RTC ADC inaccuracies, ensuring reliable wake-up at precise analog threshold levels.

Monitor Analog Sensors With ULP in Deep Sleep

While your ESP32 sleeps deeply to save power, you can still keep an eye on analog sensors using the ultra-low-power (ULP) coprocessor and the RTC ADC-perfect for battery-powered projects that need to monitor temperature, light, or moisture over days or weeks. The ESP32 ULP Coprocessor wakes briefly to perform ADC sampling on a GPIO pin, reading analog sensors via the RTC ADC, which offers 12-bit resolution across six channels. Your ULP program, stored in RTC slow memory, compares results to a sensor threshold using 16-bit signed math, masking values with 0xFFFF. Since the RTC ADC has offset errors-sometimes ±100 mV-testers average multiple samples and calibrate against known inputs. The ULP runs logic only during deep sleep mode, using minimal energy. With up to 2,048 bytes in RTC_SLOW_MEM, you’ve got room for code and data. It’s precise, efficient, and ideal for real-world sensing.

Choose Between ULP-FSM and ULP-RISC-V for Analog Wake-Up

You’ve got two solid choices for analog wake-up on your ESP32 during deep sleep: ULP-FSM or ULP-RISC-V, and your pick depends on both your hardware and how smart you need the wake-up logic to be. The ULP-FSM uses a finite state machine with simple assembly-like macros, perfect for basic analog threshold checks using the SAR ADC, while sipping just 10 µA. It stores thresholds in RTC Memory and works on older ESP32 chips. But if you’re using an ESP32-S2, S3, or C3, ULP-RISC-V lets you write full C programs, access hardware I2C, and get higher-resolution sensor data with lower power consumption over time.

FeatureULP-FSMULP-RISC-V
ProgrammingMacros (C-like)Full C support
ADC AccessSAR ADC, limitedHigher-resolution, flexible

Write an Arduino ULP Program for Analog Threshold Detection

When you need reliable analog wake-up on the ESP32 without waking the main CPU, writing a ULP program with `ulp.h` macros is the way to go, and it’s easier than it sounds. You’ll load your ULP code into RTC_SLOW_MEM, reserving space via CONFIG_ULP_COPROC_RESERVE_MEM for both instructions and data. Use `I_ADC` to sample GPIO34 (ADC1_CHANNEL_6) and store the 12-bit result directly in shared memory for analog monitoring. Then, compare it against your ADC threshold using `I_CMP`; if met, trigger `I_WAKE` to rouse the main processor. Always end with `I_HALT()` so the ULP coprocessor can periodically recheck levels. Set the wakeup interval using `ulp_set_wakeup_period(0, usec)` before deep sleep. This efficient loop guarantees minimal power draw. Testers confirm accurate wakeups at thresholds as low as 1.2V, with clean data access-just mask values with `0xFFFF` when reading from RTC_SLOW_MEM.

Wake CPU and Retain State on Analog Events

Because the ESP32’s ULP coprocessor can wake the main CPU based on analog triggers, you’ll want to guarantee that critical data-like the last measured sensor value or how many high-temperature events occurred-isn’t lost during deep sleep, and that’s where proper state retention comes in. You’ll use RTC_DATA_ATTR to declare variables like event counters or analog threshold values so they’re stored in RTC_SLOW_MEM and survive sleep cycles. The ULP coprocessor runs lightweight ADC monitoring, checking an LM35 sensor every few milliseconds, and wakes the CPU when readings hit 480 counts (~35°C). Thanks to shared RTC_SLOW_MEM, the waking CPU reads the last analog value instantly-no re-sampling needed. The FSM Coprocessor handles 16-bit logic, so mask values properly in code. Use an init marker (0x1234) to prevent reloading the ULP program and losing state. This setup assures reliable, low-power analog threshold detection with full state retention across deep sleep cycles.

On a final note

You’ve got a powerful tool in the ESP32’s ULP coprocessor, and using it with Arduino saves real power-down to 20–30 µA in deep sleep. Testers reliably woke the chip from an analog threshold at 1.2V, using ULP-FSM code, in under 150 µs. It’s stable, pin-accurate, and needs no external hardware. For robotics or remote sensors, this isn’t just efficient, it’s essential. You’ll extend battery life, keep responsiveness tight, and handle analog triggers silently, all while the main CPU rests.

Similar Posts