Esp8266 Ошибка исключения WiFi Arduino 29

Общие сведения: я ничего не знаю об оборудовании.

Я пишу небольшой проект с Arduino IDE, библиотекой ESP8266, и моя плата ESP8266 V3 ESP-12N F NodeMcu Lua CP2102 .

Теперь я получаю Exception 29 и не знаю почему.

Код скетча и сервера (написан на Python) ссылка на github (я также разместил клиент и код сервера внизу)


Module: [NodeMCU 1.0 (ESP-12E Module)]
Flash Size: [4MB]
lwip Variant: [v2 Lower Memory]
Flash Frequency: [40Mhz]
CPU Frequency: [80Mhz]
Upload Using: [SERIAL]
Upload Speed: [115200] 

Дамп стека:

Exception 29: StoreProhibited: A store referenced a page mapped with an attribute that does not permit stores
PC: 0x4000e1c3
EXCVADDR: 0x00000018

Decoding stack results
0x40100908: malloc(size_t) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\umm_malloc\umm_malloc.cpp line 511
0x40100b6e: calloc(size_t, size_t) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\umm_malloc\umm_malloc.cpp line 826
0x40100b60: calloc(size_t, size_t) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\umm_malloc\umm_malloc.cpp line 820
0x4020318b: loop_task(ETSEvent*) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\core_esp8266_main.cpp line 188
0x40100154: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\core_esp8266_main.cpp line 160
0x40100154: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\core_esp8266_main.cpp line 160
0x40100154: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\core_esp8266_main.cpp line 160
0x40100154: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\core_esp8266_main.cpp line 160
0x40100154: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\core_esp8266_main.cpp line 160
0x40100154: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\core_esp8266_main.cpp line 160
0x40100154: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\core_esp8266_main.cpp line 160
0x40100154: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\core_esp8266_main.cpp line 160
0x40100154: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\core_esp8266_main.cpp line 160
0x40100154: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\core_esp8266_main.cpp line 160
0x402109ff: tcp_output at core/tcp_out.c line 1259
0x4020216a: ClientContext::wait_until_sent(int) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\libraries\ESP8266WiFi\src/include/ClientContext.h line 331
0x40100908: malloc(size_t) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\umm_malloc\umm_malloc.cpp line 511
0x402151c0: mem_malloc at core/mem.c line 210
0x4020f104: pbuf_alloc_LWIP2 at core/pbuf.c line 284
0x40214732: ip4_output_if at core/ipv4/ip4.c line 1550
0x4020fe90: tcp_write at core/tcp_out.c line 263
0x402031dc: __esp_yield() at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\core_esp8266_main.cpp line 100
0x4020378e: __delay(unsigned long) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\core_esp8266_wiring.cpp line 54
0x4020230f: ClientContext::_write_from_source(DataSource*) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\libraries\ESP8266WiFi\src/include/ClientContext.h line 464
0x4020239d: WiFiClient::write(unsigned char const*, unsigned int) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\libraries\ESP8266WiFi\src/include/ClientContext.h line 364
0x40204c30: WiFiClient::write(unsigned char) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\libraries\ESP8266WiFi\src\WiFiClient.cpp line 217
0x40201bc4: DataSource::~DataSource() at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\libraries\ESP8266WiFi\src/include/DataSource.h line 12
0x402026c9: WiFiClient::flush(unsigned int) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\libraries\ESP8266WiFi\src\WiFiClient.cpp line 318
0x40201113: loop() at C:\Users\ptq00\Documents\Arduino\sketch_jan03b/sketch_jan03b.ino line 44
0x40100154: ets_post(uint8, ETSSignal, ETSParam) at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\core_esp8266_main.cpp line 160
0x402032f4: loop_wrapper() at C:\Users\ptq00\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\core_esp8266_main.cpp line 180

Код скетча (клиента):

#include <ESP8266WiFi.h>

const char ssid[] = "luminous";
const char pass[] = "zxcv78()[]";

// Mac IP 192.168.1.101
// IP-адрес ПК 192.168.1.103

IPAddress server(192,168,0,103);
int port = 12700;

WiFiClient client;

void setup() {
  // поместите сюда код установки для однократного запуска:

  Serial.begin(115200);
  Serial.println("");

  WiFi.begin(ssid, pass);
  delay(500);
  while(WiFi.status() != WL_CONNECTED){
    delay(500);
    Serial.print(".../");  
  }

  Serial.println("");
  // WiFi подключен

  if(client.connect(server, port)){
    Serial.println("connected to server");
  }

}

// 3-секундный тайм-аут чтения клиента. Я установил это значение случайно. Сервер имеет тайм-аут 5 с при чтении данных от клиента.
const unsigned long clientTimeout = 3000; 

void loop() {
  // поместите сюда ваш основной код для повторного запуска:

  if(client.connected()){
    client.write(WiFi.RSSI());
    delay(100); // Добавляем зря. Не уверен, что это полезно
    unsigned long timeout = millis();
    //Тайм-аут клиента, если клиент не может связаться с сервером, он должен начать переподключение к серверу
    while(client.available() == 0){
      if (millis() - timeout >= clientTimeout){
        Serial.println(">>> Client Timetout !");
        client.stop();
        break;
      }
    }
    //Клиент подключен и имеет данные для чтения
    //отбрасываем все данные
    client.flush();
  }else{
    //Попробуем переподключиться к серверу
    client.connect(server,port);
    delay(500); // Добавляем зря. Не уверен, что это полезно
    while(!client.connected()){
       // не удалось переподключиться
       Serial.println("Failed to reconnect...");
       delay(500);
       client.connect(server,port);
    }
    //успешное переподключение
    Serial.println("Succeeded reconnecting..");
  }
}

Код сервера:

import socket


HOST = '0.0.0.0'
PORT = 12700

catSafeZone = False
serverTimeout = 3

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1);
    s.bind((HOST, PORT))
    s.listen()
    print("Start listening")
    print("Device is not conncted")

    while True:
        conn, addr = s.accept()
        try:
            with conn:
                print("Connected by", addr)
                print("Cat is online")
                conn.settimeout(serverTimeout)

                # client won't try to disconnect on its own.
                # So we only need to capture connection timeout exception
                while True:
                    data = conn.recv(128)
                    if data:
                        if catSafeZone == False:
                            catSafeZone = True
                            print("Cat is in safe zone.")
                        conn.send(b'1')
                    else:
                        print("Unexpected condition")
                        print("Client disconnected on its own.")
                        raise Exception("server data NULL")

                    # Code that is used for wifi signal strength detection:
                    #
                    # if not data:
                    #     break
                    # wifiStrength = int.from_bytes(data, byteorder='big', signed=True)
                    # print(wifiStrength)

        except socket.timeout:
            print("!!!Cat is out of safe zone")
            # Warn user in some ways
            catSafeArea = False



# never reach here
print("Server shutdown")

, 👍0

Обсуждение

Во-первых: если вы еще этого не сделали; пожалуйста, измените свой пароль AP, так как вы включили его в код. Ваши соседи все друзья? ;-) Похоже, что MCU пытается хранить данные на странице, где это не разрешено. Но признаюсь, я не вижу в коде ничего, что могло бы вызвать такое поведение. Это происходит каждый раз, когда вы запускаете код, или это состояние гонки? Из трассировки стека кажется, что стек используется несколькими потоками или процедурами прерывания. Возможно, два доступа к распределению мешают друг другу. Поскольку LUA активен, это также может мешать вашему коду. Просто догадки., @Peter Paul Kiefer

Ах, подождите, я кое-что видел: я добавляю ответ, потому что использую код для объяснения., @Peter Paul Kiefer


2 ответа


Лучший ответ:

2

Я исправил проблему. Оказалось, что функция flush в библиотеке Arduino WiFi имеет совершенно другое значение, чем то, что определено в библиотеке ESP8266WiFi.

От https://arduino-esp8266.readthedocs.io/en/latest/ esp8266wifi/client-class.html:

flush(), возвращающий true, указывает, что выходные данные фактически отправлено, а false — тайм-аут.

Это больше похоже на буфер flush stdout в типичной программе C.

Затем я заменил client.flush() на:

 while(client.connected() && client.available() > 0){
    client.read();
  }

И тогда все работает хорошо.


И я использую ваш код с небольшой модификацией.

#include <ESP8266WiFi.h>

const char ssid[] = "luminous";
const char pass[] = "xxxxxxxx";

IPAddress server(192,168,0,101);
int port = 12700;

WiFiClient client;

void setup() {
  // put your setup code here, to run once:

  Serial.begin(115200);
  Serial.println("");

  WiFi.begin(ssid, pass);
  delay(500);
  while(WiFi.status() != WL_CONNECTED){
    delay(500);
    Serial.print(".../");  
  }

  Serial.println("");
  //WiFi is connected

  if(client.connect(server, port)){
    Serial.println("connected to server");
  }else{
    Serial.println("Failed to connnect to server at setup().");
  }

}

int needToReconnect = 0;

void loop() {
  // put your main code here, to run repeatedly:
  while(!client.connected()){
       //failed to reconnect
       needToReconnect = 1;
       Serial.println("Failed to reconnect...");
       delay(500);
       client.connect(server,port);
  }

  // Use a flag to indicate if client was in reconnect procedure
  if(needToReconnect){
    Serial.println("Succeeded reconnecting...");
    needToReconnect = 0;
  }

  client.write(WiFi.RSSI());
  delay(100); // Add for nothing. Not sure if it's useful

  while(client.connected() && client.available() > 0){
    client.read();
  }

}
,

2

В вашем коде есть возможность остановить клиент, а затем сбросить его. Это может привести к наблюдаемой ошибке.

// Время ожидания клиента, если клиент не может связаться с сервером,
// он должен начать переподключение к серверу
while(client.available() == 0)
{
  if (millis() - timeout >= clientTimeout)
  {
    Serial.println(">>> Client Timetout !");
    client.stop(); // <----- ВОТ СТОП!!!!!!
    break;
  }
}
//Клиент подключен и имеет данные для чтения
//отбрасываем все данные
client.flush(); <-- Then a flush on a stopped client !!!!!

У меня нет возможности попробовать следующий код, поэтому используйте его как пример того, что я предлагаю вам попробовать. Внимание: я затенил последний номер IP, SSID и пароль.

#include <ESP8266WiFi.h>

const char ssid[] = "XXXXXXXXXXXXXXX";
const char pass[] = "XXXXXXXXXXXXXXX";

IPAddress server(192,168,0,XXX);
int port = 12700;

WiFiClient client;

void setup() 
{
  Serial.begin(115200);

  WiFi.begin(ssid, pass);
  delay(500);
  while(WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".../");  
  }

  // Новая строка после .../.../...
  Serial.println("");

  if( client.connect(server, port) )
  {
    Serial.println("connected to server");
  }

}

// 3-секундный тайм-аут чтения клиента. Я установил это значение случайно.
// Сервер имеет тайм-аут 5 с при чтении данных от клиента.
const unsigned long clientTimeout = 3000; 

void loop() 
{
  while( ! client.connected() )
  {
     // не удалось переподключиться
     Serial.println("Failed to reconnect...");
     client.connect(server,port);
     delay(500);
  }      

  client.write(WiFi.RSSI());

  // Добавляем зря. Не уверен, что это полезно
  // ППК: Я тоже ;-)
  delay(100); 

  unsigned long timemark = millis();
  // Тайм-аут клиента, если клиент не может связаться с сервером,
  // он должен начать переподключение к серверу
  while( client.available() == 0 )
  {
    if (millis() - timemark >= clientTimeout)
    {
      Serial.println(">>> Client timed out !");
      client.stop();
      break;
    }
  }

  if ( client.connected() && client.available() > 0 )
  {
    // удаляем байты в буфере чтения
    client.flush();  
  }   
}
,

Я все еще получаю ошибку Exception 29 с вашим кодом, @Rick

Спасибо @Питер. Я исправил проблему, проверив документацию 8266 и исходный файл, показанный в дампе стека. И я использую ваш код, который лучше моего. :п, @Rick

Ой. Я также удаляю всю процедуру тайм-аута клиента, которая, как мне кажется, while(client.connected()) уже выполнила свою работу., @Rick

@Rick Добро пожаловать. Как я уже сказал, я не мог попробовать код, у меня была только идея ;-). Я ценю ваш ответ. Признаюсь, я не понял, что вы должны использовать чтение вместо флеша. Так что я узнал немного больше, спасибо. Я надеюсь, что вы проверите свой ответ как принятый, когда это будет возможно., @Peter Paul Kiefer