ESP32 перезапускается при попытке записи в NVS

#c #visual-studio-code #esp32 #platformio

#c #visual-studio-code #esp32 #platformio

Вопрос:

Я пытаюсь создать систему сохранения для моего проекта ESP32, и у меня есть следующий код:

 void write_string_nvs(char *memorySlot, String key, String value)
{
    nvs_handle my_handle;
    esp_err_t err = nvs_open(memorySlot, NVS_READWRITE, amp;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, amp;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 возвращает:

 assertion "heap != NULL amp;amp; "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, amp;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, amp;string_size);
        value = (char *)malloc(string_size);
        err = nvs_get_str(my_handle, wifi_slot, value, amp;string_size);

        nvs_close(my_handle);

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

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

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

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

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

Комментарии:

1. Пожалуйста, расшифруйте эту обратную трассировку и отредактируйте полученную трассировку стека в вашем вопросе. Кроме того, nvs_flash_init() успешно, верно?

2. @rustyx Я пытаюсь его расшифровать, но получаю сообщение об ошибке: ERROR: addr2line not found (C:UsersArnym.platformiopackagestoolchain-xtensabin/xtensa-esp32-elf-addr2line) ERROR: Parser not complete!

3. @rustyx да, nvs_flash_init() все должно быть в порядке, он возвращает ESP_OK

4. Ошибка, связанная с addr2line, может быть проблемой с именем пути. Можете ли вы убедиться, что он находится в том расположении, которое указано в сообщении об ошибке? Кроме того, я бы напечатал коды возврата из всех ваших вызовов библиотеки nvs.

5. @rustyx Я запускаюсь decode.py на своем рабочем столе, где у меня есть firmware.elf файл, экспортированный PlatformIO, и ошибка, показанная в сообщении, в файле с именем exc.txt . И я запускаю команду: python decoder.py -p ESP32 -e firmware.elf exc.txt на Python 3.7.1

Ответ №1:

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

Похоже, проблема в размере оперативной памяти — системе нужна оперативная память для создания nvs-pages-map, и если этого недостаточно для этой задачи — это вызывает system abort.

PS Я расшифровал свой firmware.elf в firmware.lst с адресами, кодом на ассемблере и обратным отслеживанием такой:

app_main -> initArduino -> nvs_flash_init -> nvs_flash_init_partition -> nvs_flash_init_custom -> ZN3nvs_storage_init_Ejj -> zn3nvs_storage_populatebloindicesintrusivelist -> _Znwj -> _cxa_allocate_exception -> terminatev — > cxabiv111_terminateEPFvvE — здесь система прерывает

Чтобы расшифровать файл .elf в .lst — просто скопируйте файл firmware.elf в папку с xtensa-esp32-elf-objdump.exe (вероятно, это здесь .platformiopackages toolchain-xtensa32bin) и запустите в командной строке — xtensa-esp32-elf-objdump.exe -S -l -d firmware.elf > [YourFileName].lst

Ответ №2:

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

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

write_string_nvs(slot, k, v);
  

slotName.length() вернет количество символов в slotName . slot это строка C, для которой в конце требуется нулевой завершающий символ ( ), поэтому ее необходимо объявить на один байт больше, чем количество символов в строке. Ваше объявление слишком короткое.

Вы можете обойти проблему, переписав эти строки как:

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

String его содержимое уже хранится внутри в виде строки C, поэтому c_str() метод просто дает вам указатель на буфер, которым он управляет. Будьте осторожны с этим, этот указатель не будет действительным после того, как String объект станет недействительным, поэтому, если String это переменная в функции или блоке кода, она c_str() перестанет быть действительной, когда вы покинете эту функцию или блок кода.

Поскольку это какая-то проблема с кучей или выделением памяти, возможно, ошибка находится за пределами кода, которым вы поделились. Я бы просмотрел весь код в поисках примеров, когда вы преобразуете a String в массив символов C и пытаетесь использовать вместо этого c_str() идиому.

Это довольно распространенная проблема, которая беспокоит многих программистов.

Также возможно, что проблема в вашей write_string_nvs() реализации.

Комментарии:

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