#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. Не удалось приступить к работе. Я изменил то, что вы говорите, и происходит то же самое… Возможно, я чего-то не понимаю.