Watchdog (mis)usage

hello

I am having issues with Arduino wifi Rev2 when enabling wifi, the system becomes very unstable and hangs from time to time. It is hard to predict when, sometimes after few minutes sometimes after hours, but I need a way to reset the MCU as it is controlling my aquarium (lights, co2, etc).

I configured a watchdog and noticed that the controller is reset very often, at least 3/4 times per hour, sometimes even more...can this be considered normal?

here the updated code

#include "arduino_secrets.h"
#include <Wire.h>     // enable I2C.
#include <RCSwitch.h> // enable RF transmission.
#include "rgb_lcd.h"  // enable LCD.
#include <avr/wdt.h>
#include <SPI.h>
#include <Time.h>
#include "RTClib.h"
#include "DHT.h"         // enable DHT Temperature sensor.
#include <WiFiNINA.h>    // change to #include <WiFi101.h> for MKR1000
#define LED 3 //connect LED to digital pin2
#define TOTAL_CIRCUITS 3 // <-- CHANGE THIS | set how many I2C circuits are attached to the Tentacle
#define DHTPIN A0        // what pin we're connected to
#define DHTTYPE DHT11    // DHT 11
#define WDTO_8S   9      // watchdog
DHT dht(DHTPIN, DHTTYPE);
RTC_DS1307 rtc;

// Enter your sensitive data in arduino_secrets.h
const char ssid[] = SECRET_SSID;
const char pass[] = SECRET_PASS;

// Network / Wifi settings
int status = WL_IDLE_STATUS;
WiFiClient client;

// Influx code
byte host[] = {192, 168, 1, 120};
int port = 8086;
char buff[256];

// Atlas code
char sensordata[30];                  // A 30 byte character array to hold incoming data from the sensors
byte sensor_bytes_received = 0;       // We need to know how many characters bytes have been received
byte code = 0;                        // used to hold the I2C response code.
byte in_char = 0;                     // used as a 1 byte buffer to store in bound bytes from the I2C Circuit.
int channel_ids[] = {100, 101, 102};          // <-- CHANGE THIS. A list of I2C ids that you set your circuits to.
char *channel_names[] = {"PH", "EC", "Temp"}; // <-- CHANGE THIS. A list of channel names (must be the same order as in channel_ids[]) - only used to designate the readings in serial communications

// variables & stuff
float pH, temp, ec, t, h;
rgb_lcd lcd;
const int colorR = 0;
const int colorG = 100;
const int colorB = 255;
String data;
int lights, ph_status;
int wdt_reset = 0;

// RF code
RCSwitch mySwitch = RCSwitch();

void setup()
{
  Serial.begin(9600); // Set the hardware serial port.
  Wire.begin();       // enable I2C port.

  // RF init
  mySwitch.enableTransmit(2);
  mySwitch.setPulseLength(166);
  mySwitch.setRepeatTransmit(4);

  // LCD init
  lcd.display();
  lcd.begin(16, 2);

  // Temp sensor init
  dht.begin();

  // initialize rtc
  rtc.begin();

  //connect to wifi
  wifiConnect();

  // Setup watchdog
  Serial.println("Starting watchdog");
  watchdogSetup();

}

void loop()
{
  // reset watchdog
  Serial.println("Resetting watchdog");
  wdt_reset();

  // Run readings
  for (int channel = 0; channel < TOTAL_CIRCUITS; channel++) {       // loop through all the sensors

    Wire.beginTransmission(channel_ids[channel]);     // call the circuit by its ID number.
    Wire.write('r');                          // request a reading by sending 'r'
    Wire.endTransmission();                         // end the I2C data transmission.

    delay(1000);  // AS circuits need a 1 second before the reading is ready

    sensor_bytes_received = 0;                        // reset data counter
    memset(sensordata, 0, sizeof(sensordata));        // clear sensordata array;

    Wire.requestFrom(channel_ids[channel], 48, 1);    // call the circuit and request 48 bytes (this is more then we need).
    code = Wire.read();

    while (Wire.available()) {          // are there bytes to receive?
      in_char = Wire.read();            // receive a byte.

      if (in_char == 0) {               // null character indicates end of command
        Wire.endTransmission();         // end the I2C data transmission.
        break;                          // exit the while loop, we're done here
      }
      else {
        sensordata[sensor_bytes_received] = in_char;      // append this byte to the sensor data array.
        sensor_bytes_received++;
      }
    }

    if (channel_names[channel] == "PH")
    { //sensore PH
      pH = atof(sensordata); //convert the string to a floating point number so it can be evaluated by the Arduino
      if (pH >= 6.7)
      { //if the pH is greater than or equal to 6.7, activate co2 supply via RF link
        Serial.print("pH is basic, activating  CO2 : ");
        ph_status = 1;
        digitalWrite(LED, HIGH);
        Serial.println(pH, 3);
        mySwitch.send(5330227, 24);
      }
      if (pH < 6.7)
      { //if the pH is less than or equal to 6.7, power off co2 supply via RF link
        Serial.print("pH is ok, turning off CO2 : ");
        ph_status = 0;
        digitalWrite(LED, LOW);
        Serial.println(pH, 3);
        mySwitch.send(5330236, 24);
      }
    }
    if (channel_names[channel] == "Temp")
    { //sensore temperatura
      temp = atof(sensordata); //convert the string to a floating point number so it can be evaluated by the Arduino
    }
    if (channel_names[channel] == "EC")
    { //sensore conduttività
      ec = atof(sensordata); //convert the string to a floating point number so it can be evaluated by the Arduino
    }

    Serial.print(channel_names[channel]);   // print channel name
    Serial.print(':');

    switch (code) {                       // switch case based on what the response code is.
      case 1:                             // decimal 1  means the command was successful.
        Serial.println(sensordata);       // print the actual reading
        break;                              // exits the switch case.

      case 2:                             // decimal 2 means the command has failed.
        Serial.println("command failed");   // print the error
        break;                              // exits the switch case.

      case 254:                           // decimal 254  means the command has not yet been finished calculating.
        Serial.println("circuit not ready"); // print the error
        break;                              // exits the switch case.

      case 255:                           // decimal 255 means there is no further data to send.
        Serial.println("no data");          // print the error
        break;                              // exits the switch case.
    }
  }
  // Do other stuff here (Update a display, etc)
  //delay(2500); // service the alarm timers once per second
  lcd.setRGB(colorR, colorG, colorB);
  lcd.setCursor(0, 0);
  lcd.print("pH:");
  lcd.print(pH);
  lcd.print(" ");
  lcd.print("uS:");
  lcd.print(ec);
  lcd.setCursor(0, 1);
  lcd.print("Temp: ");
  lcd.print(temp);

  h = dht.readHumidity();
  t = dht.readTemperature();

  if (isnan(t) || isnan(h))
  {
    Serial.println("Failed to read from DHT");
  }

  wifiConnect();
  influx();

  ptime(); // print time and check whether lights need to be turned on/off
  DateTime now = rtc.now();
  // if (now.hour() == 22 && now.minute() == 15)
  if (now.hour() >= 13 && now.hour() < 21) {
    LedOn();
  } else {
    LedOff();
  }
}

void LedOn()
{
  Serial.println("Turning on LED Lights");
  lights = 1;
  mySwitch.send(5330371, 24);
}

void LedOff()
{
  Serial.println("Turning off LED Lights, good night :)");
  lights = 0;
  mySwitch.send(5330380, 24);
}

void influx()
{
  //  Send data to Influx
  if (client.connect(host, port))
  {
    Serial.println("##########################");
    Serial.println("connected to Influx server");
    sprintf(buff, "aquarium ph=%.2f,temp_int=%.2f,temp_ext=%.2f,µS=%.2f,lights=%d,ph_status=%d,wdt_reset=%i", pH, temp, t, ec, lights, ph_status, wdt_reset);
    Serial.print("String being posted to Influx: ");
    Serial.println(buff);

    // send the HTTP POST request:
    client.println("POST /write?db=aquarium HTTP/1.1");
    client.println("User-Agent: Arduino/1.0");
    client.println("Host: arduino");
    client.println("Content-Type: application/x-www-form-urlencoded");
    client.println("Content-Length: " + String(strlen(buff)));
    client.println("Connection: close");
    client.println();
    client.println(buff);
    client.println();
    // flush all connections
    client.stop();
    Serial.println("client disconnected");
    Serial.println("##########################");
    delay(500);
  }
  else
  {
    // if you couldn't make a connection:
    Serial.println("EEEEEEEEEEEEEEEEEEEEEEEEE");
    Serial.println("connection failed");
    Serial.println();
    Serial.println("disconnecting from server.");
    Serial.println("EEEEEEEEEEEEEEEEEEEEEEEEE");
    client.stop();
  }
}

void ptime() {
  DateTime now = rtc.now();
  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(" - ");
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);
  Serial.println();
}

void wifiConnect() {

  // Return to loop() if already connected to the WLAN router
  if (WiFi.status() == WL_CONNECTED)
  {
    Serial.println("-----------------------------------------------");
    Serial.println("We are alredy connected to network, skipping...");
    Serial.println("-----------------------------------------------");
    return;
  }

  // Wifi connect
  status = WiFi.disconnect();
  Serial.println("+++++++++++++++++++++++++++++++++++++++");
  Serial.println("Attempting to connect to WPA network...");
  Serial.println("+++++++++++++++++++++++++++++++++++++++");
  status = WiFi.begin(ssid, pass);

  // if unable to connect, halt
  if (status != WL_CONNECTED)
  {
    Serial.println("Couldn't get a WiFi connection");
    while (true);
  }
  // if the conneciton succeeded, print network info
  else {
    Serial.println("Connected to network");
    // print your WiFi shield's IP address:
    IPAddress ip = WiFi.localIP();
    Serial.print("IP Address: ");
    Serial.println(ip);

    String fv = WiFi.firmwareVersion();
    Serial.print("Firmware version: ");
    Serial.println(fv);

    // print the received signal strength:
    long rssi = WiFi.RSSI();
    Serial.print("signal strength (RSSI):");
    Serial.print(rssi);
    Serial.println(" dBm");
  }
  // wait 10 seconds for connection:
  delay(3500);
}

void watchdogSetup() {
#ifdef ARDUINO_ARCH_MEGAAVR
  if (RSTCTRL.RSTFR & RSTCTRL_WDRF_bm) {
    Serial.println("EEEEEEEEEEEEEEEEEEEEEEEEE");
    Serial.println(F("It was a watchdog reset."));
    Serial.println("EEEEEEEEEEEEEEEEEEEEEEEEE");
    wdt_reset = 1;
    influx();
    wdt_reset = 0;
  }
  RSTCTRL.RSTFR |= RSTCTRL_WDRF_bm ;
  wdt_enable(WDT_PERIOD_8KCLK_gc);
#endif
}

No.

The watchdog is set to reset after 8 seconds and the code is littered with delays which in a worst case scenario exceeds 8 seconds. This will cause a reset even if nothing hangs, so that needs mending.

@zzmike76
Time to look at these and modify your code in line with what you learn:

Blink without delay, which is in the examples in the IDE under digital.

Also study

Using millis for timing

Demonstration for several things at the same time

Finite state machine tutorial will also be useful

1 Like

thank you very much for the links! I am not a developer, rather a sysadmin, so am trying to connect all the dots :slight_smile:

The code has already some asynch (millis) data gathering, surprisingly after trying some continous readings the amount of resets has reduced (which goes against any recommendation, which am still learning about)

Where? I don't see any use of millis in the code you posted. Just one delay(1000) that I can see.

This does not do what you think it is doing, although it may seem to work in a few circumstances.

Use the C-string function strcmp() to compare character strings.

1 Like

It makes me nervous that you have both a function and a variable called "wdt_reset"
This being C++, it's probably OK, but...

At minimum, you should do a wdt_reset() immediately before any call to delay().

It may be that there are some delays inside things like client.connect() and similar that you have no control over :frowning:

Also, the wdt may stay on AFTER a wdt reset occurs (this happens on older AVRs. I'm not sure about the 4809.) If this is the case, you may need to disable the WDT before you do any lengthy operations in setup()

1 Like

thanks for the hint, will rename the variable, indeed it can make confusion...

after commenting the delay in wifi connect function, the system is way more stable, last reset was yesterday at 19:00

You could implement your own watchdog aware delay function like this:

void wdt_delay(uint32_t ms)
{
  uint32_t start = millis();
  while (millis() - start < ms)
  {
    wdt_reset();
    delay(1);
  }
}

By doing it so, you can delay the delay of a delay's delay without being bitten by the dog.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.