NVS Data Storage and Reading in ESP32: A Comprehensive Guide

Ibrahim Bin Mansur
3 min read1 day ago

--

In the world of IoT and embedded systems, efficient data storage and retrieval are crucial. For ESP32 developers, the Non-Volatile Storage (NVS) library provides a powerful solution for storing and accessing data that persists across power cycles. In this post, we’ll dive deep into NVS data storage and reading, using real-world examples to illustrate its implementation.

Table of Contents

  1. Introduction to NVS
  2. Project Setup
  3. Writing Data to NVS
  4. Reading Data from NVS
  5. Practical Application: Storing SSL Certificates
  6. Best Practices and Considerations
  7. Conclusion

Introduction to NVS

Non-Volatile Storage (NVS) is a part of the ESP-IDF framework that allows you to store key-value pairs in flash memory. It’s particularly useful for storing configuration data, calibration parameters, or any information that needs to persist when the device is powered off.

Project Setup

Before we dive into the code, let’s look at the project setup. We’re using PlatformIO for this project, as indicated by the platformio.ini file:

[env:ESP32_S3_DEV_4MB_QD_No_PSRAM]
platform = espressif32
board = ESP32_S3_DEV_4MB_QD_No_PSRAM
framework = arduino
monitor_speed = 115200

board_build.partitions = min_spiffs.csv

This configuration targets an ESP32-S3 board with 4MB of flash and no PSRAM. We’re using the Arduino framework and a custom partition scheme (min_spiffs.csv) to allocate space for our NVS storage.

Writing Data to NVS

Let’s examine how to write data to NVS using a real-world example: storing an SSL certificate. Here’s a snippet from our write_nvs.txt file:

#include <Preferences.h>


const char* ca_cert = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIGBzCCA++gAwIBAgIUZuJCdjrF5BjeM0z317e8bIumWpUwDQYJKoZIhvcNAQEL\n" \
"pH+SlAbQPsoGdD4=\n" \
"-----END CERTIFICATE-----";

void writeCertData() {
Preferences prefs;
prefs.begin("cert_data", false);

prefs.putBytes("server_cert", ca_cert, strlen(ca_cert) + 1);

prefs.end();
Serial.println("Certificate saved to NVS");
Serial.print("Certificate size: ");
Serial.println(strlen(ca_cert) + 1);
}

void setup() {
Serial.begin(115200);
// Write certificate data to NVS
writeCertData();
}

void loop() {
// No need to do anything in the loop
}

Key points:

  1. We use the Preferences library, which provides a user-friendly interface to NVS.
  2. prefs.begin("cert_data", false) opens a namespace called "cert_data" in read-write mode.
  3. prefs.putBytes() stores the certificate as a byte array.
  4. We always call prefs.end() to close the namespace and ensure data is written to flash.

Reading Data from NVS

Now, let’s look at how to read this data back from NVS. Here’s a snippet from our read_nvs.txt file:

#include <Preferences.h>


char* server_cert = nullptr;
uint32_t server_cert_len;

void loadCertData() {
Preferences prefs;
prefs.begin("cert_data", false);

server_cert_len = prefs.getBytesLength("server_cert");
if (server_cert_len > 0) {
server_cert = new char[server_cert_len + 1];
prefs.getBytes("server_cert", server_cert, server_cert_len);
server_cert[server_cert_len] = '\0';
} else {
Serial.println("No server certificate found in NVS");
}

prefs.end();
}

void setup() {
Serial.begin(115200);

// Connect to WiFi

// Load server certificate and private key from NVS
loadCertData();

// Print the server certificate
if (server_cert != nullptr) {
Serial.println("Server Certificate:");
Serial.println(server_cert);
}
}

void loop() {

}

Key points:

  1. We first check the length of the stored data using prefs.getBytesLength().
  2. If data exists, we allocate memory and use prefs.getBytes() to retrieve it.
  3. We null-terminate the string to ensure it’s properly formatted.

Practical Application: Storing SSL Certificates

Storing SSL certificates in NVS is a common use case for secure IoT applications. By keeping certificates in NVS:

  1. We save flash space in the firmware binary.
  2. We can update certificates without reflashing the entire firmware.
  3. We can securely store multiple certificates for different purposes.

Our example demonstrates storing a CA certificate, but you could extend this to store client certificates and private keys as well.

Best Practices and Considerations

  1. Namespace Management: Use meaningful namespace names (like “cert_data”) to organize your data.
  2. Error Handling: Always check return values and handle potential errors when reading/writing NVS.
  3. Memory Management: When reading variable-length data, allocate memory dynamically and remember to free it when no longer needed.
  4. Security: While NVS provides persistence, it’s not inherently secure. For sensitive data like private keys, consider additional encryption.
  5. Wear Leveling: NVS uses wear leveling to extend flash life, but be mindful of write frequency for frequently changing data.

Conclusion

Non-Volatile Storage in ESP32 provides a robust solution for persistent data storage. By leveraging NVS, you can create more flexible and maintainable IoT applications. Whether you’re storing configuration data, certificates, or sensor calibration values, NVS offers a straightforward API to manage your data effectively.

Remember to always refer to the official ESP-IDF documentation for the most up-to-date information on NVS usage and best practices. Happy coding!

References

--

--