void hwInternalSleep(unsigned long ms) {
	// Let serial prints finish (debug, log etc)
    #ifndef MY_DISABLED_SERIAL
        MY_SERIALDEVICE.flush();
    #endif
	while (!interruptWakeUp() && ms >= 8000) { hwPowerDown(SLEEP_8S); ms -= 8000; }
	if (!interruptWakeUp() && ms >= 4000)    { hwPowerDown(SLEEP_4S); ms -= 4000; }
	if (!interruptWakeUp() && ms >= 2000)    { hwPowerDown(SLEEP_2S); ms -= 2000; }
	if (!interruptWakeUp() && ms >= 1000)    { hwPowerDown(SLEEP_1S); ms -= 1000; }
	if (!interruptWakeUp() && ms >= 500)     { hwPowerDown(SLEEP_500MS); ms -= 500; }
	if (!interruptWakeUp() && ms >= 250)     { hwPowerDown(SLEEP_250MS); ms -= 250; }
	if (!interruptWakeUp() && ms >= 125)     { hwPowerDown(SLEEP_120MS); ms -= 120; }
	if (!interruptWakeUp() && ms >= 64)      { hwPowerDown(SLEEP_60MS); ms -= 60; }
	if (!interruptWakeUp() && ms >= 32)      { hwPowerDown(SLEEP_30MS); ms -= 30; }
	if (!interruptWakeUp() && ms >= 16)      { hwPowerDown(SLEEP_15MS); ms -= 15; }
}
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) {
    // Disable interrupts until going to sleep, otherwise interrupts occurring between attachInterrupt()
    // and sleep might cause the ATMega to not wakeup from sleep as interrupt has already be handled!
	cli();
	// attach interrupts 
    _wakeUp1Interrupt  = interrupt1;
    _wakeUp2Interrupt  = interrupt2;
    if (interrupt1 != INVALID_INTERRUPT_NUM) attachInterrupt(interrupt1, wakeUp1, mode1);
	if (interrupt2 != INVALID_INTERRUPT_NUM) attachInterrupt(interrupt2, wakeUp2, mode2);
	
	if (ms>0) {
		// sleep for defined time
		hwInternalSleep(ms);
	} else {
		// sleep until ext interrupt triggered
    	hwPowerDown(SLEEP_FOREVER);
	}
    
    // Assure any interrupts attached, will get detached when they did not occur.
    if (interrupt1 != INVALID_INTERRUPT_NUM) detachInterrupt(interrupt1);
	if (interrupt2 != INVALID_INTERRUPT_NUM) detachInterrupt(interrupt2);

    // Return what woke the mcu.
    int8_t ret = MY_WAKE_UP_BY_TIMER;       // default: no interrupt triggered, timer wake up	
    if (interruptWakeUp()) ret = static_cast<int8_t>(_wokeUpByInterrupt);

    // Clear woke-up-by-interrupt flag, so next sleeps won't return immediately.
    _wokeUpByInterrupt = INVALID_INTERRUPT_NUM;

	return ret;
}
Example #3
0
int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
               const uint8_t mode2,
               uint32_t ms)
{
	// ATMega328P supports following modes to wake from sleep: LOW, CHANGE, RISING, FALLING
	// Datasheet states only LOW can be used with INT0/1 to wake from sleep, which is incorrect.
	// Ref: http://gammon.com.au/interrupts

	// Disable interrupts until going to sleep, otherwise interrupts occurring between attachInterrupt()
	// and sleep might cause the ATMega to not wakeup from sleep as interrupt has already be handled!
	cli();
	// attach interrupts
	_wakeUp1Interrupt  = interrupt1;
	_wakeUp2Interrupt  = interrupt2;

	// Attach external interrupt handlers, and clear any pending interrupt flag
	// to prevent waking immediately again.
	// Ref: https://forum.arduino.cc/index.php?topic=59217.0
	if (interrupt1 != INVALID_INTERRUPT_NUM) {
		clearPendingInterrupt(interrupt1);
		attachInterrupt(interrupt1, wakeUp1, mode1);
	}
	if (interrupt2 != INVALID_INTERRUPT_NUM) {
		clearPendingInterrupt(interrupt2);
		attachInterrupt(interrupt2, wakeUp2, mode2);
	}

	if (ms > 0u) {
		// sleep for defined time
		hwInternalSleep(ms);
	} else {
		// sleep until ext interrupt triggered
		hwPowerDown(WDTO_SLEEP_FOREVER);
	}

	// Assure any interrupts attached, will get detached when they did not occur.
	if (interrupt1 != INVALID_INTERRUPT_NUM) {
		detachInterrupt(interrupt1);
	}
	if (interrupt2 != INVALID_INTERRUPT_NUM) {
		detachInterrupt(interrupt2);
	}

	// Return what woke the mcu.
	// Default: no interrupt triggered, timer wake up
	int8_t ret = MY_WAKE_UP_BY_TIMER;
	if (interruptWakeUp()) {
		ret = static_cast<int8_t>(_wokeUpByInterrupt);
	}
	// Clear woke-up-by-interrupt flag, so next sleeps won't return immediately.
	_wokeUpByInterrupt = INVALID_INTERRUPT_NUM;

	return ret;
}
Example #4
0
void hwInternalSleep(uint32_t ms)
{
	// Sleeping with watchdog only supports multiples of 16ms.
	// Round up to next multiple of 16ms, to assure we sleep at least the
	// requested amount of time. Sleep of 0ms will not sleep at all!
	ms += 15u;

	while (!interruptWakeUp() && ms >= 16) {
		for (uint8_t period = 9u; ; --period) {
			const uint16_t comparatorMS = 1 << (period + 4);
			if ( ms >= comparatorMS) {
				hwPowerDown(period); // 8192ms => 9, 16ms => 0
				ms -= comparatorMS;
				break;
			}
		}
	}
}
Example #5
0
int8_t hwSleep(uint32_t ms)
{
	// Return what woke the mcu.
	// Default: no interrupt triggered, timer wake up
	int8_t ret = MY_WAKE_UP_BY_TIMER;
	if (ms > 0u) {
		// sleep for defined time
		hwInternalSleep(ms);
	} else {
		// sleep until ext interrupt triggered
		hwPowerDown(WDTO_SLEEP_FOREVER);
	}
	if (interruptWakeUp()) {
		ret = static_cast<int8_t>(_wokeUpByInterrupt);
	}
	// Clear woke-up-by-interrupt flag, so next sleeps won't return immediately.
	_wokeUpByInterrupt = INVALID_INTERRUPT_NUM;

	return ret;
}