ESP8266 locking up?

I have set up a current transformer sensor to see if dust filters are running in our wood-working workshop.
It is fairly simple code which I am happy to share if we need to move past my conceptual question.
The sketch reads the CT multiple times to compute an RMS average and then send it through WiFi to a Server.
The Delay() statement is used a lot within the voltage-measuring loop and - after that, in another loop - to limit reads to about one per minute.
It all works perfectly for as much as 100’s of cycles and then the connection just seems to freeze. When it restarts, it often has several more failures before it returns to normal. (The VB running on the PC, sends an ACK message when it receives a reading. If the PC doesn’t receive a reading when it expects one or if the Arduino doesn’t receive an ACK, each restarts)

I keep reading references to ESP2866 being influenced badly by over use of Delay() but don’t seem to be able find a definitive statement about what constitutes a problem and how to deal with it.

Any input on this subject would be welcome.

3 Likes

Hi Brian,

Welcome to the forums :slight_smile:

Hmm, interesting. I found this post which describes a similar problem, but not a solution. Resolving this might require some deep dives into the inner workings of the ESP8266 libraries.

However, this post might give some clues:

It suggests the watchdog timer on the ESP8266 is on by default - if your code times out the WDT, that could be causing the reset.

3 Likes

Hi Brian
The problem with Delay() is that whilst it is running the delay code it will not do anything else. So other components like WiFi and watchdog do not get serviced.
You need to use one of the many ways (as always) to count time for your measuring task whilst still servicing these other code components.
Arduino tend to use Millis() a millisecond counter and and you check the difference to see if the time is up to run your loop. I find this a bit clunky.
I prefer to use the arduino-timer library - the following is the basic blink example sketch using the library without delay

/*

 * timer_blink

 *

 * Blinks the built-in LED every second using the arduino-timer library.

 *

 */

#include <arduino-timer.h>

auto timer = timer_create_default(); // create a timer with default settings

bool toggle_led(void *) {

  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); // toggle the LED

  return true; // repeat? true

}

void setup() {

  pinMode(LED_BUILTIN, OUTPUT); // set LED pin to OUTPUT

  // call the toggle_led function every 1000 millis (1 second)

  timer.every(1000, toggle_led);

}

void loop() {

  timer.tick(); // tick the timer

}

Is that enough to get you going?

Regards
Mick

4 Likes

Thanks Oliver and Mick.
I will come back and learn some more about this stuff - particularly, Mick’s code using
<arduino-timer.h>.
In the mean time, after reading a lot of material on the web, I concluded - much as Mick mentioned - that the underlying logic in the ESP8266 can not service the needs of other components when the Arduino sketch part of its group of components is in Delay() mode.
It looks a bit clunky but any time I want to wait for a condition to be met, I use a loop that looks like this:

    Serial.println( F( "Pause to allow TCP listener time to restart" ) );
    NextReadTime = millis() + 15000;
    while ( millis() < NextReadTime )
      {
      iJunk += 1;
      delay(1);
      iJunk -= 1;
      }

or

    // Load 1000 readings into array
    while ( iNrReadings < 1000 )
      {

      if ( millis() >= NextReading )
        {
        A0ReadValue[iNrReadings] = analogRead(A0);
        iNrReadings += 1;
        NextReading = millis() + 1;
        }

        iJunk += 1; 
        iJunk -= 1;

      }

It seems to me that by calling simple calculation activities (which take microseconds) in each cycle of the loop, control returns to the internal logic within the ESP8266 to allow it to service the needs of other components.
I have made changes of this sort to both of my projects which log results to a server through WiFi. Dust level values are gathered from a Dylos monitor using an UNO Wifi Rev 2 and current transformer values which show whether a dust filter is running (and at what speed) using a WEMOS D1 R1. Both send data once a minute. Previously the WEMOS failed continually. Sometimes it got in a reasonable number of readings but - on average probably failed for about three cycles after 10 to 20 successes. The UNO was much more consistent but still had occasional read failures, and - when it did - it would have multiple fails over about an hour.
Since making these changes, both have logged a reading a minute without failures for several days now.

5 Likes

@Brian. Once coding and power issues are sorted I find the ESP8266 are superbly reliable.

I have moisture monitors sending data to Arduino IOT cloud every 10 seconds and it has been running uninterrupted for several months.

I see many posts suggesting unreliable behaviour is due to poor power supply. I suspect that this is generally not the case. I run many devices on simple USB 500ma supplies without problems.

Let us know how you go. Sounds like an interesting project.

Regards
Mick

3 Likes

Thanks Mick.
I am also asking questions on the Arduino forum so forgive me if I seem greedy!

I am still struggling with the syntax. I need two timers. One to send a reading every minute and one to read 1000 values from A0 every millisecond for a second from which to calculate an RMS value.

Do I have to include the declaration

auto timer = timer_create_default();

… to create an instance of the timer that is called “timer” by default (in which case I don’t know how to declare the second) or could I say

auto OutputTimer = timer_create_default();

… to create a timer called “OutputTimer” as well as another one called (say) “ReadTimer”. The former calling a read-calculate-send sequence of events once every minute and - within that logic - the latter being used to load an array of 1000 readings from A0 to calculate the RMS value to send.

3 Likes

Hi Brian
If the important point is to calculate the RMS every second of the the collected values then you could set up a second timer (regardless of the number of samples). You should be able to do it as suggested.
If the count of 1000 readings is important, I’d call the calculation as soon as the 1000th is collected.

3 Likes

Hi @Brian169848.
Sorry I missed your question here.
One declaration of timer will give you up to 16 tasks with the default you define the tasks with timer.every

  // call the toggle_led function every 500 millis (half second)
  timer.every(500, toggle_led);

  // call the print_message function every 1000 millis (1 second)
  timer.every(1000, print_message);

This is from the timer example timer_blink_print

3 Likes