ESP32在尝试写入NVS时重新启动

问题描述 投票:0回答:2

我正在尝试为我的ESP32项目创建一个保存系统,我有以下代码:

void write_string_nvs(char *memorySlot, String key, String value)
{
    nvs_handle my_handle;
    esp_err_t err = nvs_open(memorySlot, NVS_READWRITE, &my_handle);
    if (err == ESP_OK)
    {
        int kL = key.length();
        int vL = value.length();
        char keyA[kL + 1];
        key.toCharArray(keyA, kL + 1);
        char valueA[vL + 1];
        value.toCharArray(valueA, vL + 1);

        Serial.println("Storing \"" + String(keyA) + "\"(" + String(kL) + ")>\"" + String(valueA) + "\"(" + String(vL) + ") in NVS.");
        esp_err_t err = nvs_set_blob(my_handle, keyA, &valueA, vL);
        if (err == ESP_OK)
        {
            err = nvs_commit(my_handle);
            if (err == ESP_OK)
                Serial.println("Correctly saved \"" + key + "\" in " + String(memorySlot));
            else
                Serial.println("write_string_nvs::commit -> Could not save \"" + key + "\" in " + String(memorySlot) + ": " + esp_err_toString(err, true));
        }
        else
            Serial.println("write_string_nvs::nvs_set_blob -> Could not save \"" + key + "\" in " + String(memorySlot) + ": " + esp_err_toString(err, true) + "");
        nvs_close(my_handle);
    }
    else
        Serial.println("Could not initialize " + String(memorySlot) + " NVS slot: " + esp_err_toString(err, true) + "");
}

我从以下方式调用它,来自一个串行命令:

...
String params[3];
split(serialRead, ' ', params);

String s = params[0];
String k = params[1];
String v = params[2];

bool error = false;
if (s.length() <= 0) {
  error = true;
  Serial.println("Please, specify an storage name");
}
if (k.length() <= 0) {
  error = true;
  Serial.println("Please, specify a key");
}
if (v.length() <= 0) {
  error = true;
  Serial.println("Please, specify a value");
}

if (!error) {
  String slotName = "";
  if (startsWithIgnoreCase(s, "main")) {
    slotName = "storage";
  }
  if (startsWithIgnoreCase(s, "wifi")) {
    slotName = "wifi";
  }

  if (slotName.length() > 1) {
    Serial.println("Writing \"" + v + "\"" + " at \"\"" + k + "\" in " + slotName);

    char slot[slotName.length()];
    slotName.toCharArray(slot, slotName.length());

    write_string_nvs(slot, k, v);
  } else
    Serial.println("Specified invalid slot");
}

通过这样做,我试图创建一个命令解析器来存储值,然后使用以下命令读取它们:storage write <wifi/main> <key> <value>storage read <wifi/main> <key>

但是当我尝试输入write命令并且代码执行时,问题出现了,ESP32 Serial返回:

assertion "heap != NULL && "realloc() pointer is outside heap areas"" failed: file "/Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/heap/heap_caps.c", line 285, function: heap_caps_realloc
abort() was called at PC 0x40152903 on core 1

Backtrace: 0x40091ca4:0x3ffce0c0 0x40091ed5:0x3ffce0e0 0x40152903:0x3ffce100 0x400847a9:0x3ffce130 0x4008483d:0x3ffce150 0x4008b2e9:0x3ffce170 0x4000bedd:0x3ffce190 0x400dd4e2:0x3ffce1b0 0x400dd544:0x3ffce1d0 0x400dd6a6:0x3ffce1f0 0x400dd6d1:0x3ffce210 0x400d1b06:0x3ffce240 0x400d5939:0x3ffce260 0x400de489:0x3ffce7d0 0x40094135:0x3ffce7f0

Rebooting...

我不知道该怎么做,我尝试了一些不同的写入和读取代码,但我找不到任何正确存储值的东西。 read命令有效,但很明显,它没有返回任何内容,因为内存是空的。这是read命令,以防你想看一下:

String read_string_nvs(char *memorySlot, String key)
{
    nvs_handle my_handle;
    esp_err_t err = nvs_open(memorySlot, NVS_READWRITE, &my_handle);
    String espErrStr = esp_err_toString(err, true);
    char *value;
    if (err == ESP_OK || startsWithIgnoreCase(espErrStr, "ESP_OK"))
    {
        size_t string_size;
        int kL = key.length();
        char wifi_slot[kL + 1];
        key.toCharArray(wifi_slot, kL + 1);
        esp_err_t err = nvs_get_str(my_handle, wifi_slot, NULL, &string_size);
        value = (char *)malloc(string_size);
        err = nvs_get_str(my_handle, wifi_slot, value, &string_size);

        nvs_close(my_handle);

        return String(value);
    }
    else
        Serial.println("Could not open memory (\"" + espErrStr + "\")");
    return espErrStr;
}

我已经在这个问题上待了几个星期了,我真的不知道该怎么做,也许这个系统对我想要的东西不好,或者我可能做错了什么。

为了开发我正在使用带有PlatformIO的VSCode。

请看看它,如果你能告诉我什么是错的或做什么,我会非常高兴。

提前致谢。

c++ visual-studio-code esp32 platformio
2个回答
1
投票

我忙于同样的问题(我将使用4Mb的闪存作为nvs分区)我找到了一些线索:https://www.esp32.com/viewtopic.php?t=6815

似乎问题在于RAM大小 - 系统需要一个RAM来创建nvs-pages-map,如果它不足以完成这个任务 - 它会调用系统中止。

附:我已经将我的firmware.elf解码为firmware.lst,其地址和汇编程序代码和回溯是这样的:

app_main - > initArduino - > nvs_flash_init - > nvs_flash_init_partition - > nvs_flash_init_custom - > ZN3nvs_storage_init_Ejj - > ZN3nvs_Storage_populateBlobIndicesIntrusiveList - > _Znwj - > _cxa_allocate_exception - > terminatev - > cxabiv111_terminateEPFvvE - 这里系统中止

要将.elf解码为.lst - 只需将firmware.elf复制到xtensa-esp32-elf-objdump.exe文件夹中(可能在这里.platformio \ packages \ toolchain-xtensa32 \ bin)并在命令中运行提示 - xtensa-esp32-elf-objdump.exe -S -l -d firmware.elf> [YourFileName] .lst


0
投票

这些行有问题:

char slot[slotName.length()];
slotName.toCharArray(slot, slotName.length());

write_string_nvs(slot, k, v);

slotName.length()将返回slotName中的字符数。 slot是一个C字符串,它在末尾需要一个空终止字符(\0),所以它需要声明比字符串中的字符数多一个字节。你的宣言太短了。

您可以通过将这些行重写为:

write_string_nvs(slotName.c_str(), k, v);

String已经在内部将其内容存储为C字符串,因此c_str()方法只是为您指定了它管理的缓冲区。注意这一点,在String对象变为无效之后该指针将无效,因此如果String是函数或代码块中的变量,则当您离开该函数或代码块时,其c_str()将停止有效。

由于这是某种堆或内存分配问题,因此该错误可能超出了您共享的代码。我会查看所有代码,查找将String转换为C字符数组的实例,并尝试使用c_str()成语。

这是一个很常见的问题,它咬住了很多程序员。

问题也可能在你的write_string_nvs()实现中。

© www.soinside.com 2019 - 2024. All rights reserved.