/* a trial of sleep and watchdog behaviour
*
* also see for the test_watchdog_behaviour project
*
* ! NOTE: on hardware make sure, the fuse WDTON is unprogrammed, i.e. set to "1"
* (see for datasheet, chapter "Register description")
*
*/
#include <avr/wdt.h> // library for default watchdog functions
#include <avr/sleep.h> // library for some sleep (power save) functions
#include <avr/interrupt.h> // library for interrupts handling
#include <avr/power.h> // library for some sleep (power save) functions
// variables ...
uint8_t ledState;
// defines for WDT timeout
#define WDT_TO_16ms 0
#define WDT_TO_32ms (1 << WDP0)
#define WDT_TO_64ms (1 << WDP1)
#define WDT_TO_125ms (1 << WDP1) | (1 << WDP0)
#define WDT_TO_250ms (1 << WDP2)
#define WDT_TO_500ms (1 << WDP2) | (1 << WDP0)
#define WDT_TO_1s (1 << WDP2) | (1 << WDP1)
#define WDT_TO_2s (1 << WDP2) | (1 << WDP1) | (1 << WDP0)
#define WDT_TO_4s (1 << WDP3)
#define WDT_TO_8s (1 << WDP3) | (1 << WDP0)
// other HW defines
#define LED_PIN 13
// fwd declaration of (watchdog) functions
void wdtReset();
void wdtConfig();
void toggleLed();
// aux functions and IRS
ISR(WDT_vect) {
// the watch dog interrupt detection
// if the MCU was in a sleep mode, wake up, particularly the peripherals, where applicable
// reset the watchdog (timer/ counter)
wdtReset();
Serial.print("watchdog triggered at ");
Serial.println(millis());
toggleLed();
}
void wdtConfig() {
// disable interrupts for changing the registers
cli();
// reset status register flags
MCUSR = 0;
WDTCSR |= (1 << WDCE) | (1 << WDE); // Set WDCE (5th from left) and WDE (4th from left) to enter config mode,
// Put timer in interrupt-only mode:
WDTCSR = (1 << WDIE) | WDT_TO_4s; // set WDIE: interrupt enabled (reset disabled), and set delay interval
// re-enable interrupts
sei();
}
void wdtReset() {
wdt_reset();
}
void toggleLed() {
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
}
void sleepMode() {
Serial.println("going to sleep");
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
// Turn off the ADC while asleep.
power_adc_disable();
sleep_enable();
sleep_mode(); // does the simulator support this?
// continue code upon interrupt from here
sleep_disable();
power_all_enable();
Serial.println("awake again");
}
// --- end aux functions
void setup() {
// put your setup code here, to run once:
Serial.begin(19200);
wdtConfig();
Serial.println("watchdog started");
pinMode(LED_PIN, OUTPUT);
ledState = 0;
digitalWrite(LED_PIN, ledState);
}
void loop() {
// put your main code here, to run repeatedly, note, that it will be interrupted by the watchdog timer
// do something
// for low power, put the MCU to sleep now
sleepMode();
/* I expected the following to happen:
1. output message: watchdog started
loop of output {
2. going to sleep
... timeout acc to watchdog config
3. watchdog triggered at <millis()>
4. awake again
}
but not working in the simulator - real HW does work correctly, so, sleep is not supported yet (April 2024)
*/
}