Skip to content

Commit c05d303

Browse files
authored
Merge pull request #5227 from jepler/esp32-nvm
esp32s2: rework nvm/nvs storage
2 parents d8b3d5a + 7098d4c commit c05d303

File tree

4 files changed

+98
-19
lines changed

4 files changed

+98
-19
lines changed

locale/circuitpython.pot

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,7 +1225,7 @@ msgstr ""
12251225
msgid "Insufficient encryption"
12261226
msgstr ""
12271227

1228-
#: ports/raspberrypi/audio_dma.c
1228+
#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c
12291229
msgid "Internal audio buffer too small"
12301230
msgstr ""
12311231

@@ -1392,7 +1392,8 @@ msgstr ""
13921392
#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/I2C.c
13931393
#: ports/raspberrypi/common-hal/busio/I2C.c
13941394
#: ports/raspberrypi/common-hal/busio/SPI.c
1395-
#: ports/raspberrypi/common-hal/busio/UART.c
1395+
#: ports/raspberrypi/common-hal/busio/UART.c shared-bindings/busio/SPI.c
1396+
#: shared-bindings/busio/UART.c
13961397
msgid "Invalid pins"
13971398
msgstr ""
13981399

@@ -3915,8 +3916,10 @@ msgstr ""
39153916
#: ports/esp32s2/boards/adafruit_funhouse/mpconfigboard.h
39163917
#: ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.h
39173918
#: ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.h
3919+
#: ports/esp32s2/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
39183920
#: ports/esp32s2/boards/artisense_rd00/mpconfigboard.h
39193921
#: ports/esp32s2/boards/atmegazero_esp32s2/mpconfigboard.h
3922+
#: ports/esp32s2/boards/crumpspace_crumps2/mpconfigboard.h
39203923
#: ports/esp32s2/boards/electroniccats_bastwifi/mpconfigboard.h
39213924
#: ports/esp32s2/boards/espressif_kaluga_1.3/mpconfigboard.h
39223925
#: ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.h
@@ -3933,6 +3936,7 @@ msgstr ""
39333936
#: ports/esp32s2/boards/morpheans_morphesp-240/mpconfigboard.h
39343937
#: ports/esp32s2/boards/muselab_nanoesp32_s2_wroom/mpconfigboard.h
39353938
#: ports/esp32s2/boards/muselab_nanoesp32_s2_wrover/mpconfigboard.h
3939+
#: ports/esp32s2/boards/odt_pixelwing_esp32_s2/mpconfigboard.h
39363940
#: ports/esp32s2/boards/targett_module_clip_wroom/mpconfigboard.h
39373941
#: ports/esp32s2/boards/targett_module_clip_wrover/mpconfigboard.h
39383942
#: ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.h

ports/esp32s2/bindings/espidf/__init__.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,12 @@
2626

2727
#include "py/obj.h"
2828
#include "py/runtime.h"
29+
#include "py/mphal.h"
30+
2931

3032
#include "bindings/espidf/__init__.h"
3133

34+
#include "nvs_flash.h"
3235
#include "components/heap/include/esp_heap_caps.h"
3336

3437
//| """Direct access to a few ESP-IDF details. This module *should not* include any functionality
@@ -65,6 +68,20 @@ STATIC mp_obj_t espidf_heap_caps_get_largest_free_block(void) {
6568
}
6669
MP_DEFINE_CONST_FUN_OBJ_0(espidf_heap_caps_get_largest_free_block_obj, espidf_heap_caps_get_largest_free_block);
6770

71+
//| def erase_nvs() -> None:
72+
//| """Erase all data in the non-volatile storage (nvs), including data stored by with `microcontroller.nvm`
73+
//|
74+
//| This is necessary when upgrading from CircuitPython 6.3.0 or earlier to CircuitPython 7.0.0, because the
75+
//| layout of data in nvs has changed. The old data will be lost when you perform this operation."""
76+
STATIC mp_obj_t espidf_erase_nvs(void) {
77+
ESP_ERROR_CHECK(nvs_flash_deinit());
78+
ESP_ERROR_CHECK(nvs_flash_erase());
79+
ESP_ERROR_CHECK(nvs_flash_init());
80+
return mp_const_none;
81+
}
82+
MP_DEFINE_CONST_FUN_OBJ_0(espidf_erase_nvs_obj, espidf_erase_nvs);
83+
84+
6885
//| class IDFError(OSError):
6986
//| """Raised for certain generic ESP IDF errors."""
7087
//| ...
@@ -117,6 +134,8 @@ STATIC const mp_rom_map_elem_t espidf_module_globals_table[] = {
117134
{ MP_ROM_QSTR(MP_QSTR_heap_caps_get_free_size), MP_ROM_PTR(&espidf_heap_caps_get_free_size_obj)},
118135
{ MP_ROM_QSTR(MP_QSTR_heap_caps_get_largest_free_block), MP_ROM_PTR(&espidf_heap_caps_get_largest_free_block_obj)},
119136

137+
{ MP_ROM_QSTR(MP_QSTR_erase_nvs), MP_ROM_PTR(&espidf_erase_nvs_obj)},
138+
120139
{ MP_ROM_QSTR(MP_QSTR_IDFError), MP_ROM_PTR(&mp_type_espidf_IDFError) },
121140
{ MP_ROM_QSTR(MP_QSTR_MemoryError), MP_ROM_PTR(&mp_type_espidf_MemoryError) },
122141
};

ports/esp32s2/common-hal/nvm/ByteArray.c

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,13 @@
2424
* THE SOFTWARE.
2525
*/
2626

27+
#include <string.h>
28+
2729
#include "common-hal/nvm/ByteArray.h"
30+
#include "bindings/espidf/__init__.h"
2831

2932
#include "py/runtime.h"
33+
#include "py/gc.h"
3034
#include "nvs_flash.h"
3135

3236
uint32_t common_hal_nvm_bytearray_get_length(nvm_bytearray_obj_t *self) {
@@ -50,48 +54,94 @@ static void get_nvs_handle(nvs_handle_t *nvs_handle) {
5054
}
5155
}
5256

57+
// Get a copy of the nvm data, or an array initialized to all 0 bytes if it is not present
58+
static esp_err_t get_bytes(nvs_handle_t handle, uint8_t **buf_out) {
59+
size_t size;
60+
void *buf;
61+
esp_err_t result = nvs_get_blob(handle, "data", NULL, &size);
62+
if (result == ESP_ERR_NVS_NOT_FOUND) {
63+
size = CIRCUITPY_INTERNAL_NVM_SIZE;
64+
} else if (result != ESP_OK) {
65+
*buf_out = NULL;
66+
return result;
67+
}
68+
buf = gc_alloc(size, 0, false); // this SHOULD be the same as
69+
if (result == ESP_OK) {
70+
result = nvs_get_blob(handle, "data", buf, &size);
71+
} else {
72+
result = ESP_OK;
73+
}
74+
*buf_out = buf;
75+
return result;
76+
}
77+
5378
bool common_hal_nvm_bytearray_set_bytes(nvm_bytearray_obj_t *self,
5479
uint32_t start_index, uint8_t *values, uint32_t len) {
55-
char index[9];
5680

5781
// start nvs
5882
nvs_handle_t handle;
5983
get_nvs_handle(&handle);
6084

61-
// stage flash changes
62-
for (uint32_t i = 0; i < len; i++) {
63-
sprintf(index, "%i", start_index + i);
64-
if (nvs_set_u8(handle, (const char *)index, values[i]) != ESP_OK) {
65-
return false;
66-
}
85+
// get from flash
86+
uint8_t *buf = NULL;
87+
esp_err_t result = get_bytes(handle, &buf);
88+
if (result != ESP_OK) {
89+
gc_free(buf);
90+
nvs_close(handle);
91+
raise_esp_error(result);
92+
}
93+
94+
// erase old data, including 6.3.x incompatible data
95+
result = nvs_erase_all(handle);
96+
if (result != ESP_OK) {
97+
gc_free(buf);
98+
nvs_close(handle);
99+
raise_esp_error(result);
100+
}
101+
102+
// make our modification
103+
memcpy(buf + start_index, values, len);
104+
105+
result = nvs_set_blob(handle, "data", buf, CIRCUITPY_INTERNAL_NVM_SIZE);
106+
if (result != ESP_OK) {
107+
gc_free(buf);
108+
nvs_close(handle);
109+
raise_esp_error(result);
67110
}
68111

69-
// commit flash changes
70-
if (nvs_commit(handle) != ESP_OK) {
71-
return false;
112+
result = nvs_commit(handle);
113+
if (result != ESP_OK) {
114+
gc_free(buf);
115+
nvs_close(handle);
116+
raise_esp_error(result);
72117
}
73118

74119
// close nvs
120+
gc_free(buf);
75121
nvs_close(handle);
76122
return true;
77123
}
78124

79125
void common_hal_nvm_bytearray_get_bytes(nvm_bytearray_obj_t *self,
80126
uint32_t start_index, uint32_t len, uint8_t *values) {
81-
char index[9];
82127

83128
// start nvs
84129
nvs_handle_t handle;
85130
get_nvs_handle(&handle);
86131

87132
// get from flash
88-
for (uint32_t i = 0; i < len; i++) {
89-
sprintf(index, "%i", start_index + i);
90-
if (nvs_get_u8(handle, (const char *)index, &values[i]) != ESP_OK) {
91-
mp_raise_RuntimeError(translate("NVS Error"));
92-
}
133+
uint8_t *buf;
134+
esp_err_t result = get_bytes(handle, &buf);
135+
if (result != ESP_OK) {
136+
gc_free(buf);
137+
nvs_close(handle);
138+
raise_esp_error(result);
93139
}
94140

141+
// copy the subset of data requested
142+
memcpy(values, buf + start_index, len);
143+
95144
// close nvs
145+
gc_free(buf);
96146
nvs_close(handle);
97147
}

ports/esp32s2/mpconfigport.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,14 @@
4242

4343
#define CIRCUITPY_INTERNAL_NVM_START_ADDR (0x9000)
4444

45+
// 20kB is statically allocated to nvs, but when overwriting an existing
46+
// item, it's temporarily necessary to store both the old and new copies.
47+
// Additionally, there is some overhad for the names and values of items
48+
// in nvs, and alignment to 4kB flash erase boundaries may give better
49+
// performance characteristics (h/t @tannewt). This implies we should select an
50+
// 8kB size for CircuitPython'ns NVM.
4551
#ifndef CIRCUITPY_INTERNAL_NVM_SIZE
46-
#define CIRCUITPY_INTERNAL_NVM_SIZE (20 * 1024)
52+
#define CIRCUITPY_INTERNAL_NVM_SIZE (8 * 1024)
4753
#endif
4854

4955
#endif // __INCLUDED_ESP32S2_MPCONFIGPORT_H

0 commit comments

Comments
 (0)