I was working on a battery-powered project using an ESP32, and I ran into a problem. The device needed to go into deep sleep to save power, but I also needed it to remember a certain variable even after it woke up. Normally, when the ESP32 wakes from deep sleep, it starts over like it was just powered on. That means all variables go back to their original values unless you do something extra.
At first, I assumed I could just declare a variable and expect it to stay the same, but every time the ESP woke up, it reset everything. That wasn’t going to work for my project since I needed to track changes over time, even while the device was sleeping most of the day. So, I started looking into ways the ESP32 could keep data in memory without using too much power.
That’s when I learned that the ESP32 has a few clever tricks to help with this—specifically, something called RTC memory and another method that lets you save files right on the chip. Both turned out to be really useful, depending on what kind of data you want to keep and for how long.
Using RTC Memory to Keep Data During Deep Sleep
To solve the problem of losing variable data during deep sleep, I used something called RTC memory on the ESP32. When the ESP32 goes into deep sleep, it shuts off almost everything to save power, including the CPU and most of the RAM. But it has a small part of memory that stays on, and that’s the RTC memory. I used it to keep a counter that would keep increasing every time the device woke up from deep sleep.
In my code, I set up two counters—one normal and one with a special tag so the ESP knows to store it in RTC memory. Every time the ESP woke up, it would increment both counters. The normal one always started back at one, but the RTC one kept counting higher, because it remembered the value from before. This way, the ESP could keep track of how many times it had been woken up, even though it was technically starting fresh each time.
It’s pretty easy to use once you know where to put that little extra bit in your variable declaration. You just upload the code, open the serial monitor, and you can see the RTC counter going up, while the regular one stays the same. Just keep in mind that if you reset the board or lose power completely, the RTC memory is wiped. So it’s only good for saving things during deep sleep, not full power loss.
Here is the full code from my example.
#include <esp_sleep.h>
RTC_DATA_ATTR int rtcCounter = 0; // This will persist across deep sleep
int regularCounter = 0; // This will reset every time
void setup() {
Serial.begin(115200);
delay(1000); // Give time for Serial to initialize
rtcCounter++;
regularCounter++;
Serial.println("Waking up from deep sleep...");
Serial.print("RTC Counter (persists): ");
Serial.println(rtcCounter);
Serial.print("Regular Counter (resets): ");
Serial.println(regularCounter);
// Wait to view output before going back to sleep
delay(3000);
// Set deep sleep timer and enter deep sleep
Serial.println("Going to deep sleep for 5 seconds...");
delay(500);
esp_sleep_enable_timer_wakeup(5 * 1000000); // 5 seconds
esp_deep_sleep_start();
}
void loop() {
// Not used - ESP32 will restart from setup() after deep sleep
}
Using SPIFFS to Save Data Across Power Resets
RTC memory was great for saving data while the ESP32 was sleeping, but it didn’t help when I powered the board off completely. For cases like so where we need to keep data even when we are powered off, the ESP32 has another trick up in it sleeve, called SPPIFS. SPIFFS stands for SPI Flash File System, and it lets you save data as files right on the flash storage of the ESP32. This means the data stays even if the board loses power or gets reset, which is exactly what I needed.
I made a simple sketch that saves a counter inside a text file. Each time the ESP starts up, it reads the value from that file, adds one, and writes it back. So now, even if I unplug the board or hit the reset button, the counter keeps going from where it left off. That was really helpful for tracking how many times the device had been powered on, or for saving any kind of setting that shouldn’t be lost.
The only thing I had to watch out for was making sure the file system was properly initialized and that the file existed before trying to read or write. Once I handled that, it worked smoothly. I could remove the USB cable, plug it back in, and still see the counter going up. It felt like having a little hard drive right on the ESP32.
Here is the full code for the SPIFFS example.
#include <SPIFFS.h>
const char* path = "/counter.txt";
int readCounter() {
if (!SPIFFS.exists(path)) return 0;
File file = SPIFFS.open(path, "r");
if (!file) return 0;
int val = file.parseInt();
file.close();
return val;
}
void writeCounter(int val) {
File file = SPIFFS.open(path, "w");
if (!file) return;
file.println(val);
file.close();
}
void setup() {
Serial.begin(115200);
delay(1000);
if (!SPIFFS.begin(true)) {
Serial.println("SPIFFS Mount Failed");
return;
}
int counter = readCounter();
Serial.print("SPIFFS Counter (persistent): ");
Serial.println(counter);
counter++;
writeCounter(counter);
Serial.println("Counter incremented and saved.");
delay(3000);
}
void loop() {
// nothing to do
}
Combining RTC Memory and SPIFFS
Once I got both methods working separately, I decided to combine them into one sketch. I wanted to have one counter that keeps increasing across deep sleep cycles using RTC memory, and another counter that survives even full power loss using SPIFFS. This way, I could see exactly how many times the ESP32 had woken up from sleep and how many times it had been fully restarted.
In the code, I declared the RTC counter with that special attribute so it stays in RTC memory, and then I used the same SPIFFS file approach for the other counter. During setup, I read the SPIFFS counter from the file, incremented both counters, and saved the new SPIFFS value back to the file. After that, I put the ESP back to deep sleep for five seconds, and the cycle repeats every time it wakes up.
When I tested it, I could see the RTC counter climbing with each deep sleep, but if I hit the reset button or unplugged the board, the RTC counter would start over while the SPIFFS one kept going. That clearly showed the difference between the two. Depending on what you need for your project—saving temporary data or keeping something permanent—you can now choose the best method or use both together like I did.
Here is the full code of the combined example.
#include <SPIFFS.h>
#include <esp_sleep.h>
RTC_DATA_ATTR int rtcCounter = 0; // Survives deep sleep only
const char* spiffsPath = "/spiffs_counter.txt";
// Read SPIFFS counter
int readSpiffsCounter() {
if (!SPIFFS.exists(spiffsPath)) return 0;
File file = SPIFFS.open(spiffsPath, "r");
if (!file) return 0;
int val = file.parseInt();
file.close();
return val;
}
// Write SPIFFS counter
void writeSpiffsCounter(int val) {
File file = SPIFFS.open(spiffsPath, "w");
if (!file) return;
file.println(val);
file.close();
}
void setup() {
Serial.begin(115200);
delay(1000); // Allow Serial to initialize
if (!SPIFFS.begin(true)) {
Serial.println("SPIFFS Mount Failed");
return;
}
rtcCounter++;
int spiffsCounter = readSpiffsCounter();
spiffsCounter++;
writeSpiffsCounter(spiffsCounter);
Serial.println("=== ESP32 Wakeup ===");
Serial.printf("RTC Counter (deep sleep only): %d\n", rtcCounter);
Serial.printf("SPIFFS Counter (persistent): %d\n", spiffsCounter);
Serial.println("Going to deep sleep for 5 seconds...\n");
delay(100); // Let Serial flush
esp_sleep_enable_timer_wakeup(5 * 1000000ULL); // 5 seconds
delay(100); // Allow idle tasks to run
esp_deep_sleep_start();
}
void loop() {
// Not used
}
Conclusion
Figuring out how to keep data on the ESP32, even after deep sleep or power loss, really helped me get more out of my projects. RTC memory is great when you want to save a variable during sleep without using much power, and SPIFFS is perfect when you need something to stick around even after turning the board off completely. Each one has its place, and knowing when to use which can make your projects a lot more reliable.
Combining the two gave me a lot more control. I could track both short-term and long-term data depending on what I needed. And the best part is, once you get the hang of it, it’s actually pretty simple to use. It just takes a few lines of code to start saving your own data on the ESP32.
If you haven’t tried this yet, I really recommend giving it a go. If you liked the article then I would ask you to consider subscribing to my YT channel. I make videos to teach people about electronics and coding in an easy and understandable way. If you want to support my work, consider becoming a Patreon Member.
The links below are affiliate links. When you click on affiliate links in my articles or videos, it means I may earn a small commission if you make a purchase. These links are a way to support my work without costing you anything extra—the price you pay stays the same, whether you use the link or not. The commissions I earn help cover the costs of creating free content, so I can keep sharing knowledge and helping you with your DIY projects. It’s a win-win: you get the tools or products you need, and I get to keep creating helpful resources for everyone. Thank you for your support!
- ESP32 DevKitC Board - https://s.click.aliexpress.com/e/_oCGu9qD
- ESP32 WROOM Dev Board - https://s.click.aliexpress.com/e/_oEQBXul
- ESP32-C3 Supermini Development Board - https://s.click.aliexpress.com/e/_onu0hF3
- ESP32-C6 Dev Board - https://s.click.aliexpress.com/e/_oFYwVgN
- ESP32 Relay Board - https://s.click.aliexpress.com/e/_oFg0Sed
- ESP32 Audio Kit - https://s.click.aliexpress.com/e/_ooI3LIt
- JCD Soldering Station - https://s.click.aliexpress.com/e/_opLuOPr
- Digital Multimeter - https://s.click.aliexpress.com/e/_ok54cQN