WDT Timer longer than 8S

I have this issue where my code works when the loop is short enough around to let the wdt_reset kick in on time. But when I add code with long delays such as the SampleUVAlarm() function which takes about 10 seconds at current, the avr is reset because the pat doesnt come in under 8S. So Im thinking I need to extend my wdt timeout from 8S to perhaps 16s.

Is my thinking correct?

Here is my sketch:

#include <TimeAlarms.h>
#include <WiFlyHQ.h>
#include <SoftwareSerial.h>
#include <avr/wdt.h>

boolean initialiseSensorFlag;
unsigned long initialiseSensorTimestamp;


long previousMillis = 0;
long interval = 1000;

SoftwareSerial wifiSerial(2,3); //WIFI SHIELD CLIENT

#define DEBUG 1                       //UV Sensor
const int pinRx = 8;                  //UV Sensor
const int pinTx = 7;                  //UV Sensor
SoftwareSerial sensor(pinTx,pinRx);  //UV Sensor

float uvindex;
float mq2ratio;

WiFly wifly;                          //WIFI
String data;                          //WIFI

const char mySSID[] = "myssid";
const char myPassword[] = "mywifikey";
const char site[] = "myserver.com";

void terminal();

void setup(){ 
  Serial.begin(9600);
  Alarm.timerRepeat(1800, MainAlarm); //Every 30 mins
  Serial.println("Alarms set!");
  [color=red]wdt_enable(WDTO_8S);[/color]
}

void loop(){  
  Alarm.delay(10); // wait one second between clock display
  if (wifly.moduleCrashed==true){
    Serial.println("moduleCrashed");
    [color=red]wdt_enable(WDTO_8S);
    while (true);[/color]
  }
  
  [color=red]wdt_reset();[/color]
  
  if(initialiseSensorFlag == true && millis() - initialiseSensorTimestamp > 3000){
    initialiseSensorFlag = false;    
    SampleUVAlarm(); //  calls and executes UV Sampling
  }
}

void wifiStuff(){
   char buf[32];
   data = "";
   Serial.print("Free memory: ");
   Serial.println(wifly.getFreeMemory(),DEC);

   wifiSerial.begin(9600);
   if (!wifly.begin(&wifiSerial, &Serial)) {
       Serial.println("Failed to start wifly");
  terminal();
   }
   /* Join wifi network if not already associated */
   if (!wifly.isAssociated()) {
  /* Setup the WiFly to connect to a wifi network */
  Serial.println("Joining network");
  wifly.setSSID(mySSID);
        wifly.setPassphrase(myPassword);
  wifly.enableDHCP();

  if (wifly.join()) {
      Serial.println("Joined wifi network");
  } else {
      Serial.println("Failed to join wifi network");
      terminal();
  }
   } else {
       Serial.println("Already joined network");
   }
   
   wifly.setDeviceID("Wifly-WebClient2");
   
   Serial.print("DeviceID: ");
   Serial.println(wifly.getDeviceID(buf, sizeof(buf)));
   
   if (wifly.isConnected()) {
       Serial.println("Old connection active. Closing");
  wifly.close();
   }
  reportToCloud();
}

void initialiseSensor(){
  Serial.begin(9600);
  Serial.println("********************************************************");
}

void MainAlarm(){
  Serial.println("Main Alarm...");
  Serial.println(wifly.moduleCrashed);
  initialiseSensor();
  initialiseSensorFlag = true;
  initialiseSensorTimestamp = millis();
}

void reportToCloud() {
  Serial.println("Reporting to cloud...");
   if (wifly.available() > 0) {
  char ch = wifly.read();
  Serial.write(ch);
  if (ch == '\n') {
      /* add a carriage return */ 
      Serial.write('\r');
  }
   }
   
   if (wifly.open(site, 80)) {
       Serial.print("Connected to ");
  Serial.println(site);
  
    // Set data to send
    static char outstr[15];
    static char outstr2[15];

    String dataString = dtostrf(uvindex, 8, 2, outstr);
    String dataString2 = dtostrf(mq2ratio, 8, 2, outstr2); //UNCOMMENT
    data = String("name=" + dataString2 + "&age=" + dataString);//UNCOMMENT
    Serial.print(data);
    
        /* Send the request */
  wifly.println("POST /arduino/data_post_.php HTTP/1.0");
  wifly.println("Host: www.myserver.com"); // SERVER ADDRESS HERE TOO
        wifly.println("Content-Type: application/x-www-form-urlencoded" );
        wifly.print("Content-Length: ");
        wifly.println(data.length());
  wifly.println();
        wifly.print(data);
        Serial.println("Posted successfully");
   } else {
       Serial.println(">>Failed to connect");
   }

   if (Serial.available() > 0) {
  wifly.write(Serial.read());
   }
   
   wifly.close();
}

void SampleUVAlarm (){
  delay(10000);
}

Marciokoko:
I have this issue where my code works when the loop is short enough around to let the wdt_reset kick in on time. But when I add code with long delays such as the SampleUVAlarm() function which takes about 10 seconds

A loop that takes even 1 second to repeat would be incredibly long. Your code should be designed so that loop() repeats hundreds or thousands of times per second.

In case you have not already been referred to Several Things at a Time, it is worth a look as it uses millis() to manage timing without blocking.

...R

Yes I do use millis() here to set a timestamp and check it. I actually modified my sketch as I was debugging why things werent getting posted to the internet when I called my 2 sampling methods, but dummy data is posted when I dont call those sampling methods and I simply hardcoded values to the variables being posted. Here is the original sketch. This is what I do:

  1. I set the alarm to fire every half-hour (which sets a boolean)
  2. I wdt_enable for 8s
  3. I pat the dog every loop
  4. Also every loop I check for the boolean flag && timestamp
  5. If true, I set bool back to false and call the sampling method, the wifi method and the reportToCloud method
  6. These methods above sample (takes about 5 secs), connects to wifi (takes about 5 secs) and posts to web (takes about 4 secs).
#include <TimeAlarms.h>
#include <WiFlyHQ.h>
#include <SoftwareSerial.h>
#include <avr/wdt.h>

boolean initialiseSensorFlag;
unsigned long initialiseSensorTimestamp;


long previousMillis = 0;
long interval = 1000;

SoftwareSerial wifiSerial(2,3); //WIFI SHIELD CLIENT

#define DEBUG 1                       //UV Sensor
const int pinRx = 8;                  //UV Sensor
const int pinTx = 7;                  //UV Sensor
SoftwareSerial sensor(pinTx,pinRx);  //UV Sensor

float uvindex;
float mq2ratio;

WiFly wifly;                          //WIFI
String data;                          //WIFI

const char mySSID[] = "myssid";
const char myPassword[] = "mywifikey";
const char site[] = "myserver.com";

void terminal();

void setup(){ 
  Serial.begin(9600);
  Alarm.timerRepeat(1800, MainAlarm); //Every 30 mins
  Serial.println("Alarms set!");
  wdt_enable(WDTO_8S);
}

void loop(){  
  Alarm.delay(10); // wait one second between clock display
  if (wifly.moduleCrashed==true){
    Serial.println("moduleCrashed");
    wdt_enable(WDTO_8S);
    while (true);
  }
  
  wdt_reset();
  
  if(initialiseSensorFlag == true && millis() - initialiseSensorTimestamp > 3000){
    initialiseSensorFlag = false;    
    SampleUVAlarm(); //  calls and executes UV Sampling
    wifiStuff();
    reportToCloud();
  }
}

void wifiStuff(){
  ///////////////////WiFi CLIENT SETUP////////////////////////////////////////////
   char buf[32];
   data = "";
   Serial.print("Free memory: ");
   Serial.println(wifly.getFreeMemory(),DEC);

   wifiSerial.begin(9600);
   if (!wifly.begin(&wifiSerial, &Serial)) {
       Serial.println("Failed to start wifly");
  terminal();
   }
   /* Join wifi network if not already associated */
   if (!wifly.isAssociated()) {
  /* Setup the WiFly to connect to a wifi network */
  Serial.println("Joining network");
  wifly.setSSID(mySSID);
        wifly.setPassphrase(myPassword);
  wifly.enableDHCP();

  if (wifly.join()) {
      Serial.println("Joined wifi network");
  } else {
      Serial.println("Failed to join wifi network");
      terminal();
  }
   } else {
       Serial.println("Already joined network");
   }
   
   wifly.setDeviceID("Wifly-WebClient2");
   
   Serial.print("DeviceID: ");
   Serial.println(wifly.getDeviceID(buf, sizeof(buf)));
   
   if (wifly.isConnected()) {
       Serial.println("Old connection active. Closing");
  wifly.close();
   }
}

void initialiseSensor(){
  Serial.begin(9600);
  Serial.println("********************************************************");
}

void MainAlarm(){
  Serial.println("Main Alarm...");
  Serial.println(wifly.moduleCrashed);
  initialiseSensor();
  initialiseSensorFlag = true;
  initialiseSensorTimestamp = millis();
}

void reportToCloud() {
  Serial.println("Reporting to cloud...");
   if (wifly.available() > 0) {
  char ch = wifly.read();
  Serial.write(ch);
  if (ch == '\n') {
      /* add a carriage return */ 
      Serial.write('\r');
  }
   }
   
   if (wifly.open(site, 80)) {
       Serial.print("Connected to ");
  Serial.println(site);
  
    // Set data to send
    static char outstr[15];
    static char outstr2[15];

    String dataString = dtostrf(uvindex, 8, 2, outstr);
    //data = String("name=Station1&age=" + dataString);
    String dataString2 = dtostrf(mq2ratio, 8, 2, outstr2); 
    data = String("name=" + dataString2 + "&age=" + dataString);
    Serial.print(data);
    
        /* Send the request */
  wifly.println("POST /arduino/data_post_2.php HTTP/1.0");
  wifly.println("Host: www.myserver.com"); // SERVER ADDRESS HERE TOO
        wifly.println("Content-Type: application/x-www-form-urlencoded" );
        wifly.print("Content-Length: ");
        wifly.println(data.length());
  wifly.println();
        wifly.print(data);
        Serial.println("Posted successfully");
   } else {
       Serial.println(">>Failed to connect");
   }

   if (Serial.available() > 0) {
  wifly.write(Serial.read());
   }
   
   wifly.close();
}

/* Connect the WiFly serial to the serial monitor. */
void terminal(){
   while (1) {
  if (wifly.available() > 0) {
      Serial.write(wifly.read());
  }
  if (Serial.available() > 0) {
      wifly.write(Serial.read());
  }
   }
}

void SampleUVAlarm (){
  Serial.println("Sampling UV");
  int sensorValue;
  long  sum=0;
  for(int i=0;i<1024;i++)
   {  
      sensorValue=analogRead(A0);
      sum=sensorValue+sum;
      delay(2);
   }   
 sum = sum >> 10;
 Serial.print("The UV voltage value:");
 Serial.print(sum*4980.0/1023.0);
 Serial.print(" mV");
 delay(20);
 Serial.print("UVIndex is: ");
 uvindex = ((307*(sum*4980.0/1023.0))/200)/1000; //mW/m2 -> W/m2
 Serial.println(uvindex);
 Serial.print("\n");
 //SampleMQ2Alarm();
}

void SampleMQ2Alarm() {
  Serial.println("Sampling MQ2");
  float sensor_volt;
  float RS_gas; // Get value of RS in a GAS
  float ratio; // Get ratio RS_GAS/RS_air
  int sensorValue = analogRead(A1);
  sensor_volt=(float)sensorValue/1024*5.0;
  RS_gas = (5.0-sensor_volt)/sensor_volt; // omit *RL
 //R0 stabilized at 0.08 in secret room
  /*-Replace the name "R0" with the value of R0 in the demo of First Test -*/
  ratio = RS_gas/0.08;  // ratio = RS/R0 
  /*-----------------------------------------------------------------------*/
 
  Serial.print("MQ2 Sensor_volt = ");
  Serial.println(sensor_volt);
  Serial.print("RS_ratio = ");
  Serial.println(RS_gas);
  Serial.print("Rs/R0 = ");
  Serial.println(ratio);
  mq2ratio = ratio;
  Serial.print("\n\n");
  delay(1000);
}

Ok I found the code but there are a few things I dont want. I would want to:

  1. Replace delay(2000); with my heavy lifting code
  2. Comment out set_sleep_mode and sleep_mode()

Correct?

// watchdog interrupt
ISR(WDT_vect) 
  {
  wdt_disable();  // disable watchdog
  }

void myWatchdogEnable(const byte interval) {  
  MCUSR = 0;                          // reset various flags
  WDTCSR |= 0b00011000;               // see docs, set WDCE, WDE
  WDTCSR =  0b01000000 | interval;    // set WDIE, and appropriate delay

  wdt_reset();
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  sleep_mode();            // now goes to Sleep and waits for the interrupt
} 


void loop(){
  digitalWrite (LED, HIGH);  // awake
  delay (2000);    // ie. do stuff here
  digitalWrite (LED, LOW);  // asleep

  // sleep for a total of 20 seconds
  myWatchdogEnable (0b100001);  // 8 seconds
  myWatchdogEnable (0b100001);  // 8 seconds
  myWatchdogEnable (0b100000);  // 4 seconds

}  // end ofloop

Marciokoko:
Correct?

No.

See this.

Marciokoko:
Correct?

Does loop() repeat many many times per second?

If not, NO.

...R

Robin2:
Does loop() repeat many many times per second?

Having a very fast and streamlined loop() function is usually a good thing. It's vital if you are trying to run several asynchronous activities at the same time, and you need each of them to be responsive. But there are times when having a fast loop repeat is counterproductive and unnecessarily complicates things - this may be one of those times.

In this case, the sketch is not doing multiple things at once. It is doing one and only one thing: waiting until it is time to do something, and doing that something which involves a lengthy series of operations. It could be broken up into a state machine that does it in little chunks and allows loop() to return often, but since there is nothing else going on, it hardly seems worth the effort.

The root problem here is not that loop is taking a long time, it's that it's taking longer than the watchdog timeout. I see two viable solutions:

Solution 1) Since there are three lengthy operations, each of which is well less than the watchdog timeout period, make a simple state machine, something like this:

enum phaseType {Idle, Sample, WiFi, Cloud};
phaseType phase = Idle;

void loop(){ 
  Alarm.delay(10); // wait one second between clock display
  if (wifly.moduleCrashed==true){
    Serial.println("moduleCrashed");
    wdt_enable(WDTO_8S);
    while (true);
  }
 
  wdt_reset();
 
  if(initialiseSensorFlag == true && millis() - initialiseSensorTimestamp > 3000)
    phase = Sample;

  switch (phase)
  {
    case Sample:
        initialiseSensorFlag = false;   
        SampleUVAlarm(); //  calls and executes UV Sampling
        phase = WiFi;
        break;

    case WiFi:
        wifiStuff();
        phase = Cloud;
        break;

    case Cloud:
        reportToCloud();
        phase = Cloud;
        break;
  }
}

This will cause the three lengthy operations to be broken up into three separate iterations of loop(), each of which is less than eight seconds, so the watchdog should not expire.

But that's still a fair amount of work, yet the loop() function will still take several seconds per iteration once the sequence starts. It's really only worth the effort if the check for a crashed module should be performed more often - perhaps it's useful to check for it between the wifiStuff() and reportToCloud() calls?

Solution 2) A much simpler solution is to simply reset the watchdog timer more often:

 wdt_reset();
 
  if(initialiseSensorFlag == true && millis() - initialiseSensorTimestamp > 3000){
    initialiseSensorFlag = false;   
    SampleUVAlarm(); //  calls and executes UV Sampling
    wdt_reset();
    wifiStuff();
    wdt_reset();
    reportToCloud();
  }

This simply resets the watchdog timer between the lengthy calls, preventing the sum of the calls from causing a reset - the watchdog will only expire if any one of the calls takes longer than eight seconds.

Generally, it's good design to reset the watchdog in only one place inside of loop(). This way, you know that things are functioning normally and loop() is getting called with some regularity. It's generally not a good idea to sprinkle watchdog reset calls in the code to get you out of trouble, as it can be risky - for example, if you have a loop that is spinning and waiting for something to finish, you don't want to reset the watchdog inside that loop because it will be defeating the purpose: you won't ever know if it takes too long for that thing to finish. However, in this case, there is no looping, it's just several lengthy sequential operations - I don't see that it's a horrible thing to add a few more watchdog resets there.

A fast loop() function is a good rule - it can solve many issues, and is usually the solution when someone wants to do a few things at once. But there are exceptions to that rule, and knowing when it's safe to break the rules can greatly simplify things.

Wow! Amazingly clean and simple! Thanks so much ShapeShifter!

And thanks DaveEvans, Im looking at your example.

ShapeShifter:
A fast loop() function is a good rule - it can solve many issues, and is usually the solution when someone wants to do a few things at once. But there are exceptions to that rule, and knowing when it's safe to break the rules can greatly simplify things.

Agreed.

You are much more diligent than I am. Seasons Greetings

...R

I'm glad it helped.

Robin2:
Seasons Greetings

Thank you, and the same to you and everyone else out there in Arduino-land! :sunglasses:

First advice, don't use delay.

To get a watchdog longer than 8 seconds use the interrupt mode for the watchdog. Set up the ISR for the watchdog interrupt to count how many times it has been called. Say you want 40 seconds, then when the count gets to 5 switch the watchdog to reset mode and put it in an empty while(true) loop to hold it until it resets.

How can we put this thing in code form?