From 817bbb4bf92cff78846a8b0540d045285d04f121 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 14 Mar 2017 21:18:22 +0800 Subject: [PATCH 1/6] nvs: add missing error code descriptions --- components/nvs_flash/include/nvs.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/nvs_flash/include/nvs.h b/components/nvs_flash/include/nvs.h index 5f7a93a7b0..7deca54440 100644 --- a/components/nvs_flash/include/nvs.h +++ b/components/nvs_flash/include/nvs.h @@ -31,16 +31,16 @@ typedef uint32_t nvs_handle; #define ESP_ERR_NVS_BASE 0x1100 /*!< Starting number of error codes */ #define ESP_ERR_NVS_NOT_INITIALIZED (ESP_ERR_NVS_BASE + 0x01) /*!< The storage driver is not initialized */ #define ESP_ERR_NVS_NOT_FOUND (ESP_ERR_NVS_BASE + 0x02) /*!< Id namespace doesn’t exist yet and mode is NVS_READONLY */ -#define ESP_ERR_NVS_TYPE_MISMATCH (ESP_ERR_NVS_BASE + 0x03) /*!< TBA */ +#define ESP_ERR_NVS_TYPE_MISMATCH (ESP_ERR_NVS_BASE + 0x03) /*!< The type of set or get operation doesn't match the type of value stored in NVS */ #define ESP_ERR_NVS_READ_ONLY (ESP_ERR_NVS_BASE + 0x04) /*!< Storage handle was opened as read only */ #define ESP_ERR_NVS_NOT_ENOUGH_SPACE (ESP_ERR_NVS_BASE + 0x05) /*!< There is not enough space in the underlying storage to save the value */ #define ESP_ERR_NVS_INVALID_NAME (ESP_ERR_NVS_BASE + 0x06) /*!< Namespace name doesn’t satisfy constraints */ #define ESP_ERR_NVS_INVALID_HANDLE (ESP_ERR_NVS_BASE + 0x07) /*!< Handle has been closed or is NULL */ #define ESP_ERR_NVS_REMOVE_FAILED (ESP_ERR_NVS_BASE + 0x08) /*!< The value wasn’t updated because flash write operation has failed. The value was written however, and update will be finished after re-initialization of nvs, provided that flash operation doesn’t fail again. */ -#define ESP_ERR_NVS_KEY_TOO_LONG (ESP_ERR_NVS_BASE + 0x09) /*!< TBA */ -#define ESP_ERR_NVS_PAGE_FULL (ESP_ERR_NVS_BASE + 0x0a) /*!< TBA */ -#define ESP_ERR_NVS_INVALID_STATE (ESP_ERR_NVS_BASE + 0x0b) /*!< TBA */ -#define ESP_ERR_NVS_INVALID_LENGTH (ESP_ERR_NVS_BASE + 0x0c) /*!< TBA */ +#define ESP_ERR_NVS_KEY_TOO_LONG (ESP_ERR_NVS_BASE + 0x09) /*!< Key name is too long */ +#define ESP_ERR_NVS_PAGE_FULL (ESP_ERR_NVS_BASE + 0x0a) /*!< Internal error; never returned by nvs_ API functions */ +#define ESP_ERR_NVS_INVALID_STATE (ESP_ERR_NVS_BASE + 0x0b) /*!< NVS is in an inconsistent state due to a previous error. Call nvs_flash_init and nvs_open again, then retry. */ +#define ESP_ERR_NVS_INVALID_LENGTH (ESP_ERR_NVS_BASE + 0x0c) /*!< String or blob length is not sufficient to store data */ /** * @brief Mode of opening the non-volatile storage From 5a23ec4dc4dc39189f8de35d0adab522c56fe97d Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 14 Mar 2017 21:24:56 +0800 Subject: [PATCH 2/6] nvs: check that storage has at least one free page This change adds a check for the free page count to nvs_flash_init. Under normal operation, NVS keeps at least one free page available, except for transient states such as freeing up new page. Due to external factors (such as NVS partition size reduction) this free page could be lost, making NVS operation impossible. Previously this would cause an error when performing any nvs_set operation or opening a new namespace. With this change, an error is returned from nvs_flash_init to indicate that NVS partition is in such a state. --- components/nvs_flash/README.rst | 4 +++- components/nvs_flash/include/nvs.h | 1 + components/nvs_flash/include/nvs_flash.h | 6 +++++- components/nvs_flash/src/nvs_pagemanager.cpp | 5 +++++ components/nvs_flash/test_nvs_host/test_nvs.cpp | 17 +++++++++++++++++ docs/api/storage/nvs_flash.rst | 4 +++- 6 files changed, 34 insertions(+), 3 deletions(-) diff --git a/components/nvs_flash/README.rst b/components/nvs_flash/README.rst index ade5518aa5..f9602fc8bf 100644 --- a/components/nvs_flash/README.rst +++ b/components/nvs_flash/README.rst @@ -9,10 +9,12 @@ Non-volatile storage (NVS) library is designed to store key-value pairs in flash Underlying storage ^^^^^^^^^^^^^^^^^^ -Currently NVS uses a portion of main flash memory through ``spi_flash_{read|write|erase}`` APIs. The range of flash sectors to be used by the library is provided to ``nvs_flash_init`` function. +Currently NVS uses a portion of main flash memory through ``spi_flash_{read|write|erase}`` APIs. The library uses the first partition with ``data`` type and ``nvs`` subtype. Future versions of this library may add other storage backends to keep data in another flash chip (SPI or I2C), RTC, FRAM, etc. +.. note:: if an NVS partition is truncated (for example, when the partition table layout is changed), its contents should be erased. ESP-IDF build system provides a ``make erase_flash`` target to erase all contents of the flash chip. + Keys and values ^^^^^^^^^^^^^^^ diff --git a/components/nvs_flash/include/nvs.h b/components/nvs_flash/include/nvs.h index 7deca54440..6e5af231ab 100644 --- a/components/nvs_flash/include/nvs.h +++ b/components/nvs_flash/include/nvs.h @@ -41,6 +41,7 @@ typedef uint32_t nvs_handle; #define ESP_ERR_NVS_PAGE_FULL (ESP_ERR_NVS_BASE + 0x0a) /*!< Internal error; never returned by nvs_ API functions */ #define ESP_ERR_NVS_INVALID_STATE (ESP_ERR_NVS_BASE + 0x0b) /*!< NVS is in an inconsistent state due to a previous error. Call nvs_flash_init and nvs_open again, then retry. */ #define ESP_ERR_NVS_INVALID_LENGTH (ESP_ERR_NVS_BASE + 0x0c) /*!< String or blob length is not sufficient to store data */ +#define ESP_ERR_NVS_NO_FREE_PAGES (ESP_ERR_NVS_BASE + 0x0d) /*!< NVS partition doesn't contain any empty pages. This may happen if NVS partition was truncated. Erase the whole partition and call nvs_flash_init again. */ /** * @brief Mode of opening the non-volatile storage diff --git a/components/nvs_flash/include/nvs_flash.h b/components/nvs_flash/include/nvs_flash.h index 0162a8f8ac..8307fe3521 100644 --- a/components/nvs_flash/include/nvs_flash.h +++ b/components/nvs_flash/include/nvs_flash.h @@ -21,7 +21,11 @@ extern "C" { /** * @brief Initialize NVS flash storage with layout given in the partition table. * - * @return ESP_OK if storage was successfully initialized. + * @return + * - ESP_OK if storage was successfully initialized. + * - ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages + * (which may happen if NVS partition was truncated) + * - one of the error codes from the underlying flash storage driver */ esp_err_t nvs_flash_init(void); diff --git a/components/nvs_flash/src/nvs_pagemanager.cpp b/components/nvs_flash/src/nvs_pagemanager.cpp index 768b30667a..943f54f2f8 100644 --- a/components/nvs_flash/src/nvs_pagemanager.cpp +++ b/components/nvs_flash/src/nvs_pagemanager.cpp @@ -105,6 +105,11 @@ esp_err_t PageManager::load(uint32_t baseSector, uint32_t sectorCount) } } + // partition should have at least one free page + if (mFreePageList.size() == 0) { + return ESP_ERR_NVS_NO_FREE_PAGES; + } + return ESP_OK; } diff --git a/components/nvs_flash/test_nvs_host/test_nvs.cpp b/components/nvs_flash/test_nvs_host/test_nvs.cpp index 282d4de48e..ff35a84d11 100644 --- a/components/nvs_flash/test_nvs_host/test_nvs.cpp +++ b/components/nvs_flash/test_nvs_host/test_nvs.cpp @@ -1108,6 +1108,23 @@ TEST_CASE("read/write failure (TW8406)", "[nvs]") } } +TEST_CASE("nvs_flash_init checks for an empty page", "[nvs]") +{ + const size_t blob_size = 2048; // big enough so that only one can fit into a page + uint8_t blob[blob_size] = {0}; + SpiFlashEmulator emu(5); + TEST_ESP_OK( nvs_flash_init_custom(0, 5) ); + nvs_handle handle; + TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) ); + TEST_ESP_OK( nvs_set_blob(handle, "1", blob, blob_size) ); + TEST_ESP_OK( nvs_set_blob(handle, "2", blob, blob_size) ); + TEST_ESP_OK( nvs_set_blob(handle, "3", blob, blob_size) ); + TEST_ESP_OK( nvs_commit(handle) ); + nvs_close(handle); + // first two pages are now full, third one is writable, last two are empty + // init should fail + TEST_ESP_ERR( nvs_flash_init_custom(0, 3), ESP_ERR_NVS_NO_FREE_PAGES ); +} TEST_CASE("dump all performance data", "[nvs]") { diff --git a/docs/api/storage/nvs_flash.rst b/docs/api/storage/nvs_flash.rst index ce1af94546..b6cf6f2210 100644 --- a/docs/api/storage/nvs_flash.rst +++ b/docs/api/storage/nvs_flash.rst @@ -48,6 +48,7 @@ Macros .. doxygendefine:: ESP_ERR_NVS_PAGE_FULL .. doxygendefine:: ESP_ERR_NVS_INVALID_STATE .. doxygendefine:: ESP_ERR_NVS_INVALID_LENGTH +.. doxygendefine:: ESP_ERR_NVS_NO_FREE_PAGES Type Definitions ^^^^^^^^^^^^^^^^ @@ -61,6 +62,7 @@ Enumerations Functions ^^^^^^^^^ +.. doxygenfunction:: nvs_flash_init .. doxygenfunction:: nvs_open .. doxygenfunction:: nvs_set_i8 .. doxygenfunction:: nvs_set_u8 @@ -86,5 +88,5 @@ Functions .. doxygenfunction:: nvs_erase_all .. doxygenfunction:: nvs_commit .. doxygenfunction:: nvs_close -.. doxygenfunction:: nvs_flash_init + From 94b9898ca73a70e904ce023dfdc5cb82868370d4 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 14 Mar 2017 21:27:27 +0800 Subject: [PATCH 3/6] phy_init: move NVS init into relevant function, check errors This change also modifies logging statements to print hexadecimal error codes, which are easier to look up. --- components/esp32/phy_init.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/components/esp32/phy_init.c b/components/esp32/phy_init.c index 5fbeeb7c88..e1b22d6a99 100644 --- a/components/esp32/phy_init.c +++ b/components/esp32/phy_init.c @@ -118,7 +118,7 @@ const esp_phy_init_data_t* esp_phy_get_init_data() } esp_err_t err = esp_partition_read(partition, 0, init_data_store, init_data_store_length); if (err != ESP_OK) { - ESP_LOGE(TAG, "failed to read PHY data partition (%d)", err); + ESP_LOGE(TAG, "failed to read PHY data partition (0x%x)", err); return NULL; } if (memcmp(init_data_store, PHY_INIT_MAGIC, sizeof(phy_init_magic_pre)) != 0 || @@ -167,10 +167,15 @@ static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle, esp_err_t esp_phy_load_cal_data_from_nvs(esp_phy_calibration_data_t* out_cal_data) { - nvs_handle handle; - esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READONLY, &handle); + esp_err_t err = nvs_flash_init(); if (err != ESP_OK) { - ESP_LOGD(TAG, "%s: failed to open NVS namespace (%d)", __func__, err); + ESP_LOGW(TAG, "%s: failed to initialize NVS (0x%x)", __func__, err); + return err; + } + nvs_handle handle; + err = nvs_open(PHY_NAMESPACE, NVS_READONLY, &handle); + if (err != ESP_OK) { + ESP_LOGD(TAG, "%s: failed to open NVS namespace (0x%x)", __func__, err); return err; } else { @@ -185,7 +190,7 @@ esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t* cal_da nvs_handle handle; esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READWRITE, &handle); if (err != ESP_OK) { - ESP_LOGD(TAG, "%s: failed to open NVS namespace (%d)", __func__, err); + ESP_LOGD(TAG, "%s: failed to open NVS namespace (0x%x)", __func__, err); return err; } else { @@ -202,7 +207,7 @@ static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle, uint32_t cal_data_version; err = nvs_get_u32(handle, PHY_CAL_VERSION_KEY, &cal_data_version); if (err != ESP_OK) { - ESP_LOGD(TAG, "%s: failed to get cal_version (%d)", __func__, err); + ESP_LOGD(TAG, "%s: failed to get cal_version (0x%x)", __func__, err); return err; } uint32_t cal_format_version = phy_get_rf_cal_version() & (~BIT(16)); @@ -216,7 +221,7 @@ static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle, size_t length = sizeof(cal_data_mac); err = nvs_get_blob(handle, PHY_CAL_MAC_KEY, cal_data_mac, &length); if (err != ESP_OK) { - ESP_LOGD(TAG, "%s: failed to get cal_mac (%d)", __func__, err); + ESP_LOGD(TAG, "%s: failed to get cal_mac (0x%x)", __func__, err); return err; } if (length != sizeof(cal_data_mac)) { @@ -234,7 +239,7 @@ static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle, length = sizeof(*out_cal_data); err = nvs_get_blob(handle, PHY_CAL_DATA_KEY, out_cal_data, &length); if (err != ESP_OK) { - ESP_LOGE(TAG, "%s: failed to get cal_data(%d)", __func__, err); + ESP_LOGE(TAG, "%s: failed to get cal_data(0x%x)", __func__, err); return err; } if (length != sizeof(*out_cal_data)) { @@ -267,7 +272,6 @@ static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle, void esp_phy_load_cal_and_init(void) { #ifdef CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE - nvs_flash_init(); esp_phy_calibration_mode_t calibration_mode = PHY_RF_CAL_PARTIAL; if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) { calibration_mode = PHY_RF_CAL_NONE; @@ -285,7 +289,7 @@ void esp_phy_load_cal_and_init(void) } esp_err_t err = esp_phy_load_cal_data_from_nvs(cal_data); if (err != ESP_OK) { - ESP_LOGW(TAG, "failed to load RF calibration data, falling back to full calibration"); + ESP_LOGW(TAG, "failed to load RF calibration data (0x%x), falling back to full calibration", err); calibration_mode = PHY_RF_CAL_FULL; } From f59f13efd5afb2342b399e2af3d79375285fb506 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 14 Mar 2017 21:35:20 +0800 Subject: [PATCH 4/6] examples: remove nvs_flash_init from examples which do not use NVS --- examples/get-started/blink/main/blink.c | 3 --- examples/get-started/hello_world/main/hello_world_main.c | 2 -- examples/peripherals/i2s/main/app_main.c | 3 --- .../peripherals/touch_pad_interrupt/main/tp_interrupt_main.c | 5 ----- examples/peripherals/touch_pad_read/main/tp_read_main.c | 4 ---- 5 files changed, 17 deletions(-) diff --git a/examples/get-started/blink/main/blink.c b/examples/get-started/blink/main/blink.c index f97572ac21..698bad218a 100644 --- a/examples/get-started/blink/main/blink.c +++ b/examples/get-started/blink/main/blink.c @@ -9,8 +9,6 @@ #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp_system.h" -#include "nvs_flash.h" #include "driver/gpio.h" #include "sdkconfig.h" @@ -42,6 +40,5 @@ void blink_task(void *pvParameter) void app_main() { - nvs_flash_init(); xTaskCreate(&blink_task, "blink_task", 512, NULL, 5, NULL); } diff --git a/examples/get-started/hello_world/main/hello_world_main.c b/examples/get-started/hello_world/main/hello_world_main.c index c8b9f5f0c9..e1955d8755 100644 --- a/examples/get-started/hello_world/main/hello_world_main.c +++ b/examples/get-started/hello_world/main/hello_world_main.c @@ -10,7 +10,6 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_system.h" -#include "nvs_flash.h" void hello_task(void *pvParameter) { @@ -26,6 +25,5 @@ void hello_task(void *pvParameter) void app_main() { - nvs_flash_init(); xTaskCreate(&hello_task, "hello_task", 2048, NULL, 5, NULL); } diff --git a/examples/peripherals/i2s/main/app_main.c b/examples/peripherals/i2s/main/app_main.c index 9c8f80fd56..8072cff6ac 100644 --- a/examples/peripherals/i2s/main/app_main.c +++ b/examples/peripherals/i2s/main/app_main.c @@ -11,8 +11,6 @@ #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp_system.h" -#include "nvs_flash.h" #include "driver/i2s.h" #include @@ -48,7 +46,6 @@ void app_main() .data_in_num = -1 //Not used }; - nvs_flash_init(); i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); i2s_set_pin(I2S_NUM, &pin_config); diff --git a/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c b/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c index fd4fe5b276..90f94f65f7 100644 --- a/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c +++ b/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c @@ -9,8 +9,6 @@ #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp_system.h" -#include "nvs_flash.h" #include "esp_log.h" #include "driver/touch_pad.h" @@ -95,9 +93,6 @@ static void touch_pad_rtc_intr(void * arg) void app_main() { - ESP_LOGI(TAG, "Starting"); - nvs_flash_init(); - // Initialize touch pad peripheral ESP_LOGI(TAG, "Initializing touch pad"); touch_pad_init(); diff --git a/examples/peripherals/touch_pad_read/main/tp_read_main.c b/examples/peripherals/touch_pad_read/main/tp_read_main.c index accfe5027a..69bb87d17e 100644 --- a/examples/peripherals/touch_pad_read/main/tp_read_main.c +++ b/examples/peripherals/touch_pad_read/main/tp_read_main.c @@ -9,8 +9,6 @@ #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp_system.h" -#include "nvs_flash.h" #include "driver/touch_pad.h" @@ -34,8 +32,6 @@ void touch_pad_read_task(void *pvParameter) void app_main() { - nvs_flash_init(); - // Initialize touch pad peripheral touch_pad_init(); From 4813ab2d28081ca1f7682343e721485b1a53cd19 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 14 Mar 2017 21:39:44 +0800 Subject: [PATCH 5/6] examples: check return value of nvs_flash_init nvs_flash_init may return an error code in some cases, and applications should check this error code (or at least assert on it being ESP_OK, to make potential issues more immediately obvious). This change modifies all the examples which use NVS to check the error code. Most examples get a simple ESP_ERROR_CHECK assert, while NVS examples, OTA example, and NVS unit tests get a more verbose check which may be used in real applications. --- components/nvs_flash/test/test_nvs.c | 16 ++++++++++-- examples/bluetooth/blufi/main/blufi_main.c | 2 +- .../protocols/coap_client/main/coap_client.c | 2 +- .../protocols/coap_server/main/coap_server.c | 2 +- .../http_request/main/http_request_main.c | 2 +- .../https_request/main/https_request_main.c | 2 +- .../protocols/mdns/main/mdns_example_main.c | 2 +- .../openssl_client/main/openssl_client.c | 2 +- .../openssl_server/main/openssl_server.c | 2 +- examples/protocols/sntp/main/sntp_main.c | 2 +- .../storage/nvs_rw_blob/main/nvs_rw_blob.c | 15 ++++++++--- .../storage/nvs_rw_value/main/nvs_rw_value.c | 25 +++++++++++++------ examples/system/ota/main/ota_example.c | 16 +++++++++++- .../main/wpa2_enterprise_main.c | 2 +- 14 files changed, 68 insertions(+), 24 deletions(-) diff --git a/components/nvs_flash/test/test_nvs.c b/components/nvs_flash/test/test_nvs.c index db97879bc2..07d01db468 100644 --- a/components/nvs_flash/test/test_nvs.c +++ b/components/nvs_flash/test/test_nvs.c @@ -6,14 +6,26 @@ #include "unity.h" #include "nvs.h" #include "nvs_flash.h" -#include "esp_spi_flash.h" +#include "esp_partition.h" +#include "esp_log.h" #include +static const char* TAG = "test_nvs"; TEST_CASE("various nvs tests", "[nvs]") { nvs_handle handle_1; - TEST_ESP_OK(nvs_flash_init()); + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES) { + ESP_LOGW(TAG, "nvs_flash_init failed (0x%x), erasing partition and retrying", err); + const esp_partition_t* nvs_partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); + assert(nvs_partition && "partition table must have an NVS partition"); + ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) ); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK( err ); + TEST_ESP_ERR(nvs_open("test_namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND); TEST_ESP_ERR(nvs_set_i32(handle_1, "foo", 0x12345678), ESP_ERR_NVS_INVALID_HANDLE); diff --git a/examples/bluetooth/blufi/main/blufi_main.c b/examples/bluetooth/blufi/main/blufi_main.c index b46ffb4648..d35ab71214 100644 --- a/examples/bluetooth/blufi/main/blufi_main.c +++ b/examples/bluetooth/blufi/main/blufi_main.c @@ -312,7 +312,7 @@ void app_main() { esp_err_t ret; - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); initialise_wifi(); esp_bt_controller_init(); diff --git a/examples/protocols/coap_client/main/coap_client.c b/examples/protocols/coap_client/main/coap_client.c index 7c0df1afec..a45f748d4a 100644 --- a/examples/protocols/coap_client/main/coap_client.c +++ b/examples/protocols/coap_client/main/coap_client.c @@ -199,7 +199,7 @@ static void wifi_conn_init(void) void app_main(void) { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); wifi_conn_init(); xTaskCreate(coap_demo_thread, "coap", 2048, NULL, 5, NULL); } diff --git a/examples/protocols/coap_server/main/coap_server.c b/examples/protocols/coap_server/main/coap_server.c index 75e3296f79..f232853889 100644 --- a/examples/protocols/coap_server/main/coap_server.c +++ b/examples/protocols/coap_server/main/coap_server.c @@ -185,7 +185,7 @@ static void wifi_conn_init(void) void app_main(void) { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); wifi_conn_init(); xTaskCreate(coap_demo_thread, "coap", 2048, NULL, 5, NULL); diff --git a/examples/protocols/http_request/main/http_request_main.c b/examples/protocols/http_request/main/http_request_main.c index 3831ae65b9..130729f06f 100644 --- a/examples/protocols/http_request/main/http_request_main.c +++ b/examples/protocols/http_request/main/http_request_main.c @@ -174,7 +174,7 @@ static void http_get_task(void *pvParameters) void app_main() { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); initialise_wifi(); xTaskCreate(&http_get_task, "http_get_task", 2048, NULL, 5, NULL); } diff --git a/examples/protocols/https_request/main/https_request_main.c b/examples/protocols/https_request/main/https_request_main.c index b953252aac..305b562205 100644 --- a/examples/protocols/https_request/main/https_request_main.c +++ b/examples/protocols/https_request/main/https_request_main.c @@ -325,7 +325,7 @@ static void https_get_task(void *pvParameters) void app_main() { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); initialise_wifi(); xTaskCreate(&https_get_task, "https_get_task", 8192, NULL, 5, NULL); } diff --git a/examples/protocols/mdns/main/mdns_example_main.c b/examples/protocols/mdns/main/mdns_example_main.c index d19fd1ae68..50b74e08ca 100644 --- a/examples/protocols/mdns/main/mdns_example_main.c +++ b/examples/protocols/mdns/main/mdns_example_main.c @@ -178,7 +178,7 @@ static void mdns_task(void *pvParameters) void app_main() { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); initialise_wifi(); xTaskCreate(&mdns_task, "mdns_task", 2048, NULL, 5, NULL); } diff --git a/examples/protocols/openssl_client/main/openssl_client.c b/examples/protocols/openssl_client/main/openssl_client.c index 69e16141be..16c9a0efa6 100644 --- a/examples/protocols/openssl_client/main/openssl_client.c +++ b/examples/protocols/openssl_client/main/openssl_client.c @@ -220,6 +220,6 @@ static void wifi_conn_init(void) void app_main(void) { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); wifi_conn_init(); } diff --git a/examples/protocols/openssl_server/main/openssl_server.c b/examples/protocols/openssl_server/main/openssl_server.c index c74bb0e41f..e1d0619d29 100755 --- a/examples/protocols/openssl_server/main/openssl_server.c +++ b/examples/protocols/openssl_server/main/openssl_server.c @@ -255,6 +255,6 @@ static void wifi_conn_init(void) void app_main(void) { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); wifi_conn_init(); } diff --git a/examples/protocols/sntp/main/sntp_main.c b/examples/protocols/sntp/main/sntp_main.c index 438505d7b6..5a29fcac87 100644 --- a/examples/protocols/sntp/main/sntp_main.c +++ b/examples/protocols/sntp/main/sntp_main.c @@ -93,7 +93,7 @@ void app_main() static void obtain_time(void) { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); initialise_wifi(); xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY); diff --git a/examples/storage/nvs_rw_blob/main/nvs_rw_blob.c b/examples/storage/nvs_rw_blob/main/nvs_rw_blob.c index c0a865eb6a..6232984f44 100644 --- a/examples/storage/nvs_rw_blob/main/nvs_rw_blob.c +++ b/examples/storage/nvs_rw_blob/main/nvs_rw_blob.c @@ -13,6 +13,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_system.h" +#include "esp_partition.h" #include "nvs_flash.h" #include "nvs.h" #include "driver/gpio.h" @@ -146,9 +147,17 @@ esp_err_t print_what_saved(void) void app_main() { - nvs_flash_init(); - - esp_err_t err; + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES) { + // NVS partition was truncated and needs to be erased + const esp_partition_t* nvs_partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); + assert(nvs_partition && "partition table must have an NVS partition"); + ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) ); + // Retry nvs_flash_init + err = nvs_flash_init(); + } + ESP_ERROR_CHECK( err ); err = print_what_saved(); if (err != ESP_OK) printf("Error (%d) reading data from NVS!\n", err); diff --git a/examples/storage/nvs_rw_value/main/nvs_rw_value.c b/examples/storage/nvs_rw_value/main/nvs_rw_value.c index 1b3e06b859..db01a6afc4 100644 --- a/examples/storage/nvs_rw_value/main/nvs_rw_value.c +++ b/examples/storage/nvs_rw_value/main/nvs_rw_value.c @@ -13,23 +13,32 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_system.h" +#include "esp_partition.h" #include "nvs_flash.h" #include "nvs.h" void app_main() { - nvs_flash_init(); - - nvs_handle my_handle; - esp_err_t err; - - printf("\n"); + // Initialize NVS + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES) { + // NVS partition was truncated and needs to be erased + const esp_partition_t* nvs_partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); + assert(nvs_partition && "partition table must have an NVS partition"); + ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) ); + // Retry nvs_flash_init + err = nvs_flash_init(); + } + ESP_ERROR_CHECK( err ); // Open - printf("Opening Non-Volatile Storage (NVS) ... "); + printf("\n"); + printf("Opening Non-Volatile Storage (NVS) handle... "); + nvs_handle my_handle; err = nvs_open("storage", NVS_READWRITE, &my_handle); if (err != ESP_OK) { - printf("Error (%d) opening NVS!\n", err); + printf("Error (%d) opening NVS handle!\n", err); } else { printf("Done\n"); diff --git a/examples/system/ota/main/ota_example.c b/examples/system/ota/main/ota_example.c index 06ed81e638..bc910f70c5 100644 --- a/examples/system/ota/main/ota_example.c +++ b/examples/system/ota/main/ota_example.c @@ -21,6 +21,7 @@ #include "esp_ota_ops.h" #include "esp_partition.h" +#include "nvs.h" #include "nvs_flash.h" #define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID @@ -279,7 +280,20 @@ void main_task(void *pvParameter) void app_main() { - nvs_flash_init(); + // Initialize NVS. + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES) { + // OTA app partition table has a smaller NVS partition size than the non-OTA + // partition table. This size mismatch may cause NVS initialization to fail. + // If this happens, we erase NVS partition and initialize NVS again. + const esp_partition_t* nvs_partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); + assert(nvs_partition && "partition table must have an NVS partition"); + ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) ); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK( err ); + initialise_wifi(); xTaskCreate(&main_task, "main_task", 8192, NULL, 5, NULL); } diff --git a/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c b/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c index 7d325c76a0..0932aec931 100644 --- a/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c +++ b/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c @@ -148,7 +148,7 @@ static void wpa2_enterprise_task(void *pvParameters) void app_main() { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); initialise_wifi(); xTaskCreate(&wpa2_enterprise_task, "wpa2_enterprise_task", 4096, NULL, 5, NULL); } From 447ffb23d5b441e9836a63d7798fd3ab6a0fc495 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 15 Mar 2017 16:51:52 +0800 Subject: [PATCH 6/6] nvs: print page state as text in nvs_dump --- components/nvs_flash/src/nvs_page.cpp | 29 ++++++++++++++++++++++++++- components/nvs_flash/src/nvs_page.hpp | 2 ++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/components/nvs_flash/src/nvs_page.cpp b/components/nvs_flash/src/nvs_page.cpp index 80ccb1f6d0..a24c7214bb 100644 --- a/components/nvs_flash/src/nvs_page.cpp +++ b/components/nvs_flash/src/nvs_page.cpp @@ -811,10 +811,37 @@ void Page::invalidateCache() { mFindInfo = CachedFindInfo(); } + +const char* Page::pageStateToName(PageState ps) +{ + switch (ps) { + case PageState::CORRUPT: + return "CORRUPT"; + + case PageState::ACTIVE: + return "ACTIVE"; + + case PageState::FREEING: + return "FREEING"; + + case PageState::FULL: + return "FULL"; + + case PageState::INVALID: + return "INVALID"; + + case PageState::UNINITIALIZED: + return "UNINITIALIZED"; + + default: + assert(0 && "invalid state value"); + return ""; + } +} void Page::debugDump() const { - printf("state=%x addr=%x seq=%d\nfirstUsed=%d nextFree=%d used=%d erased=%d\n", (int) mState, mBaseAddress, mSeqNumber, static_cast(mFirstUsedEntry), static_cast(mNextFreeEntry), mUsedEntryCount, mErasedEntryCount); + printf("state=%x (%s) addr=%x seq=%d\nfirstUsed=%d nextFree=%d used=%d erased=%d\n", (uint32_t) mState, pageStateToName(mState), mBaseAddress, mSeqNumber, static_cast(mFirstUsedEntry), static_cast(mNextFreeEntry), mUsedEntryCount, mErasedEntryCount); size_t skip = 0; for (size_t i = 0; i < ENTRY_COUNT; ++i) { printf("%3d: ", static_cast(i)); diff --git a/components/nvs_flash/src/nvs_page.hpp b/components/nvs_flash/src/nvs_page.hpp index c1f430cae5..66b6e847c8 100644 --- a/components/nvs_flash/src/nvs_page.hpp +++ b/components/nvs_flash/src/nvs_page.hpp @@ -220,6 +220,8 @@ protected: assert(entry < ENTRY_COUNT); return mBaseAddress + ENTRY_DATA_OFFSET + static_cast(entry) * ENTRY_SIZE; } + + static const char* pageStateToName(PageState ps); protected: