Mastering Esp8266 Millis Functionality During Deep Sleep Mode

how to get esp8266 millis to run during deep sleep

The ESP8266 is a popular microcontroller known for its low power consumption and Wi-Fi capabilities, making it ideal for IoT projects. However, when using deep sleep mode to conserve energy, the `millis()` function, which is crucial for timing operations, stops incrementing because the microcontroller’s main clock is disabled. This poses a challenge for applications requiring precise timing or periodic wake-ups. To address this, developers often use the `RTC memory` (Real-Time Clock memory) to store a counter that tracks elapsed time across sleep cycles. By saving the `millis()` value before entering deep sleep and restoring it upon wake-up, the counter can be manually incremented to simulate continuous `millis()` operation. Additionally, leveraging the ESP8266’s built-in `RTC timer` for wake-up intervals ensures accurate timing without relying on `millis()`. This approach allows projects to maintain timing functionality while maximizing energy efficiency during deep sleep.

Characteristics Values
Deep Sleep Compatibility millis() does not increment during deep sleep on ESP8266.
Workaround Use a separate timer or RTC (Real-Time Clock) to track time during deep sleep.
RTC Memory Utilize RTC memory to store a timestamp before entering deep sleep.
RTC Timer Use ESP.deepSleep() with a wake-up timer to simulate time tracking.
External RTC Integrate an external RTC module (e.g., DS3231) for accurate timekeeping.
Interrupt Pins Use RTC GPIO pins (GPIO16) for wake-up interrupts.
Power Consumption RTC-based solutions consume minimal power during deep sleep.
Accuracy External RTC modules provide higher accuracy than internal RTC.
Code Example Store millis() in RTC memory before sleep and restore it after wake-up.
Limitations RTC memory on ESP8266 is limited (80 bytes) and volatile.
Alternative Use a combination of millis() and RTC timer for hybrid tracking.
Libraries ESP8266WiFi.h, Wire.h (for external RTC), ESP.h for deep sleep.
Wake-Up Sources Timer, GPIO interrupt, or external RTC alarm.
Time Drift Internal RTC may drift over time; external RTC is more reliable.
Application Suitable for low-power IoT devices requiring periodic wake-ups.

shunsleep

Setting RTC Timer for Wake-Up

The ESP8266's deep sleep mode is a powerful feature for conserving energy, but it poses a challenge when you need to keep track of time using the `millis()` function, as it does not increment during deep sleep. To address this, you can leverage the Real-Time Clock (RTC) timer to schedule wake-ups at precise intervals. Setting the RTC timer for wake-up involves configuring the ESP8266 to exit deep sleep after a specified duration, allowing you to maintain a sense of elapsed time without relying on `millis()`.

To begin, you must include the necessary libraries and initialize the RTC memory. The ESP8266 has RTC memory that remains active during deep sleep, enabling you to store variables and timer values. Use the `user_rtc_memory` structure to store the wake-up interval or any other data needed across sleep cycles. Before entering deep sleep, write the desired wake-up time or interval to the RTC memory. This ensures that the ESP8266 knows when to wake up, even though `millis()` is not operational during this state.

Next, configure the deep sleep wake-up mechanism using the RTC timer. The ESP8266 supports wake-up from deep sleep based on a time interval specified in microseconds. Use the `ESP.deepSleep()` function and pass the wake-up interval in microseconds. For example, to wake up every 60 seconds, you would call `ESP.deepSleep(60e6)`. This function sets the RTC timer and puts the ESP8266 into deep sleep mode until the timer expires. Ensure that the wake-up interval aligns with your application's timing requirements.

After waking up from deep sleep, retrieve any necessary data from the RTC memory to continue your program's execution. Since `millis()` resets to zero after each wake-up, use the RTC memory to store and track elapsed time or other state information. By combining the RTC timer for wake-up with RTC memory for data persistence, you can effectively manage timing and state across deep sleep cycles without relying on `millis()`.

Finally, test and calibrate your setup to ensure accurate wake-up intervals. Factors such as clock drift or variations in sleep duration can affect timing precision. Consider using an external time source or adjusting the wake-up interval to compensate for any discrepancies. By carefully setting the RTC timer for wake-up and managing RTC memory, you can achieve reliable and energy-efficient operation of your ESP8266-based projects, even when `millis()` is not available during deep sleep.

shunsleep

Using External Interrupts to Trigger Wake

The ESP8266's deep sleep mode is a powerful feature for conserving energy, but it halts the execution of most functions, including the `millis()` timer. This can be problematic for applications requiring precise timing or periodic tasks during sleep. One effective solution is to utilize external interrupts to trigger wake-up events, allowing the ESP8266 to exit deep sleep and resume operation when specific conditions are met. This approach ensures that the device remains responsive without continuously consuming power.

To implement external interrupts for wake-up, the ESP8266's GPIO pins can be configured to detect changes in their state, such as a rising or falling edge. When such a change occurs, the ESP8266 wakes from deep sleep, enabling the execution of code and the resumption of the `millis()` timer. The first step is to identify the appropriate GPIO pin to use as the interrupt source. Not all GPIO pins support wake-up functionality, so refer to the ESP8266 datasheet to select a compatible pin. For example, GPIO16 is commonly used for this purpose due to its low-power wake-up capability.

Once the GPIO pin is selected, it must be configured to trigger an interrupt on the desired edge (rising, falling, or both). This is done using the `attachInterrupt()` function in the Arduino IDE. For instance, `attachInterrupt(digitalPinToInterrupt(GPIO_PIN), wakeUpFunction, RISING)` sets up the pin to wake the ESP8266 when a rising edge is detected. The `wakeUpFunction` is a user-defined function that executes immediately upon wake-up, allowing you to handle the event and proceed with your application logic.

Before entering deep sleep, the ESP8266 must be configured to enable wake-up via the chosen GPIO pin. This is achieved using the `ESP.deepSleep()` function with the appropriate wake-up mode specified. For example, `ESP.deepSleep(0, WAKE_RF_DISABLED, GPIO_PIN, RISING)` configures the device to wake up when a rising edge is detected on the specified GPIO pin. The `WAKE_RF_DISABLED` parameter ensures that the RF module remains off during sleep, further reducing power consumption.

Finally, it's crucial to ensure that the external interrupt source is stable and reliable to avoid unintended wake-up events. This may involve using pull-up or pull-down resistors to maintain a consistent pin state when the interrupt signal is inactive. By carefully configuring the GPIO pin and interrupt conditions, you can effectively use external interrupts to wake the ESP8266 from deep sleep, enabling precise timing and event-driven functionality while minimizing power usage. This method is particularly useful for battery-powered projects or applications requiring long periods of inactivity punctuated by brief periods of activity.

shunsleep

Optimizing Deep Sleep Current Consumption

The ESP8266's deep sleep mode is a powerful feature for conserving energy in battery-powered projects, but optimizing its current consumption requires careful consideration. One common challenge is maintaining timekeeping during deep sleep, as the `millis()` function, which relies on the ESP8266's internal timer, stops counting while the chip is asleep. To address this, developers often turn to external hardware timers or real-time clocks (RTCs) that can run independently of the ESP8266's main processor. By using an external RTC, such as the DS3231, you can track time accurately during deep sleep without relying on the ESP8266's internal timer. This approach ensures that your device wakes up at precise intervals, minimizing unnecessary power consumption.

Another strategy for optimizing deep sleep current consumption is to disable all unnecessary peripherals and GPIO pins before entering sleep mode. The ESP8266 draws additional current when these components are active, even in deep sleep. By configuring the GPIO pins to a low-power state and disabling unused peripherals like Wi-Fi, you can significantly reduce the quiescent current. For example, setting GPIO pins to input mode with pull-up or pull-down resistors disabled can help eliminate leakage currents. Additionally, ensuring that the analog-to-digital converter (ADC) and other power-hungry modules are turned off before deep sleep can further lower the overall current draw.

Selecting the appropriate wake-up source is critical for minimizing power consumption during deep sleep. The ESP8266 supports multiple wake-up methods, including timer-based wake-up, external interrupts, and RTC-based wake-up. For applications requiring precise timing, using an external RTC to trigger the wake-up is ideal, as it allows the ESP8266 to remain in deep sleep until the exact moment it needs to activate. Alternatively, if your project can tolerate less precise timing, using the internal RTC memory of the ESP8266 with a wake-up interval can be sufficient. However, this method may introduce slight timing inaccuracies due to the internal RTC's limited accuracy in deep sleep.

Reducing the deep sleep wake-up time is another effective way to optimize power consumption. The ESP8266 consumes more power during the wake-up process, so minimizing this duration is crucial. To achieve this, pre-configure as much of the system as possible before entering deep sleep, such as setting up Wi-Fi credentials or initializing sensors. Upon waking, the ESP8266 can immediately perform its tasks without spending extra time on setup, thereby reducing active time and overall energy usage. Additionally, using lightweight protocols and minimizing data transmission can further decrease the time the ESP8266 remains active, contributing to lower power consumption.

Finally, consider the power supply and voltage regulator efficiency when optimizing deep sleep current consumption. The ESP8266's deep sleep current is influenced by the external circuitry, including the voltage regulator. Using a low-quiescent-current regulator, such as the MCP1700, can help reduce power losses in the supply chain. Furthermore, ensuring that the power supply itself is efficient and stable can prevent unnecessary current draw. For battery-powered applications, monitoring the battery's discharge curve and selecting a suitable voltage range for the ESP8266 can also contribute to prolonged battery life. By addressing both the ESP8266's internal settings and the external power management, you can achieve optimal deep sleep current consumption for your project.

shunsleep

Handling Millis Overflow in Sleep Mode

When working with the ESP8266 and utilizing deep sleep mode, one critical challenge is handling the `millis()` function, which is essential for timing operations. The `millis()` function increments every millisecond since the ESP8266 started, but it overflows back to zero after approximately 49.7 days. In deep sleep mode, the ESP8266’s internal timer stops, causing `millis()` to reset to zero upon wake-up. This behavior can lead to incorrect timing calculations, especially in applications requiring long-term tracking of elapsed time. To address this, developers must implement strategies to manage `millis()` overflow and maintain accurate timing across sleep cycles.

One effective approach to handling `millis()` overflow in sleep mode is to use non-volatile memory (NVS) or the RTC (Real-Time Clock) memory of the ESP8266. Before entering deep sleep, store the current value of `millis()` in RTC memory. Upon wake-up, retrieve this stored value and add it to the new `millis()` reading. This technique effectively extends the `millis()` counter beyond its natural overflow limit, allowing it to continue tracking time across multiple sleep cycles. Libraries like `ESP8266TrueRandom` or custom implementations can simplify this process by providing functions to read from and write to RTC memory.

Another method involves using an external real-time clock (RTC) module, such as the DS3231, to keep track of elapsed time independently of the ESP8266’s `millis()` function. The external RTC continues to run during deep sleep, providing an accurate time reference. Upon wake-up, the ESP8266 can synchronize its internal timer with the external RTC, ensuring continuity in timekeeping. This approach eliminates the need to manage `millis()` overflow directly but requires additional hardware and power considerations.

For applications that do not require precise timekeeping but still need to track relative time intervals, a simpler solution is to use a counter stored in non-volatile memory. Increment this counter before each deep sleep cycle and use it to calculate elapsed time upon wake-up. This method avoids the complexities of `millis()` overflow but may not provide the same level of accuracy, especially for long sleep durations. It is best suited for tasks like periodic sensor readings or data logging with flexible timing requirements.

Lastly, developers can leverage the `esp_deep_sleep_get_wake_time()` function, which returns the duration the ESP8266 has been in deep sleep. By combining this value with a stored `millis()` offset, it is possible to reconstruct the total elapsed time since the device started. This approach requires careful management of variables across sleep cycles but offers a lightweight solution without additional hardware. Proper testing and validation are essential to ensure the implementation handles edge cases, such as power interruptions or unexpected resets.

In summary, handling `millis()` overflow in deep sleep mode on the ESP8266 requires a combination of hardware and software strategies. Whether using RTC memory, external RTC modules, or custom counters, the goal is to maintain continuity in timekeeping across sleep cycles. Each method has its trade-offs in terms of complexity, accuracy, and resource usage, so the choice depends on the specific requirements of the application. By carefully implementing these techniques, developers can ensure reliable timing operations even in low-power, deep-sleep scenarios.

shunsleep

Synchronizing Time After Deep Sleep Wake

When working with the ESP8266 and utilizing deep sleep modes, one common challenge is maintaining accurate timekeeping, especially with the `millis()` function, which does not increment during deep sleep. To address this, synchronizing time after waking from deep sleep is crucial. The first step is to establish a reliable time source. The ESP8266 can connect to an NTP (Network Time Protocol) server to fetch the current time upon waking. This requires enabling Wi-Fi functionality and using the `WiFiUDP` library to communicate with an NTP server. By querying the server, the device can obtain the current UTC time, which can then be used as a reference point.

Once the ESP8266 wakes from deep sleep, it should immediately attempt to connect to Wi-Fi and fetch the time from the NTP server. This process involves initializing the Wi-Fi interface, connecting to the network, and sending an NTP request. Libraries like `ESP8266WiFi` and `NTPClient` can simplify this task. After receiving the time, it is essential to calculate the time elapsed since the device entered deep sleep. This can be done by storing the `millis()` value before entering deep sleep and comparing it with the current `millis()` value after waking. However, since `millis()` resets after waking, an external Real-Time Clock (RTC) or a non-volatile storage method (like EEPROM) can be used to store the sleep duration.

To compensate for the time lost during deep sleep, the fetched NTP time should be adjusted by adding the stored sleep duration. This ensures that the device’s internal clock remains synchronized with real-world time. For example, if the device was asleep for 12 hours and the NTP server reports the current time as 12:00 PM, the adjusted time would be 12:00 AM (assuming it went to sleep at that time). This adjusted time can then be used as the new reference point for `millis()`-based timing operations.

Another approach is to use the ESP8266’s built-in RTC memory to maintain a counter of sleep cycles. By incrementing this counter each time the device wakes up, you can track the total sleep duration across multiple cycles. This method avoids the need for external components but requires careful management of the RTC memory to prevent data loss. Combining this with NTP synchronization ensures both accuracy and reliability in timekeeping.

Finally, it is important to handle edge cases, such as NTP server unavailability or Wi-Fi connection failures. In such scenarios, the device should fall back to using the last known synchronized time and the stored sleep duration. Implementing retries for Wi-Fi and NTP requests can improve robustness. Additionally, logging the synchronization process can help debug issues and ensure the system behaves as expected. By carefully synchronizing time after deep sleep, the ESP8266 can maintain accurate timing for applications requiring precise scheduling or timestamping.

Frequently asked questions

The `millis()` function does not increment during deep sleep because the ESP8266's main clock is turned off. To track time during deep sleep, use the `RTC` (Real-Time Clock) functions like `esp_deep_sleep_get_wake_time()` or `esp_deep_sleep_get_wake_cause()` to measure sleep duration.

No, `millis()` resets to 0 after waking from deep sleep. Instead, store the wake-up time using `RTC` functions and calculate elapsed time manually or use a library like `ESP8266TrueRandom` that leverages RTC timers.

You can simulate `millis()` by storing the last wake-up time in RTC memory and adding the sleep duration upon wake-up. Use `system_deep_sleep_set_option(0)` to preserve RTC memory and track time across sleep cycles.

Use `esp_deep_sleep_get_wake_time()` to get the wake-up timestamp and calculate the difference between wake-up times to measure sleep duration. This method relies on the RTC, which remains active during deep sleep.

Written by
Reviewed by

Explore related products

Share this post
Print
Did this article help you?

Leave a comment