2

I hope somebody can shed some light on this problem. I've researched the internet and forums and noticed that others have experienced similar problems.

This sketch runs fine for a couple of hours...it activates a relay approximately every hour, has a 10 second loop for an LED flash and then enters sleep mode. The watchdog timer is set to 8 seconds and wakes it up from sleep. I don't know why it works for a couple of hours and then gets caught into some sort of loop with the LED flashing rapidly. The requirements for disabling and resetting the watchdog might be the problem but I just don't know where to go next. I have seen a few discussions on memory leakage but not sure what that means or how to check for it. I also wonder if need to add any short delays after resets, etc. Additionally, when I press the reset button it has no effect on restarting the sketch. The sketch is running on a breadboard atMega328p-pu. Any help would be greatly appreciated.

ps. in the preview I noticed the # statements are not shown. They are the following libraries: avr/sleep.h, avr/power.h, avr/wdt.h

// In this sketch, the LED's flash every 10 seconds, then at each approximately 1 hour period, the relay is activated
// for 12 seconds.  It uses the WDT at its maximum 8 second delay to wakeup the circuit from low power sleep.

// Source: citizen-sensing.org/2013/07/arduino-watchdog/

// Check this out for good explanation on the Watchdog timer and code.
// http://www.leonardomiliani.com/en/2013/impariamo-ad-usare-il-watchdog-2/

// SEE NOTE at the end on known WDT reset issue

#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>


int j = 1; // Elapsed time multiplication factor
int j2 = 0; // previous j value 
float tCumm = 0.0; // Cummulative time
float hSet = 1.0; // Set relay activation once per hour
float hSet2 = 0.0; // Previous hSet value

// Create sleepNow function

void sleepNow() {

  wdt_reset();
  wdt_disable();

  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Selecting the lowest power setting

// Set watchdog parameters
  MCUSR &= ~(1<<WDRF); // reset status flag
  WDTCSR |= (1<<WDCE) | (1<<WDE); // required to enable configuration changes
  WDTCSR = (1<<WDP0) | (1<<WDP3); // set the pre-scalar for 10, ie 8 seconds delay 
  WDTCSR |= (1<<WDIE); // enable interrupt mode

// Disable the ADC
  ADCSRA &= ~(1<<ADEN); // Set bit 7 in ADC register to 1 to disable the ADC 

// Ready for sleep
  sleep_enable(); // Enable sleep function
  sleep_mode(); // Go to sleep.  Will wake up upon interrupt via Watchdog timer in this sketch.

// disable sleep after waking up
  sleep_disable(); // Disable sleep for now after Watchdog timer interrupt activation
}

void setup() {

  pinMode(4, OUTPUT); // set pin 4 as output for LED
  pinMode(7, OUTPUT); // set pin 7 as output for relay   
}

void loop() {

  // 10 second LED flashing + sleep loop

  for (int i = 0; i < 2; i++) {
  digitalWrite(4, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(200);               // wait for 0.2 sec
  digitalWrite(4, LOW);    // turn the LED off by making the voltage LOW
  delay(200);              // wait for 0.2 second
}

  // Add delay for total approx 2 sec
  delay(1200);

  // Start sleep / Low power / Watchdog interrupt
  sleepNow();

  // Cummulative time in increments of 10 seconds
  tCumm = ((2.0 + 8.0)*j)/3600.;

  // Time multiplication factor. Used to increment tCumm. Never resets to zero.
  j2 = j;
  j = j2 + 1;

  // Check to see if tCumm exceeds the user defined period (hSet) before activating relay
  if (tCumm > hSet) {

  // Activate relay for 12 seconds
    digitalWrite(7, HIGH);
    delay(12000);
    digitalWrite(7,LOW);

  // Reset hSet for next relay activation time
    hSet2 = hSet;
    hSet = hSet2 + 1.0;

    } 
}


ISR (WDT_vect) {

}

NOTE from an online discussion: The problem is that a RESET does not turn off the watchdog timer once it has been turned on, and neither does the bootloader. So you set things up to have the watchdog cause a reset in 15ms, and the reset occurs. Now the bootloader starts up, and starts its LED-flashing, and OOPS another 15ms has gone by with no one feeding the watchdog, and it resets again. This repeats until a power cycle turns off the watchdog.
(This behavior is explicitly described in the ATmega datasheet...)

1
  • You should put the wdt_disable(); at the end of sleepNow. It doesn't make much sense to disable it right before setting it. I always put a distinct blinking pattern in the setup function, so I can detect when the Arduino is reset.
    – Gerben
    Commented May 24, 2016 at 17:27

2 Answers 2

1

You have a watch dog timer for 8 seconds and when you activate the relays you do a delay of 12.
This means that your watchdog will trigger when you activate the relays.

3
  • Do you think I need to add a wdt_reset() or wdt_disable(), or both, right after the sleepNow() command in the loop function?
    – Jaime
    Commented May 24, 2016 at 17:29
  • Given that the watchdog appears to be operating in interrupt mode (with an ISR that does nothing) rather than reset mode, I'm not sure that this matters. The routine which goes to sleep seems like it is attempting to establish a suitable watchdog state before doing that, so it's not clear how an additional wdt timeout during the delay would matter. But watchdog usage definitely needs careful thought. Commented May 24, 2016 at 18:18
  • But watchdog usage definitely needs careful thought. indeed. And using it with delays is making it very hard to predict what is ongoing.
    – jantje
    Commented May 24, 2016 at 19:42
1

Looking at this declaration

int j = 1; // Elapsed time multiplication factor
int j2 = 0; // previous j value 

and then this code

// Cummulative time in increments of 10 seconds
  tCumm = ((2.0 + 8.0)*j)/3600.;

 // Time multiplication factor. Used to increment tCumm. Never resets to zero.
  j2 = j;
  j = j2 + 1;

along with the associated comments seems to indicate that this variable "j" which is a (signed) int only increments without ever resetting, and is critical to the process of calculating the next time at which your code will act.

Your includes indicate that you are building for an AVR-based Arduino, and under the compiler used, an int on this platform is only 16 bits, meaning it has a range of -32768 to 32767. Most modern platforms including this one use 2's complement representation, and most non-DSP platforms including this one do not use saturating arithmetic. Therefore, incrementing a positive number beyond the positive limit will actually product a negative value. Once your target time exceeds the maximum possible result of a calculation that has a positive int as an input, it becomes a target you will never be able to achieve.

Given the the amount of time your loop takes to execute, such integer overflow may not be not the issue you are hitting first, and does not seem perfectly correlated to your rapid-cycling failure mode. But if your loop takes around 10 seconds, it seems like this would be an issue in a little less than four days.

1
  • Thx..j increments 1 every 10 seconds...so.if I use a 5 hour period for example, j gets up to only 1800...5*60*60/10...yes it will definitely run into the limit in 3-4 days looks like and will have to be fixed for sure...but now it only runs 2-3 hours...I think there is something about my watchdog setup that I'm missing with the resets, disabling, etc but i'm just guessing...
    – Jaime
    Commented May 24, 2016 at 18:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.