Need advice for Sleep Modes on atmega328p

Go To Last Post
3 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

 

I've the code ready for my application which is working correctly. Now I want to optimize power consumption by using an appropriate sleep mode.

 

The program consists of some ISR routines for timer0 and timer1, and pin change interrupts, see some pseudo code below. An atmega328p and an external quartz crystal or a ceramic resonator is used, some tact switches and some leds.

 

The main loop consits essentially of:

  1. a "do {} while (!keypressed)" loop.
  2. The program logic is handled via the interrupts
    • compare match ISR for the timer and decreasing a counter and switching some LEDs
    • as well as waiting for a button pressed (with a software debouncing waiting for a stable state over 50ms.). Using this second interrupts a global variable "keypressed" will be set.

 

 

Pseudo code looks like this:

// Interrupt for Timer/Counter0 Compare Match A
ISR ( TIMER0_COMPA_vect )
{
	// interrupt routine fired every 1ms gone

	// button debounce mechanism for T1..3 (PC0..2)
	// - the button is assumed to be stable if "pressed" status occurs 50x (=50ms) in a row
	// - temp_state_button_pressed is set in pin change interrupt routine (ISR (PCINT1_vect))

	// an orange led effect is done with timer0/A and a counter that reaches 0
}

// Interrupt for Timer/Counter1 Compare Match A
ISR ( TIMER1_COMPA_vect )
{
	// 1s gone
	
    // some other counter are decreased and some leds flipped if 0 is reached
	}
}

// Interrupt for Timer/Counter1 Compare Match B
ISR ( TIMER1_COMPB_vect )
{
	// similar tasks as in ISR ( TIMER1_COMPA_vect )
}

// Interrupt for switches
ISR ( PCINT1_vect )
{
	// if an pin chance occures, a variable is changed to "pressed", which then will be evaluated in ISR ( TIMER0_COMPA_vect )
}

int main(void)
{
	// Initialization
	init_global_vars();					// initialize global variables 
	init_io_pins();						// configure all I/O pins, active pin change interrupts, copy PINC state (should be 0)
	init_timers();						// initialize timer0 and timer1
	sei (); 							// Enable global interrupts
	
#ifdef _POWER_SAVE_
	// disable unused modules
	enable_ppr();						// set PRR (power reduction register)
	
	// Initialize sleep mode
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);	// or SLEEP_MODE_IDLE SLEEP_MODE_PWR_SAVE SLEEP_MODE_STANDBY  
#endif //_POWER_SAVE_
	
	while (1)
	{
		
#ifdef _POWER_SAVE_
        sleep_enable();
        sleep_bod_disable();
        sleep_cpu();
        sleep_disable();
#endif //_POWER_SAVE_

		// key pressed?
		do 
		{
			// just wait for a key pressed
		} while ( !program_status.T1.button_pressed && !program_status.T2.button_pressed 
			&& !program_status.T3.button_pressed);
		
		// do some things
	}
}

Thus, what I need to have available during sleep is:

  • timer0 and timer1 including the compare match interrupts
  • pin change interrupts
  • external quartz/resonator
  • I/O for the leds

 

Wakeup should be triggered using:

  • pin chance
  • timer compare match

 

In the datasheet, chapter 10.1 sleep modes it seems like only IDLE or STANDBY can be used.

 

Is that correct?

How can I check that the correct mode has been entered (I've got atmel-ice and dW available)?

What would be your best practive?

 

 

Thanks in advance for your support!

 

Regards

Andreas

 

 

This topic has a solution.

Last Edited: Sun. Dec 20, 2015 - 12:25 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The key consideration when sleeping is what peripherals must remain operative. You indicate you are using TIMER0 and TIMER1, which are clocked from CLKio. That clock domain is enabled in IDLE sleep mode, and disabled in all other sleep modes.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, understood. Thanks for the clarification.

 

That is, whenever I use TIMER0 or TIMER1, CLKio is necessary and thus only IDLE mode can be selected.

 

I now decided to take a two-step approach, going to (1) SLEEP_MODE_IDLE whenever waiting for a timer to match or a pin change to happen, and after 60 secs of waiting in the main loop for any user interaction going to SLEEP_MODE_PWR_DOWN.