Skip to content

delayMicroseconds() - crash #2240

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Gorkde opened this issue Jul 6, 2016 · 14 comments
Closed

delayMicroseconds() - crash #2240

Gorkde opened this issue Jul 6, 2016 · 14 comments

Comments

@Gorkde
Copy link

Gorkde commented Jul 6, 2016

ESP12F

I'm working on a PWM Routine (not finished still in progress) which did crash for some reason (code#1).

unbenannt

Then I assumed it's too fast so I added delay(1) in the loop and no crash occured anymore (code#2).

Then I thought to make the delay smaller so I changed delay(1) to delayMicroseconds(100) and it did crash again.

So I changed delayMicroseconds(100) to delayMicroseconds(1000) which should be the same as delay(1) which didnt crash. But it does crash again with that! (code#3).

Code 1:

#include <ShiftRegister74HC595.h>

ShiftRegister74HC595 ShiftRegOut (1, 2, 4, 5); // Schieberegister Objekt erstellen (Anz. Register, Datenpin, Schiebetaktpin, Speichertaktpin (latch-pin)

void setup()
{
  Serial.begin(115200);
  ShiftRegOut.setAllLow();
}

void loop()
{
  FadeOutput(2, 0, 255, 4.16);
  delay(500);
  /*  FadeOutput(2, 255, 0, 1);
    delay(500);*/
}

int FadeOutput(int Pin, int StartWert, int EndWert, float Zeit)                                                 // Bei Fade 0-255 max. 4.195 Sek möglich
{
  if (StartWert < 0 || StartWert > 255 || EndWert < 0 || EndWert > 255 || StartWert == EndWert || Zeit > 4.195)  // Bei falscher Parameterübergabe Fehler zurückmelden
  {
    return (-1);
    Serial.print("ERROR!");
  }

  if (StartWert < EndWert)
  {
    long MillisZeit = millis();

    float Freq = (EndWert - StartWert) / Zeit;
    long Zyklus = 1000000 / Freq;

    Serial.print("Freq: ");
    Serial.println(Freq);
    Serial.print("Zykluslaenge[Microsecs]: ");
    Serial.println(Zyklus);

    for (int i = StartWert; i <= EndWert; i++)
    {
      PWMOutput(Pin, i, Freq);
      // NO DELAY HERE
    }

    MillisZeit = millis() - MillisZeit;
    Serial.print("Fade-Zeit[ms]: ");
    Serial.println(MillisZeit);
    Serial.print("\n");
  }
  /*
    else if (StartWert > EndWert)
    {
      for (int i = StartWert; i >= EndWert; i--)
      {
        PWMOutput(Pin, i, 300);
      }
    }
  */
}

void PWMOutput(int Pin, int PWM_Wert, float PWM_Freq)   // PWM_Wert 0-255 - Freq >61Hz sonst Probleme wegen max. Millis() Länge.
{
  long Zykluslaenge = 1000000 / PWM_Freq;
  float ProzentAN = PWM_Wert / 255.0;
  int AN_Zeit = ProzentAN * Zykluslaenge;
  int AUS_Zeit = Zykluslaenge - AN_Zeit;
  Serial.print("PWM_Freq ");
  Serial.println(PWM_Freq);
  Serial.print("PWM_Wert ");
  Serial.println(PWM_Wert);
  Serial.print("Zykluslaenge ");
  Serial.println(Zykluslaenge);
  Serial.print("ProzentAN ");
  Serial.println(ProzentAN);
  Serial.print("ON Time ");
  Serial.println(AN_Zeit);
  Serial.print("OFF Time ");
  Serial.println(AUS_Zeit);
  Serial.print("\n");

  if (AN_Zeit > 0)
  {
    ShiftRegOut.set(Pin, HIGH);
    delayMicroseconds(AN_Zeit);
  }
  ShiftRegOut.set(Pin, LOW);
  delayMicroseconds(AUS_Zeit);
}

Code 2:

#include <ShiftRegister74HC595.h>

ShiftRegister74HC595 ShiftRegOut (1, 2, 4, 5); // Schieberegister Objekt erstellen (Anz. Register, Datenpin, Schiebetaktpin, Speichertaktpin (latch-pin)

void setup()
{
  Serial.begin(115200);
  ShiftRegOut.setAllLow();
}

void loop()
{
  FadeOutput(2, 0, 255, 4.16);
  delay(500);
  /*  FadeOutput(2, 255, 0, 1);
    delay(500);*/
}

int FadeOutput(int Pin, int StartWert, int EndWert, float Zeit)                                                 // Bei Fade 0-255 max. 4.195 Sek möglich
{
  if (StartWert < 0 || StartWert > 255 || EndWert < 0 || EndWert > 255 || StartWert == EndWert || Zeit > 4.195)  // Bei falscher Parameterübergabe Fehler zurückmelden
  {
    return (-1);
    Serial.print("ERROR!");
  }

  if (StartWert < EndWert)
  {
    long MillisZeit = millis();

    float Freq = (EndWert - StartWert) / Zeit;
    long Zyklus = 1000000 / Freq;

    Serial.print("Freq: ");
    Serial.println(Freq);
    Serial.print("Zykluslaenge[Microsecs]: ");
    Serial.println(Zyklus);

    for (int i = StartWert; i <= EndWert; i++)
    {
      PWMOutput(Pin, i, Freq);
      delay(1);          // THIS DOESN'T CRASH FOR ME!
    }

    MillisZeit = millis() - MillisZeit;
    Serial.print("Fade-Zeit[ms]: ");
    Serial.println(MillisZeit);
    Serial.print("\n");
  }
  /*
    else if (StartWert > EndWert)
    {
      for (int i = StartWert; i >= EndWert; i--)
      {
        PWMOutput(Pin, i, 300);
      }
    }
  */
}

void PWMOutput(int Pin, int PWM_Wert, float PWM_Freq)   // PWM_Wert 0-255 - Freq >61Hz sonst Probleme wegen max. Millis() Länge.
{
  long Zykluslaenge = 1000000 / PWM_Freq;
  float ProzentAN = PWM_Wert / 255.0;
  int AN_Zeit = ProzentAN * Zykluslaenge;
  int AUS_Zeit = Zykluslaenge - AN_Zeit;
  Serial.print("PWM_Freq ");
  Serial.println(PWM_Freq);
  Serial.print("PWM_Wert ");
  Serial.println(PWM_Wert);
  Serial.print("Zykluslaenge ");
  Serial.println(Zykluslaenge);
  Serial.print("ProzentAN ");
  Serial.println(ProzentAN);
  Serial.print("ON Time ");
  Serial.println(AN_Zeit);
  Serial.print("OFF Time ");
  Serial.println(AUS_Zeit);
  Serial.print("\n");

  if (AN_Zeit > 0)
  {
    ShiftRegOut.set(Pin, HIGH);
    delayMicroseconds(AN_Zeit);
  }
  ShiftRegOut.set(Pin, LOW);
  delayMicroseconds(AUS_Zeit);
}

Code 3:

#include <ShiftRegister74HC595.h>

ShiftRegister74HC595 ShiftRegOut (1, 2, 4, 5); // Schieberegister Objekt erstellen (Anz. Register, Datenpin, Schiebetaktpin, Speichertaktpin (latch-pin)

void setup()
{
  Serial.begin(115200);
  ShiftRegOut.setAllLow();
}

void loop()
{
  FadeOutput(2, 0, 255, 4.16);
  delay(500);
  /*  FadeOutput(2, 255, 0, 1);
    delay(500);*/
}

int FadeOutput(int Pin, int StartWert, int EndWert, float Zeit)                                                 // Bei Fade 0-255 max. 4.195 Sek möglich
{
  if (StartWert < 0 || StartWert > 255 || EndWert < 0 || EndWert > 255 || StartWert == EndWert || Zeit > 4.195)  // Bei falscher Parameterübergabe Fehler zurückmelden
  {
    return (-1);
    Serial.print("ERROR!");
  }

  if (StartWert < EndWert)
  {
    long MillisZeit = millis();

    float Freq = (EndWert - StartWert) / Zeit;
    long Zyklus = 1000000 / Freq;

    Serial.print("Freq: ");
    Serial.println(Freq);
    Serial.print("Zykluslaenge[Microsecs]: ");
    Serial.println(Zyklus);

    for (int i = StartWert; i <= EndWert; i++)
    {
      PWMOutput(Pin, i, Freq);
      delayMicroseconds(1000);          // THIS DOES CRASH TOO!
    }

    MillisZeit = millis() - MillisZeit;
    Serial.print("Fade-Zeit[ms]: ");
    Serial.println(MillisZeit);
    Serial.print("\n");
  }
  /*
    else if (StartWert > EndWert)
    {
      for (int i = StartWert; i >= EndWert; i--)
      {
        PWMOutput(Pin, i, 300);
      }
    }
  */
}

void PWMOutput(int Pin, int PWM_Wert, float PWM_Freq)   // PWM_Wert 0-255 - Freq >61Hz sonst Probleme wegen max. Millis() Länge.
{
  long Zykluslaenge = 1000000 / PWM_Freq;
  float ProzentAN = PWM_Wert / 255.0;
  int AN_Zeit = ProzentAN * Zykluslaenge;
  int AUS_Zeit = Zykluslaenge - AN_Zeit;
  Serial.print("PWM_Freq ");
  Serial.println(PWM_Freq);
  Serial.print("PWM_Wert ");
  Serial.println(PWM_Wert);
  Serial.print("Zykluslaenge ");
  Serial.println(Zykluslaenge);
  Serial.print("ProzentAN ");
  Serial.println(ProzentAN);
  Serial.print("ON Time ");
  Serial.println(AN_Zeit);
  Serial.print("OFF Time ");
  Serial.println(AUS_Zeit);
  Serial.print("\n");

  if (AN_Zeit > 0)
  {
    ShiftRegOut.set(Pin, HIGH);
    delayMicroseconds(AN_Zeit);
  }
  ShiftRegOut.set(Pin, LOW);
  delayMicroseconds(AUS_Zeit);
}
@me-no-dev
Copy link
Collaborator

reason is that your whole routine is fully blocking for the cpu and it takes more than the watch dog permits (thus triggering soft wdt reset). The reason why it does not crash when you add delay() is that delay() actually switches the context back to the system while you are delaying and feeding the watchdog this way.

@Gorkde
Copy link
Author

Gorkde commented Jul 6, 2016

Yes but why is it working with delay(1) and not with delayMicroseconds(1000) ???

There must be something up right?

Will change it lateron anyway to work without delay but just discovered the problem while testing.

@me-no-dev
Copy link
Collaborator

and I just explained it to you. delay(1) will let the system run for 1ms. delayMicroseconds(1000) will halt for 1ms and not give the system a chance to do it's thing.

@Gorkde
Copy link
Author

Gorkde commented Jul 6, 2016

Ok, I assumed delayMicroseconds(1000) would do the same. So it doesn't?

@me-no-dev
Copy link
Collaborator

no it does not. The ESP as opposed to AVR Arduinos (and others) has WiFi and full network stack running in the background that needs to process the network often. When you delayMicroseconds you actually prevent that from happening and the longer you the, more the chance to soft wdt becomes. delay() on the other hand, returns power to the system and checks on return if the time for returning to your code has come and if not, gives power to the system again.
sort of

void delayMicroseconds(uint32_t us){
  uint32_t start = micros();
  while(micros() - start < us){}
}

vod delay(uint32_t ms){
  uint32_t start = millis();
  while(millis() - start < ms){
    yield();//give the system a chance to execute
  }
}

@Gorkde
Copy link
Author

Gorkde commented Jul 6, 2016

Thanks! Didn't know that.

@Gorkde Gorkde closed this as completed Jul 6, 2016
@Gorkde
Copy link
Author

Gorkde commented Jul 6, 2016

Hmmmm...

Changed the PWM Routine now so it has no delay and removed the delay above but it crashes at the same point as it did before I added delay(1).

It always crashes at "PWM_Wert 194" once don't add delay(1) in the counting loop.

  if (AN_Zeit > 0)
  {
    unsigned long StartzeitAN = micros();
    ShiftRegOut.set(Pin, HIGH);
    while (micros() - StartzeitAN < AN_Zeit);
  }
  unsigned long StartzeitAUS = micros();
  ShiftRegOut.set(Pin, LOW);
  while (micros() - StartzeitAUS < AUS_Zeit);
}

@Gorkde Gorkde reopened this Jul 6, 2016
@me-no-dev
Copy link
Collaborator

but it MUST have delay! else your routine takes too long and you crash the system

@me-no-dev
Copy link
Collaborator

or at least optimistic_yield(10000); or just yield();

@pieman64
Copy link

pieman64 commented Jul 6, 2016

@Gorkde I believe what @me-no-dev stated was that delay(1) MUST be used as your routine "takes too long to run" but that you can't substitute delayMicroseconds(1000) for delay(1) i.e. delay(1) is a very specific function.

@Gorkde
Copy link
Author

Gorkde commented Jul 6, 2016

Ok, thanks, will include yield then!

@Gorkde Gorkde closed this as completed Jul 6, 2016
@Gorkde
Copy link
Author

Gorkde commented Jul 6, 2016

One last question:

How often do I need to add delay(1) or yield() ?
What time could my loop take before I risk the ESP resetting?

And... is delay(1) enough or does it need to be a larger time?

@Gorkde Gorkde reopened this Jul 6, 2016
@me-no-dev
Copy link
Collaborator

even delay(0) will work. Should be as often as you can spare, but not more than 100ms let's say

@Gorkde
Copy link
Author

Gorkde commented Jul 6, 2016

Ok, thanks, got 38ms at the moment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants