yahboom
HomeLearn
Solution
Blog
Online Store
About Us
EN/中文
ESP32 Core Board📖
1. ESP32 Introduction
  • 1. ESP32S3 Overview
  • 2. Environment Setup Introduction
  • 3. Dev Board Introduction
2. ESP-IDF Development Tutorial
1. Before Development
  • 1. Environment Setup (Windows)
  • 2. Environment Setup (Linux)
  • 3. Build and Flash
2. Basic Peripherals
  • 1. LED Control
  • 2. Button Detection
  • 3. Peripheral Interrupts
  • 4. ESP_TIMER
  • 5. GPTIMER
  • 6. Watchdog Timer
  • 7. DMA
  • 8. ADC
  • 9. PWM Breathing LED
  • 10. RGB LED Effects
3. Serial Communication and Storage System
  • 1. Serial UART Communication Experiment
  • 2. I2C_OLED Display Experiment
  • 3. SPI Bus Communication Experiment
  • 4. PSRAM External Memory Experiment
  • 5. Flash Read and Write Experiment
  • 6. USB Emulated Mass Storage Experiment
4. FreeRTOS operating system
  • 1.FreeRTOS Core Concepts Theory
  • 2.Task Creation and Management
  • 3.Queue
  • 4.Binary Semaphore
  • 5.Mutex
  • 6.Event Groups
  • 7.Software Timer
  • 8.Task Scheduler
  • 9.Low Power Mode
  • 10.Deadlock
  • 11.Priority Inversion
5. Network Protocols and Wireless Communication
  • 1. WIFI Network Basics
  • 2. WIFI STA Mode
  • 3. WIFI AP Mode
  • 4. UDP Client Experiment
  • 5. UDP Server Experiment
  • 6. TCP Client Experiment
  • 7. TCP Server Experiment
  • 8. Socket Programming Basics
  • 9. HTTP Client Experiment
  • 10. HTTP Server Experiment
  • 11. MQTT IoT Communication Protocol
  • 12. WIFI OTA Upgrade
  • 13. Bluetooth Fundamentals
  • 14. Bluetooth Slave Mode
  • 15. Bluetooth Master Mode
6. Audio Applications
  • 1.I2S Microphone Recording and U-Disk Playback
  • 2.I2S Audio Playback Experiment
  • 3.Repeater Experiment
7. Xiaozhi AI Voice
  • 1. Burn Xiaozhi Firmware
  • 2. Network and Configuration
  • 3. AI Agent Settings
  • 4. Program Analysis
  • 5. Free Chat
3. Arduino Development Course
1. Before Development
  • 1. Environment Setup
  • 2. Build and Flash
2. Basic Peripherals
  • 1. LED Control
  • 2. Button Detection
  • 3. Peripheral Interrupts
  • 4. ESP_TIMER
  • 5. GPTIMER
  • 6. Watchdog Timer
  • 7. ADC
  • 8. PWM Breathing LED
  • 9. RGB LED Effects
3. Serial Communication and Storage System
  • 1. Serial UART Communication
  • 2. I2C OLED Display
  • 3. SPI Bus Communication
  • 4. Flash Read and Write
  • 5. USB Emulated Mass Storage
4. Network Protocols and Wireless Communication
  • 1. WIFI Network Basics
  • 2. WIFI STA Mode
  • 3. WIFI AP Mode
  • 4. UDP Server Experiment
  • 5. UDP Client Experiment
  • 6. TCP Client Experiment
  • 7. TCP Server Experiment
  • 8. HTTP Client Experiment
  • 9. HTTP Server Experiment
  • 10. MQTT IoT Communication Protocol
  • 11. WIFI OTA Upgrade
  • 12. Bluetooth Fundamentals
  • 13. Bluetooth Slave Mode
  • 14. Bluetooth Master Mode
5. Audio Applications
  • 1.I2S Microphone Recording and U-Disk Playback
  • 2.I2S Audio Playback Experiment
  • 3.Repeater Experiment
4. MicroPython Development Course
1. Before Development
  • 1. Environment Setup
  • 2. Build and Flash
  • 3. Thonny IDE
2. Basic Peripherals
  • 1. LED Control
  • 2. Button Detection
  • 3. Peripheral Interrupts
  • 4. TIMER_IT
  • 5. Watchdog Timer
  • 6. ADC
  • 7. PWM Breathing LED
  • 8. RGB LED Effects
3. Serial Communication and Storage System
  • 1. Serial UART Communication Experiment
  • 2. I2C_OLED Display Experiment
  • 3. SPI Bus Communication Experiment
  • 4. Flash Read and Write Experiment
  • 5. Print Storage
4. Network Protocols and Wireless Communication
  • 1. WIFI Network Basics
  • 2. WIFI STA Mode
  • 3. WIFI AP Mode
  • 4. UDP Client Experiment
  • 5. UDP Server Experiment
  • 6. TCP Client Experiment
  • 7. TCP Server Experiment
  • 8. HTTP Client Experiment
  • 9. HTTP Server Experiment
  • 10. MQTT
  • 11. Bluetooth Fundamentals
  • 12. Bluetooth Slave Mode
  • 13. Bluetooth Master Mode
5. Audio Applications
  • 1. I2S Audio Playback Experiment
  • 2. Repeater Experiment
Download
  • Code
  • Hardware_Info
  • 3D_Model_File
  • Software_Tools
  • VMware
  • VM_File
Download ZIP

Welcome to ESP32 Core Board repository

5. Flash Read and Write Experiment

Flash Read and Write Experiment


Flash Read and Write Experiment1. NVS Overview2. Core Concepts2.1 NVS Key-Value Model2.2 NVS Supported Data Types2.3 NVS Operation Flow2.4 NVS Internal Principle3. ESP32-S3 NVS Hardware Specifications4. Project Architecture and FlowNVS Key Naming Scheme5. Hardware Dependencies6. Source Code Details6.1 nvs_init() — NVS Partition Initialization6.2 uart_read_line() — Line Input (with Echo + Backspace)6.3 Append Write (Command '1')6.4 Read All (Command '2')6.5 Delete by Index (Command '3') — Auto Re-index6.6 Clear All (Command '4')6.7 app_main() — Entry Point7. Operation Flow7.1 Build and Flash Process7.2 Normal Interaction Example7.3 Edge Cases8. FAQ


1. NVS Overview

NVS (Non-Volatile Storage) is a key-value storage library provided by ESP-IDF, based on a dedicated partition in SPI Flash. NVS encapsulates wear-leveling and power-failure protection on Flash, allowing developers to read and write persistent data like using a "dictionary" without worrying about low-level erase details.

Typical use cases:

ScenarioDescription
Wi-Fi CredentialsSSID + password persistence
Device ConfigurationCalibration values, thresholds, mode selection
Device Run CountersPower-on count, runtime duration
User Data LoggingLog entries, sensor history (this example)
OTA Status FlagsFirmware version, upgrade flags

This project demonstrates complete NVS CRUD operations via UART0 interactive menu: append write, read all, delete by index (auto re-index), clear all.


2. Core Concepts

2.1 NVS Key-Value Model

NVS organizes data in a three-level structure: Namespace → Key → Value:

Flash Partition
  └─ Namespace "data_store"
       ├─ "count"   → 3   (int32_t)
       ├─ "dat1"    → "Hello"   (string)
       ├─ "dat2"    → "World"   (string)
       └─ "dat3"    → "ESP32"   (string)

Analogy: Namespace ≈ database table, Key ≈ column name, Value ≈ cell.

2.2 NVS Supported Data Types

TypeFunctionsSize
Integernvs_set_i8() / nvs_set_i16() / nvs_set_i32() / nvs_set_i64()1~8 bytes
Stringnvs_set_str()Variable, ≤ 1984 bytes
Binary Blobnvs_set_blob()Variable, ≤ 1984 bytes

2.3 NVS Operation Flow

xxxxxxxxxx
1. nvs_flash_init()          Initialize NVS partition
2. nvs_open("namespace")     Open namespace, get handle
3. nvs_set_xxx() / nvs_get_xxx()  Write / Read
4. nvs_commit()              Commit write (persist to flash)
5. nvs_close()               Close handle

Important: Data is not immediately written to Flash after nvs_set_xxx(). You must call nvs_commit() to persist. Power loss immediately after write may cause data loss.

2.4 NVS Internal Principle

NVS uses a log-structured storage on Flash — new data is appended, old data is marked invalid, and background GC (garbage collection) runs automatically:

xxxxxxxxxx
Flash Sector 1:  [dat1=Hello][dat2=World][count=2][...........]
Flash Sector 2:  [dat2=World_v2]                        ← Update: append new record
Flash Sector 3:  [.........................................]  ← Free / GC

This design naturally supports power-failure protection: writing new records does not erase old data, and interrupted operations can rollback to the previous version on restart.


3. ESP32-S3 NVS Hardware Specifications

FeatureParameter
Storage MediumSPI Flash (internal or external)
Partition Typedata, nvs
Minimum Erase Unit4 KB (1 sector)
Max Namespace CountLimited by Flash partition size
Max Key CapacityString/Blob ≤ 1984 bytes
Erase/Write Endurance≥ 100,000 cycles (Flash physical characteristic)
Power-Failure ProtectionLog-structured write naturally supports
EncryptionOptional NVS Encryption

4. Project Architecture and Flow

xxxxxxxxxx
app_main()
  ├─ uart_param_config()          Configure UART0: 115200-8N1
  ├─ uart_driver_install()        Install UART driver
  ├─ nvs_init()                   Initialize NVS partition (erase if needed)
  ├─ nvs_get_i32("count")         Read current entry count on boot
  ├─ printf()                     Print interactive menu
  └─ while(1)
       ├─ uart_read_line()        Read one line of user input (echo + backspace)
       └─ switch(cmd)
            ├─ '1' → Append Write     datN = user input, count++
            ├─ '2' → Read All         Iterate dat1..datN and print
            ├─ '3' → Delete by idx     Delete specified index, shift entries forward, count--
            └─ '4' → Clear All        nvs_flash_erase() entire partition

NVS Key Naming Scheme

KeyTypeDescription
countint32_tCurrent entry count
dat1, dat2, dat3, ...stringUser data entries

5. Hardware Dependencies

Hardware Connection: None. Interacts with PC serial terminal via UART0 (USB serial).

Required Components: nvs_flash, driver/uart, FreeRTOS


6. Source Code Details

6.1 nvs_init() — NVS Partition Initialization

This function handles NVS Flash partition initialization. If nvs_flash_init() returns "no free pages" or "version mismatch" errors (common after first flash or partition table change), it automatically erases the entire NVS partition and re-initializes to ensure normal read/write operations.

xxxxxxxxxx
/**
 * @brief  NVS initialization
 */
void nvs_init() {
    // Try to initialize NVS partition
    esp_err_t err = nvs_flash_init();
    // Check for no free pages or new version
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        nvs_flash_erase();  // Erase NVS space
        err = nvs_flash_init();
    }
}

6.2 uart_read_line() — Line Input (with Echo + Backspace)

This function implements a simple line editor: reads user input byte-by-byte from UART0 and echoes to terminal, ends on newline \n or \r, handles backspace (\b or DEL=127) by deleting previous character and echoing erase sequence \b \b for interactive terminal input.

​x
/**
 * @brief  Read a line from UART (with echo)
 * @param  buf      Receive buffer
 * @param  max_len  Max buffer length
 * @return Number of bytes read (excluding \0)
 */
static int uart_read_line(uint8_t *buf, int max_len) {
    int total = 0;
    while (total < max_len - 1) {
        uint8_t ch;
        int n = uart_read_bytes(UART_NUM_0, &ch, 1, portMAX_DELAY);
        if (n <= 0) continue;

        if (ch == '\n') {           // LF: end of line
            uart_write_bytes(UART_NUM_0, "\r\n", 2);  // Echo newline
            break;
        }
        if (ch == '\r') {           // CR
            uart_write_bytes(UART_NUM_0, "\r\n", 2);
            // Consume the following \n
            uart_read_bytes(UART_NUM_0, &ch, 1, 1);
            break;
        }
        if (ch == '\b' || ch == 127) {   // Backspace key
            if (total > 0) {
                total--;
                // Erase one char
                uart_write_bytes(UART_NUM_0, "\b \b", 3);
            }
            continue;
        }
        buf[total++] = ch;
        uart_write_bytes(UART_NUM_0, &ch, 1);  // Echo
    }
    buf[total] = '\0';  // Null terminator
    return total;
}

6.3 Append Write (Command '1')

After user inputs command 1 and enters text content, the program increments dataCount and stores it in NVS with key datN (N is current entry number), while updating the count key to record total entry count. After writing, nvs_commit() is called to persist to Flash.

xxxxxxxxxx
// 1: Append write data
if (cmd == '1') {
    printf("Enter content to save:\n");
    len = uart_read_line(data, BUF_SIZE);
    if (len <= 0) {
        printf("Empty input, skipped\n");
        continue;
    }

    // Open namespace (read-write mode)
    nvs_open("data_store", NVS_READWRITE, &handle);
    dataCount++;
    char key[16];
    sprintf(key, "dat%ld", (long)dataCount);  // Build key name

    // Write string value
    nvs_set_str(handle, key, (char *)data);
    // Update entry count
    nvs_set_i32(handle, "count", dataCount);
    nvs_commit(handle);   // Commit to flash
    nvs_close(handle);    // Close handle

    printf("Entry %ld saved: %s\n", (long)dataCount, (char *)data);
}

6.4 Read All (Command '2')

Opens namespace in read-only mode, reads count to get total entry count, then iterates dat1 ~ datN to read and print each entry. If count=0, shows "no data".

xxxxxxxxxx
// 2: Read all saved data
else if (cmd == '2') {
    // Open namespace (read-only mode)
    nvs_open("data_store", NVS_READONLY, &handle);
    // Read total entry count
    nvs_get_i32(handle, "count", &dataCount);

    if (dataCount == 0) {
        printf("No data\n");
    } else {
        printf("=== All data (%ld entries) ===\n", (long)dataCount);
        for (int i = 1; i <= dataCount; i++) {
            // Build key name
            char key[16]; sprintf(key, "dat%d", i);
            char buf[256]; size_t buf_len = sizeof(buf);
            // Read string value
            if (nvs_get_str(handle, key, buf, &buf_len) == ESP_OK) {
                printf("%d: %s\n", i, buf);
            }
        }
    }
    nvs_close(handle);
}

6.5 Delete by Index (Command '3') — Auto Re-index

After user inputs the entry number to delete, the program validates the range, then shifts all subsequent entries one position forward starting from the delete position, finally erases the leftover last key and updates count. Re-indexing ensures dat1 ~ datN remain consecutive with no gaps or disorder.

xxxxxxxxxx
// 3: Delete specified index, then re-index
else if (cmd == '3') {
    printf("Enter entry number to delete:\n");
    len = uart_read_line(data, BUF_SIZE);
    if (len <= 0) continue;
    int delNum = atoi((char *)data);  // Parse index

    nvs_open("data_store", NVS_READWRITE, &handle);
    nvs_get_i32(handle, "count", &dataCount);

    // Validate index range
    if (delNum < 1 || delNum > dataCount) {
        printf("Invalid number (1-%ld)\n", (long)dataCount);
        nvs_close(handle);
        continue;
    }

    // Shift subsequent entries forward
    for (int i = delNum; i < dataCount; i++) {
        // Current key
        char key_cur[16];  sprintf(key_cur, "dat%d", i);
        // Next key
        char key_next[16]; sprintf(key_next, "dat%d", i + 1);
        char buf[256]; size_t buf_len = sizeof(buf);

        if (nvs_get_str(handle, key_next, buf, &buf_len) == ESP_OK) {
            // Move to previous key
            nvs_set_str(handle, key_cur, buf);
            nvs_erase_key(handle, key_next);      // Erase old key
        }
    }
    // Erase the now-unused last key
    char last_key[16]; sprintf(last_key, "dat%ld", (long)dataCount);
    nvs_erase_key(handle, last_key);

    dataCount--;
    nvs_set_i32(handle, "count", dataCount);  // Update count
    nvs_commit(handle);   // Commit to flash
    nvs_close(handle);    // Close handle

    printf("Entry %d deleted (total %ld)\n", delNum, (long)dataCount);
}

6.6 Clear All (Command '4')

Calls nvs_flash_erase() to erase the entire NVS partition, then re-initializes and resets dataCount to 0. All stored data will be completely cleared.

xxxxxxxxxx
// 4: Clear all NVS storage space
else if (cmd == '4') {
    nvs_flash_erase();   // Erase entire NVS partition
    nvs_init();          // Re-initialize
    dataCount = 0;       // Reset counter
    printf("All data cleared!\n");
}

6.7 app_main() — Entry Point

Main function sequentially: UART0 initialization (115200-8N1) → NVS initialization → Read stored entry count on boot → Print interactive menu → Enter while(1) loop to wait for user input, dispatch to corresponding CRUD module based on first character 1/2/3/4.

xxxxxxxxxx
/**
 * @brief  Application entry point
 */
void app_main(void) {
    // UART config 115200 8N1
    uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
    };
    uart_param_config(UART_NUM_0, &uart_config);
    // Install UART driver
    uart_driver_install(UART_NUM_0, BUF_SIZE * 2, 0, 0, NULL, 0);

    nvs_init();  // Initialize NVS

    nvs_handle_t handle;
    int32_t dataCount = 0;
    // Read stored count on boot
    nvs_open("data_store", NVS_READWRITE, &handle);
    nvs_get_i32(handle, "count", &dataCount);
    nvs_close(handle);

    // Print interactive menu
    printf("\n==================================\n");
    printf("   ESP32-S3 NVS Flash Storage\n");
    printf(" 1 = Append Write\n");
    printf(" 2 = Read All Data\n");
    printf(" 3 = Delete Specified Data\n");
    printf(" 4 = Clear All Data\n");
    printf("==================================\n");

    while (1) {
        printf("\nCMD> ");
        fflush(stdout);  // Flush output immediately

        len = uart_read_line(data, BUF_SIZE);
        if (len <= 0) { vTaskDelay(10); continue; }
        char cmd = (char)data[0];  // First char as command

        // Dispatch by command
        if (cmd == '1') { /* ... Append write ... */ }
        else if (cmd == '2') { /* ... Read All ... */ }
        else if (cmd == '3') { /* ... Delete by index ... */ }
        else if (cmd == '4') { /* ... Clear All ... */ }

        vTaskDelay(20);  // Yield CPU
    }
}

7. Operation Flow

7.1 Build and Flash Process

For detailed flash process: 1. Before Development → 3. Build and Flash

7.2 Normal Interaction Example

xxxxxxxxxx
=================================
   ESP32-S3 NVS Flash Storage
 1 = Append Write
 2 = Read All Data
 3 = Delete Specified Data
 4 = Clear All Data
=================================

CMD> 1
Enter content to save:
Hello World!
Entry 1 saved: Hello World!

CMD> 1
Enter content to save:
ESP32-S3 NVS Demo
Entry 2 saved: ESP32-S3 NVS Demo

CMD> 2
=== All data (2 entries) ===
1: Hello World!
2: ESP32-S3 NVS Demo

CMD> 3
Enter entry number to delete:
1
Entry 1 deleted (total 1)

CMD> 2
=== All data (1 entries) ===
1: ESP32-S3 NVS Demo

CMD> 4
All data cleared!

CMD> 2
No data

实例演示

7.3 Edge Cases

  • Power Cycle Restart: Data committed before power loss persists. On boot, the program automatically reads count and restores data state.

For example: Operations before power loss

断电前操作

After power reconnect:

断电重连后

  • Continuous Delete: After re-indexing, entries are always numbered consecutively from 1 with no index holes.

  • Empty Data Read: When count=0, selecting command 2 outputs No data.


8. FAQ

SymptomCauseSolution
Boot error ESP_ERR_NVS_NO_FREE_PAGESFirst flash / partition table change / NVS fullCode handles it — auto erase and re-initialize
Data lost after power lossnvs_commit() not calledEnsure nvs_commit() after each nvs_set_xxx()
String read truncatedbuf_len too smallIncrease buffer, or read actual length first then allocate
nvs_open returns failureNamespace doesn't exist / partition not initializedCheck if nvs_flash_init() was called first
NVS partition space insufficientToo many entries / single value too largeString ≤ 1984 bytes, total capacity depends on partition size (default 24KB)
Terminal interaction no responseUART0 not initialized / serial tool not openedConfirm terminal connected to correct COM port, baud rate 115200
PSRAM External Memory Experiment
USB Emulated Mass Storage Experiment

COMPANY

  • About us
  • Team Style
  • Blog

LEARNING & EXPLORATION

  • Tutorials
  • Edge AI hardware
  • Educational robots
  • Embedded intelligent hardware

WHERE TO BUY

  • Yahboom Online Store
  • Amazon
  • Alibaba
  • AliExpress
  • Mercado

TECHNOLOGY SUPPORT

  • Email: support@yahboom.com

BE A DISTRIBUTOR

  • Email: sales@yahboom.com
QR Code

Copyright © 2017-2026 Yahboom. All Rights Reserved.

EN/中文