• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Нужна помощь Esp вылетает при попытке подключения к WIFI

Ewanse

New member
Подключаю esp-8266 к роутеру, по началу все работает. Через несколько дней, esp отключается и уходит в бесконечную перезагрузку. Перезагрузка происходит только во время подключения к wifi. Ошибок в коде нет, код не меняется, если не дать esp подключиться к роутеру, все продолжает работать, не перезагружаясь. Можно перепрошить, но как только вновь вводишь логин-пароль роутера устройство начинает вылетать.
Проблему решает только перезагрузка самого роутера. После перезагрузки роутера esp работает еще пару дней.
Причем с роутер работает как ни в чем не бывало. Ноуты и телефоны конектятся без проблем. Вылетает только esp с mongoose. На других прошивках этого не наблюдал.
Можно ли както получить подробный лог ошибки чтобы отправить разработчикам?
Может быть в какойто момент роутер шлет неправильный пакет который проглатывается всеми устройствами но крашит mongoose?
 

lsm

Разработчик Smart.js
Команда форума
В UART должен вывалиться лог с крешдампом, его сохраните и сделайте анализ как тут написано:
Mongoose OS Documentation

Когда получите GDB консоль, сделайте там `bt` и пришлите получившийся бек-трейс.
 

nikolz

Well-known member
Подключаю esp-8266 к роутеру, по началу все работает. Через несколько дней, esp отключается и уходит в бесконечную перезагрузку. Перезагрузка происходит только во время подключения к wifi. Ошибок в коде нет, код не меняется, если не дать esp подключиться к роутеру, все продолжает работать, не перезагружаясь. Можно перепрошить, но как только вновь вводишь логин-пароль роутера устройство начинает вылетать.
Проблему решает только перезагрузка самого роутера. После перезагрузки роутера esp работает еще пару дней.
Причем с роутер работает как ни в чем не бывало. Ноуты и телефоны конектятся без проблем. Вылетает только esp с mongoose. На других прошивках этого не наблюдал.
Можно ли както получить подробный лог ошибки чтобы отправить разработчикам?
Может быть в какойто момент роутер шлет неправильный пакет который проглатывается всеми устройствами но крашит mongoose?
Предположу,
У Вас логическая ошибка в программе.
Два варианта ошибки:
1) При потере соединения Вы пытаетесь установить его снова и тратите на это память, не освобождая ее. В результате наступает нехватка памяти и постоянный кирдык.
2) Есть цикл с ожиданием. В результате бесконечного ожидания срабатывает WD и наступает кирдык опять же.
 

gerkimuyda

New member
Еще хочу напомнить, что надо следить за переполнением счетчика времени. Стандартный millis() переполняется каждую 72 минуту. И если реализовывать проверку типа
timeout = millis() + 1000;
if( timeout < millis() )
можно неожиданно наткнутся на неправильное исполнение команд и получить глюк.

Чтобы уйти от 32-битности таймера к 64-битному, используют код:
Код:
#define MAC_TIMER64BIT_COUNT_ADDR 0x3ff21048

uint64 ICACHE_FLASH_ATTR get_mac_time(void) {
    union { volatile uint32 dw[2]; uint64 dd; }ux;
    volatile uint32 * ptr = (volatile uint32 *)MAC_TIMER64BIT_COUNT_ADDR;
    ux.dw[0] = ptr[0]; ux.dw[1] = ptr[1];
    if(ux.dw[1] != ptr[1]) { ux.dw[0] = ptr[0]; ux.dw[1] = ptr[1]; }
    return ux.dd;
}
Не факт, что это ваш случай, но просто напомнило именно подобный глюк. Да и текст пусть будет на форуме, если кто-то столкнется с таймером и будет искать решение.
 

Ewanse

New member
Спасибо, с логом ошибок от esp придется подождать некоторое время, пока не отвалится снова.
Тут все зависит от роутера)
 

enjoynering

Well-known member
вы уверенны?

Еще хочу напомнить, что надо следить за переполнением счетчика времени. Стандартный millis() переполняется каждую 72 минуту.
millis() возвращает uint32_t, а это на минуточку 4249967295 миллисекунд или 4249967.295 секунд или 70832.78825 минут или 1180.54647083 часов или 49.189 дня
 

gerkimuyda

New member
Уверен, т.к. сам отлавливал такой баг и его решал.
Вот вам описание в других источниках: The function millis() rolls over in about 72 minutes. Is there an alternative with longer rollover time/no rollover? · Issue #675 · SmingHub/Sming · GitHub

millis() on ESP8266 has a roll over of 72 minutes. (Based on microsecond tick.)
millis() on Arduino (AVR) has a roll over of 49 days. (Based on millisecond tick.)

the "problem" currently is, that millis() relies on system_get_time() from espressif SDK which is a 32bit Integer and cannot be changed.

Или вы забыли, что тема не в ветке Arduino IDE, и подразумевает функции SDK, а тут другие правила?

Проверяется просто - скомпилируйте и оставьте на 3 часа. Потом сообщите о результатах o_O
И да - 49 дней тоже малопригодно для "не светодиодом помигать" :cool:
 

enjoynering

Well-known member
Простите не посмотрел что это ветка про native SDK.

Но ардуино код построен вокруг native SDK. Значит и там такая же баг/фича с переполнением счетчика millis после 72 минут?
 

gerkimuyda

New member
Но ардуино код построен вокруг native SDK. Значит и там такая же баг/фича с переполнением счетчика millis после 72 минут?
Нет. Ведь там не микросекунды отдаются, а миллисекунды. И в Arduino IDE все получается именно так, как вы написали выше. Да обойти это ограничение в SDK ведь не сложно (встречал варианты с введением второй переменной, в которую складируют количество переполнений (а ля старший регистр))

А если рассказать про мой случай - то само по себе переполнение не вызывало ошибку. Но неправильная работа (из-за переполнения) приводила к многократному исполнению кода, который нуждался в дополнительной памяти, и освобождал ее он чуть попозже... Вот и получалось, что все работало идеально два часа, а потом резко Exception.

Тут подробно описали про переполнение, ардуину и способы сравнений:
How can I handle the millis() rollover?
 
Последнее редактирование:

enjoynering

Well-known member
Да обойти это ограничение в SDK ведь не сложно (встречал варианты с введением второй переменной, в которую складируют количество переполнений (а ля старший регистр))
угу я так делаю, для подсчета uptime модуля на arduino ide.

Код:
uint32_t NTP_Client::getUptime()
{
  uint32_t uptime           = 0;
  bool     expectedOverflow = false;

  uptime = millis() / NTP_MILLISECONDS_IN_SECOND;       //convert msec to sec

  if (uptime >= 4294907UL)                              //timer is going to overflow in 1 min/60sec
  {
    expectedOverflow = true;                            //set overflow flag
  }

  if (expectedOverflow == true && uptime <= 60)         //timer overflowed less than 60sec ago
  {
    this->_overflowCounter++;                           //each overflow = 4,294,967 seconds with costant error +0.295 seconds
    expectedOverflow = false;                           //clear overflow flag
  }

  uptime = this->_overflowCounter * 4294967UL + uptime;

  return uptime;
}
я почему влез в тему, щас пишу ntp клиента на arduino и модуль постоянно виснет через ~30 минут в районе udp запроса. пямять не утекает - хип постоянен. в лог ничего не валится. голову сломал. а тут вы про 72 минуты. думал вот моя ошибка и начал уточнять. оказывается нет.
 

gerkimuyda

New member
щас пишу ntp клиента на arduino и модуль постоянно виснет через ~30 минут в районе udp запроса.
А зачем его писать, если он есть в SDK готовый? На событие по получению IP адреса (после подключения вайфая) ставите инициализацию.
Код:
    sntp_stop();
    sntp_set_update_delay(1800000); //30 min
    sntp_setservername(0,"time.windows.net");
    sntp_set_timezone(2); //GMT+2
    sntp_init();
и все. SDK сама в фоне запросы посылает. А вы только значение получаете
Код:
    uint32 time = sntp_get_current_timestamp();
    if(time == 0) { time = get_mac_time() / 1000000;  }
А в ардуино был такой код, но его надо переделать для обхода переполнения millis():
Код:
unsigned long unixTime = 0;
unsigned long millisTime = 0;
unsigned long currentTime = 0;
unsigned long periodNTP = 1800000; //time between NTP time-synchronize
unsigned long millisNTP = 0;
byte packetBuffer[48]; //NTP buffer to hold incoming and outgoing packets

unsigned long inline ntpUnixTime (UDP &udp) ICACHE_FLASH_ATTR {
  int udpInited = udp.begin(2390);  if(!udpInited){ udp.stop(); return 0; }
  memset(packetBuffer, 0, 48);
  packetBuffer[0] = 0b11100011;/* LI, Version, Mode */  packetBuffer[1] = 0;/* Stratum, or type of clock */  packetBuffer[2] = 6;/* Polling Interval */  packetBuffer[3] = 0xEC;/* Peer Clock Precision */
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;  packetBuffer[13]  = 0x4E;  packetBuffer[14]  = 49;  packetBuffer[15]  = 52;
  udp.flush(); udp.beginPacket(CFG_TIME, 123); udp.write(packetBuffer, 48);  udp.endPacket();
    delay(1000);
  if(udp.parsePacket()) { udp.read(packetBuffer, 48);
    udp.flush(); udp.stop();
    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    return secsSince1900 - 2208988800UL; // convert NTP time to Unix time
  }else{ udp.flush(); udp.stop(); return 0; }
}

void mainNTP(boolean force=false) ICACHE_FLASH_ATTR {
  if( (millisTime - millisNTP < periodNTP)&&(!force) ) { return; }
  Serial.print( print_time()+" NTP: Time synchronization "); unsigned long unixTimeUpdate=ntpUnixTime(udp);  millisTime = millis();
  if(unixTimeUpdate>0) { unixTime=unixTimeUpdate; Serial.print("- done. ["+print_time(unixTime)+"]\n"); millisNTP = millisTime; }
  else{ Serial.print("failed!\n"); }
  currentTime = unixTime + (millisTime - (unixTime>1500000000?millisNTP:0))/1000;
}
Ардуиновский прошу не рассматривать, давно это было и его надо переделывать. Но функция получения времени по udp мной использовалась ранее другая, которая была глючной и через какой-то период начинала выдавать неправильное время!
Попробуйте эту функцию объединить с вышеприведенной get_mac_time() вместо millis() и тогда не надо будет заботится о переполнениях. Или используйте встроенный sntp в sdk, но там есть одна особенность, после sntp_init() надо дать пару секунд, пока в фоне SDK получит время. Именно в фоне (т.е. нельзя блокировать процессы). И отследить этот момент - нет возможности. (только на таймер повесить проверку)
 
Последнее редактирование:

enjoynering

Well-known member
угу у меня похож на второй, но без косяков

например по стандарту RFC 5905-Network Time Protocol
Код:
packetBuffer[12]  = 49;  packetBuffer[13]  = 0x4E;  packetBuffer[14]  = 49;  packetBuffer[15]  = 52;
это отправка 4-х букв INIR. что это такое? такого обозначения в стандарте нет. если уж так хочется что то написать серверу то пишите XXXX. эти символы зарезервированны для эксперементов.

Код:
packetBuffer[12]  = 'X';  packetBuffer[13]  = 'X';  packetBuffer[14]  = 'X';  packetBuffer[15]  = 'X';

вот это вообще адь и израиль
Код:
packetBuffer[2] = 6 /* Polling Interval */
по стандарту сюда оправляется число tau, а сам интервал в секундах рассчитывается так интервал=2^tau. на интервал также действуют ограничения мин 16сек и макс 131072сек. теперь возьмем мин интервал 16сек для него tau=4. у вас 6 это значит что интервал = 64сек но вы тут же объявлете

Код:
unsigned long periodNTP = 1800000; //time between NTP time-synchronizeunsigned long millisNTP = 0;
и серверу от этого зоопарка плохо. эта копипаста гуляет по инету очень давно, но никто почему то не интересовался за столько лет - а что же я отправляю.
 
Последнее редактирование:

gerkimuyda

New member
Функция ntpUnixTime не моя, но с моим роутером она работает нормально (у меня NTP обслуживает роутер) и без проблем. Но я ушел в своей задаче из ардуины в SDK.
Третий кусок - то мои две строки, но они слились (объявление переменных) при вставке в форум.

По поводу 1N14: UDP NTP Clients - 1N14 is a model of Nixie Tube use in some Nixie Clock projects.
 
Последнее редактирование:

enjoynering

Well-known member
то что вы ушли в SDK это здорово. я пока не нашел толкового описания как начать им пользоваться.
да второй вариант работает, но только потому, что сервера пока игнорируют этот ужос. ну или потому что Polling Interval не сильно нужен для client unicast/server unicast mode когда вы послали запрои и вам отвелили. а вот если активировать broadcast server/broadcast client когда клиент с сервером договаривается об интервале и потом клиент уже ничего не тправляет а только слушает в назначенное время то тут с настроиками 6-1800000 все копипастеры будут в пролете
 

Ewanse

New member
Вылетело сегодня утром. Роутер пока не перезагружал поэтому пока могу ловить ошибку.
Получается не всегда, так как в большинстве случаев mos зависает.
  1. Скопировал дамп в console.log,
  2. Склонировал проект с githab,
  3. Пробую выполнить make из документации, (использую windows и git bash) ничего не происходит - консоль ожидает ввода
Есть ли гдето туториал для тупиц где все разжевано?)
На всякий случай выкладываю весь консольный вывод с дампом:
 

Вложения

Ewanse

New member
Заметил что вылет происходит если к роутеру подключается восьмое устройство. Esp сразу вылетает, остальные устройства работают в штатном режиме.
 
Сверху Снизу