esp8266 / Arduino

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

while loop causes reset #3680

Closed Phil1988 closed 7 years ago

Phil1988 commented 7 years ago

Description

I lost 4 hours now on this problem by searching the given debug messages and solder/desolder, rewrite the code etc but it might have something to do with a while loop and the watchdog...

I am using a WeMos to control a DRV8825 and a stepper driver that is sitting on a rail. The next step for me is to do a calibration drive, where the distance of the rail is beeing measured. Because the the calibration should not beeing aborted by anything I want to use a while loop.

The problem is, that the while loop causes the WeMos to soft-reset. See my very simplified example sketch to get an idea of the problem.

I have had the messages: rst cause:2, boot mode:(3,6) rst cause:2, boot mode:(1,6) rst cause:4, boot mode:(1,6)

It's no power issue (measured with a good multimeter and a oscilloscope).

Hardware

Hardware: WeMos D1 mini Core Version: (I dont know)

Settings in IDE

Module: WeMos D1 R2 & mini Flash Size: 4M (3M SPIFFS) CPU Frequency: 80Mhz Upload Speed: 921600 Upload Using: SERIAL

Sketch

unsigned longcurrentTimeoutMillis = 0; 
unsigned long previousTimeoutMillis = 0;        
unsigned int timeout = 10000;          

// time variables for stepping to prevent blocking function ...
// ... of delay() during stepping for smoother movements and faster reaction
unsigned long currentMicros = 0;
unsigned long previousStepperMicros = 0;       

// time beween a HIGH and a LOW puls in µs 
// so this value * 2 is the time needed for one step)     
unsigned int stepSpeed = 50;       
bool stepPuls = 0;

long unsigned int stepCounter = 0;
float distance = 0;

void setup() 
{
  //inputs and outputs and all the setup stuff is here
}

void loop() 
{
  if (a_button_is_pushed)
  {
    calibrate();
  }
}

void calibrate()
{
  //set direction to drive left
  setDirectionLeft();

  //save actual time
  previousTimeoutMillis = millis();  

  //check if the motor is not left and the timout didnt run out
  while( !(sliderIsLeft()) && ((currentTimeoutMillis - previousTimeoutMillis) < timeout) )  
  {

//**** The program/motor stops here in the while loop after about 3 seconds ****//
//**** with the given debug message below ****//

    //save actual time for timeout
    currentTimeoutMillis = millis();  

    //save actual time for step-timing
    currentMicros = micros();  
    if (currentMicros - previousStepperMicros >= stepSpeed) 
    {
      // save the last time a HIGH/LOW puls was given out
      previousStepperMicros = currentMicros;

      if (stepPuls == 1)
      {
        stepPuls = 0;
      }
      else if (stepPuls == 0)
      {
        stepPuls = 1;

        //count the steps that was made
        stepCounter++;
      }
      digitalWrite(stepPin , stepPuls); 
    }  

  }
  else
  {
    Serial.print("The motor is left now and has made ");
    Serial.print(stepCounter);
    Serial.println(" steps.");
  }
}

Debug Messages

Soft WDT reset

ctx: cont 
sp: 3ffef260 end: 3ffef490 offset: 01b0

>>>stack>>>
3ffef410:  3ffee354 3ffee440 3ffee440 40202344  
3ffef420:  3ffe8510 3ffee440 3ffee34c 40201fde  
3ffef430:  3ffee364 00000000 3ffee440 40202320  
3ffef440:  3ffee358 3ffee440 00000000 3ffee350  
3ffef450:  3ffee358 00000000 3ffee45c 402020a1  
3ffef460:  00000000 00000000 00000001 3ffee464  
3ffef470:  3fffdad0 00000000 3ffee45c 402028e8  
3ffef480:  feefeffe feefeffe 3ffee470 40100114  
<<<stack<<<

 ets Jan  8 2013,rst cause:2, boot mode:(3,6)

load 0x4010f000, len 1384, room 16 
tail 8
chksum 0x2d
csum 0x2d
v09f0c112
Pablo2048 commented 7 years ago

Oh, come on. This has been described so many times in the forum. Do study ESP8266 watchdog (do some search for "soft WDT reset") and apply at least one yield() in right place. BTW this has nothing to do with Arduino ESP8266 Core and is off-topic here :-(

Phil1988 commented 7 years ago

Hello @Pablo2048 and thanks to you quick response. I found a lot of ideas that caused this problem (like power issue or use wdt_disable(); and wdt_enable();)

So can I just simply use the yield() -function every while loop to make it work? Will this cause a performance issue (i dont know how long the yield() needs)? Would it also work to disable the watchdog timer as long as the loop runs and start it afterwards?

I am completely new to ESP8266 so what would be the best (in view of performance) solution and what is the watchdog doing? (so what will not work if I stop the watchdog during the while loop?)

Thanks in advance and sorry that I cant find the solution/workaround in the forum.

Pablo2048 commented 7 years ago

Ok, where You did the search for this and how exactly does Your question look like that forum/google search engine did not find any related info? ( https://github.com/esp8266/Arduino/issues/2866 , https://forum.arduino.cc/index.php?topic=442570.0 , https://stackoverflow.com/questions/44100043/nodemcu-wdt-reset ) At least You have to readthedoc http://arduino-esp8266.readthedocs.io/en/latest/reference.html?highlight=yield#timing-and-delays ...

devyte commented 7 years ago

@Phil1988 your functions can't take too much time to execute without going back, because the wifi stack must be serviced. If you don't service it, you get mem corruption and blowups. There is a hardware wdt and a software wdt in place to assure you don't do this. This is not the right place to ask for help, this is an issue tracker for the core. Closing as off-topic, see #3655 .

klein0r commented 6 years ago

Thanks to all. Just added a delay(0); in my while loop. This stopped the endless software reset party 😄 Pretty strange...

Spudlicious commented 6 years ago

Your delay(0) tip has rescued an old man, thanks! My tombstone would have the inscription "WDT broke his heart", except that I'm planning to be cremated.

friesandacoke commented 6 years ago

Thank for posting your solution. Despite the snarky responses, there isn't a simple to find quick fix like your delay(0); suggestion. Cheers!

LucasEtchezuri commented 6 years ago

Hi, delay(0) consume time too !! a better solution is... some like this...

if ((millis() - tiempo) > 1000) { delay(0); tiempo = millis(); }

then... you execute delay(0) only 1 time per second !!

delay(0) takes more time that the entire while !!