esp8266 / Arduino

ESP8266 core for Arduino
GNU Lesser General Public License v2.1
15.97k stars 13.34k forks source link

calling begin() on Wiznet5500lwIP driver without hardware being connected crashes #8498

Open infrafast opened 2 years ago

infrafast commented 2 years ago

Basic Infos

Platform

Settings in IDE

Problem Description

I use the Wiznet5500lwIP driver to drive a W5500 chip. The host ESP can use either wifi or ethernet. Therefore the chip is only powered if a physical switch is set on the board to allow saving energy if user choose wifi The problem is that when callig begin() of the driver, it crashes (see dump) if the W5500 is not powered up.

MCVE Sketch


#include <Arduino.h>

Wiznet5500lwIP ethDriver(D2);   

    cableLink = ethDriver.begin(mac);    
    if (cableLink) {
      ESP.wdtDisable();
      loopElapsedTime = millis();
      while (!ethDriver.connected() && (millis() - loopElapsedTime < ETHCONNECTTIMEOUT)) ;
      ESP.wdtEnable(1000);
    } 

    if (!ethDriver.connected()) {
      cableLink = false;
      ethDriver.end();      
      WiFi.mode(WIFI_STA);
      if (!connectWiFi()){        
        stopWifi();             
        WiFi.mode(WIFI_AP_STA);                  
        WiFi.softAP(conf.getValue(MODCONFAPNAME), "", random(12) + 1, false, 1);            
      } 
    }

Debug Messages

Soft WDT reset

stack>>>

0x4023678e in Wiznet5500::wizchip_spi_write_byte(unsigned char) at lib\lwIP_w5500\src\utility/w5500.h:203 (inlined by) Wiznet5500::wizchip_read(unsigned char, unsigned short) at lib\lwIP_w5500\src\utility/w5500.cpp:47 0x402369cc in Wiznet5500::setSn_CR(unsigned char) at lib\lwIP_w5500\src\utility/w5500.cpp:126 0x40236cef in Wiznet5500::getSn_SR() at lib\lwIP_w5500\src\utility/w5500.h:687 (inlined by) Wiznet5500::begin(unsigned char const) at lib\lwIP_w5500\src\utility/w5500.cpp:366 0x4020ef8f in LwipIntfDev::begin(unsigned char const, unsigned short) at C:\Users\progman.platformio\packages\framework-arduinoespressif8266\cores\esp8266/LwipIntfDev.h:169 0x4023a8e8 in String::changeBuffer(unsigned int) at C:\Users\progman.platformio\packages\framework-arduinoespressif8266\cores\esp8266/WString.cpp:202 0x4023c53c in esp_yield at C:\Users\progman.platformio\packages\framework-arduinoespressif8266\cores\esp8266/core_esp8266_main.cpp:123 0x4023cee1 in delay at C:\Users\progman.platformio\packages\framework-arduinoespressif8266\cores\esp8266/core_esp8266_wiring.cpp:57 0x4022fab8 in std::enable_if<std::_and<std::not_<std::is_tuple_like >, std::is_move_constructible, std::is_move_assignable >::value, void>::type std::swap(std::_Any_data&, std::_Any_data&) at c:\users\progman.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/move.h:197 (inlined by) std::function<bool (PingerResponse const&)>::swap(std::function<bool (PingerResponse const&)>&) at c:\users\progman.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/std_function.h:483 (inlined by) std::function<bool (PingerResponse const&)>::operator=(std::function<bool (PingerResponse const&)> const&) at c:\users\progman.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/std_function.h:398 (inlined by) Pinger::OnReceive(std::function<bool (PingerResponse const&)>) at .pio\libdeps\debug_version\ESP8266-ping\src/Pinger.cpp:71 0x402212d7 in setup at src/main.cpp:4982 0x40250524 in std::_Function_handler<bool (PingerResponse const&), setup::{lambda(PingerResponse const&)#1}>::_M_manager(std::_Any_data&, std::_Function_handler<bool (PingerResponse const&), setup::{lambda(PingerResponse const&)#1}> const&, std::_Manager_operation) at c:\users\progman.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/std_function.h:271 0x402080e0 in std::_Function_handler<bool (PingerResponse const&), setup::{lambda(PingerResponse const&)#1}>::_M_invoke(std::_Any_data const&, PingerResponse const&) at src/main.cpp:4964 (inlined by) invoke_impl<bool, setup()::<lambda(const PingerResponse&)>&, const PingerResponse&> at c:\users\progman.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/invoke.h:60 (inlined by) __invoke_r<bool, setup()::<lambda(const PingerResponse&)>&, const PingerResponse&> at c:\users\progman.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/invoke.h:113 (inlined by) _M_invoke at c:\users\progman.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\include\c++\10.3.0\bits/std_function.h:291 0x4023c61b in loop_wrapper() at C:\Users\progman.platformio\packages\framework-arduinoespressif8266\cores\esp8266/core_esp8266_main.cpp:198 0x4010059d in cont_wrapper at C:\Users\progman.platformio\packages\framework-arduinoespressif8266\cores\esp8266/cont.S:81

infrafast commented 2 years ago

The outcome of my first investigation is the following: the call to setSn_CR enter a while loop which never ends and trigger the watchdog

void Wiznet5500::setSn_CR(uint8_t cr) { // Write the command to the Command Register wizchip_write(BlockSelectSReg, Sn_CR, cr);

// Now wait for the command to complete 
 while (wizchip_read(BlockSelectSReg, Sn_CR));

}

it should include a timeout:

void Wiznet5500::setSn_CR(uint8_t cr) { // Write the command to the Command Register wizchip_write(BlockSelectSReg, Sn_CR, cr);

// Now wait for the command to complete 5**0ms timeout (should be enough)
long loopElapsedTime = millis();**
while (wizchip_read(BlockSelectSReg, Sn_CR) **&& (millis() - loopElapsedTime < 50)**);

}

equally, we have a while loop in the end function call to which I have added a timeout check

void Wiznet5500::end() { setSn_CR(Sn_CR_CLOSE);

// clear all interrupt of the socket
setSn_IR(0xFF);

// Wait for socket to change to closed with 500ms timeout
**long loopElapsedTime = millis();**
while (getSn_SR() != SOCK_CLOSED **&& (millis() - loopElapsedTime < 500)**);

...

I am not sure the implementation fits the current code rules & practices but at least, this solve the issue