0

I'm trying to put my ATTiny into sleep mode and than wake it up. I use this code to put it to sleep:

void go_to_sleep(){
is_sleeping = true;
RED_HIGH;
YELLOW_HIGH;
GREEN_HIGH;
sleep_enable();
sei();
sleep_cpu();
sleep_disable();

}

Than I use external interrupt but nothing happens.

ISR(INT0_vect)
{
    if(is_sleeping){
        awake();
    }
    if(BUTTON_LOW){ // przycisk wciśnięty?
        _delay_ms(80);
        if(BUTTON_LOW){ // nadal wciśnięty?
            do_thing();
        }
    }
}
void awake(){
    is_sleeping = false;
    RED_LOW;
    YELLOW_HIGH;
    GREEN_HIGH;
}

Any ideas welcomed.

I add main to show that interrupt works fine, I've tested it without sleep mode:

int main(void)
{
MCUCR |= 1<<SE; // zezwolenie na sleep mode
GIMSK |= 1<<INT0; // int0 enable
MCUCR |= 0<<ISC00 | 1<<ISC01; //przerwanie zboczem opadającym
sei(); // zezwolenie na przerwania

//OUTPUTS
DDRB |= RED | YELLOW  | GREEN;
//INPUTS
DDRB &= ~BUTTON;
// Podciągnięcie przycisku do VCC
PORTB |= BUTTON;

set_sleep_mode(SLEEP_MODE_PWR_DOWN); // ustaw tryb sleep modu, ta linijka nie uruchamia go

//Stan początkowy
RED_LOW;
YELLOW_HIGH;
GREEN_HIGH;

timer0(TIMER_PRESCALER_1024,255);

while(1);
}
Piotr Konopacki
  • 85
  • 1
  • 2
  • 7
  • `sei()` isn't that some code to disable interrupts? in which case would the external interrupts be masked? – Jean-François Fabre Nov 13 '17 at 10:57
  • 1
    @Jean-FrançoisFabre no, on AVR, interrupts are enabled when the interrupt flag is *set* (as opposed to e.g. the 6502 which has the opposite logic of the interrupt flag). See e.g. [my working code](https://github.com/Zirias/shuttercontrol/blob/master/shutterctl_attiny84/event.c#L155)... –  Nov 13 '17 at 10:58
  • 2
    in general, your ISR is probably **doing too much**. A *delay* inside an ISR is asking for trouble anyways. ISRs should be as short and quick as possible, try only setting (volatile) flags and doing the work in your main code. –  Nov 13 '17 at 11:05
  • @FelixPalmen that's the 6502 SEI instruction which gave me that idea :) – Jean-François Fabre Nov 13 '17 at 11:43
  • @Jean-FrançoisFabre It is a known defect in Atmel cores. They plagiarized most of their assembler from Motorola, but inverted the meaning of the `sei` and `cli` instructions. So on Atmel, `sei` means allow interrupts, while on Motorola-ish cores it means block all interrupts. They inverted the meaning of the `I` bit in the CCR. – Lundin Nov 13 '17 at 11:43
  • As for why the interrupt doesn't work, you must configure some setting for that particular hardware peripheral (a timer?) and tell it that it should wake the CPU up. I don't know this particular MCU, but that's usually how it goes. – Lundin Nov 13 '17 at 11:45

2 Answers2

0

You must enable the INT0 interrupt in the General Interrupt Mask Register.... enter image description here

Add the line...

GIMSK |= _BV( PCIE );

...before you go to sleep and activating the INT0 pin (by default having a low level) should wake the MCU from sleep.

Note that with your code as shown, I'm not sure that you would be able to tell that the CPU had woken up. Try having an output on a pin for high just before you sleep, and then have it go low when you wake so you will know it happened.

bigjosh
  • 1,273
  • 13
  • 19
  • I use sei() in main function. Isn't that enough? – Piotr Konopacki Nov 14 '17 at 14:16
  • `sei()` does make it possible for an interrupt to happen, but you must individually enable each interrupt source also. In your case, the external interrupt source is enabled by the `INT0` bit in the `GIMSK` register. Other interrupts are enabled in other places. – bigjosh Nov 14 '17 at 18:09
0

I believe you cross-posted your issue with waking up from power-down mode. Verify if my answer to the other question works for you here, i.e. that you cannot wake from power-down using falling edge detection on INT0 because of absence of I/O clock when powered-down.

andy
  • 757
  • 5
  • 13