Перезагрузка ESP32 при преобразовании строки в шестнадцатеричный массив
Я написал этот код для преобразования строки в шестнадцатеричный массив.
const char* hexstring = "0x21 0x73 0x10 0xfa 0x7a 0x00 0xff .../*40995 character long string*/....0xaa"
void setup() {
char* temp;
//Serial.printf("%s",hexstring);
unsigned int number[8199];
number[0] = strtoul (hexstring,&temp,16);
for(int i=1;i<8199;i++)
number[i]= (int)strtoul(temp, &temp, 16);
for(int i=0;i<8199;i++)
{
if(i%64)
printf("\n");
printf("%d, ",number[i]);
}
}
void loop(){
}
Но это вызывает перезагрузку ESP32.
Может ли кто-нибудь помочь мне с причиной?
@Just doin Gods work, 👍-1
Обсуждение1 ответ
Лучший ответ:
void setup() {
char* temp;
//Serial.printf("%s",hexstring);
unsigned int number[8199]; <----- too much.
Итак, вы пытаетесь поместить в стек объект размером 32796 байт. Я точно не знаю, почему вы видите то проявление, которым вы являетесь, но я не удивлен.
Я просто взял ESP32-CAM и начал играть с разными размерами и обнаружил, что около 1800 (unsigned int
s) — это то место, где все начинает идти не так, как надо, иногда, а не постоянно. По подсчету 2000 он постоянно перезагружается с rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
с переходом на rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
и позже примерно до 5000 становится rst:0x8 (TG1WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
Я могу заполнить некоторые детали позже, если я изучу их глубже. ESP32 и SDK достаточно сложны, поэтому вполне может существовать функция, которая позволит использовать более высокий уровень стека. Но это в основном для удовлетворения любопытства.
Обычно не помещают в стек очень большие объекты (относительно размера системы). Я не решаюсь сказать вам, что именно вы должны делать; меня не удивит, если вам вообще не нужен этот массив для того, что вы в конечном итоге хотите сделать, но это другой вопрос). Итак, я просто скажу, что извлеките его из стека с помощью динамического выделения памяти (например, с помощью new
или malloc
), возможно, используя интеллектуальный указатель (например, std ::unique_ptr
), чтобы управлять этим, поскольку они доступны в ESP32, или, возможно, просто сделать переменную static
локальной или глобальной. Или еще раз, если возможно, выяснить, почему вам может не понадобиться этот массив.
Простое минимальное изменение
Итак, я не собираюсь говорить вам, что это хорошая идея, но минимальное изменение будет состоять в том, чтобы static
квалифицировать это как static unsigned int number[8199];
Тогда вы не получите эту причину сброса здесь, по этой причине.
Некоторые подробности для тех, кому интересно
Если вы хотите увидеть некоторые внутренности, посмотрите на ядро ESP32 для Arduino, где оно создает задачу, которая в конечном итоге запускает setup()
для вас. Вы можете видеть, что он вызывает getArduinoLoopTaskStackSize()
возвращает ARDUINO_LOOP_STACK_SIZE
, который по умолчанию равен 8192
. 8192 байта, а не unsigned int
. Поскольку sizeof(unsigned int)
равен 4, это очень приблизительно находится в районе 1800 unsigned int
, когда все начало разваливаться в мое тестирование выше. Вместо того, чтобы копаться в конфигурации, я просто сделал скетч, который выполняет Serial.println(getArduinoLoopTaskStackSize());
и да, он печатает 8192.
getArduinoLoopTaskStackSize
– это слабо определенная функция, которая позволяет переопределять что-то в другом месте программа для перегрузки стандартной. Итак, просто из любопытства я написал следующее:
size_t getArduinoLoopTaskStackSize(void) {
size_t r_size = sizeof(unsigned int [8199]); // точно такой же размер вашего массива
r_size += r_size >> 3; // добавить около 1/8 (или 12,5%) дополнительно
return r_size;
}
Он больше не вылетает. Должны ли вы это сделать? Возможно нет. Но если у вас когда-нибудь появится веская причина поместить массив 32 КБ в стек на ESP32, это может быть вариантом. Я в основном просто сделал это, чтобы посмотреть, что произойдет. Его почти не тестировали.
- esp32, platformio A fatal error occurred: Packet content transfer stopped (received 8 bytes) *** [upload] Error 2
- Ошибка A fatal error occurred: Failed to connect to ESP32: Wrong boot mode detected (0x13)! The chip needs to be in download mode. [upload] Error 2
- Текстовая часть превышает доступное место на плате
- WiFiClient.cpp: 517 flush (): сбой на fd 48, errno: 11, «Больше нет процессов», что это значит?
- Использование MPU6050 с ESP32 Cam - MPU Не обнаружено
- Как выбрать альтернативные контакты I2C на ESP32?
- Драйверы для чипа последовательного порта CH9102X
- Как преобразовать форматированный оператор print в строковую переменную?
Я не совсем понимаю, что вы пытаетесь сделать со своим кодом. Это не имеет большого смысла для меня. Во-первых: почему вы предоставляете
&temp
дляstrtoul()
? temp — неинициализированный указатель, @chrislПочему вы пишете
number[0]
два раза вместо того, чтобы использоватьnumber[i]
? Почему этот цикл for имеет длину всего 5 итераций, а другой, который не записывает число, имеет длину 8199 итераций? В общем, я не знаю, как помочь здесь, кроме как указать на эти вещи. Может быть, опишите, что вы пытаетесь сделать, @chrisl@chrisl Я исправил это, это должно было быть «число [i]», немного поискав, я нашел способ преобразовать строку шестнадцатеричных значений в массив шестнадцатеричных значений. Итак, я попробовал это в онлайн-компиляторе C, он отлично работает. Например,
const char* hexstring = "0x21 0x49..." становится
unsigned int number[8199]=[33, 73...`, @Just doin Gods workПлохо, я отредактировал код, чтобы попробовать более короткую строку, и по ошибке скопировал ее. Я исправил это сейчас. Итерация 8199, @Just doin Gods work
Тем не менее, почему вы используете
temp
неинициализированным? В этой позиции параметр является конечным указателем (указатель на то место, где должно остановиться преобразование). Нулевой указатель здесь означает преобразование до конца строки. Так что это сводится к тому, чтоtemp
неявно инициализируется нулевым указателем. Возможно, это относится к вашему онлайн-компилятору. Пожалуйста, попробуйте использоватьNULL
вместоtemp
илиstrtoul()
, @chrisl@chrisl, _ «где преобразование должно остановиться» _ на самом деле используется как _output_ not input. Он не говорит
strtoul
, где остановить лексирование, он даетstrtoul
средство сообщить вызывающей стороне, где он остановился. Таким образом, вы можете использовать его, чтобы выяснить, где возобновить следующую операцию, что они и делают. Если вы дадите емуNULL
, вы просто скажете: «Мне все равно, где» вы остановились. Если вы дадите ему указатель на указатель символа, вы скажете: «Мне все равно, где вы остановились, скажите мне этим указателем, на что я вам указываю»., @timemage@timemage А, ладно, значит, я неправильно понял, @chrisl