ESP32 перезагружается при попытке записи в NVS - PullRequest
0 голосов
/ 26 марта 2019

Я пытаюсь создать систему сохранения для моего проекта 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...

Я не знаю, что делать, я пробовал разные коды записи и чтения, но не могу найти ни одного такогохранит значения правильно.Команда чтения работает, но, очевидно, она ничего не возвращает, потому что память пуста.Вот команда чтения, на случай, если вы захотите взглянуть на нее:

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;
}

Я занимаюсь этой проблемой уже несколько недель, и я действительно не знаю, что делать, может быть, системане подходит для того, что я хочу, или я могу делать что-то не так.

Для разработки я использую VSCode с PlatformIO.

Пожалуйста, посмотрите, и если вы могли бы сказать мне,что не так или что делать, я был бы очень рад.

Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 05 апреля 2019

Я занят той же проблемой (я собираюсь использовать 4 МБ флэш-памяти в качестве раздела nvs), и я нашел некоторую подсказку: https://www.esp32.com/viewtopic.php?t=6815

Кажется, что проблема заключается вс размером оперативной памяти - системе требуется оперативная память для создания карты nvs-pages, а если этого недостаточно для выполнения этой задачи - она ​​вызывает прерывание работы системы.

PS Я расшифровал файл firmware.elf в прошивке.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 голосов
/ 26 марта 2019

Эти строки проблематичны:

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().

...