简体   繁体   中英

avr sleep mode and wake up

I'm trying to put my AtTiny 13 to sleep and wake it up with interrupt. It does go to sleep but it never wakes up. The whole code:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <avr/sleep.h>

#define RED (1<<PB4)
#define RED_HIGH PORTB |=RED
#define RED_LOW PORTB &= ~RED
#define RED_TOG PORTB ^= RED

#define BUTTON 1<<PB1

volatile static bool is_sleeping;

ISR(INT0_vect)
{
    RED_TOG;
    is_sleeping = true;
}

int main(void){

    GIMSK |= 1<<INT0;
    MCUCR |= 0<<ISC00 | 1<<ISC01;
    sei();

    DDRB |= RED;
    DDRB &= ~BUTTON;
    PORTB |= BUTTON;

    RED_HIGH;
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);

    while(1){
        if(is_sleeping){
            sleep_enable();
            sei();
            sleep_cpu();
            sleep_disable();
        }
    }
}

According to sleep.h data it should work. Any ideas?

Update: it does not have problems with waking up from IDLE mode;

Assuming no hardware wiring issues your code is working as follow: after booting your LED is turned on and while-loop is idling since is_sleeping is initially set to zero. First INT0 interrupt toggles LED (turns it off) and sets is_sleeping flag so that while-loop will enter to guarded code in next turn. That code turns MCU to sleep on sleep_mcu() line. Once INT0 interrupt awaits MCU it continues from last place ie it goes back to sleep because is_sleeping is still set! (and in your code is never turned back to false). It means that right after MCU awakes it goes to sleep almost instantly and is off until next INT0 interrupt.

So to answer you question it never wakes up I would say: it does wake up but for really short moment. If you measure current (eg with scope and shunt resistor) you would observe spikes when it wakes and goes asleep immediatelly.

Regardless of you main problem pay attention to code quality. Embedded programming is far from forgiving and you may stuck for hours on trivial mistakes. For instance always be defensive with macro definitions. You defined BUTTON as 1<<PB1 without parens. Difference is that later on you get hit by operators precedence. For instance using DDRB &= ~BUTTON you do not have what you expect. Your right side expression unfolds to 11111100 (because ~1<<1 is 11111110 << 1 ) while you wanted 11111101 (because ~(1<<1) is ~ 00000010 ). If you use PB0 for something else you would expect unwanted behavior.

Also when copying sample code make sure you understand what it stands for. The sample in sleep.h relies on using both sei and cli complementary. In your code you only insist on re-enablig interrupts in loop, which is pointless here.

EDIT: Since you claim wake up works in "idle" mode, then your next issue is that you expect system to wake up on falling edge by setting pair (ISC00,ISC01) to (0,1) in MCUCR . See datasheet chapter 9.2 that says "Note that recognition of falling or rising edge interrupts on INT0 requires the presence of an I/O clock" while table in chapter 7.1 says that Clk_I/0 not present in power-down mode. Your only choice it to make INT0 external interrupt to trigger on low level by setting pair (ISC00,ISC01) to (0,0) in MCUCR .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM