diff --git a/Examples/powerDownMoreTime_LongWatchDog/powerDownMoreTime_LongWatchDog.ino b/Examples/powerDownMoreTime_LongWatchDog/powerDownMoreTime_LongWatchDog.ino
new file mode 100644
index 0000000..611dc88
--- /dev/null
+++ b/Examples/powerDownMoreTime_LongWatchDog/powerDownMoreTime_LongWatchDog.ino
@@ -0,0 +1,90 @@
+//Choose one of these see the samples
+#define TEST_LOWPOWER
+//#define TEST_LONGWATCHDOG
+//#define TEST_LOWPOWER_AND_LONGWATCHDOG
+
+#include "LowPower.h"
+
+#ifndef TEST_LOWPOWER
+ //This is the code if you want to use the AUTOLONGRESET feature, only define AUTOLONGRESETcounterMAX. You could put a watchdog feature for minutes, even hours.
+ #include "avr/wdt.h"
+ #define AUTOLONGRESETcounterMAX 3 //Number of times of ISR(WDT_vect) to autoreset the board. I will autoreset the board after 8 secondes x AUTOLONGRESETcounterMAX
+ volatile boolean autoLongResetCounterEnabled = false;
+ volatile int autoLongResetCounter;
+ void ISR_RUTINE() { //This function is declared as WEAK in LowPower library, so you can override if you want.
+ if (autoLongResetCounterEnabled) {
+ autoLongResetCounter += 1;
+ if (autoLongResetCounter < AUTOLONGRESETcounterMAX - 1) { //-1 is because of the next lines (see: WDTCSR = 0b00001000 | 0b100001;) I will wait again 8 seconds
+ wdt_reset(); // Reset timer, still in interrupt mode
+ } else {
+ wdt_enabled(WDTO_8S);
+ MCUSR = 0;
+ WDTCSR |= 0b00011000; //WDCE y WDE = 1 --> config mode
+ WDTCSR = 0b00001000 | 0b100001; //clear WDIE (interrupt mode disabled), set WDE (reset mode enabled) and set interval to 8 seconds
+ //We could take out "-1" from "if" and sleep here for 64 ms, but I prefer to repeat the 8s loop again, finally I get what I want.
+ }
+ } else {
+ // It is only for sleep (autoLongResetCounterEnabled = false), so I copy source code from LowPower.h
+ // WDIE & WDIF is cleared in hardware upon entering this ISR
+ wdt_disable();
+ }
+ }
+
+ void wdt_long_enable() {
+ autoLongResetCounter = 0;
+ autoLongResetCounterEnabled = true;
+ cli(); //disabled ints
+ MCUSR = 0; //clear reset status
+ WDTCSR |= 0b00011000; //WDCE y WDE = 1 --> config mode
+ WDTCSR = 0b01000000 | 0b100001; //set WDIE (interrupt mode enabled), clear WDE (reset mode disabled) and set interval to 8 seconds
+ sei(); //enable ints
+ }
+
+ void wdt_long_disable() {
+ autoLongResetCounterEnabled = false;
+ wdt_disable();
+ }
+#endif
+
+void setup() {
+#ifndef TEST_LOWPOWER
+ wdt_long_disable();
+#endif
+
+ pinMode(13, OUTPUT);
+ digitalWrite(13, LOW);
+
+ Serial.begin(115200);
+ Serial.println("LowPower ISR weak TEST - FROM SETUP");
+ delay(100);
+#ifndef TEST_LOWPOWER
+ wdt_long_enable(); //You have to enabled it when you want.
+#endif
+}
+
+void loop() {
+#ifdef TEST_LONGWATCHDOG
+ //In real sketch you have to remove the comment in the next line
+ //wdt_long_enable(); //Each loop, or each time you want, you have to reenable it to "reset" the timer,
+ // otherwise, after AUTOLONGRESETcounterMAX x 8 seconds, your arduino will autoreset itself.
+ delay(1000);
+ Serial.print(millis()/1000);
+ Serial.println(" seconds"); //After AUTOLONGRESETcounterMAX x 8 seconds you will see again the "LowPower ISR weak TEST - FROM SETUP" that is printed in SETUP,
+ //That is meant that the IC has autoreseted itself.
+#endif
+#ifdef TEST_LOWPOWER
+ LowPower.powerDownMoreTime(10, ADC_OFF, BOD_OFF); //Working perfectly without defining a new ISR_RUTINE
+ digitalWrite(13, HIGH);
+ delay(500);
+ digitalWrite(13, LOW);
+#endif
+#ifdef TEST_LOWPOWER_AND_LONGWATCHDOG
+ wdt_long_disable(); //Disable WatchDog before sleeping.
+ LowPower.powerDownMoreTime(10, ADC_OFF, BOD_OFF); //Working perfectly defining my new special ISR_RUTINE that can give me a LONG WATCHDOG AUTORESET feature
+ wdt_long_enable(); //Enabe it again
+ digitalWrite(13, HIGH);
+ delay(500);
+ digitalWrite(13, LOW);
+ delay(100000); //With this delay, it will autoreset
+#endif
+}
diff --git a/LowPower.cpp b/LowPower.cpp
index 5543bd6..448942b 100644
--- a/LowPower.cpp
+++ b/LowPower.cpp
@@ -1,7 +1,7 @@
/*******************************************************************************
* LowPower Library
-* Version: 1.60
-* Date: 01-04-2016
+* Version: 1.70
+* Date: 11-20-2017
* Author: Lim Phang Moh
* Company: Rocket Scream Electronics
* Website: www.rocketscream.com
@@ -13,6 +13,9 @@
*
* Revision Description
* ======== ===========
+* 1.70 Added support for ATTINY85, ATTINY84 and declare ISR_RUTINE weak for
+* your own ISR_RUTINE in your sketch
+* Add powerDownMoreTime function to sleep more than 8 seconds.
* 1.60 Added support for ATmega256RFR2. Contributed by Rodmg.
* 1.50 Fixed compiler optimization (Arduino IDE 1.6.x branch) on BOD enable
* function that causes the function to be over optimized.
@@ -625,6 +628,49 @@ void LowPowerClass::idle(period_t period, adc_t adc, timer5_t timer5,
#endif
+#if defined (__AVR_ATtiny85__) || defined (__AVR_ATtiny84__)
+void LowPowerClass::idle(period_t period, adc_t adc, timer1_t timer1, timer0_t timer0, usi_t usi)
+{
+ // Temporary clock source variable
+ unsigned char clockSource = 0;
+
+ if (adc == ADC_OFF)
+ {
+ ADCSRA &= ~(1 << ADEN);
+ power_adc_disable();
+ }
+
+ if (timer1 == TIMER1_OFF) power_timer1_disable();
+ if (timer0 == TIMER0_OFF) power_timer0_disable();
+ if (usi == USI_OFF) power_usi_disable();
+
+ if (period != SLEEP_FOREVER)
+ {
+ wdt_enable(period);
+ #if defined (__AVR_ATtiny85__) || defined (__AVR_ATtiny84__)
+ WDTCR |= (1 << WDIE);
+ #else
+ WDTCSR |= (1 << WDIE);
+ #endif
+ }
+
+ lowPowerBodOn(SLEEP_MODE_IDLE);
+
+ if (adc == ADC_OFF)
+ {
+ power_adc_enable();
+ ADCSRA |= (1 << ADEN);
+ }
+
+ if (timer1 == TIMER1_OFF) power_timer1_enable();
+ if (timer0 == TIMER0_OFF) power_timer0_enable();
+ if (usi == USI_OFF) power_usi_enable();
+}
+
+#endif
+
+#if !((defined __AVR_ATtiny85__) || (defined __AVR_ATtiny84__))
+
/*******************************************************************************
* Name: adcNoiseReduction
* Description: Putting microcontroller into ADC noise reduction state. This is
@@ -700,63 +746,6 @@ void LowPowerClass::adcNoiseReduction(period_t period, adc_t adc,
#endif
}
-/*******************************************************************************
-* Name: powerDown
-* Description: Putting microcontroller into power down state. This is
-* the lowest current consumption state. Use this together with
-* external pin interrupt to wake up through external event
-* triggering (example: RTC clockout pin, SD card detect pin).
-*
-* Argument Description
-* ========= ===========
-* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake
-* up resource:
-* (a) SLEEP_15MS - 15 ms sleep
-* (b) SLEEP_30MS - 30 ms sleep
-* (c) SLEEP_60MS - 60 ms sleep
-* (d) SLEEP_120MS - 120 ms sleep
-* (e) SLEEP_250MS - 250 ms sleep
-* (f) SLEEP_500MS - 500 ms sleep
-* (g) SLEEP_1S - 1 s sleep
-* (h) SLEEP_2S - 2 s sleep
-* (i) SLEEP_4S - 4 s sleep
-* (j) SLEEP_8S - 8 s sleep
-* (k) SLEEP_FOREVER - Sleep without waking up through WDT
-*
-* 2. adc ADC module disable control. Turning off the ADC module is
-* basically removing the purpose of this low power mode.
-* (a) ADC_OFF - Turn off ADC module
-* (b) ADC_ON - Leave ADC module in its default state
-*
-* 3. bod Brown Out Detector (BOD) module disable control:
-* (a) BOD_OFF - Turn off BOD module
-* (b) BOD_ON - Leave BOD module in its default state
-*
-*******************************************************************************/
-void LowPowerClass::powerDown(period_t period, adc_t adc, bod_t bod)
-{
- if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN);
-
- if (period != SLEEP_FOREVER)
- {
- wdt_enable(period);
- WDTCSR |= (1 << WDIE);
- }
- if (bod == BOD_OFF)
- {
- #if defined __AVR_ATmega328P__
- lowPowerBodOff(SLEEP_MODE_PWR_DOWN);
- #else
- lowPowerBodOn(SLEEP_MODE_PWR_DOWN);
- #endif
- }
- else
- {
- lowPowerBodOn(SLEEP_MODE_PWR_DOWN);
- }
-
- if (adc == ADC_OFF) ADCSRA |= (1 << ADEN);
-}
/*******************************************************************************
* Name: powerSave
@@ -996,20 +985,101 @@ void LowPowerClass::powerExtStandby(period_t period, adc_t adc, bod_t bod,
}
#endif
}
+#endif
+
+
+/*******************************************************************************
+* Name: powerDown
+* Description: Putting microcontroller into power down state. This is
+* the lowest current consumption state. Use this together with
+* external pin interrupt to wake up through external event
+* triggering (example: RTC clockout pin, SD card detect pin).
+*
+* Argument Description
+* ========= ===========
+* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake
+* up resource:
+* (a) SLEEP_15MS - 15 ms sleep
+* (b) SLEEP_30MS - 30 ms sleep
+* (c) SLEEP_60MS - 60 ms sleep
+* (d) SLEEP_120MS - 120 ms sleep
+* (e) SLEEP_250MS - 250 ms sleep
+* (f) SLEEP_500MS - 500 ms sleep
+* (g) SLEEP_1S - 1 s sleep
+* (h) SLEEP_2S - 2 s sleep
+* (i) SLEEP_4S - 4 s sleep
+* (j) SLEEP_8S - 8 s sleep
+* (k) SLEEP_FOREVER - Sleep without waking up through WDT
+*
+* 2. adc ADC module disable control. Turning off the ADC module is
+* basically removing the purpose of this low power mode.
+* (a) ADC_OFF - Turn off ADC module
+* (b) ADC_ON - Leave ADC module in its default state
+*
+* 3. bod Brown Out Detector (BOD) module disable control:
+* (a) BOD_OFF - Turn off BOD module
+* (b) BOD_ON - Leave BOD module in its default state
+*
+*******************************************************************************/
+void LowPowerClass::powerDown(period_t period, adc_t adc, bod_t bod)
+{
+ if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN);
+
+ if (period != SLEEP_FOREVER)
+ {
+ wdt_enable(period);
+ #if defined (__AVR_ATtiny85__) || defined (__AVR_ATtiny84__)
+ WDTCR |= (1 << WDIE);
+ #else
+ WDTCSR |= (1 << WDIE);
+ #endif
+ }
+ if (bod == BOD_OFF)
+ {
+ #if defined __AVR_ATmega328P__
+ lowPowerBodOff(SLEEP_MODE_PWR_DOWN);
+ #else
+ lowPowerBodOn(SLEEP_MODE_PWR_DOWN);
+ #endif
+ }
+ else
+ {
+ lowPowerBodOn(SLEEP_MODE_PWR_DOWN);
+ }
+
+ if (adc == ADC_OFF) ADCSRA |= (1 << ADEN);
+}
+
+
+void LowPowerClass::powerDownMoreTime(unsigned long seconds, adc_t adc, bod_t bod)
+{
+ while (seconds >= 8) {powerDown(SLEEP_8S, adc, bod); seconds -=8; }
+ if (seconds >= 4) {powerDown(SLEEP_4S, adc, bod); seconds -=4; }
+ if (seconds >= 2) {powerDown(SLEEP_2S, adc, bod); seconds -=2; }
+ if (seconds >= 1) {powerDown(SLEEP_1S, adc, bod); seconds -=1; }
+}
+
+
/*******************************************************************************
* Name: ISR (WDT_vect)
* Description: Watchdog Timer interrupt service routine. This routine is
* required to allow automatic WDIF and WDIE bit clearance in
-* hardware.
+* hardware. You could override ISR_RUTINE in your sketch
*
*******************************************************************************/
-ISR (WDT_vect)
-{
+__attribute__((weak))
+void ISR_RUTINE() {
// WDIE & WDIF is cleared in hardware upon entering this ISR
- wdt_disable();
+ wdt_disable();
+}
+ISR (WDT_vect)
+{
+ ISR_RUTINE();
}
+
+
#elif defined (__arm__)
#if defined (__SAMD21G18A__)
/*******************************************************************************
diff --git a/LowPower.h b/LowPower.h
index 82f6f44..8df0225 100644
--- a/LowPower.h
+++ b/LowPower.h
@@ -115,6 +115,12 @@ enum idle_t
IDLE_2
};
+enum usi_t
+{
+ USI_OFF,
+ USI_ON
+};
+
class LowPowerClass
{
public:
@@ -140,14 +146,22 @@ class LowPowerClass
void idle(period_t period, adc_t adc, timer4_t timer4,
timer3_t timer3, timer1_t timer1, timer0_t timer0,
spi_t spi, usart1_t usart1, twi_t twi, usb_t usb);
+ #elif (defined __AVR_ATtiny85__) || (defined __AVR_ATtiny84__)
+ void idle(period_t period, adc_t adc, timer1_t timer1, timer0_t timer0, usi_t usi);
#else
#error "Please ensure chosen MCU is either 168, 328P, 32U4, 2560 or 256RFR2."
#endif
+
+ #if !((defined __AVR_ATtiny85__) || (defined __AVR_ATtiny84__))
void adcNoiseReduction(period_t period, adc_t adc, timer2_t timer2) __attribute__((optimize("-O1")));
- void powerDown(period_t period, adc_t adc, bod_t bod) __attribute__((optimize("-O1")));
void powerSave(period_t period, adc_t adc, bod_t bod, timer2_t timer2) __attribute__((optimize("-O1")));
void powerStandby(period_t period, adc_t adc, bod_t bod) __attribute__((optimize("-O1")));
void powerExtStandby(period_t period, adc_t adc, bod_t bod, timer2_t timer2) __attribute__((optimize("-O1")));
+ #endif
+
+ void powerDown(period_t period, adc_t adc, bod_t bod) __attribute__((optimize("-O1")));
+ void powerDownMoreTime(unsigned long seconds, adc_t adc, bod_t bod) __attribute__((optimize("-O1")));
+
#elif defined (__arm__)
diff --git a/README.md b/README.md
index c241cad..c37ec12 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
### Low-Power
Lightweight low power library for Arduino.
-Version: 1.60
+Version: 1.70
Date: 01-04-2016
@@ -12,6 +12,8 @@ Devices Supported:
* ATMega2560
* ATMega256RFR2
* ATSAMD21G18A
+* ATTINY85
+* ATTINY84
####Notes:
External interrupt during standby on ATSAMD21G18A requires a patch to the Arduino SAMD Core in order for it to work. Fix is provided by this particular pull request.
diff --git a/keywords.txt b/keywords.txt
index c01a5b8..07134f0 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -13,6 +13,8 @@
idle KEYWORD2
adcNoiseReduction KEYWORD2
powerDown KEYWORD2
+powerDownMoreTime KEYWORD2
+ISR_RUTINE KEYWORD2
powerSave KEYWORD2
powerStandby KEYWORD2
powerExtStandby KEYWORD2
diff --git a/library.properties b/library.properties
index 1ba34b5..f62a484 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
name=Low-Power
-version=1.6
+version=1.7
author=Rocket Scream Electronics
maintainer=Rocket Scream Electronics
sentence=Lightweight power management library