Merge branch 'feature/nvs_flash_erase_verify_v6.0' into 'release/v6.0'

feat(nvs_flash): Added verification of flash erase operation (v6.0)

See merge request espressif/esp-idf!46948
This commit is contained in:
Martin Vychodil
2026-03-24 17:45:29 +08:00
4 changed files with 74 additions and 0 deletions
+17
View File
@@ -51,4 +51,21 @@ menu "NVS"
default n default n
help help
This option enforces internal use of Block Device Layer instead ESP_Partition. This option enforces internal use of Block Device Layer instead ESP_Partition.
config NVS_FLASH_VERIFY_ERASE
bool "Enable verification of erase operations by reading back the erased data"
default n
help
This option ensures that erase operations are verified by reading back the flash memory.
config NVS_FLASH_ERASE_ATTEMPTS
int "Total number of flash erase attempts in case the erase verification fails"
depends on NVS_FLASH_VERIFY_ERASE
range 1 10
default 2
help
Configures the total number of flash erase attempts. The flash erase operation will be attempted
up to this number of times before returning an error.
Minimum value is 1, maximum value is 10.
endmenu endmenu
@@ -58,7 +58,52 @@ esp_err_t NVSPartition::write(size_t dst_offset, const void* src, size_t size)
esp_err_t NVSPartition::erase_range(size_t dst_offset, size_t size) esp_err_t NVSPartition::erase_range(size_t dst_offset, size_t size)
{ {
#ifndef CONFIG_NVS_FLASH_VERIFY_ERASE
return esp_partition_erase_range(mESPPartition, dst_offset, size); return esp_partition_erase_range(mESPPartition, dst_offset, size);
#else
esp_err_t err = ESP_FAIL;
// Loop up to the CONFIG_NVS_FLASH_ERASE_ATTEMPTS times to attempt the erase operation.
for (int attempt = 0; attempt < CONFIG_NVS_FLASH_ERASE_ATTEMPTS; ++attempt)
{
// In the loop, do the flash erase followed by a read(s) to verify the success of the operation.
// Perform the erase operation.
esp_err_t err = esp_partition_erase_range(mESPPartition, dst_offset, size);
if (err != ESP_OK)
{
continue; // Erase failed, continue to the next attempt.
}
// Validate the erase operation by reading back the erased area.
// Buffer of some reasonable size to read back and check.
const size_t buf_size = 32;
uint8_t buf[buf_size];
size_t remaining = size;
size_t read_offset = dst_offset;
while (remaining > 0)
{
size_t to_read = (remaining < buf_size) ? remaining : buf_size;
err = esp_partition_read_raw(mESPPartition, read_offset, buf, to_read);
if (err != ESP_OK) {
break; // Read failed, break to attempt erase again.
}
for (size_t i = 0; i < to_read; ++i)
{
if (buf[i] != 0xFF)
{
err = ESP_ERR_NOT_FINISHED; // Verification failed.
break;
}
}
remaining -= to_read;
read_offset += to_read;
}
if(err == ESP_OK) return ESP_OK; // Erase and verification succeeded do not need to attempt again.
}
return err; // All attempts exhausted, return the last error.
#endif // CONFIG_NVS_FLASH_VERIFY_ERASE
} }
uint32_t NVSPartition::get_address() uint32_t NVSPartition::get_address()
@@ -133,6 +133,12 @@ If NVS encryption is not used, it is possible for anyone with physical access to
The library does try to recover from conditions when flash memory is in an inconsistent state. In particular, one should be able to power off the device at any point and time and then power it back on. This should not result in loss of data, except for the new key-value pair if it was being written at the moment of powering off. The library should also be able to initialize properly with any random data present in flash memory. The library does try to recover from conditions when flash memory is in an inconsistent state. In particular, one should be able to power off the device at any point and time and then power it back on. This should not result in loss of data, except for the new key-value pair if it was being written at the moment of powering off. The library should also be able to initialize properly with any random data present in flash memory.
Unstable Power Conditions
-------------------------
When NVS is used in systems powered by weak or unstable energy sources (such as solar or battery), flash erase operations may occasionally fail to complete without being detected by the application. This can create a mismatch between the actual flash contents and the expected layout of reserved pages. In rare cases, especially during unexpected power loss, this may exhaust the available NVS pages and cause partition initialization to fail with the error ``ESP_ERR_NVS_NO_FREE_PAGES``.
To address this issue, the Kconfig option :ref:`CONFIG_NVS_FLASH_VERIFY_ERASE` enables verification of flash erase operations by reading back the affected page. If the page is not fully erased to ``0xFF`` after a ``flash_erase`` operation, the erase is retried until the page is correctly cleared. The total number of erase attempts, including the initial attempt, is controlled by the Kconfig option :ref:`CONFIG_NVS_FLASH_ERASE_ATTEMPTS`.
.. _nvs_encryption: .. _nvs_encryption:
@@ -133,6 +133,12 @@ NVS 迭代器
当 flash 处于不一致状态时,NVS 库会尝试恢复。在任何时间点关闭设备电源,然后重新打开电源,不会导致数据丢失;但如果关闭设备电源时正在写入新的键值对,这一键值对可能会丢失。该库还应该能够在 flash 中存在任何随机数据的情况下正常初始化。 当 flash 处于不一致状态时,NVS 库会尝试恢复。在任何时间点关闭设备电源,然后重新打开电源,不会导致数据丢失;但如果关闭设备电源时正在写入新的键值对,这一键值对可能会丢失。该库还应该能够在 flash 中存在任何随机数据的情况下正常初始化。
电源不稳定状态
-------------------------
当 NVS 用于弱电源或不稳定电源系统(如太阳能或电池供电系统)时,flash 擦除操作可能偶尔无法彻底完成,而应用程序无法检测到这一问题。这会导致实际 flash 内容与预留页面的预期布局不一致。在极少数情况下(特别是在意外断电时),可能造成可用 NVS 页面耗尽,导致分区初始化失败并返回 ``ESP_ERR_NVS_NO_FREE_PAGES`` 错误。
为解决此问题,可通过 Kconfig 选项 :ref:`CONFIG_NVS_FLASH_VERIFY_ERASE` 启用 flash 擦除操作的验证机制,通过回读受影响页面进行检测。若在 ``flash_erase`` 操作后页面未完全擦除为 ``0xFF``,系统将重试擦除操作直至页面被正确清空。包括首次尝试在内的擦除尝试总次数可通过 Kconfig 选项 :ref:`CONFIG_NVS_FLASH_ERASE_ATTEMPTS` 进行配置。
.. _nvs_encryption: .. _nvs_encryption: