feat(examples): Add storage/nvsgen example

Showcases the use of `nvs_create_partition_image` CMake function
Remove mentions of NVS multipage blob version 1 so it's not encouraged
This commit is contained in:
Adam Múdry
2023-08-04 10:46:58 +02:00
parent 5e5220a77c
commit b988242b07
10 changed files with 201 additions and 7 deletions

View File

@@ -94,7 +94,7 @@ This utility helps generate NVS partition binary files which can be flashed sepa
Instead of calling the ``nvs_partition_gen.py`` tool manually, the creation of the partition binary files can also be done directly from CMake using the function ``nvs_create_partition_image``:: Instead of calling the ``nvs_partition_gen.py`` tool manually, the creation of the partition binary files can also be done directly from CMake using the function ``nvs_create_partition_image``::
nvs_create_partition_image(<partition> <csv> [FLASH_IN_PROJECT] [VERSION 1 | 2] [DEPENDS dep dep dep ...]) nvs_create_partition_image(<partition> <csv> [FLASH_IN_PROJECT] [DEPENDS dep dep dep ...])
**Positional Arguments**: **Positional Arguments**:
@@ -118,12 +118,6 @@ Instead of calling the ``nvs_partition_gen.py`` tool manually, the creation of t
- Description - Description
* - ``FLASH_IN_PROJECT`` * - ``FLASH_IN_PROJECT``
- Name of the NVS parition - Name of the NVS parition
* - ``VERSION {1,2}``
- Set multipage blob version (Default: Version 2)
Version 1 = support disabled
Version 2 = support enabled
* - ``DEPENDS`` * - ``DEPENDS``
- Specify files on which the command depends - Specify files on which the command depends

View File

@@ -61,6 +61,16 @@ examples/storage/nvs_rw_value_cxx:
temporary: true temporary: true
reason: lack of runners reason: lack of runners
examples/storage/nvsgen:
disable:
- if: IDF_TARGET == "esp32c2"
temporary: true
reason: target esp32c2 is not supported yet
disable_test:
- if: IDF_TARGET in ["esp32s2", "esp32s3", "esp32c3", "esp32c6", "esp32h2"]
temporary: true
reason: lack of runners, should be same for every target
examples/storage/partition_api/partition_find: examples/storage/partition_api/partition_find:
disable: disable:
- if: IDF_TARGET == "esp32c2" - if: IDF_TARGET == "esp32c2"

View File

@@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(nvsgen)

View File

@@ -0,0 +1,54 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
# NVS Partition Image Generation on Build Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates how to use the NVS image generation tool [nvs_partition_gen.py](../../../components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py) to automatically create a NVS partition image from the contents of a CSV file during build, with an option of automatically flashing the created image on invocation of `idf.py -p PORT flash`. For more information, see description of `nvs_partition_gen.py` on the ESP-IDF Programming Guide under API Reference > Storage API > NVS Partition Generator Utility.
The following gives an overview of the example:
1. There is a file `nvs_data.csv` from which the NVS partition image will be created.
2. The function `nvs_create_partition_image` is used to specify that a NVS image should be created during build for the `nvs` partition. It is called from [the main component's CMakeLists.txt](./main/CMakeLists.txt). `FLASH_IN_PROJECT` specifies that the created image should be flashed on invocation of `idf.py -p PORT flash` together with app, bootloader, partition table, etc. For both build systems, the image is created on the example's build directory with the output filename `nvs.bin`.
3. Upon invocation of `idf.py -p PORT flash monitor`, application loads and finds there is already a valid and pre-filled NVS partition in the `nvs` partition with values same as those in `nvs_data.csv` file. The application is then able to read those values.
## How to use example
### Build and flash
To run the example, type the following command:
```CMake
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example output
Here is the example's console output:
```
...
I (357) example: Opening Non-Volatile Storage (NVS) handle
I (357) example: Done
I (357) example: Reading values from NVS
255
-128
65535
4294967295
-2147483648
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Fusce quis risus justo.
Suspendisse egestas in nisi sit amet auctor.
Pellentesque rhoncus dictum sodales.
In justo erat, viverra at interdum eget, interdum vel dui.
I (387) example: Reading values from NVS done - all OK
```
The logic of the example is contained in a [single source file](./main/nvsgen_example_main.c), and it should be relatively simple to match points in its execution with the log outputs above.

View File

@@ -0,0 +1,8 @@
idf_component_register(SRCS "nvsgen_example_main.c"
INCLUDE_DIRS ".")
# Create a NVS image from the contents of the `nvs_data` CSV file
# that fits the partition named 'nvs'. FLASH_IN_PROJECT indicates that
# the generated image should be flashed when the entire project is flashed to
# the target with 'idf.py -p PORT flash'.
nvs_create_partition_image(nvs ../nvs_data.csv FLASH_IN_PROJECT)

View File

@@ -0,0 +1,89 @@
/* Non-Volatile Storage (NVS) Image Generation on Build Example
*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "nvs.h"
static const char *TAG = "example";
void app_main(void)
{
// Initialize NVS
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
// NVS partition was truncated and needs to be erased
// Retry nvs_flash_init
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
// Open the pre-filled NVS partition called "nvs"
ESP_LOGI(TAG, "Opening Non-Volatile Storage (NVS) handle");
nvs_handle_t my_handle;
err = nvs_open_from_partition("nvs", "storage", NVS_READONLY, &my_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error (%s) opening NVS handle!\n", esp_err_to_name(err));
return;
}
ESP_LOGI(TAG, "The NVS handle successfully opened");
// Read values
ESP_LOGI(TAG, "Reading values from NVS");
uint8_t u8_val = 0;
err = nvs_get_u8(my_handle, "u8_key", &u8_val);
ESP_ERROR_CHECK(err);
printf("%"PRIu8"\n", u8_val);
assert(u8_val == 255);
int8_t i8_val = 0;
err = nvs_get_i8(my_handle, "i8_key", &i8_val);
ESP_ERROR_CHECK(err);
printf("%"PRIi8"\n", i8_val);
assert(i8_val == -128);
uint16_t u16_val = 0;
err = nvs_get_u16(my_handle, "u16_key", &u16_val);
ESP_ERROR_CHECK(err);
printf("%"PRIu16"\n", u16_val);
assert(u16_val == 65535);
uint32_t u32_val = 0;
err = nvs_get_u32(my_handle, "u32_key", &u32_val);
ESP_ERROR_CHECK(err);
printf("%"PRIu32"\n", u32_val);
assert(u32_val == 4294967295);
int32_t i32_val = 0;
err = nvs_get_i32(my_handle, "i32_key", &i32_val);
ESP_ERROR_CHECK(err);
printf("%"PRIi32"\n", i32_val);
assert(i32_val == -2147483648);
size_t str_len = 0;
err = nvs_get_str(my_handle, "str_key", NULL, &str_len);
ESP_ERROR_CHECK(err);
assert(str_len == 222);
char* str_val = (char*) malloc(str_len);
err = nvs_get_str(my_handle, "str_key", str_val, &str_len);
ESP_ERROR_CHECK(err);
printf("%s\n", str_val);
assert(str_val[0] == 'L');
free(str_val);
// Close
nvs_close(my_handle);
ESP_LOGI(TAG, "Reading values from NVS done - all OK");
}

View File

@@ -0,0 +1,13 @@
# Sample csv file
key,type,encoding,value
storage,namespace,,
u8_key,data,u8,255
i8_key,data,i8,-128
u16_key,data,u16,65535
u32_key,data,u32,4294967295
i32_key,data,i32,-2147483648
str_key,data,string,"Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Fusce quis risus justo.
Suspendisse egestas in nisi sit amet auctor.
Pellentesque rhoncus dictum sodales.
In justo erat, viverra at interdum eget, interdum vel dui."
Can't render this file because it has a wrong number of fields in line 2.

View File

@@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 # Name, Type, SubType, Offset, Size, Flags
4 nvs, data, nvs, 0x9000, 0x6000,
5 phy_init, data, phy, 0xf000, 0x1000,
6 factory, app, factory, 0x10000, 1M,

View File

@@ -0,0 +1,11 @@
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32
def test_nvsgen_example(dut: Dut) -> None:
dut.expect('Reading values from NVS', timeout=10)
dut.expect('Reading values from NVS done - all OK', timeout=10)

View File

@@ -0,0 +1,3 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv"