attiny13A won't wake up from sleep

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

Hello,
I quite new to AVR. Im using the 13A and want to put the device to sleep, then wake it up using a push button on PB1 for INT0. This same button toggle modes which work, but once in mode 3 (sleep) it wont wake up. It should wake up and then go back to mode 0.
But doesnt.

Thank you in advance.

#define F_CPU 1200000UL

#include 
#include 
#include 
#include 
#include 

static volatile uint8_t counter;

 ///////////////////////////////////////////////////////////////////////////////
int main(void) {
	// turn off unused peripherals to save power
	ACSR = 1<<ACD; // disable analog comparator
	DIDR0 = 1<<ADC3D | 1<<ADC2D | 1<<ADC1D | 1<<ADC0D | 1<<AIN1D | 1<<AIN0D;
   
	DDRB  = (0<<DDB5)| (1<<DDB4)| (1<<DDB3)| (1<<DDB2)| (0<<DDB1)| (1<<DDB0);

	PORTB = (0<<PB5) | (1<<PB4) | (1<<PB3) | (1<<PB2) | (1<<PB1) | (1<<PB0);  

	MCUCR |= (1<<SE);                   // enable idle sleep mode
 
 	GIMSK = _BV (INT0);					 
 	MCUCR = _BV (ISC01);				 

	TCCR0A = (1<<WGM01) | (1<<WGM00);	// Select Fast PWM Mode
 			 
	sei();								 

	counter = 0;
 	 
	 while(1){
		 
		switch(counter) {
			case 0: // stuff goes here

			case 1: // stuff goes here

			case 2: // stuff goes here
					
			case 3: // off - deepest sleep mode
          		  
		  	while(1) {	// deepest sleep mode
			cli();   
			set_sleep_mode(SLEEP_MODE_PWR_DOWN;
			sei();
			sleep_mode();	// go to sleep and wait for interrupt... 
			counter = 0;
			}				
			break;
}//switch
}//while
}//main

///////////////////////////////////////////////////////////////////////////////

ISR(INT0_vect){
   
	counter++;
      	  if(counter > 3){
		  counter = 0;
	  }		  
  	
return;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Fixed code tags above. Your text it supposed to go between [code] and [/ code] (extra space added after the / but it is not added for real code).

Or simply paste the code, highlight it and click on the CODE button.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

Thankyou. I realized in my haste posting, for case 1 and 2 they simply blink an led once and twice respectively so I know I'm switching thru the modes. But when I go to the last mode it never comes out of sleep.

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

Is waking up from the sleep and makes counter=0 then go to sleep again. You can see the wakeup with a multimeter. Remove the second while

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

Still nothing - Im stumped. I have a switch (hardware debounced) connected to PB1 on the tiny13A. Pressing it pulls PB1 to ground (transition 1 to 0). It works to step thru all modes, and gets into sleep mode 3, but never comes out.

Any thoughts ?


// Multi level lava lamp

#define F_CPU 1200000UL  
#include 
#include 
#include 
#include 
#include 

static volatile uint8_t counter;
 
 

void bright(volatile uint8_t new_brightness){

  
      TCCR0B = 0x00;			// Stop clock
      TCNT0 = 0;
      OCR0A = new_brightness;		 
      TIMSK0 &= ~(1<<TOIE0);	 
											
      TCCR0A |= (1<<COM0A1) | (1<<COM0A0);
      TCCR0B = (1<<CS01);		// Use the internal clock / 8 = 150 KHz
            
      return;
}

///////////////////////////////////////////////////////////////////////////////

  int main(void) {
   
	DDRB  = (1<<DDB5)| (0<<DDB4)| (1<<DDB3)| (1<<DDB2)| (0<<DDB1)| (1<<DDB0);  //PB4 and PB1 as inputs, others set as out.
	PORTB = (1<<PB5) | (1<<PB4) | (1<<PB3) | (1<<PB2) | (1<<PB1) | (1<<PB0);  
	MCUCR = _BV (ISC01);	// INT0 is falling edge.
	PCMSK = _BV (PCINT4);	// PCINT4 = PB4 pin 3.
	GIMSK = _BV (INT0);		// Enable external interrupt INT0.
	TCCR0A = (1<<WGM01) | (1<<WGM00);	// Select Fast PWM Mode
	//TCCR0B = (1<<CS00);	// Use the internal clock for the counter with no prescaling.
	sei();			// Enable interrupts (best to do this after all the initializations are done)
	
	counter = 0;		// Our starting mode.
 	 	 
	 while(1){
		switch(counter) {
			
			case 0: // 100%				
				bright(254);			 
				while(counter == 0){	 
 				}						 
				break;
			case 1: // Dimmer
				bright(24);
				while(counter == 1){
				}				
				break;
			case 2: // Dimmer
				bright(4);
				break;
			case 3: // off - deepest sleep mode
 				set_sleep_mode(SLEEP_MODE_PWR_DOWN);	// Use the Power_Down sleep mode   
				cli();					// Clear Interrupts so we are not bothered while going into sleep.
				sleep_enable();		// enable sleep mode (MCUCR |= (1<<SE))
				sei();			// enable interrupts
				sleep_cpu();		// g'night.
				sleep_disable();		// Woken up, reset the SE bit.
				sei();			// Re-enable Interrupts
				
				counter = 0;
				break;
														
		}//switch
	 }//while
}//main

///////////////////////////////////////////////////////////////////////////////

ISR(INT0_vect){
		
	  counter++;
      	  if(counter > 3){
	  counter = 0;
	  }		  
return;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

then wake it up using a push button on PB1 for INT0.

What does the datasheet say about waking up from power-down sleep using an external interrupt? Something about "low-level only" perhaps?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Quote:
Something about "low-level only" perhaps?

p. 30 "Note: 1. For INT0, only level interrupt."
and p. 31 "
Only an External Reset, a Watchdog Reset, a Brown-out
Reset, an external level interrupt on INT0, or a pin change interrupt can wake up the MCU. This
sleep mode halts all generated clocks, allowing operation of asynchronous modules only."
So the clock stops, but INT0 operates on it asynchonously without the need for a clk.
So... I'm not clear on the meaning of "low-level" only.

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

Look at MCUCR and the ICSmn bits.

Now, it gets a hair tricky, ans level-triggered interrupt keeps firing. So you need to disable it in the ISR, and clear the flag before re-enabling. perhaps simpler to use pin-change instead? But then you need to debounce a button/switch to avoid multiple hits.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
         case 3: // off - deepest sleep mode
             set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // Use the Power_Down sleep mode   
            cli();               // Clear Interrupts so we are not bothered while going into sleep.
            sleep_enable();      // enable sleep mode (MCUCR |= (1<<SE))

GIFR = _BV(INTF0); // clear an existing hit
GIMSK |= _BV(INT0); // re-enable interrupt
            sei();         // enable interrupts
            sleep_cpu();      // g'night.
            sleep_disable();      // Woken up, reset the SE bit.
// superfluous            sei();         // Re-enable Interrupts
            
            counter = 0;
            break;
...
ISR(INT0_vect){
      
GIMSK &= ~(_BV(INT0)); // disable level-triggered interrupt

     counter++;
           if(counter > 3){
     counter = 0;
     }       
return;
} 
 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

hmm, pressing the button only increments it to case 1 now, and doesnt get any further.

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

thank you for the input.
so.. maybe the better question to ask, is
1) how would I know the int keeps firing - I dont see that in the datasheet.
and
2) Why do I need to disable it in the ISR? The ISR sets the flag in the GIFR, and auto clears it when the ISR is done executing it. Im using the ISR to increment a counter to go thru the modes which works. Its coming out of sleep when it doesnt seem to know the INT0 has been hit.

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

Quote:

1) how would I know the int keeps firing - I dont see that in the datasheet.

Eh?
tiny13 datasheet wrote:
When the INT0 interrupt is enabled and is configured as level triggered, the interrupt will trigger as long as the pin is held low.

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

ok, I have a momentary switch on PB1 that debounced via hardware. In the code example given above it seems to disable my interrupt the first time thru and never recovers.

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

Quote:

momentary

Just to note that in terms of a micro "momentary" may be 1,000's if not 10's of 1,000's of cycles.

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

Quote:

In the code example given above it seems to disable my interrupt the first time thru and never recovers.

How are you determining this? How are you determining this value for "counter"?

Your code as last shown, with my changes, will awaken, CLEAR "COUNTER", and immediately go back to sleep. It will keep doing this until you happen to release the button in the proper microsecond or two. As written, there is a race between clearing the flag and actually going to sleep.

For just those reasons I've been using pin-change to awaken since it became available some years ago.

A general approach:
1) Do some useful stuff. This takes some time; more than e.g. a few microseconds.
2) Decide nothing important is happening; time for a nap.
2a) "Nothing important" includes the "wake" button not being triggered. In your case, you'd wait until the button pin is high.
3) Prepare for sleep. (in a real app, shut down peripherals, PRR, etc.)
4) Crawl into bed and go to sleep.
5) Awaken when the alarm goes off.
6) Carry out your morning ablutions. (in a real app, PRR & peripheral startup)
7) Go to step 1).

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.