Using Watchdog to wake up from sleep

I want to write code that will have my Arduino wake up from a low power mode sleep, read some sensors then go back to sleep. So I'm trying to learn about sleeping and the watchdog timer.

Before even attempting to make the Arduino sleep in low power mode, I thought I'd start with some dirt-simple code that uses the watchdog interrupt and integrate "sleep" functionality later.

My simple code turns the LED on for 1 second during setup() then flashes quickly once per second in loop(). I can watch the LED to verify that the watchdog is working and resetting the Arduino every 8 seconds.

Although it works, the LED gets very dim after the first time through the code. Additionally, it stays dim even if I remove power from the Arduino and power it up again (through the USB connection). The only way to get the LED bright again is to download the code again.

#include <avr/wdt.h>

const byte LED = 13;

void setup ()
{
	digitalWrite(LED, HIGH);
	delay(1000);
	digitalWrite(LED, LOW);
	wdt_enable(WDTO_8S);		// starts counting, i.e. turns on the watchdog timer
}

void loop () 
{
	for (int i=0; i<15; ++i)
	{
		digitalWrite(LED, HIGH);
		delay(100);
		digitalWrite(LED, LOW);
		delay(900);
	}
}

I have a few questions but the simplest one is:

  1. Why doe the LED get dim after a WDT interrupt?

I've read a dozen examples on-line showing various examples of using the watchdog and sleep mode; none of the examples I've seen seem to do things the same way and that makes me have more questions:

  1. Why do some coders use the functions with the wdt_ prefix and other coders manipulate the registers directly? Is there a reason, like is using the wdt_ functions limited in functionality?

  2. Instead of resetting the Arduino, how do I make the WDT go to an ISR in my code instead? I've seen the macro "ISR(wdt_vect)" used. I tried including it in my code but the Arduino still gets reset.

Why doe the LED get dim after a WDT interrupt?

You have no interrupt. The wdt just resets the processor.

Take a look at the AVR_LIBC man pages for the wdt library here:

http://avr-libc.nongnu.org/user-manual/group__avr__watchdog.html

Pay Special Attention to the warning:

Note that for newer devices (ATmega88 and newer, effectively any AVR that has the option to also generate interrupts), the watchdog timer remains active even after a system reset (except a power-on condition), using the fastest prescaler value (approximately 15 ms). It is therefore required to turn off the watchdog early during program startup, the datasheet recommends a sequence like the following:

'tis been too many years. Tiny85 code:

/* 
   M. Ray Burnette 20140210 Open Source: for "Hot Yet?" publication
   Coding Badly Tiny core: https://code.google.com/p/arduino-tiny/
   Binary sketch size: 2,852 bytes (of a 8,192 byte maximum)
   Arduino 1.0.5 No bootloader used.  Upload via ISP.
   Project 3.3V Attiny85 @8MHz internal,  under 10mA idle at 68F


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

boolean flag_wdt = 1;

int pinT = PB3;           // Thermistor source voltage
int pinR = PB0;           // Digital pin #0  Red
int pinG = PB1;           // Digital pin #1  Green
int pinB = PB4;           // Digital pin #4  Blue
int r; int g; int b;
const int nToSleep = 50 ; // # of stable temp readings before sleep
const int Delay =    100; // main loop delay in mS
double ADCcount;
double ADCprevious;
int nCount;
int ThermistorPin  = 1 ;  // A1 is physical pin #7 (PB2)

void setup()
{
  // WDTO_15MS, WDTO_30MS, WDTO_60MS, WDTO_120MS, WDTO_250MS, WDTO_500MS, 
  // WDTO_1S, WDTO_2S, WDTO_4S, WDTO_8S
  setup_watchdog(WDTO_4S);  // Periodic Heartbeat to awaken deep sleep()
  sleep_disable();
  pinMode(pinT, OUTPUT); digitalWrite(pinT, HIGH);  // Thermistor Source
  pinMode(pinR, OUTPUT);
  pinMode(pinG, OUTPUT);
  pinMode(pinB, OUTPUT);
}
  
void loop() 
{
  wdt_reset();    // pat K9
  ADCcount = analogRead(ThermistorPin) ;
  if (ADCcount == ADCprevious) ++nCount;
  if ( nCount > nToSleep )
  { // prepare for low current power-down state
    pinMode(pinR, INPUT); digitalWrite(pinR, HIGH);  // pullup enabled
    pinMode(pinG, INPUT); digitalWrite(pinG, HIGH);
    pinMode(pinB, INPUT); digitalWrite(pinB, HIGH);
    SleepLonger:    // Come here to re-sleep
    pinMode(pinT, INPUT); digitalWrite(pinT, HIGH);
      system_sleep();
      sleep_disable();  // deep sleep until WDT kicks
      pinMode(pinT, OUTPUT); digitalWrite(pinT, HIGH);
      delay(50);
      // Yawn, exercise a few reads for stabilization
      for (uint8_t z=0; z<5; z++) {
        ADCcount = analogRead(ThermistorPin) ;
      }
      if (abs(ADCcount - ADCprevious) < 4) goto SleepLonger;  // hysteresis
    // restore LED output drivers ... temp has gone up
    pinMode(pinR, OUTPUT); digitalWrite(pinR, HIGH);
    pinMode(pinG, OUTPUT); digitalWrite(pinG, HIGH);
    pinMode(pinB, OUTPUT); digitalWrite(pinB, HIGH);
    nCount = 0;
  } else {
  // 261 = 32F, 447 = 64F, 537 = 75F, 575 = 82F
  b = map(ADCcount, 261,  447, 100, 255 );
  g = map(ADCcount, 435,  574, 250, 100);  // overlap green & blue
  r = map(ADCcount, 575, 1023, 250,  50);

  if (ADCcount > 574)              // HOT: ADCcount goes up with increase temperature
    {
      // Show only Red when Hot with Red intensity increasing with temperature
      analogWrite(pinR,   r);
      analogWrite(pinG, 255);      // 255 = 100% High == NO LED Current Common Anode --> Vcc
      analogWrite(pinB, 255);      // Blue Off
    } else {                       // Cold to Cool transition with Blue fading into Green
      analogWrite(pinR, 255);      // Red Off
      analogWrite(pinG, g);
      analogWrite(pinB, b);        // Brighter Blue with colder temp
    }
  }
  ADCprevious = ADCcount;
  delay(Delay);
}

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
// http://www.insidegadgets.com/wp-content/uploads/2011/02/ATtiny85_watchdog_example.zip
void system_sleep()
{
    cbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter OFF
    power_all_disable ();                // power off ADC, Timer 0 and 1, serial interface
    set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
    noInterrupts ();                     // timed sequence coming up
    sleep_enable();
    interrupts ();                       // interrupts are required now
    sleep_mode();                        // System sleeps here
    sleep_disable();                     // System continues execution here when watchdog timed out
    power_all_enable ();                 // power everything back on
    sbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter ON
}

// 0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms, 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
void setup_watchdog(int ii)
{
  byte bb;
  int ww;
  if (ii > 9 ) ii=9;
  bb=ii & 7;
  if (ii > 7) bb|= (1<<5);
  bb|= (1<<WDCE);
  ww=bb;

  MCUSR &= ~(1<<WDRF);
  // start timed sequence
  WDTCR |= (1<<WDCE) | (1<<WDE);
  // set new watchdog timeout value
  WDTCR = bb;
  WDTCR |= _BV(WDIE);
}
  
// Watchdog Interrupt Service / is executed when watchdog timed out
ISR(WDT_vect) {
     // wdt_disable();  // disable watchdog
}

Hope this example helps.

Ray


LEDs all have diodes with cathode to uC: Red, Green, Blue

It wouldn't hurt to take a spin through this:

How is your LED wired?

a7

1.

You have not included the following line in the setup() function of your sketch:

pinMode(LED, OUTPUT);

2.

The following Table contains the answer to your question.
WDTmodeOfOperation

3.
Test Sketch: This sketch demonstrates that the MCU goes to ISR() after WDT's timeout. (It can be modified to demonstrate ISR() and RESET() modes.)

#include <avr/wdt.h>
volatile bool flag = false;
const byte LED = 13;

void setup ()
{
  Serial.begin(9600);
  pinMode (LED, OUTPUT);
  //---for debugging-----
  digitalWrite(LED, HIGH);
  delay(2000);
  digitalWrite(LED, LOW);
  delay(2000);
  //---------------------
  
  MCUSR = 0;   //reset 
  WDTCSR = (1 << WDCE) | (1 << WDE); //must be for timed-sequence
  //the following line must be executed after the above line
  WDTCSR = (0 << WDE) | bit (WDIE) | bit (WDP3) | bit (WDP0); // set WDIE, and 8 s delay
}

void loop()
{
  if (flag == true)
  {
    for (byte i = 0; i < 5; i++)
    {
      digitalWrite (LED, HIGH);
      delay (100);
      digitalWrite (LED, LOW);
      delay (100);
    }
    flag = false;
  }
}

ISR (WDT_vect)
{
  flag = true;
}

Maybe I missed it, but which Arduino are you using? Or are you using a bare chip?

I've used the LowPowerLab library on a battery powered custom 328P board to wake from sleep in multiples of 8 seconds or so (it's not a precise 8 seconds) to achieve extended periods of sleep such as 1 hour - ish!.

Arduino UNO Board (the default).

Please, post your codes.

This is the most basic example from the low power library:

// **** INCLUDES *****
#include "LowPower.h"

void setup()
{
    // No setup is required for this library
}

void loop() 
{
    // Enter power down state for 8 s with ADC and BOD module disabled
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);  
    
    // Do something here
    // Example: Read sensor, data logging, data transmission.
}

Clearly it doesn't do very much on the surface, but it is the cornerstone of my low power setup. If you just want to sleep for an extended period, then this is my routine that does that:

// ==================================================================
// Power down the system for the desired number of seconds. Note that
// the time interval is approximate because the watchdog oscillator
// frequency is not meant to be accurate.
// ==================================================================
void longSleep( uint16_t sleepInSeconds )
{
  if ( sleepInSeconds & 0x01 ) LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF);
  if ( sleepInSeconds & 0x02 ) LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF);
  if ( sleepInSeconds & 0x04 ) LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF);

  while ( sleepInSeconds & 0xFFFFFFF8 ) {
    sleepInSeconds = sleepInSeconds - 8;
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
  }
}

and the defined sleep periods I have are:

// 1 hour = 3600 seconds
const uint16_t delayOneHour = 3600;
const uint16_t delay5Mins = 300;
const uint16_t delay10Mins = 600;
const uint16_t delay15Mins = 900;
const uint16_t delay30Mins = 1800;
const uint16_t delay10Seconds = 10;

On reflection, probably should have called the constants sleepXXMins rather than delayXXMins!

Just in case anybody wants to see the complete sketch, here it is:

/*
 * XRobotiX Board - RFM69 Node sketch based on the LowPowerLab gateway demo code.
 *
 * The sketch supports ACK, encryption, and Automatic Transmission Control.
 * The sketch uses a simple implementation like MySensors to talk to the gateway.
 **********************************************************************************
 * SETUP TO SIMPLY REPORT BATTERY VOLTAGE & TEMPERATURE
 * Uses the Moteino clone board - badged as XRobotiX LoRa development board.
 * 
 * READING VCC - 3 x AA BATTERY VERSION
 * Reading the supply voltage on the LoRa Development Board using external resistors
 * Resistor setup is Vin to 2M2 to a 560K to Gnd + a 100n cap in parallel with the 560K.
 * The centre tap of the potential divider goes to ADC7.
 * 
 *  Vin --[ 2M2 ]-+-[ 560K ]-- GND 
 *                +-[ 100n ]-- GND
 *          A7 ---'
 *          
 * TEMPERATURE - DS18B20
 * Simple read of the DS18B20 sensor connected to D4 (PD4)
 */

#include <OneWire.h>
#include <DallasTemperature.h>
#include <mshaCore.h>
#include <RFM69.h> 
#include <LowPower.h>

const char sketchVersion[] PROGMEM = {"1.0a"};

#if defined (ARDUINO_AVR_XROBOTIX_DEV_BOARD)
  // only the XRobotiX boards use the HCW variant
  #define USING_RFM69HW_HCW 1
#else
  #define USING_RFM69HW_HCW 0
#endif

#define SERIAL_BAUD   9600

#define CHILD_ID1 10   // Id of the #1 sensor child - motion sensor

// Data wire is plugged into port pin PD4 (digital pin 4 on the Arduino UNO)
#define ONE_WIRE_BUS 4

// Setup a oneWire instance to communicate with any OneWire device
OneWire oneWire(ONE_WIRE_BUS);  

// Pass oneWire reference to DallasTemperature library
DallasTemperature sensors(&oneWire);

// 1 hour = 3600 seconds
const uint16_t delayOneHour = 3600;
const uint16_t delay5Mins = 300;
const uint16_t delay10Mins = 600;
const uint16_t delay15Mins = 900;
const uint16_t delay30Mins = 1800;
const uint16_t delay10Seconds = 10;

// configuration data stored in internal EEPROM
struct mshaEEConfigType eeConfig;

// char buffer for general use
char chBuff[ 32 ];

void setup() {
  bool eeReadResult; 

  // enable the internal pullup resistor for the motion sensor input
  pinMode( 4, INPUT_PULLUP );
  
  Serial.begin(SERIAL_BAUD);
  delay(500);
  
  Serial.println(F("# myHomeAutomation RFM69 Serial Node - MySensors Protocol."));
  Serial.print(F("# myRFM69PeriodicReporting.ino v"));
  Serial.println(  (__FlashStringHelper*)sketchVersion );
  Serial.println(F("# Built on " __DATE__ " at " __TIME__ ));
  Serial.println(F("# Configured for hourly voltage & temperature reports."));
  
#if defined (ARDUINO_AVR_XROBOTIX_DEV_BOARD)
  Serial.println(F("# Compiled for XRobotiX LoRa development board"));
#elif defined (ARDUINO_AVR_UNO)
  Serial.println(F("# Compiled for Arduino UNO + HS Electors shield"));
#else
  Serial.println(F("# Compiled for unknown hardware <---- !!!"));
#endif

  // get our stored settings from internal EEPROM
  eeReadResult = getEESettings();
  
  // uncomment the lines below to force a specific Node ID
  // eeConfig.param[ MSHA_NODE_ID ] = 3;
  // mshaEEWriteSettings( (uint8_t *)&eeConfig, sizeof(eeConfig) );
  // eeReadResult = true;

  // hardware reset the radio to get back to a known state
  resetRadio();

  if ( mshaInitRadio( eeConfig.param[MSHA_NODE_ID], USING_RFM69HW_HCW ) == false ) {
    Serial.println(F("HALT: Setup failed."));
    while(1);
  }
  delay(100);
  
  // if the EEPROM settings are invalid, then we need a new node ID, so get one
  // and stay here till we do
  if ( eeReadResult == false ) {
    Serial.println(F("# INFO: Attempting to get new node ID."));    
    while ( mshaGetNewNodeID( &eeConfig.param[ MSHA_NODE_ID ] ) == false ) {
      delay( 5000 );
    }
    // save the settings now we have a node ID
    mshaEEWriteSettings( (uint8_t *)&eeConfig, sizeof(eeConfig) );
    Serial.print(F("# INFO: Got & saved new node ID "));
    Serial.println( eeConfig.param[MSHA_NODE_ID] );
  }
  
  // if we get this far, then the radio module is setup ready to go.
  presentation();

  // Start up the 1-wire library
  sensors.begin();

  // put the RFM69 into ultra low power mode
  mshaRadioSleep();
}

//****************************************************************************
// presentation
//----------------------------------------------------------------------------
// Announce to the controller via the gateway what sensors we have.
// This needs to succeed before we can carry on so it won't return until it
// succeeds in getting the information across.
//****************************************************************************
void presentation()
{
  // each of these messages has to succeed before we can continue, so keep
  // trying until they all arrive - i.e ACK recevied from gateway  
  // Send the sketch version information to the gateway
  Serial.print("\nSN ");
  while ( mshaSendSketchName(F("Periodic Reporter")) == false ) delay(2000);
  delay(500);
  Serial.print("\nSV ");
  while ( mshaSendSketchVersion( (__FlashStringHelper*)sketchVersion ) == false ) delay(2000);
  delay(500);
  
  // Register all our INTERNAL sensors to the controller via the gateway (they will be created as child devices)
  Serial.print("\nC1 ");
  while ( mshaPresent( 1, S_MULTIMETER, "Battery" ) == false ) delay(2000);
  delay(500);
  Serial.print("\nC2 ");
  while ( mshaPresent( 2, S_TEMP, "DS18B20" ) == false ) delay(2000);
  delay(500);

  // if the gateway detects child sensor #3 and it's defined as S_SOUND, then
  // it will automatically generate an S_SOUND message to the controller for
  // every received message and populate it with the RSSI of that message! 
  Serial.print("\nC3 ");  
  while ( mshaPresent( 3, S_SOUND, "RSSI" ) == false ) delay(2000);
  delay(500);
}

//****************************************************************************
// loop
//****************************************************************************
void loop() {
  bool result;

  // short delay after waking from SLEEP mode for things to settle down
  delay(10);

  // Send the command to get temperatures
  sensors.requestTemperatures();
  dtostrf( sensors.getTempCByIndex(0), 5, 2, chBuff );
  Serial.print( chBuff ); Serial.println( " C" );
  mshaSend( 2, V_TEMP, chBuff );

  delay( 1000 );

  dtostrf( readVcc(), 5, 3, chBuff );
  Serial.print( chBuff ); Serial.println( " V" );
  mshaSend( 1, V_VOLTAGE, chBuff );
  
  delay( 1000 );

  // put the RFM69 back into ultra low power mode
  mshaRadioSleep();

  longSleep( delay30Mins );
}

//============================================================================
// RETRIEVE EEPROM SETTINGS
// Retreve stored settings from internal EEPROM.
// Returns TRUE if settings are valid, otherwise returns FALSE.
// If the settings are invalid, then all the settings are zero'd and the
// NODE ID setting is set to 255.
//============================================================================
bool getEESettings()
{
  bool eeReadResult;
  char buff[8];
  
  // retrieve the stored settings from internal EEPROM
  eeReadResult = mshaEEReadSettings( (uint8_t *)&eeConfig, sizeof(eeConfig) );
  Serial.print(F("# "));
  
  // print them out
  for(int i=0; i<MSHA_EE_PARAM_COUNT; i++) {
    sprintf(buff, "%02X ", eeConfig.param[i] );
    Serial.print( buff );
  }
  Serial.println();
  
  if ( eeReadResult == false ) {
    for (int i=0; i<sizeof(eeConfig); i++ ) eeConfig.param[i] = 0;
    eeConfig.param[MSHA_NODE_ID] = MSHA_DEFAULT_NODE_ID;
    Serial.println(F("# WARN: EEPROM settings invalid - default to Node 255."));    
  }
  
  return eeReadResult;
}

// ==================================================================
// Power down the system for the desired number of seconds. Note that
// the time interval is approximate because the watchdog oscillator
// frequency is not meant to be accurate.
// ==================================================================
void longSleep( uint16_t sleepInSeconds )
{
  if ( sleepInSeconds & 0x01 ) LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF);
  if ( sleepInSeconds & 0x02 ) LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF);
  if ( sleepInSeconds & 0x04 ) LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF);

  while ( sleepInSeconds & 0xFFFFFFF8 ) {
    sleepInSeconds = sleepInSeconds - 8;
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
  }
}

//============================================================================
// RESET THE RADIO
// UNO + HS Electros Shield + nRF24L01->RFM69 adapter - uses PB1 (pin 9)
// AA Node + nRF24L01->RFM69 adapter - uses PB1 (pin 9)
// XRobotiX RFM69/96 dev board - uses PB0 (pin 8)
//============================================================================
void resetRadio()
{
#if defined (ARDUINO_AVR_UNO) || defined (ARDUINO_AVR_AANODE)
  // If the board is an UNO, then we're using the HS Electros shield
  // reset the radio - via PB1 - pin 9
  pinMode( 9, OUTPUT );
  digitalWrite( 9, LOW );
  delay( 10 );
  digitalWrite( 9, HIGH );
  delay( 10 );
  digitalWrite( 9, LOW );
  delay( 100 );
  Serial.println(F("# Radio reset."));
#endif
#if defined (ARDUINO_AVR_XROBOTIX_DEV_BOARD)
  // XRobotiX board has reset mod to reset the radio - via PB0 - pin 8
  pinMode(8, OUTPUT);     // set PB0 as an OUTPUT pin
  digitalWrite(8, HIGH);  // RFM69 RESET pin HIGH = RESET
  delay(1);               // delay 1000us
  digitalWrite(8, LOW);   // RFM69 RESET pin LOW
  delay(10);              // wait 10ms
  Serial.println(F("# Radio reset."));
#endif
}

// ==================================================================
// Read the supply voltage and return a voltage in millivolts
// ==================================================================
// XRobotiX Board:
// There is a potential divider across the battery supply with a 2M2
// to +ve and a 560K to Gnd. There is a 100n across the 560K.
// This generates about 1.014V with 5V coming from the batteries.
// ==================================================================
// AA-Node Board:
// The AA node method does not use any external components.
// The voltatge is calculated as ( vRef x 1024 x 1000 ) / ADCReading
// which is 1.1 x 1024 x 1000 (=1126400) / ADCReading.
// ==================================================================
float readVcc()
{
  uint32_t result;
  
#if defined (ARDUINO_AVR_XROBOTIX_DEV_BOARD)
  // XRobotiX specific code
  // select 1.1v internal reference
  analogReference( INTERNAL );
  
  // read ADC channel 7 twice, ignore the first result
  analogRead(7);
  result = analogRead(7);
  
  // adc reading x 5.28 - multiply by 0xA8F5 and shift right 13 times
  // to get the voltage in millivolts - roughly!
  result = result * 0xA8F5;
  result = result>>13;
#endif

#if defined (ARDUINO_AVR_AANODE)
  // AA-Node specific code
  // enable the ADC - in case it's turned off!
  ADCSRA |= (1 << ADEN);

  // set the reference voltage to be AVcc and the signal to measure, the internal 1.1V reference
  ADMUX = (1 << REFS0) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1);
  delay(10); // Wait for Vref to settle down

  // start a conversion
  ADCSRA |= (1 << ADSC);

  // and wait for it to complete - ADSC goes low on completion
  while ( (ADCSRA & (1 << ADSC)) != 0 );

  // read the result of the conversion
  result = (uint32_t)ADC;
  result = 1126400L / result; // Calculate Vcc (in mV)
#endif

  // result is in millivolts - need volts for Domoticz
  return ((float)result) / 1000.0;
}

It's mainly for an XRobotiX board which is a clone of a Moteino board - consisting of a 328P, crystal, regulator, and a few discretes. I've added an RFM69HCW module to the rear and a daughter board that holds the DS18B20 temperature sensor as well as the potential divider to measure the battery voltage.

I couldn't get the MySensors library to work with my RFM69 boards, so I rolled my own version of it for the nodes and gateway that connects to a re-purposed thin client running Linux Lite and Domoticz.

Some boards run off 3x AA batteries and last over 6 months on one set. One board currently on month 11! Other boards are built into a cheap solar garden PIR light and are wired straight across the rechargeable battery. They just keep going as long as the battery is good and there's enough sunlight to recharge them.

Thank you Ray, helpful but is a good example of one of the things I don't understand (yet) - Why wouldn't you simply use "wdt_enable(ii);" instead of going through all that register manipulation in your setup_watchdog(ii)?

Wow, so many responses. Turns out I'm not very good at figuring out how to respond individually on this forum so I'll put all my responses here:

jremington - some documentation calls the watchdog resetting the processor an interrupt even though there's no ISR. At any rate, I get your point. I've seen that documentation before, I overlooked the point about resetting the WDT early. Thanks.

mrburnette - Ray, rather than use wdt_enable, you enable the WD by manipulating registers instead. One of my questions was why? Turns out GolamMostafa provided the answer why. Basically, if you want to use an ISR, you've got no choice - you have to learn how to manipulate the registers.

Alto777 - The LED is the on-board LED that comes with the board. Which BTW, is actually an Adafruit ItsyBitsy 32u4 (3V).

GolamMostafa - You Humble Me - Sure enough, I left off the pinmode instruction. SMH. Also, you provided the answer to why you need to manipulate the registers. You don't have a choice if you want to provide the code for the ISR. And thanks for the test sketch, It clears up a lot.

Markd833 - I'm using the Adafruit ItsyBitsy 32u4 (3V). You provided an example of "LowPower.powerDown(...)" - I haven't had time to try that out yet but if that does what I think it does, it's the single like of code that solves all my problems in the world (well not all). Thank you.

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