This is an old revision of the document!


Sleep and Low Power

We want to collect data from sensors and then periodically send packets of data. When we do not want to do this at a high frequency, we have some dead times. This leads to high energy consumption, which can have a significant impact on the battery life of sparrow when it is powered by a battery.

Bellow you can see the code for sleep library.

#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <Arduino.h>
#include <util/delay.h>
#include "SparrowVsleep.h"
 
// #define DEBUG // uncomment for debunging
			  // (also comment /* (1 << PRUSART0) */ from PRR0 )
 
int global_seconds;
bool global_data_retention;
 
ISR(WDT_vect)
{
	#ifdef DEBUG
		Serial.println("Watchdog Interrupt ");
		Serial.flush();
 
		Serial.print("global_seconds: ");
		Serial.println(global_seconds);
		Serial.flush();
	#endif
 
	if (global_seconds == 0)
	{
		Serial.println();
		Serial.println("Ready sleep");
		// reenable the transciever
		PRR1 &= ~(1 << PRTRX24);
 
		// reenable ADC
		ADCSRA = (1 << ADEN);
 
		//restore PRR
		PRR0 = 0;
		PRR1 = 0;
 
		wdt_disable();
	}
	else
	{
	    #ifdef DEBUG
			Serial.println();
			Serial.println("going to sleep again");
		#endif
 
		// going to sleep again
		choose(global_seconds);
	}
}
 
void choose(int seconds)
{
	#ifdef DEBUG
		Serial.println("entering choose function");
		Serial.flush();
	#endif
 
	if(seconds % 8 == 0)
	{
		#ifdef DEBUG
			Serial.println("choose 8");
			Serial.flush();
		#endif
		setup_WDT(8);
	}
	else if (seconds % 4 == 0)
	{
		#ifdef DEBUG
			Serial.println("choose 4");
			Serial.flush();
		#endif
		setup_WDT(4);
	}
	else if (seconds % 2 == 0)
	{
		#ifdef DEBUG
			Serial.println("choose 2");
			Serial.flush();
		#endif
		setup_WDT(2);
	}
	else if (seconds % 1 == 0)
	{
		#ifdef DEBUG
			Serial.println("choose 1");
			Serial.flush();
		#endif
		setup_WDT(1);
	}
	else
	{
		//TODO for less than 1 second
		return;
	}
}
 
void setup_WDT(int situation)
{
	#ifdef DEBUG
		Serial.println("setup WDT");
		Serial.flush();
	#endif
 
	cli();
 
	wdt_reset(); // reset the WDT timer
	MCUSR &= ~(1 << WDRF); // Clear the reset flag. (because the data sheet said to)
 
	// Setup Watchdog for interrupt and not reset, and a approximately x seconds timeout
	switch (situation)
	{
		// wake up after 8 seconds
		case 8: // Enter in configuration mode
				WDTCSR = (1 << WDCE) | (1 << WDE);
				WDTCSR = (1 << WDIE) | (1 << WDP3) | (1 << WDP0);
				global_seconds -= 8;
				#ifdef DEBUG
					Serial.println("WDT 8");
					Serial.flush();
				#endif
				break;
 
		// wake up after 4 seconds
		case 4: // Enter in configuration mode
				WDTCSR = (1 << WDCE) | (1 << WDE);
				WDTCSR = (1 << WDIE) | (1 << WDP3);
				global_seconds -= 4;
				#ifdef DEBUG
					Serial.println("WDT 4");
					Serial.flush();
				#endif
				break;
 
		// wake up after 2 seconds
		case 2: // Enter in configuration mode
				WDTCSR = (1 << WDCE) | (1 << WDE);
				WDTCSR = (1 << WDIE) | (1 << WDP2) | (1 << WDP1) | (1 << WDP0);
				global_seconds -= 2;
				#ifdef DEBUG
					Serial.println("WDT 2");
					Serial.flush();
				#endif
				break;
 
		// wake up after 1 second
		case 1: // Enter in configuration mode
				WDTCSR = (1 << WDCE) | (1 << WDE);
				WDTCSR = (1 << WDIE) | (1 << WDP2) | (1 << WDP1);
				global_seconds -= 1;
				#ifdef DEBUG
					Serial.println("WDT 1");
					Serial.flush();
				#endif
				break;
 
		//TODO for less than 1 second
	}
	sei();
 
	// sleep setup and going to sleep
	SparrowV_SleepSet(global_data_retention);
}
 
void SparrowV_SleepSet(bool data_retention)
{
	#ifdef DEBUG
		Serial.println("sleep setup");
		Serial.flush();
	#endif
 
	// prepare Deep-sleep Mode
 
	// transcieverul off
	PRR1 |= (1 << PRTRX24);
 
	//  Shut down ADC before invoking the PRR bit for it
	ADCSRA = 0;
 
	// Power reduction registers
	PRR0 |= (1 << PRTWI) | (1 << PRTIM2) | (1 << PRTIM0) | (1 << PRPGA)
	    | (1 << PRTIM1) | (1 << PRSPI) | (1 << PRADC) | (1 << PRUSART0);
 
	PRR1 |= (1 << PRTIM5) | (1 << PRTIM4) | (1 << PRTIM3) | (1 << PRUSART1)
			| (1 << PRUSART1);
 
	// Data renention (if no data retention max 8s sleep and then restart)
	if (data_retention == false) {
	   PRR2 |= (1 << PRRAM3) | (1 << PRRAM2) | (1 << PRRAM1) | (1 << PRRAM0);
	}
 
	// Sleep Mode Control Register (sleep enable & power down)
	SMCR = (1 << SE) | (0 << SM0) | (1 << SM1) | (0 << SM2);
 
	// comand for sleep
	sleep_cpu();
}
 
void SparrowV_SleepInit(int seconds, bool data_retention)
{
	// update global variables
	global_seconds = seconds;
	global_data_retention = data_retention;
 
	#ifdef DEBUG
		Serial.println("global_seconds: ");
		Serial.println(global_seconds);
		Serial.flush();
	#endif
 
	choose(seconds);
}