diff --git a/LowPower.cpp b/LowPower.cpp new file mode 100644 index 0000000..5543bd6 --- /dev/null +++ b/LowPower.cpp @@ -0,0 +1,1062 @@ +/******************************************************************************* +* LowPower Library +* Version: 1.60 +* Date: 01-04-2016 +* Author: Lim Phang Moh +* Company: Rocket Scream Electronics +* Website: www.rocketscream.com +* +* This is a lightweight low power library for Arduino. +* +* This library is licensed under Creative Commons Attribution-ShareAlike 3.0 +* Unported License. +* +* Revision Description +* ======== =========== +* 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. +* 1.40 Added support for ATSAMD21G18A. +* Library format compliant with Arduino IDE 1.5.x. +* 1.30 Added support for ATMega168, ATMega2560, ATMega1280 & ATMega32U4. +* Tested to work with Arduino IDE 1.0.1 - 1.0.4. +* 1.20 Remove typo error in idle method for checking whether Timer 0 was +* turned off. +* Remove dependecy on WProgram.h which is not required. +* Tested to work with Arduino IDE 1.0. +* 1.10 Added #ifndef for sleep_bod_disable() for compatibility with future +* Arduino IDE release. +* 1.00 Initial public release. +*******************************************************************************/ +#if defined (__AVR__) + #include + #include + #include + #include +#elif defined (__arm__) + +#else + #error "Processor architecture is not supported." +#endif + +#include "LowPower.h" + +#if defined (__AVR__) +// Only Pico Power devices can change BOD settings through software +#if defined __AVR_ATmega328P__ +#ifndef sleep_bod_disable +#define sleep_bod_disable() \ +do { \ + unsigned char tempreg; \ + __asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \ + "ori %[tempreg], %[bods_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" "\n\t" \ + "andi %[tempreg], %[not_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" \ + : [tempreg] "=&d" (tempreg) \ + : [mcucr] "I" _SFR_IO_ADDR(MCUCR), \ + [bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \ + [not_bodse] "i" (~_BV(BODSE))); \ +} while (0) +#endif +#endif + +#define lowPowerBodOn(mode) \ +do { \ + set_sleep_mode(mode); \ + cli(); \ + sleep_enable(); \ + sei(); \ + sleep_cpu(); \ + sleep_disable(); \ + sei(); \ +} while (0); + +// Only Pico Power devices can change BOD settings through software +#if defined __AVR_ATmega328P__ +#define lowPowerBodOff(mode)\ +do { \ + set_sleep_mode(mode); \ + cli(); \ + sleep_enable(); \ + sleep_bod_disable(); \ + sei(); \ + sleep_cpu(); \ + sleep_disable(); \ + sei(); \ +} while (0); +#endif + +// Some macros is still missing from AVR GCC distribution for ATmega32U4 +#if defined __AVR_ATmega32U4__ + // Timer 4 PRR bit is currently not defined in iom32u4.h + #ifndef PRTIM4 + #define PRTIM4 4 + #endif + + // Timer 4 power reduction macro is not defined currently in power.h + #ifndef power_timer4_disable + #define power_timer4_disable() (PRR1 |= (uint8_t)(1 << PRTIM4)) + #endif + + #ifndef power_timer4_enable + #define power_timer4_enable() (PRR1 &= (uint8_t)~(1 << PRTIM4)) + #endif +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega328P/168 into idle state. Please make sure you +* understand the implication and result of disabling module. +* +* 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: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +* 4. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 5. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 6. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 7. usart0 USART0 module disable control: +* (a) USART0_OFF - Turn off USART0 module +* (b) USART0_ON - Leave USART0 module in its default state +* +* 8. twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +*******************************************************************************/ +#if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__) +void LowPowerClass::idle(period_t period, adc_t adc, timer2_t timer2, + timer1_t timer1, timer0_t timer0, + spi_t spi, usart0_t usart0, twi_t twi) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + + power_timer2_disable(); + } + + 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 (spi == SPI_OFF) power_spi_disable(); + if (usart0 == USART0_OFF) power_usart0_disable(); + if (twi == TWI_OFF) power_twi_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + power_timer2_enable(); + } + + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart0 == USART0_OFF) power_usart0_enable(); + if (twi == TWI_OFF) power_twi_enable(); +} +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega32U4 into idle state. Please make sure you +* understand the implication and result of disabling module. +* Take note that Timer 2 is not available and USART0 is replaced +* with USART1 on ATmega32U4. +* +* 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: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer4 Timer 4 module disable control: +* (a) TIMER4_OFF - Turn off Timer 4 module +* (b) TIMER4_ON - Leave Timer 4 module in its default state +* +* 4. timer3 Timer 3 module disable control: +* (a) TIMER3_OFF - Turn off Timer 3 module +* (b) TIMER3_ON - Leave Timer 3 module in its default state +* +* 5. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 6. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 7. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 8. usart1 USART1 module disable control: +* (a) USART1_OFF - Turn off USART1 module +* (b) USART1_ON - Leave USART1 module in its default state +* +* 9. twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +* 10.usb USB module disable control: +* (a) USB_OFF - Turn off USB module +* (b) USB_ON - Leave USB module in its default state +*******************************************************************************/ +#if defined __AVR_ATmega32U4__ +void LowPowerClass::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) +{ + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer4 == TIMER4_OFF) power_timer4_disable(); + if (timer3 == TIMER3_OFF) power_timer3_disable(); + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart1 == USART1_OFF) power_usart1_disable(); + if (twi == TWI_OFF) power_twi_disable(); + if (usb == USB_OFF) power_usb_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer4 == TIMER4_OFF) power_timer4_enable(); + if (timer3 == TIMER3_OFF) power_timer3_enable(); + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart1 == USART1_OFF) power_usart1_enable(); + if (twi == TWI_OFF) power_twi_enable(); + if (usb == USB_OFF) power_usb_enable(); +} +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega2560 & ATmega1280 into idle state. Please make sure +* you understand the implication and result of disabling module. +* Take note that extra Timer 5, 4, 3 compared to an ATmega328P/168. +* Also take note that extra USART 3, 2, 1 compared to an +* ATmega328P/168. +* +* 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: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer5 Timer 5 module disable control: +* (a) TIMER5_OFF - Turn off Timer 5 module +* (b) TIMER5_ON - Leave Timer 5 module in its default state +* +* 4. timer4 Timer 4 module disable control: +* (a) TIMER4_OFF - Turn off Timer 4 module +* (b) TIMER4_ON - Leave Timer 4 module in its default state +* +* 5. timer3 Timer 3 module disable control: +* (a) TIMER3_OFF - Turn off Timer 3 module +* (b) TIMER3_ON - Leave Timer 3 module in its default state +* +* 6. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +* 7. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 8. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 9. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 10.usart3 USART3 module disable control: +* (a) USART3_OFF - Turn off USART3 module +* (b) USART3_ON - Leave USART3 module in its default state +* +* 11.usart2 USART2 module disable control: +* (a) USART2_OFF - Turn off USART2 module +* (b) USART2_ON - Leave USART2 module in its default state +* +* 12.usart1 USART1 module disable control: +* (a) USART1_OFF - Turn off USART1 module +* (b) USART1_ON - Leave USART1 module in its default state +* +* 13.usart0 USART0 module disable control: +* (a) USART0_OFF - Turn off USART0 module +* (b) USART0_ON - Leave USART0 module in its default state +* +* 14.twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +*******************************************************************************/ +#if defined (__AVR_ATmega2560__) || defined (__AVR_ATmega1280__) +void LowPowerClass::idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart3_t usart3, usart2_t usart2, usart1_t usart1, + usart0_t usart0, twi_t twi) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + + power_timer2_disable(); + } + + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_disable(); + if (timer4 == TIMER4_OFF) power_timer4_disable(); + if (timer3 == TIMER3_OFF) power_timer3_disable(); + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart3 == USART3_OFF) power_usart3_disable(); + if (usart2 == USART2_OFF) power_usart2_disable(); + if (usart1 == USART1_OFF) power_usart1_disable(); + if (usart0 == USART0_OFF) power_usart0_disable(); + if (twi == TWI_OFF) power_twi_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + power_timer2_enable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_enable(); + if (timer4 == TIMER4_OFF) power_timer4_enable(); + if (timer3 == TIMER3_OFF) power_timer3_enable(); + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart3 == USART3_OFF) power_usart3_enable(); + if (usart2 == USART2_OFF) power_usart2_enable(); + if (usart1 == USART1_OFF) power_usart1_enable(); + if (usart0 == USART0_OFF) power_usart0_enable(); + if (twi == TWI_OFF) power_twi_enable(); +} +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega256RFR2 into idle state. Please make sure +* you understand the implication and result of disabling module. +* Take note that extra Timer 5, 4, 3 compared to an ATmega328P/168. +* Also take note that extra USART 1 compared to an +* ATmega328P/168. +* +* 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: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer5 Timer 5 module disable control: +* (a) TIMER5_OFF - Turn off Timer 5 module +* (b) TIMER5_ON - Leave Timer 5 module in its default state +* +* 4. timer4 Timer 4 module disable control: +* (a) TIMER4_OFF - Turn off Timer 4 module +* (b) TIMER4_ON - Leave Timer 4 module in its default state +* +* 5. timer3 Timer 3 module disable control: +* (a) TIMER3_OFF - Turn off Timer 3 module +* (b) TIMER3_ON - Leave Timer 3 module in its default state +* +* 6. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +* 7. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 8. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 9. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 10.usart1 USART1 module disable control: +* (a) USART1_OFF - Turn off USART1 module +* (b) USART1_ON - Leave USART1 module in its default state +* +* 11.usart0 USART0 module disable control: +* (a) USART0_OFF - Turn off USART0 module +* (b) USART0_ON - Leave USART0 module in its default state +* +* 12.twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +*******************************************************************************/ +#if defined (__AVR_ATmega256RFR2__) +void LowPowerClass::idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart1_t usart1, + usart0_t usart0, twi_t twi) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + + power_timer2_disable(); + } + + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_disable(); + if (timer4 == TIMER4_OFF) power_timer4_disable(); + if (timer3 == TIMER3_OFF) power_timer3_disable(); + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart1 == USART1_OFF) power_usart1_disable(); + if (usart0 == USART0_OFF) power_usart0_disable(); + if (twi == TWI_OFF) power_twi_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + power_timer2_enable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_enable(); + if (timer4 == TIMER4_OFF) power_timer4_enable(); + if (timer3 == TIMER3_OFF) power_timer3_enable(); + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart1 == USART1_OFF) power_usart1_enable(); + if (usart0 == USART0_OFF) power_usart0_enable(); + if (twi == TWI_OFF) power_twi_enable(); +} +#endif + + +/******************************************************************************* +* Name: adcNoiseReduction +* Description: Putting microcontroller into ADC noise reduction state. This is +* a very useful state when using the ADC to achieve best and low +* noise signal. +* +* 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. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::adcNoiseReduction(period_t period, adc_t adc, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_ADC); + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + } + #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 +* Description: Putting microcontroller into power save state. This is +* the lowest current consumption state after power down. +* Use this state together with an external 32.768 kHz crystal (but +* 8/16 MHz crystal/resonator need to be removed) to provide an +* asynchronous clock source to Timer 2. Please take note that +* Timer 2 is also used by the Arduino core for PWM operation. +* Please refer to wiring.c for explanation. Removal of the external +* 8/16 MHz crystal/resonator requires the microcontroller to run +* on its internal RC oscillator which is not so accurate for time +* critical operation. +* +* 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 +* +* 4. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerSave(period_t period, adc_t adc, bod_t bod, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + 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_SAVE); + #else + lowPowerBodOn(SLEEP_MODE_PWR_SAVE); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_PWR_SAVE); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + } + #endif +} + +/******************************************************************************* +* Name: powerStandby +* Description: Putting microcontroller into power standby state. +* +* 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::powerStandby(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_STANDBY); + #else + lowPowerBodOn(SLEEP_MODE_STANDBY); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_STANDBY); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); +} + +/******************************************************************************* +* Name: powerExtStandby +* Description: Putting microcontroller into power extended standby state. This +* is different from the power standby state as it has the +* capability to run Timer 2 asynchronously. +* +* 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. +* (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 +* +* 4. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerExtStandby(period_t period, adc_t adc, bod_t bod, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + 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_EXT_STANDBY); + #else + lowPowerBodOn(SLEEP_MODE_EXT_STANDBY); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_EXT_STANDBY); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + } + #endif +} + +/******************************************************************************* +* Name: ISR (WDT_vect) +* Description: Watchdog Timer interrupt service routine. This routine is +* required to allow automatic WDIF and WDIE bit clearance in +* hardware. +* +*******************************************************************************/ +ISR (WDT_vect) +{ + // WDIE & WDIF is cleared in hardware upon entering this ISR + wdt_disable(); +} + +#elif defined (__arm__) +#if defined (__SAMD21G18A__) +/******************************************************************************* +* Name: standby +* Description: Putting SAMD21G18A into idle mode. This is the lowest current +* consumption mode. Requires separate handling of clock and +* peripheral management (disabling and shutting down) to achieve +* the desired current consumption. +* +* Argument Description +* ========= =========== +* 1. idleMode Idle mode level (0, 1, 2) where IDLE_2 level provide lowest +* current consumption in this mode. +* +*******************************************************************************/ +void LowPowerClass::idle(idle_t idleMode) +{ + SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; + PM->SLEEP.reg = idleMode; + __DSB(); + __WFI(); +} + +/******************************************************************************* +* Name: standby +* Description: Putting SAMD21G18A into standby mode. This is the lowest current +* consumption mode. Use this together with the built-in RTC (use +* RTCZero library) or external pin interrupt to wake up through +* external event triggering. +* +* Argument Description +* ========= =========== +* 1. NIL +* +*******************************************************************************/ +void LowPowerClass::standby() +{ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + __DSB(); + __WFI(); +} + +#else + #error "Please ensure chosen MCU is ATSAMD21G18A." +#endif +#else + #error "Processor architecture is not supported." +#endif + +LowPowerClass LowPower; diff --git a/LowPower.h b/LowPower.h new file mode 100644 index 0000000..82f6f44 --- /dev/null +++ b/LowPower.h @@ -0,0 +1,169 @@ +#ifndef LowPower_h +#define LowPower_h + +#include "Arduino.h" + +enum period_t +{ + SLEEP_15MS, + SLEEP_30MS, + SLEEP_60MS, + SLEEP_120MS, + SLEEP_250MS, + SLEEP_500MS, + SLEEP_1S, + SLEEP_2S, + SLEEP_4S, + SLEEP_8S, + SLEEP_FOREVER +}; + +enum bod_t +{ + BOD_OFF, + BOD_ON +}; + +enum adc_t +{ + ADC_OFF, + ADC_ON +}; + +enum timer5_t +{ + TIMER5_OFF, + TIMER5_ON +}; + +enum timer4_t +{ + TIMER4_OFF, + TIMER4_ON +}; + +enum timer3_t +{ + TIMER3_OFF, + TIMER3_ON +}; + +enum timer2_t +{ + TIMER2_OFF, + TIMER2_ON +}; + +enum timer1_t +{ + TIMER1_OFF, + TIMER1_ON +}; + +enum timer0_t +{ + TIMER0_OFF, + TIMER0_ON +}; + +enum spi_t +{ + SPI_OFF, + SPI_ON +}; + +enum usart0_t +{ + USART0_OFF, + USART0_ON +}; + +enum usart1_t +{ + USART1_OFF, + USART1_ON +}; + +enum usart2_t +{ + USART2_OFF, + USART2_ON +}; + +enum usart3_t +{ + USART3_OFF, + USART3_ON +}; + +enum twi_t +{ + TWI_OFF, + TWI_ON +}; + +enum usb_t +{ + USB_OFF, + USB_ON +}; + +enum idle_t +{ + IDLE_0, + IDLE_1, + IDLE_2 +}; + +class LowPowerClass +{ + public: + #if defined (__AVR__) + + #if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__) + void idle(period_t period, adc_t adc, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart0_t usart0, twi_t twi); + #elif defined __AVR_ATmega2560__ + void idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart3_t usart3, usart2_t usart2, usart1_t usart1, + usart0_t usart0, twi_t twi); + #elif defined __AVR_ATmega256RFR2__ + void idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart1_t usart1, + usart0_t usart0, twi_t twi); + #elif defined __AVR_ATmega32U4__ + 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); + #else + #error "Please ensure chosen MCU is either 168, 328P, 32U4, 2560 or 256RFR2." + #endif + 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"))); + + #elif defined (__arm__) + + #if defined (__SAMD21G18A__) + void idle(idle_t idleMode); + void standby(); + #else + #error "Please ensure chosen MCU is ATSAMD21G18A." + #endif + + #else + + #error "Processor architecture is not supported." + + #endif +}; + +extern LowPowerClass LowPower; +#endif diff --git a/old/1/tomtom.gps.auto.on/tomtom.gps.auto.on.ino b/old/1/tomtom.gps.auto.on/tomtom.gps.auto.on.ino new file mode 100644 index 0000000..f637e1b --- /dev/null +++ b/old/1/tomtom.gps.auto.on/tomtom.gps.auto.on.ino @@ -0,0 +1,49 @@ +// The TomTom Mkii Bluetooth GPS receiver does not automatically turn on when power is applied via its charging port. +// The power button must be held for approximately 1 second to turn it on. +// This program is intented to be used with an ardunio with an I/O pin connected to one of the leads of the power button +// to simulate a power button press and turn the device on as soon as the arduino powers on. + +// pin to be connected to tomtom gps power button +#define pwrbuttonpin 10 +// delay for simulated power button hold-down +#define pwrbuttondelay 1200 +// built-in led pin +#define ledpin 13 + +void setup() { + //pinMode(ledpin, OUTPUT); + + // set pwrbuttonpin pin HIGH (to 5v) + digitalWrite(pwrbuttonpin, HIGH); + + // short pwrbuttonpin to ground + // (simulate button press) + pinMode(pwrbuttonpin, OUTPUT); + //digitalWrite(ledpin, HIGH); + + // wait + delay(pwrbuttondelay); + + // disconnect pwrbuttonpin (input mode = high impediance) + // (simulate button release) + pinMode(pwrbuttonpin, INPUT); + //digitalWrite(ledpin, LOW); +} + +void loop() { + /* + delay(pwrbuttondelay); + + // short pwrbuttonpin to ground + // (simulate button press) + pinMode(pwrbuttonpin, OUTPUT); + digitalWrite(ledpin, HIGH); + + delay(pwrbuttondelay); + + // disconnect pwrbuttonpin (input mode = high impediance) + // (simulate button release) + pinMode(pwrbuttonpin, INPUT); + digitalWrite(ledpin, LOW); + */ +} diff --git a/old/2/tomtom.gps.auto.on/LowPower.cpp b/old/2/tomtom.gps.auto.on/LowPower.cpp new file mode 100644 index 0000000..5543bd6 --- /dev/null +++ b/old/2/tomtom.gps.auto.on/LowPower.cpp @@ -0,0 +1,1062 @@ +/******************************************************************************* +* LowPower Library +* Version: 1.60 +* Date: 01-04-2016 +* Author: Lim Phang Moh +* Company: Rocket Scream Electronics +* Website: www.rocketscream.com +* +* This is a lightweight low power library for Arduino. +* +* This library is licensed under Creative Commons Attribution-ShareAlike 3.0 +* Unported License. +* +* Revision Description +* ======== =========== +* 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. +* 1.40 Added support for ATSAMD21G18A. +* Library format compliant with Arduino IDE 1.5.x. +* 1.30 Added support for ATMega168, ATMega2560, ATMega1280 & ATMega32U4. +* Tested to work with Arduino IDE 1.0.1 - 1.0.4. +* 1.20 Remove typo error in idle method for checking whether Timer 0 was +* turned off. +* Remove dependecy on WProgram.h which is not required. +* Tested to work with Arduino IDE 1.0. +* 1.10 Added #ifndef for sleep_bod_disable() for compatibility with future +* Arduino IDE release. +* 1.00 Initial public release. +*******************************************************************************/ +#if defined (__AVR__) + #include + #include + #include + #include +#elif defined (__arm__) + +#else + #error "Processor architecture is not supported." +#endif + +#include "LowPower.h" + +#if defined (__AVR__) +// Only Pico Power devices can change BOD settings through software +#if defined __AVR_ATmega328P__ +#ifndef sleep_bod_disable +#define sleep_bod_disable() \ +do { \ + unsigned char tempreg; \ + __asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \ + "ori %[tempreg], %[bods_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" "\n\t" \ + "andi %[tempreg], %[not_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" \ + : [tempreg] "=&d" (tempreg) \ + : [mcucr] "I" _SFR_IO_ADDR(MCUCR), \ + [bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \ + [not_bodse] "i" (~_BV(BODSE))); \ +} while (0) +#endif +#endif + +#define lowPowerBodOn(mode) \ +do { \ + set_sleep_mode(mode); \ + cli(); \ + sleep_enable(); \ + sei(); \ + sleep_cpu(); \ + sleep_disable(); \ + sei(); \ +} while (0); + +// Only Pico Power devices can change BOD settings through software +#if defined __AVR_ATmega328P__ +#define lowPowerBodOff(mode)\ +do { \ + set_sleep_mode(mode); \ + cli(); \ + sleep_enable(); \ + sleep_bod_disable(); \ + sei(); \ + sleep_cpu(); \ + sleep_disable(); \ + sei(); \ +} while (0); +#endif + +// Some macros is still missing from AVR GCC distribution for ATmega32U4 +#if defined __AVR_ATmega32U4__ + // Timer 4 PRR bit is currently not defined in iom32u4.h + #ifndef PRTIM4 + #define PRTIM4 4 + #endif + + // Timer 4 power reduction macro is not defined currently in power.h + #ifndef power_timer4_disable + #define power_timer4_disable() (PRR1 |= (uint8_t)(1 << PRTIM4)) + #endif + + #ifndef power_timer4_enable + #define power_timer4_enable() (PRR1 &= (uint8_t)~(1 << PRTIM4)) + #endif +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega328P/168 into idle state. Please make sure you +* understand the implication and result of disabling module. +* +* 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: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +* 4. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 5. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 6. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 7. usart0 USART0 module disable control: +* (a) USART0_OFF - Turn off USART0 module +* (b) USART0_ON - Leave USART0 module in its default state +* +* 8. twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +*******************************************************************************/ +#if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__) +void LowPowerClass::idle(period_t period, adc_t adc, timer2_t timer2, + timer1_t timer1, timer0_t timer0, + spi_t spi, usart0_t usart0, twi_t twi) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + + power_timer2_disable(); + } + + 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 (spi == SPI_OFF) power_spi_disable(); + if (usart0 == USART0_OFF) power_usart0_disable(); + if (twi == TWI_OFF) power_twi_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + power_timer2_enable(); + } + + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart0 == USART0_OFF) power_usart0_enable(); + if (twi == TWI_OFF) power_twi_enable(); +} +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega32U4 into idle state. Please make sure you +* understand the implication and result of disabling module. +* Take note that Timer 2 is not available and USART0 is replaced +* with USART1 on ATmega32U4. +* +* 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: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer4 Timer 4 module disable control: +* (a) TIMER4_OFF - Turn off Timer 4 module +* (b) TIMER4_ON - Leave Timer 4 module in its default state +* +* 4. timer3 Timer 3 module disable control: +* (a) TIMER3_OFF - Turn off Timer 3 module +* (b) TIMER3_ON - Leave Timer 3 module in its default state +* +* 5. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 6. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 7. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 8. usart1 USART1 module disable control: +* (a) USART1_OFF - Turn off USART1 module +* (b) USART1_ON - Leave USART1 module in its default state +* +* 9. twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +* 10.usb USB module disable control: +* (a) USB_OFF - Turn off USB module +* (b) USB_ON - Leave USB module in its default state +*******************************************************************************/ +#if defined __AVR_ATmega32U4__ +void LowPowerClass::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) +{ + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer4 == TIMER4_OFF) power_timer4_disable(); + if (timer3 == TIMER3_OFF) power_timer3_disable(); + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart1 == USART1_OFF) power_usart1_disable(); + if (twi == TWI_OFF) power_twi_disable(); + if (usb == USB_OFF) power_usb_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer4 == TIMER4_OFF) power_timer4_enable(); + if (timer3 == TIMER3_OFF) power_timer3_enable(); + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart1 == USART1_OFF) power_usart1_enable(); + if (twi == TWI_OFF) power_twi_enable(); + if (usb == USB_OFF) power_usb_enable(); +} +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega2560 & ATmega1280 into idle state. Please make sure +* you understand the implication and result of disabling module. +* Take note that extra Timer 5, 4, 3 compared to an ATmega328P/168. +* Also take note that extra USART 3, 2, 1 compared to an +* ATmega328P/168. +* +* 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: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer5 Timer 5 module disable control: +* (a) TIMER5_OFF - Turn off Timer 5 module +* (b) TIMER5_ON - Leave Timer 5 module in its default state +* +* 4. timer4 Timer 4 module disable control: +* (a) TIMER4_OFF - Turn off Timer 4 module +* (b) TIMER4_ON - Leave Timer 4 module in its default state +* +* 5. timer3 Timer 3 module disable control: +* (a) TIMER3_OFF - Turn off Timer 3 module +* (b) TIMER3_ON - Leave Timer 3 module in its default state +* +* 6. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +* 7. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 8. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 9. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 10.usart3 USART3 module disable control: +* (a) USART3_OFF - Turn off USART3 module +* (b) USART3_ON - Leave USART3 module in its default state +* +* 11.usart2 USART2 module disable control: +* (a) USART2_OFF - Turn off USART2 module +* (b) USART2_ON - Leave USART2 module in its default state +* +* 12.usart1 USART1 module disable control: +* (a) USART1_OFF - Turn off USART1 module +* (b) USART1_ON - Leave USART1 module in its default state +* +* 13.usart0 USART0 module disable control: +* (a) USART0_OFF - Turn off USART0 module +* (b) USART0_ON - Leave USART0 module in its default state +* +* 14.twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +*******************************************************************************/ +#if defined (__AVR_ATmega2560__) || defined (__AVR_ATmega1280__) +void LowPowerClass::idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart3_t usart3, usart2_t usart2, usart1_t usart1, + usart0_t usart0, twi_t twi) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + + power_timer2_disable(); + } + + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_disable(); + if (timer4 == TIMER4_OFF) power_timer4_disable(); + if (timer3 == TIMER3_OFF) power_timer3_disable(); + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart3 == USART3_OFF) power_usart3_disable(); + if (usart2 == USART2_OFF) power_usart2_disable(); + if (usart1 == USART1_OFF) power_usart1_disable(); + if (usart0 == USART0_OFF) power_usart0_disable(); + if (twi == TWI_OFF) power_twi_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + power_timer2_enable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_enable(); + if (timer4 == TIMER4_OFF) power_timer4_enable(); + if (timer3 == TIMER3_OFF) power_timer3_enable(); + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart3 == USART3_OFF) power_usart3_enable(); + if (usart2 == USART2_OFF) power_usart2_enable(); + if (usart1 == USART1_OFF) power_usart1_enable(); + if (usart0 == USART0_OFF) power_usart0_enable(); + if (twi == TWI_OFF) power_twi_enable(); +} +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega256RFR2 into idle state. Please make sure +* you understand the implication and result of disabling module. +* Take note that extra Timer 5, 4, 3 compared to an ATmega328P/168. +* Also take note that extra USART 1 compared to an +* ATmega328P/168. +* +* 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: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer5 Timer 5 module disable control: +* (a) TIMER5_OFF - Turn off Timer 5 module +* (b) TIMER5_ON - Leave Timer 5 module in its default state +* +* 4. timer4 Timer 4 module disable control: +* (a) TIMER4_OFF - Turn off Timer 4 module +* (b) TIMER4_ON - Leave Timer 4 module in its default state +* +* 5. timer3 Timer 3 module disable control: +* (a) TIMER3_OFF - Turn off Timer 3 module +* (b) TIMER3_ON - Leave Timer 3 module in its default state +* +* 6. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +* 7. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 8. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 9. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 10.usart1 USART1 module disable control: +* (a) USART1_OFF - Turn off USART1 module +* (b) USART1_ON - Leave USART1 module in its default state +* +* 11.usart0 USART0 module disable control: +* (a) USART0_OFF - Turn off USART0 module +* (b) USART0_ON - Leave USART0 module in its default state +* +* 12.twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +*******************************************************************************/ +#if defined (__AVR_ATmega256RFR2__) +void LowPowerClass::idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart1_t usart1, + usart0_t usart0, twi_t twi) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + + power_timer2_disable(); + } + + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_disable(); + if (timer4 == TIMER4_OFF) power_timer4_disable(); + if (timer3 == TIMER3_OFF) power_timer3_disable(); + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart1 == USART1_OFF) power_usart1_disable(); + if (usart0 == USART0_OFF) power_usart0_disable(); + if (twi == TWI_OFF) power_twi_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + power_timer2_enable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_enable(); + if (timer4 == TIMER4_OFF) power_timer4_enable(); + if (timer3 == TIMER3_OFF) power_timer3_enable(); + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart1 == USART1_OFF) power_usart1_enable(); + if (usart0 == USART0_OFF) power_usart0_enable(); + if (twi == TWI_OFF) power_twi_enable(); +} +#endif + + +/******************************************************************************* +* Name: adcNoiseReduction +* Description: Putting microcontroller into ADC noise reduction state. This is +* a very useful state when using the ADC to achieve best and low +* noise signal. +* +* 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. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::adcNoiseReduction(period_t period, adc_t adc, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_ADC); + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + } + #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 +* Description: Putting microcontroller into power save state. This is +* the lowest current consumption state after power down. +* Use this state together with an external 32.768 kHz crystal (but +* 8/16 MHz crystal/resonator need to be removed) to provide an +* asynchronous clock source to Timer 2. Please take note that +* Timer 2 is also used by the Arduino core for PWM operation. +* Please refer to wiring.c for explanation. Removal of the external +* 8/16 MHz crystal/resonator requires the microcontroller to run +* on its internal RC oscillator which is not so accurate for time +* critical operation. +* +* 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 +* +* 4. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerSave(period_t period, adc_t adc, bod_t bod, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + 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_SAVE); + #else + lowPowerBodOn(SLEEP_MODE_PWR_SAVE); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_PWR_SAVE); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + } + #endif +} + +/******************************************************************************* +* Name: powerStandby +* Description: Putting microcontroller into power standby state. +* +* 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::powerStandby(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_STANDBY); + #else + lowPowerBodOn(SLEEP_MODE_STANDBY); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_STANDBY); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); +} + +/******************************************************************************* +* Name: powerExtStandby +* Description: Putting microcontroller into power extended standby state. This +* is different from the power standby state as it has the +* capability to run Timer 2 asynchronously. +* +* 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. +* (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 +* +* 4. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerExtStandby(period_t period, adc_t adc, bod_t bod, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + 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_EXT_STANDBY); + #else + lowPowerBodOn(SLEEP_MODE_EXT_STANDBY); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_EXT_STANDBY); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + } + #endif +} + +/******************************************************************************* +* Name: ISR (WDT_vect) +* Description: Watchdog Timer interrupt service routine. This routine is +* required to allow automatic WDIF and WDIE bit clearance in +* hardware. +* +*******************************************************************************/ +ISR (WDT_vect) +{ + // WDIE & WDIF is cleared in hardware upon entering this ISR + wdt_disable(); +} + +#elif defined (__arm__) +#if defined (__SAMD21G18A__) +/******************************************************************************* +* Name: standby +* Description: Putting SAMD21G18A into idle mode. This is the lowest current +* consumption mode. Requires separate handling of clock and +* peripheral management (disabling and shutting down) to achieve +* the desired current consumption. +* +* Argument Description +* ========= =========== +* 1. idleMode Idle mode level (0, 1, 2) where IDLE_2 level provide lowest +* current consumption in this mode. +* +*******************************************************************************/ +void LowPowerClass::idle(idle_t idleMode) +{ + SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; + PM->SLEEP.reg = idleMode; + __DSB(); + __WFI(); +} + +/******************************************************************************* +* Name: standby +* Description: Putting SAMD21G18A into standby mode. This is the lowest current +* consumption mode. Use this together with the built-in RTC (use +* RTCZero library) or external pin interrupt to wake up through +* external event triggering. +* +* Argument Description +* ========= =========== +* 1. NIL +* +*******************************************************************************/ +void LowPowerClass::standby() +{ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + __DSB(); + __WFI(); +} + +#else + #error "Please ensure chosen MCU is ATSAMD21G18A." +#endif +#else + #error "Processor architecture is not supported." +#endif + +LowPowerClass LowPower; diff --git a/old/2/tomtom.gps.auto.on/LowPower.h b/old/2/tomtom.gps.auto.on/LowPower.h new file mode 100644 index 0000000..82f6f44 --- /dev/null +++ b/old/2/tomtom.gps.auto.on/LowPower.h @@ -0,0 +1,169 @@ +#ifndef LowPower_h +#define LowPower_h + +#include "Arduino.h" + +enum period_t +{ + SLEEP_15MS, + SLEEP_30MS, + SLEEP_60MS, + SLEEP_120MS, + SLEEP_250MS, + SLEEP_500MS, + SLEEP_1S, + SLEEP_2S, + SLEEP_4S, + SLEEP_8S, + SLEEP_FOREVER +}; + +enum bod_t +{ + BOD_OFF, + BOD_ON +}; + +enum adc_t +{ + ADC_OFF, + ADC_ON +}; + +enum timer5_t +{ + TIMER5_OFF, + TIMER5_ON +}; + +enum timer4_t +{ + TIMER4_OFF, + TIMER4_ON +}; + +enum timer3_t +{ + TIMER3_OFF, + TIMER3_ON +}; + +enum timer2_t +{ + TIMER2_OFF, + TIMER2_ON +}; + +enum timer1_t +{ + TIMER1_OFF, + TIMER1_ON +}; + +enum timer0_t +{ + TIMER0_OFF, + TIMER0_ON +}; + +enum spi_t +{ + SPI_OFF, + SPI_ON +}; + +enum usart0_t +{ + USART0_OFF, + USART0_ON +}; + +enum usart1_t +{ + USART1_OFF, + USART1_ON +}; + +enum usart2_t +{ + USART2_OFF, + USART2_ON +}; + +enum usart3_t +{ + USART3_OFF, + USART3_ON +}; + +enum twi_t +{ + TWI_OFF, + TWI_ON +}; + +enum usb_t +{ + USB_OFF, + USB_ON +}; + +enum idle_t +{ + IDLE_0, + IDLE_1, + IDLE_2 +}; + +class LowPowerClass +{ + public: + #if defined (__AVR__) + + #if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__) + void idle(period_t period, adc_t adc, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart0_t usart0, twi_t twi); + #elif defined __AVR_ATmega2560__ + void idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart3_t usart3, usart2_t usart2, usart1_t usart1, + usart0_t usart0, twi_t twi); + #elif defined __AVR_ATmega256RFR2__ + void idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart1_t usart1, + usart0_t usart0, twi_t twi); + #elif defined __AVR_ATmega32U4__ + 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); + #else + #error "Please ensure chosen MCU is either 168, 328P, 32U4, 2560 or 256RFR2." + #endif + 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"))); + + #elif defined (__arm__) + + #if defined (__SAMD21G18A__) + void idle(idle_t idleMode); + void standby(); + #else + #error "Please ensure chosen MCU is ATSAMD21G18A." + #endif + + #else + + #error "Processor architecture is not supported." + + #endif +}; + +extern LowPowerClass LowPower; +#endif diff --git a/old/2/tomtom.gps.auto.on/tomtom.gps.auto.on.ino b/old/2/tomtom.gps.auto.on/tomtom.gps.auto.on.ino new file mode 100644 index 0000000..99459c5 --- /dev/null +++ b/old/2/tomtom.gps.auto.on/tomtom.gps.auto.on.ino @@ -0,0 +1,98 @@ +#include "LowPower.h" + +// The TomTom Mkii Bluetooth GPS receiver does not automatically turn on when power is applied via its charging port. +// The power button must be held for approximately 1 second to turn it on. +// This program is intented to be used with an ardunio with an I/O pin connected to one of the leads of the power button +// to simulate a power button press and turn the device on as soon as the arduino powers on. + +const int ledpin = 13; // built-in led pin +const int pwrbuttonpin = 10; //[BLUE] pin to be connected to tomtom gps power button +const int inputpowerpin = 2; //[RED] pin to be connected to positive voltage of power adaptor jack (NEED external pulldown) +const int gpspowerpin = 9; //[YELLOW] pin to be connected to GPS circuit to detect when GPS is powered on + +// delay for simulated power button hold-down (ms) +const int pwrbuttondelay = 1300; + +// how many power button presses we need to do +volatile unsigned int presses = 0; + +volatile byte ledstate = LOW; // built-in led state +byte inputpowerpin_state = LOW; // inputpowerpin state +byte inputpowerpin_state_last = LOW; // last inputpowerpin state +byte inputpowerpin_state_stab = LOW; +byte inputpowerpin_state_stab_last = LOW; + +unsigned long lastDebounceTime = 0; +unsigned long debounceDelay = 100; + +void press_power_button() { + // short pwrbuttonpin to HIGH + // (simulate button press) + digitalWrite(pwrbuttonpin, HIGH); + pinMode(pwrbuttonpin, OUTPUT); + + digitalWrite(ledpin, HIGH); + + // wait + delay(pwrbuttondelay); + + // "disconnect" pwrbuttonpin (input mode = high impediance) + // (simulate button release) + pinMode(pwrbuttonpin, INPUT); + digitalWrite(pwrbuttonpin, LOW); + + digitalWrite(ledpin, LOW); + +} + +void power_state_check() { + if (digitalRead(inputpowerpin) != digitalRead(gpspowerpin)) { + presses++; + } + ledstate = !ledstate; + Serial.print(ledstate); + Serial.println(" change"); +} + +void setup() { + Serial.begin(9600); + + pinMode(ledpin, OUTPUT); + + // set pwrbuttonpin pin low (to gnd?) + pinMode(pwrbuttonpin, INPUT); + digitalWrite(pwrbuttonpin, LOW); + + // probably only using interrupt for lowerpower wakeup + // attachInterrupt(digitalPinToInterrupt(inputpowerpin), power_state_check, CHANGE); + +} + +void loop() { + + // read powerbuttonpin + inputpowerpin_state = digitalRead(inputpowerpin); + // every time inputpowerpin changes, reset debounce timer + if (inputpowerpin_state != inputpowerpin_state_last) { + lastDebounceTime = millis(); + } + + // if inputpowerpin state has not changed in (debounceDelay)ms then accept current state + if((millis() - lastDebounceTime) > debounceDelay) { + // store new stable state + inputpowerpin_state_stab = inputpowerpin_state; + } + + if (inputpowerpin_state_stab != inputpowerpin_state_stab_last) { + // ledstate = !ledstate; + if (inputpowerpin_state_stab != digitalRead(gpspowerpin)) { + press_power_button(); + } + } + + // store last states for debouncing and stable state + inputpowerpin_state_stab_last = inputpowerpin_state_stab; + inputpowerpin_state_last = inputpowerpin_state; + + +} diff --git a/old/3/tomtom.gps.auto.on/LowPower.cpp b/old/3/tomtom.gps.auto.on/LowPower.cpp new file mode 100644 index 0000000..5543bd6 --- /dev/null +++ b/old/3/tomtom.gps.auto.on/LowPower.cpp @@ -0,0 +1,1062 @@ +/******************************************************************************* +* LowPower Library +* Version: 1.60 +* Date: 01-04-2016 +* Author: Lim Phang Moh +* Company: Rocket Scream Electronics +* Website: www.rocketscream.com +* +* This is a lightweight low power library for Arduino. +* +* This library is licensed under Creative Commons Attribution-ShareAlike 3.0 +* Unported License. +* +* Revision Description +* ======== =========== +* 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. +* 1.40 Added support for ATSAMD21G18A. +* Library format compliant with Arduino IDE 1.5.x. +* 1.30 Added support for ATMega168, ATMega2560, ATMega1280 & ATMega32U4. +* Tested to work with Arduino IDE 1.0.1 - 1.0.4. +* 1.20 Remove typo error in idle method for checking whether Timer 0 was +* turned off. +* Remove dependecy on WProgram.h which is not required. +* Tested to work with Arduino IDE 1.0. +* 1.10 Added #ifndef for sleep_bod_disable() for compatibility with future +* Arduino IDE release. +* 1.00 Initial public release. +*******************************************************************************/ +#if defined (__AVR__) + #include + #include + #include + #include +#elif defined (__arm__) + +#else + #error "Processor architecture is not supported." +#endif + +#include "LowPower.h" + +#if defined (__AVR__) +// Only Pico Power devices can change BOD settings through software +#if defined __AVR_ATmega328P__ +#ifndef sleep_bod_disable +#define sleep_bod_disable() \ +do { \ + unsigned char tempreg; \ + __asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \ + "ori %[tempreg], %[bods_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" "\n\t" \ + "andi %[tempreg], %[not_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" \ + : [tempreg] "=&d" (tempreg) \ + : [mcucr] "I" _SFR_IO_ADDR(MCUCR), \ + [bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \ + [not_bodse] "i" (~_BV(BODSE))); \ +} while (0) +#endif +#endif + +#define lowPowerBodOn(mode) \ +do { \ + set_sleep_mode(mode); \ + cli(); \ + sleep_enable(); \ + sei(); \ + sleep_cpu(); \ + sleep_disable(); \ + sei(); \ +} while (0); + +// Only Pico Power devices can change BOD settings through software +#if defined __AVR_ATmega328P__ +#define lowPowerBodOff(mode)\ +do { \ + set_sleep_mode(mode); \ + cli(); \ + sleep_enable(); \ + sleep_bod_disable(); \ + sei(); \ + sleep_cpu(); \ + sleep_disable(); \ + sei(); \ +} while (0); +#endif + +// Some macros is still missing from AVR GCC distribution for ATmega32U4 +#if defined __AVR_ATmega32U4__ + // Timer 4 PRR bit is currently not defined in iom32u4.h + #ifndef PRTIM4 + #define PRTIM4 4 + #endif + + // Timer 4 power reduction macro is not defined currently in power.h + #ifndef power_timer4_disable + #define power_timer4_disable() (PRR1 |= (uint8_t)(1 << PRTIM4)) + #endif + + #ifndef power_timer4_enable + #define power_timer4_enable() (PRR1 &= (uint8_t)~(1 << PRTIM4)) + #endif +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega328P/168 into idle state. Please make sure you +* understand the implication and result of disabling module. +* +* 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: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +* 4. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 5. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 6. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 7. usart0 USART0 module disable control: +* (a) USART0_OFF - Turn off USART0 module +* (b) USART0_ON - Leave USART0 module in its default state +* +* 8. twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +*******************************************************************************/ +#if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__) +void LowPowerClass::idle(period_t period, adc_t adc, timer2_t timer2, + timer1_t timer1, timer0_t timer0, + spi_t spi, usart0_t usart0, twi_t twi) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + + power_timer2_disable(); + } + + 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 (spi == SPI_OFF) power_spi_disable(); + if (usart0 == USART0_OFF) power_usart0_disable(); + if (twi == TWI_OFF) power_twi_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + power_timer2_enable(); + } + + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart0 == USART0_OFF) power_usart0_enable(); + if (twi == TWI_OFF) power_twi_enable(); +} +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega32U4 into idle state. Please make sure you +* understand the implication and result of disabling module. +* Take note that Timer 2 is not available and USART0 is replaced +* with USART1 on ATmega32U4. +* +* 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: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer4 Timer 4 module disable control: +* (a) TIMER4_OFF - Turn off Timer 4 module +* (b) TIMER4_ON - Leave Timer 4 module in its default state +* +* 4. timer3 Timer 3 module disable control: +* (a) TIMER3_OFF - Turn off Timer 3 module +* (b) TIMER3_ON - Leave Timer 3 module in its default state +* +* 5. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 6. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 7. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 8. usart1 USART1 module disable control: +* (a) USART1_OFF - Turn off USART1 module +* (b) USART1_ON - Leave USART1 module in its default state +* +* 9. twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +* 10.usb USB module disable control: +* (a) USB_OFF - Turn off USB module +* (b) USB_ON - Leave USB module in its default state +*******************************************************************************/ +#if defined __AVR_ATmega32U4__ +void LowPowerClass::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) +{ + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer4 == TIMER4_OFF) power_timer4_disable(); + if (timer3 == TIMER3_OFF) power_timer3_disable(); + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart1 == USART1_OFF) power_usart1_disable(); + if (twi == TWI_OFF) power_twi_disable(); + if (usb == USB_OFF) power_usb_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer4 == TIMER4_OFF) power_timer4_enable(); + if (timer3 == TIMER3_OFF) power_timer3_enable(); + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart1 == USART1_OFF) power_usart1_enable(); + if (twi == TWI_OFF) power_twi_enable(); + if (usb == USB_OFF) power_usb_enable(); +} +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega2560 & ATmega1280 into idle state. Please make sure +* you understand the implication and result of disabling module. +* Take note that extra Timer 5, 4, 3 compared to an ATmega328P/168. +* Also take note that extra USART 3, 2, 1 compared to an +* ATmega328P/168. +* +* 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: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer5 Timer 5 module disable control: +* (a) TIMER5_OFF - Turn off Timer 5 module +* (b) TIMER5_ON - Leave Timer 5 module in its default state +* +* 4. timer4 Timer 4 module disable control: +* (a) TIMER4_OFF - Turn off Timer 4 module +* (b) TIMER4_ON - Leave Timer 4 module in its default state +* +* 5. timer3 Timer 3 module disable control: +* (a) TIMER3_OFF - Turn off Timer 3 module +* (b) TIMER3_ON - Leave Timer 3 module in its default state +* +* 6. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +* 7. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 8. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 9. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 10.usart3 USART3 module disable control: +* (a) USART3_OFF - Turn off USART3 module +* (b) USART3_ON - Leave USART3 module in its default state +* +* 11.usart2 USART2 module disable control: +* (a) USART2_OFF - Turn off USART2 module +* (b) USART2_ON - Leave USART2 module in its default state +* +* 12.usart1 USART1 module disable control: +* (a) USART1_OFF - Turn off USART1 module +* (b) USART1_ON - Leave USART1 module in its default state +* +* 13.usart0 USART0 module disable control: +* (a) USART0_OFF - Turn off USART0 module +* (b) USART0_ON - Leave USART0 module in its default state +* +* 14.twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +*******************************************************************************/ +#if defined (__AVR_ATmega2560__) || defined (__AVR_ATmega1280__) +void LowPowerClass::idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart3_t usart3, usart2_t usart2, usart1_t usart1, + usart0_t usart0, twi_t twi) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + + power_timer2_disable(); + } + + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_disable(); + if (timer4 == TIMER4_OFF) power_timer4_disable(); + if (timer3 == TIMER3_OFF) power_timer3_disable(); + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart3 == USART3_OFF) power_usart3_disable(); + if (usart2 == USART2_OFF) power_usart2_disable(); + if (usart1 == USART1_OFF) power_usart1_disable(); + if (usart0 == USART0_OFF) power_usart0_disable(); + if (twi == TWI_OFF) power_twi_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + power_timer2_enable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_enable(); + if (timer4 == TIMER4_OFF) power_timer4_enable(); + if (timer3 == TIMER3_OFF) power_timer3_enable(); + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart3 == USART3_OFF) power_usart3_enable(); + if (usart2 == USART2_OFF) power_usart2_enable(); + if (usart1 == USART1_OFF) power_usart1_enable(); + if (usart0 == USART0_OFF) power_usart0_enable(); + if (twi == TWI_OFF) power_twi_enable(); +} +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega256RFR2 into idle state. Please make sure +* you understand the implication and result of disabling module. +* Take note that extra Timer 5, 4, 3 compared to an ATmega328P/168. +* Also take note that extra USART 1 compared to an +* ATmega328P/168. +* +* 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: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer5 Timer 5 module disable control: +* (a) TIMER5_OFF - Turn off Timer 5 module +* (b) TIMER5_ON - Leave Timer 5 module in its default state +* +* 4. timer4 Timer 4 module disable control: +* (a) TIMER4_OFF - Turn off Timer 4 module +* (b) TIMER4_ON - Leave Timer 4 module in its default state +* +* 5. timer3 Timer 3 module disable control: +* (a) TIMER3_OFF - Turn off Timer 3 module +* (b) TIMER3_ON - Leave Timer 3 module in its default state +* +* 6. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +* 7. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 8. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 9. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 10.usart1 USART1 module disable control: +* (a) USART1_OFF - Turn off USART1 module +* (b) USART1_ON - Leave USART1 module in its default state +* +* 11.usart0 USART0 module disable control: +* (a) USART0_OFF - Turn off USART0 module +* (b) USART0_ON - Leave USART0 module in its default state +* +* 12.twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +*******************************************************************************/ +#if defined (__AVR_ATmega256RFR2__) +void LowPowerClass::idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart1_t usart1, + usart0_t usart0, twi_t twi) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + + power_timer2_disable(); + } + + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_disable(); + if (timer4 == TIMER4_OFF) power_timer4_disable(); + if (timer3 == TIMER3_OFF) power_timer3_disable(); + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart1 == USART1_OFF) power_usart1_disable(); + if (usart0 == USART0_OFF) power_usart0_disable(); + if (twi == TWI_OFF) power_twi_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + power_timer2_enable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_enable(); + if (timer4 == TIMER4_OFF) power_timer4_enable(); + if (timer3 == TIMER3_OFF) power_timer3_enable(); + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart1 == USART1_OFF) power_usart1_enable(); + if (usart0 == USART0_OFF) power_usart0_enable(); + if (twi == TWI_OFF) power_twi_enable(); +} +#endif + + +/******************************************************************************* +* Name: adcNoiseReduction +* Description: Putting microcontroller into ADC noise reduction state. This is +* a very useful state when using the ADC to achieve best and low +* noise signal. +* +* 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. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::adcNoiseReduction(period_t period, adc_t adc, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_ADC); + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + } + #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 +* Description: Putting microcontroller into power save state. This is +* the lowest current consumption state after power down. +* Use this state together with an external 32.768 kHz crystal (but +* 8/16 MHz crystal/resonator need to be removed) to provide an +* asynchronous clock source to Timer 2. Please take note that +* Timer 2 is also used by the Arduino core for PWM operation. +* Please refer to wiring.c for explanation. Removal of the external +* 8/16 MHz crystal/resonator requires the microcontroller to run +* on its internal RC oscillator which is not so accurate for time +* critical operation. +* +* 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 +* +* 4. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerSave(period_t period, adc_t adc, bod_t bod, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + 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_SAVE); + #else + lowPowerBodOn(SLEEP_MODE_PWR_SAVE); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_PWR_SAVE); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + } + #endif +} + +/******************************************************************************* +* Name: powerStandby +* Description: Putting microcontroller into power standby state. +* +* 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::powerStandby(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_STANDBY); + #else + lowPowerBodOn(SLEEP_MODE_STANDBY); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_STANDBY); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); +} + +/******************************************************************************* +* Name: powerExtStandby +* Description: Putting microcontroller into power extended standby state. This +* is different from the power standby state as it has the +* capability to run Timer 2 asynchronously. +* +* 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. +* (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 +* +* 4. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerExtStandby(period_t period, adc_t adc, bod_t bod, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + 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_EXT_STANDBY); + #else + lowPowerBodOn(SLEEP_MODE_EXT_STANDBY); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_EXT_STANDBY); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + } + #endif +} + +/******************************************************************************* +* Name: ISR (WDT_vect) +* Description: Watchdog Timer interrupt service routine. This routine is +* required to allow automatic WDIF and WDIE bit clearance in +* hardware. +* +*******************************************************************************/ +ISR (WDT_vect) +{ + // WDIE & WDIF is cleared in hardware upon entering this ISR + wdt_disable(); +} + +#elif defined (__arm__) +#if defined (__SAMD21G18A__) +/******************************************************************************* +* Name: standby +* Description: Putting SAMD21G18A into idle mode. This is the lowest current +* consumption mode. Requires separate handling of clock and +* peripheral management (disabling and shutting down) to achieve +* the desired current consumption. +* +* Argument Description +* ========= =========== +* 1. idleMode Idle mode level (0, 1, 2) where IDLE_2 level provide lowest +* current consumption in this mode. +* +*******************************************************************************/ +void LowPowerClass::idle(idle_t idleMode) +{ + SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; + PM->SLEEP.reg = idleMode; + __DSB(); + __WFI(); +} + +/******************************************************************************* +* Name: standby +* Description: Putting SAMD21G18A into standby mode. This is the lowest current +* consumption mode. Use this together with the built-in RTC (use +* RTCZero library) or external pin interrupt to wake up through +* external event triggering. +* +* Argument Description +* ========= =========== +* 1. NIL +* +*******************************************************************************/ +void LowPowerClass::standby() +{ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + __DSB(); + __WFI(); +} + +#else + #error "Please ensure chosen MCU is ATSAMD21G18A." +#endif +#else + #error "Processor architecture is not supported." +#endif + +LowPowerClass LowPower; diff --git a/old/3/tomtom.gps.auto.on/LowPower.h b/old/3/tomtom.gps.auto.on/LowPower.h new file mode 100644 index 0000000..82f6f44 --- /dev/null +++ b/old/3/tomtom.gps.auto.on/LowPower.h @@ -0,0 +1,169 @@ +#ifndef LowPower_h +#define LowPower_h + +#include "Arduino.h" + +enum period_t +{ + SLEEP_15MS, + SLEEP_30MS, + SLEEP_60MS, + SLEEP_120MS, + SLEEP_250MS, + SLEEP_500MS, + SLEEP_1S, + SLEEP_2S, + SLEEP_4S, + SLEEP_8S, + SLEEP_FOREVER +}; + +enum bod_t +{ + BOD_OFF, + BOD_ON +}; + +enum adc_t +{ + ADC_OFF, + ADC_ON +}; + +enum timer5_t +{ + TIMER5_OFF, + TIMER5_ON +}; + +enum timer4_t +{ + TIMER4_OFF, + TIMER4_ON +}; + +enum timer3_t +{ + TIMER3_OFF, + TIMER3_ON +}; + +enum timer2_t +{ + TIMER2_OFF, + TIMER2_ON +}; + +enum timer1_t +{ + TIMER1_OFF, + TIMER1_ON +}; + +enum timer0_t +{ + TIMER0_OFF, + TIMER0_ON +}; + +enum spi_t +{ + SPI_OFF, + SPI_ON +}; + +enum usart0_t +{ + USART0_OFF, + USART0_ON +}; + +enum usart1_t +{ + USART1_OFF, + USART1_ON +}; + +enum usart2_t +{ + USART2_OFF, + USART2_ON +}; + +enum usart3_t +{ + USART3_OFF, + USART3_ON +}; + +enum twi_t +{ + TWI_OFF, + TWI_ON +}; + +enum usb_t +{ + USB_OFF, + USB_ON +}; + +enum idle_t +{ + IDLE_0, + IDLE_1, + IDLE_2 +}; + +class LowPowerClass +{ + public: + #if defined (__AVR__) + + #if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__) + void idle(period_t period, adc_t adc, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart0_t usart0, twi_t twi); + #elif defined __AVR_ATmega2560__ + void idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart3_t usart3, usart2_t usart2, usart1_t usart1, + usart0_t usart0, twi_t twi); + #elif defined __AVR_ATmega256RFR2__ + void idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart1_t usart1, + usart0_t usart0, twi_t twi); + #elif defined __AVR_ATmega32U4__ + 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); + #else + #error "Please ensure chosen MCU is either 168, 328P, 32U4, 2560 or 256RFR2." + #endif + 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"))); + + #elif defined (__arm__) + + #if defined (__SAMD21G18A__) + void idle(idle_t idleMode); + void standby(); + #else + #error "Please ensure chosen MCU is ATSAMD21G18A." + #endif + + #else + + #error "Processor architecture is not supported." + + #endif +}; + +extern LowPowerClass LowPower; +#endif diff --git a/old/3/tomtom.gps.auto.on/tomtom.gps.auto.on.ino b/old/3/tomtom.gps.auto.on/tomtom.gps.auto.on.ino new file mode 100644 index 0000000..6b5a6b5 --- /dev/null +++ b/old/3/tomtom.gps.auto.on/tomtom.gps.auto.on.ino @@ -0,0 +1,115 @@ +#include "LowPower.h" + +// The TomTom Mkii Bluetooth GPS receiver does not automatically turn on when power is applied via its charging port. +// The power button must be held for approximately 1 second to turn it on. +// This program is intented to be used with an ardunio with an I/O pin connected to one of the leads of the power button +// to simulate a power button press and turn the device on as soon as power is applied to the charging port and also turn +// the device off when power is removed from the charging port. + +const int ledpin = 13; // built-in led pin +const int pwrbuttonpin = 4; //[BLUE] pin to be connected to tomtom gps power button "sense" lead +const int inputpowerpin = 2; //[RED] pin to be connected to positive voltage of power adaptor jack (NEED external pulldown) +const int gpspowerpin = 5; //[YELLOW] pin to be connected to GPS circuit to detect when GPS is powered on + +// delay for simulated power button hold-down (ms) +const unsigned long pwrbuttondelay = 1100; + +byte inputpowerpin_state = LOW; // inputpowerpin state +byte inputpowerpin_state_last = LOW; // last inputpowerpin state +byte inputpowerpin_state_stab = LOW; // stable (debounced) inputpowerpin state +int inputpowerpin_state_stab_last = -1; // last stable (debounced) inputpowerpin state (for detecting state change) + // (set as neither LOW nor HIGH so that it will run change code at least once) +// debounce vars +unsigned long lastDebounceTime = 0; +const unsigned long debounceDelay = 1000; + +// time we should start waiting from to determine when we can sleep +unsigned long sleepWaitDelayStart = 0; + +// function to "press" power button +void press_power_button() { + // short pwrbuttonpin to HIGH + // (simulate button press) + digitalWrite(pwrbuttonpin, HIGH); + pinMode(pwrbuttonpin, OUTPUT); + + // digitalWrite(ledpin, HIGH); + + // wait + delay(pwrbuttondelay); + + // "disconnect" pwrbuttonpin (input mode = high impediance) + // (simulate button release) + pinMode(pwrbuttonpin, INPUT); + digitalWrite(pwrbuttonpin, LOW); + + // digitalWrite(ledpin, LOW); + + // reset sleep wait + sleepWaitDelayStart = millis(); +} + +// need dummy function for interrupt binding (we are just using interrupt for low power mode) +void wakeup() { +} + +// go into low power sleep mode until interrupt happens (change in state of input power pin) +void sleepUntilPwrChange() { + digitalWrite(ledpin, LOW); + + // setup interrupt, then sleep until interrupt triggers + attachInterrupt(digitalPinToInterrupt(inputpowerpin), wakeup, CHANGE); + LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); + + // detach interrupt as soon as we wake up b/c we don't need it again until we sleep the next time + detachInterrupt(digitalPinToInterrupt(inputpowerpin)); + + // reset sleep wait (need enough time to do debouncing on input power pin signal and press power button) + // if we don't reset sleep timer here then it will just immediately sleep on next loop() cycle without doing anything... + sleepWaitDelayStart = millis(); + digitalWrite(ledpin, HIGH); +} + +void setup() { + // turn on built-in led + pinMode(ledpin, OUTPUT); + digitalWrite(ledpin, HIGH); + + // set pwrbuttonpin pin low (to gnd?) + pinMode(pwrbuttonpin, INPUT); + digitalWrite(pwrbuttonpin, LOW); +} + +void loop() { + + // read powerbuttonpin + inputpowerpin_state = digitalRead(inputpowerpin); + + // every time inputpowerpin changes, reset debounce timer + if (inputpowerpin_state != inputpowerpin_state_last) { + lastDebounceTime = millis(); + } + + // if inputpowerpin state has not changed in (debounceDelay)ms then accept current state + if((millis() - lastDebounceTime) > debounceDelay) { + // store new stable state + inputpowerpin_state_stab = inputpowerpin_state; + } + + // if input power pin and gps power state is mis-matched then we need to "press" button to toggle gps power state + if (inputpowerpin_state_stab != inputpowerpin_state_stab_last) { + if (inputpowerpin_state_stab != digitalRead(gpspowerpin)) { + press_power_button(); + } + } + + if ((millis() - sleepWaitDelayStart) > ((pwrbuttondelay + debounceDelay) * 2)) { + // sleep until inputpowerpin changes state + sleepUntilPwrChange(); + } + + // store last states for debouncing and stable state + inputpowerpin_state_stab_last = inputpowerpin_state_stab; + inputpowerpin_state_last = inputpowerpin_state; + +} diff --git a/tomtom.gps.auto.on.ino b/tomtom.gps.auto.on.ino new file mode 100644 index 0000000..b8cc5e1 --- /dev/null +++ b/tomtom.gps.auto.on.ino @@ -0,0 +1,151 @@ +#include "LowPower.h" + +// The TomTom Mkii Bluetooth GPS receiver does not automatically turn on when power is applied via its charging port. +// The power button must be held for approximately 1 second to toggle it on/off. +// This program is intented to be used with an ardunio with an I/O pin connected to one of the leads of the power button +// to simulate a power button press and turn the device on as soon as power is applied to the charging port and also turn +// the device off when power is removed from the charging port. + +// Also this program will wake the GPS unit periodically so that it can maintain a good GPS lock. (the unit automatically +// turns itself off after 5 minutes if it is not connected to anything via bluetooth, so the battery will not be used very much) + +const int ledpin = 13; // built-in led pin +const int pwrbuttonpin = 4; //[BLUE] pin to be connected to tomtom gps power button "sense" lead +const int inputpowerpin = 2; //[RED] pin to be connected to positive voltage of power adaptor jack (NEED external pulldown) +const int gpspowerpin = 5; //[YELLOW] pin to be connected to GPS circuit to detect when GPS is powered on + +// delay for simulated power button hold-down (ms) +const unsigned long pwrbuttondelay = 1100; + +byte inputpowerpin_state = LOW; // inputpowerpin state +byte inputpowerpin_state_last = LOW; // last inputpowerpin state +byte inputpowerpin_state_stab = LOW; // stable (debounced) inputpowerpin state +int inputpowerpin_state_stab_last = -1; // last stable (debounced) inputpowerpin state (for detecting state change) + // (set as neither LOW nor HIGH so that it will run change code at least once) +// debounce vars +unsigned long lastDebounceTime = 0; +const unsigned long debounceDelay = 1000; + +// time we should start waiting from to determine when we can sleep +unsigned long sleepWaitDelayStart = 0; + +// flag for external interrupt +volatile bool inputpowerpin_wakeupflag = false; + +// counter for how many 8sec sleep cycles have been completed +unsigned int eightsec_sleepcounter = 0; + +// number of 8sec sleep periods we want to sleep between GPS power-ons +// const unsigned int eightsec_sleeps = 450; // wakeup once every 1hr (1hr = 3600sec, 3600sec / 8sec = 450) +const unsigned int eightsec_sleeps = 900; // wakeup once every 2hr (2hr = 7200sec, 7200sec / 8sec = 900) + +// function to "press" power button +void press_power_button() { + // short pwrbuttonpin to HIGH + // (simulate button press) + digitalWrite(pwrbuttonpin, HIGH); + pinMode(pwrbuttonpin, OUTPUT); + + // digitalWrite(ledpin, HIGH); + + // wait + delay(pwrbuttondelay); + + // "disconnect" pwrbuttonpin (input mode = high impediance) + // (simulate button release) + pinMode(pwrbuttonpin, INPUT); + digitalWrite(pwrbuttonpin, LOW); + + // digitalWrite(ledpin, LOW); + + // reset sleep wait + sleepWaitDelayStart = millis(); +} + +// function for interrupt binding +void inputpowerpin_wakeup() { + // (interrupt was triggered) + inputpowerpin_wakeupflag = true; +} + +// go into low power sleep mode until interrupt happens (change in state of input power pin) +void sleepUntilPwrChange() { + digitalWrite(ledpin, LOW); + + // setup interrupt, then sleep until interrupt triggers + attachInterrupt(digitalPinToInterrupt(inputpowerpin), inputpowerpin_wakeup, CHANGE); + // LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); //(for previous sleep until external CHANGE interrupt ONLY operation) + + eightsec_sleepcounter = 0; + + // infinite loop + while (true) { + // do 8s sleep + LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); + eightsec_sleepcounter++; + + // if we have slept enough that it is time for periodic GPS turn-on: + if (eightsec_sleepcounter >= eightsec_sleeps) { + // if GPS is powered off then press button to turn it on + if (digitalRead(gpspowerpin) == LOW) press_power_button(); + eightsec_sleepcounter = 0; + } + + // if inputpowerpin_wakeupflag then exit inf loop + if (inputpowerpin_wakeupflag) break; + } + + // detach interrupt as soon as we wake up b/c we don't need it again until we sleep the next time + detachInterrupt(digitalPinToInterrupt(inputpowerpin)); + + inputpowerpin_wakeupflag = false; + + // reset sleep wait (need enough time to do debouncing on input power pin signal and press power button) + // if we don't reset sleep timer here then it will just immediately sleep on next loop() cycle without doing anything... + sleepWaitDelayStart = millis(); + digitalWrite(ledpin, HIGH); +} + +void setup() { + // turn on built-in led + pinMode(ledpin, OUTPUT); + digitalWrite(ledpin, HIGH); + + // set pwrbuttonpin pin low (to gnd?) + pinMode(pwrbuttonpin, INPUT); + digitalWrite(pwrbuttonpin, LOW); +} + +void loop() { + + // read powerbuttonpin + inputpowerpin_state = digitalRead(inputpowerpin); + + // every time inputpowerpin changes, reset debounce timer + if (inputpowerpin_state != inputpowerpin_state_last) { + lastDebounceTime = millis(); + } + + // if inputpowerpin state has not changed in (debounceDelay)ms then accept current state + if((millis() - lastDebounceTime) > debounceDelay) { + // store new stable state + inputpowerpin_state_stab = inputpowerpin_state; + } + + // if input power pin and gps power state is mis-matched then we need to "press" button to toggle gps power state + if (inputpowerpin_state_stab != inputpowerpin_state_stab_last) { + if (inputpowerpin_state_stab != digitalRead(gpspowerpin)) { + press_power_button(); + } + } + + if ((millis() - sleepWaitDelayStart) > ((pwrbuttondelay + debounceDelay) * 2)) { + // sleep until inputpowerpin changes state + sleepUntilPwrChange(); + } + + // store last states for debouncing and stable state + inputpowerpin_state_stab_last = inputpowerpin_state_stab; + inputpowerpin_state_last = inputpowerpin_state; + +} diff --git a/tomtom.gps.auto.on.notes.txt b/tomtom.gps.auto.on.notes.txt new file mode 100644 index 0000000..8514f2e --- /dev/null +++ b/tomtom.gps.auto.on.notes.txt @@ -0,0 +1,304 @@ +v = I * r + +I = 0.2ma + +v = 5v + +5 = 0.0002 * r + + +button leads: +outer pins always 5v when power is applied +inner pins goto ~4.4-4.6v when button is pressed +current flowing when shorting button leads thru ammeter is 0.2ma +max dc current per I/O pin is 40ma (https://www.arduino.cc/en/Main/ArduinoBoardProMini) + +removed battery +got gps fix +unplugged 5v ac power +waited 5min +plugged in power +took 4min to get gps fix... +got fix, unplugged for 1 min, then it took 2 mins to get fix + +put battery back in +took a long time to get fix +powered off for 30 sec, powered on and took a couple seconds to get fix +powered off for 5 mins, powered on and took 5 seconds to get fix + +removed battery +plugged in to ac power +took ~5mins to get fix +disconnected dc power plug from gps unit for ~1sec, plugged back in and took 1m30s to get fix +disconnected dc power plug from gps unit for 30sec, plugged back in and took 6mins to get fix +disconnected power plug from wall for ~1sec, plugged back in and took ~2min to get fix + +put battery back in +took ~10-13mins(gave up waiting and left...) to get fix +powered off(via button)(still plugged in to ac power) for 30 sec, powered on and took 5sec to get fix +powered off(via button)(still plugged in to ac power) for 5 mins, powered on and took 6mins to get fix + but i forgot to connect phone so it auto-powered-off after 5 mins... + did it again and it got fix in like 5 secs... +powered off(via button)(NOT plugged in to ac power) for 30 sec, powered on and took 5sec to get fix +powered off(via button)(NOT plugged in to ac power) for 5 min, powered on and took 5sec to get fix +powered off(via button)(NOT plugged in to ac power) for 42 min, powered on and took 5sec to get fix + + +will need to: +power arduino from gps unit's battery + just find 5v somewhere + can steal from other lead of button?? (since this has 5v when battery is installed and power is not connected) + BUT if arduino is powered from battery then need to figure out how much it will drain... + can look up information about how to minimize the drain +detect 5v from power adaptor with an I/O pin +then whenever power is lost simulate button press to turn gps unit off + +check out low power tips (http://www.home-automation-community.com/arduino-low-power-how-to-run-atmega328p-for-a-year-on-coin-cell-battery/) + maybe remove power LED and/or regulator?? +use low power library to save battery + https://github.com/rocketscream/Low-Power/blob/master/Examples/powerDownWakeExternalInterrupt/powerDownWakeExternalInterrupt.ino +use interrupt with CHANGE mode https://www.arduino.cc/en/Reference/AttachInterrupt + on power plug pin to detect change in power plugged->unplugged, unplugged->plugged +have input pin connected to power plug (for interrupt) and also to some part of internal circuit that is only powered when GPS unit is in "ON" state (when green light is on (or blinking)) +then every time CHANGE interrupt is triggered for change in power plug state, check for mismatch between power plug state and "ON" state of internal circuit and if mismatched then press_power_button() +since docs say that delay()/mills() won't work inside interrupt function, will have to set a flag or something that will cause press_power_button() to happen later + might want to make this flag a counter in case miltiple CHANGE(s) of power plug interrupt happen before a single press_power_button() can complete; this way they will sort of be "queued" up and the final state of power should be correct + +problem: interrupt for CHANGE on input power triggers MANY multiple times +might want to use low power sleep code and just use CHANGE interrupt to wake up + first detatch interrupt, then debounce input power pin state, then do inputpower-gpspower state check and do button press + +don't use unsigned for timer vars (delete "unsigned") +in case of millis() rollover: if millis()-debounce/whatever var: set debounce/whatever var = millis() again + also need to handle for sleep time start +check what type millis() returns + docs say type is unsigned long + what result do you get when you do (lower.unsigned.int - higher.unsigned.int) ?? , can test in computer c++ ?? + tested this ON WINDOWS PC C++, unsigned 1 - unsigned 2 = 4294967295, so some huge number... + NEED TO TEST subtracting big number from small number on ARDUINO HARDWARE and also casting result as (int) +search for millis() rollover solution/code... +can test final code for rollover handling by manually replacing millis() with lower number? (but just one time in loop...use flag or something) + of make test_millis() and add huge number to millis() so it will roll over soon + +according to https://www.baldengineer.com/arduino-how-do-you-reset-millis.html rollover is "handled" automatically if you just do (unsigned long)(var_b - var_a) +but what if millis() rolls over and then goes like 1ms past the delay var...then it will think that only 1ms has passed when it is really (unsigned long) + 1 ms +maybe JUST init all time vars after wakeup?? (no can't do this b/c can't init millis()...) +I do not think that this will be a problem because sleeptimestart and debouncetimestart are re-set after wakeup + +NEED TO CHECK what gpspowerpin (yellow) voltage does when green LED is flashing (when gps has fix)...does it stay HIGH as long as gps circuit is powered on or does it change when led flashes? + checked: it is consistant 3.3v when LED is flashing when it has a fix + + +pad9 and pad12 (under battery) will be 0v if "off" and ~3.34v if "ON" if plugged in to power or not + + + +wires: +black: [pin GND] +GND (from power plug) +red: [pin 2] +V from power plug +blue: [pin 4] power button (sense lead, set to HIGH to simulate button press) +yellow: [pin 5] 3.3v when "ON", 0v when "OFF" +purple: [pin VCC] power button (powered lead, ~4.14v when "OFF", ~3.9v when "ON") + (will use this to power arduino)10 + +make longer wires coming out of gps unit +make them go into single connector +remove pins on other side (where required pin#2 for interrupt is) +just put one right-angle pin on pin#2 +remove power led +remove power regulator? + +problem: +when turing car to ACC(by not holding down clutch) and then going to ON(starting engine), the phone fails to connect +what happens is that when going from OFF to ACC, the gps unit will get turned on, and then when going from ACC to ON it will loose power for a brief time (appears to be ~1/2sec?) and get turned off and then regain power and get turned on again +so power states are changed correctly but I think that the phone is trying to connect during the brief ~1/2sec power of period +will try: +changing debounce delay from 100msec to longer than the brief power off (so greater than ~500msec?) + +problem: +when turning car off (engine running->OFF) sometimes gps will fail to power off +need to pay attention to sleep LED to see if it ever turns on when this occurs...(does CHANGE interrupt for inputpowerpin happen?) (it must not??) +I had removed 10k pulldown resistor from inputpowerpin before installing in car b/c i had thought it was not necessary +will try: +now I have reinstalled 10k pulldown resistor on inputpowerpin +will see if this still occurs... + + + +can maybe have it wake up for a while every hour or so to get a better fix/take less time to get a fix later?? +would have to use lo power library to make it periodically wake up +looks like longest time it can sleep for it 8seconds? +would have to have it wake up every 8sec and increment something to be able to turn on gps every hour?? +I assume millis() pauses when it is asleep?? +does interrupt also wake it up when it is sleeping for 8sec?? + hope it does or it won't work... (yes it does, tested this) +each 8sec wakeup: + have it inc counter(to 1-2hrs or w/e) + then if it hits 1-2hr limit then + turn on gps for a few (5?) minutes + check gpspowerpin state: if off then press power button + go to sleep again until time to turn it off?? + (can't be more than 5 mins b/c of auto power off...) + maybe letting it auto-power off is the simplest option??? + reset timer/incrementer + don't do anything else like check power state pins to save power (does this save power?? can't find any info that says it does) + then sleep for 8sec again +for each powerpin CHANGE interrupt + do normal gpspowerpin state check and power button press if needed + + +implemented this; made it wake up about every hour and turn on GPS (let it turn itself off after 5mins of no connection) +when testing this first had it wake up every 6mins so I could watch it and see what happened + (I set it to do 45 loops of 8sec sleep b/c 6min=360sec and 360/8=45) +noticed that it woke up in about 6min:30sec instead of 6 mins +there is very little code that runs other than the 8sec sleep so I wouldn't expect it to take so much longer... +I should make it turn on LED whenever it wakes for each 8sec loop just to see how long it is spending awake... + + +in order to have it be on for less time can maybe somehow detect if it has GPS fix and then turn off as soon at it does +(because there is probably no benefit to keeping it on longer once it already has a fix??) +would have to detect blinking of LED?? unless I could randomly find some other signal somewhere inside that indicated GPS fix + + +also maybe could have arduino detect battery level and not turn on gps if it gets too low? +not sure if this would work with current setup b/c it is powered off of battery and I think it uses this voltage for reference of what highest for analog input is?? (so if i used analog input to measure battery voltage it would always see it as the highest value?) + + +gps unit battery always seems to go dead after a while +with code that was only turning it on/off when power was applied it would last ~a week or two +with code that turned it on every hour (until it timed out after 5 mins) it would last a few days +possible causes: + - gps unit is unable to be turned on and charge battery at the same time (because I am never giving it power without it being turned on) + this could be caused by arduino being attached?? + + - arduino is using too much power (even when in sleep mode) and draining battery when car is off and power is not applied + - battery is draining on its own when car is off and power is not applied + +trying to measure battery level +with battery nearly dead (red LED on), purple wire measured 3.61 volts + when charging it seems to stay at ~4v but if i stop charging then i can see that this voltage goes to a bit higher than ~3.6v + so i guess I can only see battery voltage level from this wire when not charging?? + will let it charge for a few hours and then stop charging and check voltage = ___ +then when it is fully charged I will run it without arduino attached and see if it can maintain full battery level for a week or so (or at least not have battery voltage go down) + +am running gps unit in car without arduino attached +checking voltage level +3.95v +after driving for a few mins with gps unit turned on it went up slightly to 3.96v +after doing this a few more times can see it always go up by about 0.01v, now it is at 3.98v +fully charged it is at 4.16v, (unplugged from power and gps off) + 3.85v unplugged and gps on +so it seems like it can keep charging the battery with short drives and short off times in-between at least... +left off overnight fully charged and it was at 4.15v, so really not discharging at all... + more checking(still not charging and gps off): 8:15pm=4.15v, next morning 6:15am=4.15v + drove to work, after i got there still @ 4.15v, also orange charge LED never turned on + so it must be running the GPS off of the power plug and not using the battery at all and not charging it b/c it is full??? + manually turned on gps unit when power was not plugged in/on and let it timeout after 5mins + battery went from 4.16 to 4.15v + turned gps off and turned on power plug and it did not charge...battery not low enough? + did another 5mins of gps on and battery went down to 4.14v, then turned gps off and turned on power and it was charging + left off overnight, battery still 4.14v, turned on power and it is charging, but then when I turn on GPS it stops charging...wtf...still need to get battery lower to make it keep charging?? +will have to see what it does when left off for a few days... + + +testing arduino power comsumption with a meter +plugged in to 5v usb power from computer, using 1hr wakeup code +it's is drawing 51.5mA when awake and 37.5mA when asleep...wtf this is waaaayyy too much..... +trying old code that only wakes when power changes state....same current draw...wtf +removed external 10k pulldown resistor from pin 2 in case this is doing something weird (NO pins are connected to ANYTHING except power pin and gnd)...same current draw +tried example sleep forever code from guy who made sleep library that I am using (powerDownWakeExternalInterrupt.ino)...~40mA..about the same draw... +tried test code from here http://playground.arduino.cc/Learning/ArduinoSleepCode + and same draw... +this makes no sense...current is way too high... +maybe this arduino pro mini is broken somehow???...i did fry a few input pins a while back... +ordered a new one to test for $4... + +tried this code http://arduino.stackexchange.com/questions/16024/high-power-consumption-during-power-down-mode +with old ardunio duemilanove (atmega 168) +and got it down to 11mA (using 5v pin) used VIN pin and it want down to 9mA +but tried same code with pro mini and it only went down to ~40mA... + +finally got new $4 arduino pro mini +burned blink program +current changing between 17-20mA (when led turns on) +wrote program that does nothing = 17mA +tried this code http://arduino.stackexchange.com/questions/16024/high-power-consumption-during-power-down-mode +now down to 3mA +this is very close to what it is supposed to be according to + http://www.home-automation-community.com/arduino-low-power-how-to-run-atmega328p-for-a-year-on-coin-cell-battery/ +woo +now trying powerDownWakeExternalInterrupt.ino example code from LowPower library +only down to 7.33mA, weird +removed attachInterrupt() call that sets up wakeup interrupt +now down to 3mA +maybe it was waking up b/c there was no pullup on interrupt pin? + +now trying my code for gps thing +starts at 20mA when awake, then goes down to 3mA when it sleeps, good +now removing power led and power regulator +severed power lED trace, now down to 0.27mA when asleep +removed power regulator, now only down to 0.25mA...was expecting lower...wtf... + +need to try powerDownWakeExternalInterrupt.ino code with removed LED and regulator to see if less current... +tried powerDownWakeExternalInterrupt.ino code with default LOW interrupt and it went down to 4mA (but still had pulldown on this interrupt pin so it must have been triggering constantly?) +tried powerDownWakeExternalInterrupt.ino code with default LOW interrupt and removed pulldown and still 4mA...could still be triggering with noise?? +tried powerDownWakeExternalInterrupt.ino code with default HIGH interrupt and it went down to 0.1uA...uh this is too low?? +tried with old gps code that uses power_down_forever instead of 8s power down = 0.1uA + tried touching interrupt pin (pin2) to 5v and it woke up and slept again OK +so basically 8s sleep code that turns on the gps every hour used 0.25mA and sleep forever code uses waaaaayyy less (0.1uA) +but wait...burned 8s sleep gps code again and now it is only using 6.4uA.....wtf...i tried this before and it was 0.25mA...this makes no sense + tried touching interrupt pin (pin2) to 5v and it woke up and slept again OK +tried adding delay after every 8s sleep temporarily to observe power usage, can see it jump up to 16mA and then back down to 6uA + + +installed new aruino pro mini with code to turn on gps unit every 1hr (for 5mins timeout) +5:18 PM 10/17/2016 battery voltage is 4.14v +next morning at 9:28 AM 10/18/2016 battery voltage is 4.02v + rate is 0.12v/16h = 0.0075v/h +want to try with old code that does not turn on every 1h to make sure arduino is not draining too much in sleep mode +starting time 10:46 AM 10/18/2016 and voltage 4.05v +checked again at 6:45 PM 10/18/2016 (8hs later) and voltage is 4.05v +so arduino only is drawing nearly nothing, good + +switched back to 1hr gps turn on code +night before work day, 6:55 PM 10/18/2016 battery level is 4.04v +drove to store and charged to 4.06v 7:46 PM 10/18/2016 +will check to see how battery level changes over the next few days +next morning battery level is 3.97v 6:08 AM 10/19/2016 +after driving to work battery level is 4.06v, 0634am + so basically driving to work exactly charged up the amount that was drained overnight... +after work before driving home battery level is 3.94v, 718pm +but stopped to pick up sushi for a few mins, not sure how long... +after driving home battery level is 4.07v, 756pm + +next morning battery level is 3.97v 6:16 AM 10/20/2016 +after getting to work 0641am, 4.06v +after work 0737pm, 3.93v +after getting home, 0813pm, 4.04v + +next morning battery level is 3.95v 6:29 AM 10/21/2016 +after getting to work 0655am, 4.05v +after work 726pm, 3.93v +after getting home, 753pm, 4.02v + +discharge rate (for 5min on per hour) is about 0.01v/h +charge rate is 0.0036v/min, 0.216v/h + + +attempt to figure how long we can keep battery charged: +manual says: +battery capacity is 1200mAh +battery will last for 10 hours of use +battery will charge in "less than 4 hours" (I will assume 4 hrs) +so gps power consumption is: 1200(mAh) / I(mA) = 10(h), I = 120mA +arduino power consumption: 0.25mA, so arduino will consume: 0.25mAh (or now it is really 6uA??(0.006mA)) +charge rate: 1200(mAh) / I(mA) = 4(h), I = 300mA +so 5mins of gps usage will consume: 120mA * (5m/60m) = 10mAh +so if we are running the gps for 5mins every hour, total power consumption wil be 10mAh + 0.25mAh = 10.25mAh + +how long it will take to charge 10mAh: 300(mAh)/1(h) = 10.25mAh/X(h), [(10.25/300) * 60 (for minutes)], X = 2.05min = 2min3sec +so if we are running the gps for 5mins every hour, then we will need to charge for 2min3sec for each hour the car is off +(this is assuming that the charge rate is still 300(mAh)/1(h) even when the gps unit is on which may not be true...) +so for 12hrs at work, we would need 24.6min to charge + this is probably just barely as long as my commute...not sure this is enough to keep battery charged... + might have to switch to turning on gps once every 2 hours?