ATTINY85 / external inerrupt INT0 / RISING

Hallo,
I'm trying for days to get ATTINY85 external interrupt on rising edge working. I've looked around very extendly and read the datsheet carefully. But the code doesn't work. Here it is:

#include <avr/sleep.h>
#include <avr/wdt.h>

/* macros

  • sbi(): a macro to set the bit(the second argument) of the address(the first argument) to 1.
    */
    #ifndef cbi
    #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= -_BV(bit))
    #endif
    #ifndef sbi
    #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
    #endif

volatile int i, i1;
volatile int wakePin = 2; // choose input pin (for PIR sensor) INT0, PCINT2 (PB2) / IC-Pin 7
volatile int ledPin = 4; // choose the pin for the LED (PB4) / IC-Pin 3

/*

  • here the interrupt is handled after wakeup
    */
    ISR(INT0_vect) {
    for (int i = 0; i < 6; i++){ // ISR-handler information on led
    digitalWrite(ledPin, HIGH);
    delay(200);
    digitalWrite(ledPin, LOW);
    delay(200);
    }
    cli(); // disable interrupts
    cbi(GIMSK,INT0); // turns off INT0 as interrupt pin
    sleep_disable(); // clear sleep enable bit
    }

volatile void system_sleep() {
sbi(GIMSK,INT0); // Changes Interrupt to PB2 (PCINT2 / INT0)
sbi(MCUCR, ISC01);
sbi(MCUCR, ISC00);

set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable(); // sets the Sleep Enable bit in the MCUCR Register (SE BIT)
sei(); // enable interrupts
sleep_mode(); // sleep begins here, the device is actually put to sleep!!
}

void setup() {
pinMode(wakePin, INPUT); // declare sensor as input
pinMode(ledPin, OUTPUT);
for (int i = 0; i < 3; i++){ // setup information on led
digitalWrite(ledPin, HIGH);
delay(150);
digitalWrite(ledPin, LOW);
delay(45);
}
}

void loop(){
delay(1000);
digitalWrite(ledPin, HIGH);
delay (1000);
digitalWrite(ledPin, LOW);
delay(1000);
system_sleep(); // Runs the system_sleep() function
}

It bases mainly on this example . There is a resistor between GND and PIN 7. If I set PIN 7 to HIGH nothing happens. IF I set only ISC01 nothing happens, neither with the resistor on GND and setting Pin7 to HIGH nor resistor on VCC and setting Pin7 to LOW. Same with ISC00 ist setted and ISC01 not.
The only workink constalation is ISC00 = LOW and ISC01 = LOW. But I need the RISING option.

Than for helpis

I'm curious to see how far you get with this. I had exactly the same problem with an ATTINY84 recently (getting it to wake up on being triggered by a PIR) and had to change my code to wake up on a pin change interrupt instead of an external interrupt, and that works perfectly well.

On reading the data sheet very carefully, I came to the conclusion that it would work for INT0 waking up only on a level change and not an edge trigger. That level can only be LOW on an ATTINY85.

In Chapter 9.2 External Interrupts, there appears to be a distinction between level and edge triggering:

. . .
The INT0 interrupts can be triggered by a falling or rising edge or a low level.
. . .

This also makes it clearer, again from the datasheet Ch 9.2:

Note that recognition of falling or rising edge
interrupts on INT0 requires the presence of an I/O clock

The clock is not running in this sleep mode.

I have seen examples ( Gammon Forum : Electronics : Microprocessors : Power saving techniques for microprocessors sketch J ) for the ATMEGA328P where it wakes up OK on an edge trigger and the data sheet has more or less the same wording, so there is also clearly something that I do not understand.

By the way, your link above does not work.

aahhhh, thank you! I've got it now. Yes, that's it. The exact link is example (hope it works now) Thank you again.

6v6gt:
I have seen examples ( Gammon Forum : Electronics : Microprocessors : Power saving techniques for microprocessors sketch J ) for the ATMEGA328P where it wakes up OK on an edge trigger and the data sheet has more or less the same wording, so there is also clearly something that I do not understand.

This is more than a year old thread, but I will comment this in case somebody encounters this later. The datasheet are wrong on that part in the table. Nick Gammon confirmed that in 2015 from Atmel staff: Gammon Forum : Electronics : Microprocessors : Interrupts
Every type of interrupt (both edge and level) will wake up the AVR from sleep. I've confirmed this in hardware on at least attiny10 & atmega328p. And I think this is the same for every other AVR MCU with same type of INTx interrupt(s). The Microchip should really fix this at once.

OK but this thread was about this behaviour on an ATTINY85. This (triggering of external interrupts in sleep mode) is exactly where there is a difference between the ATMEGA and ATTINY. It looks like there has been a cut and paste error between the data sheets. Yes it works on an ATMEGA328P but not on an ATTINY85.

This topic appears here from time to time

https://forum.arduino.cc/index.php?topic=536524.0
https://forum.arduino.cc/index.php?topic=585581.0
https://forum.arduino.cc/index.php?topic=530130.0

Keywords for searches:

ATTINY edge triggered interrupt fails to wakeup
ATMEGA can wakeup on rising edge interrupt
ATMEGA datasheet error external interrupts sleep mode
AVR wakeup by external interrupt

Well at least not every attiny are affected (by not waking up). I can confirm that attiny10 does wakes up on falling edge INT0 interrupt. Tested in hardware.

Hi, I found this topic because I was searching information about sleep modes for ATtiny44a family. I designed my pcbs with Kicad but seems like I made a mistake by reading the datasheet of the MCU. Actually I've a push-button connected to PB0 of the attiny44-a that according of datasheet is PCINT8. But seems like for low level sleep modes I should have to use INT0 or PB2, am I right? That means If I want to wake up my MCU from sleep_pwr_down, I have to connect the pushbutton to PB2. Let me know what you thinks, thanks!

I guess you are using @DrAzzy's ATtiny core GitHub - SpenceKonde/ATTinyCore: Arduino core for ATtiny 1634, 828, x313, x4, x41, x5, x61, x7 and x8.
Pin PB0 (PCINT8) would appear to be valid choice for using a push button to wake the device. You have to configure a pin change interrupt (which is a bit trickier than using an external edge triggered interrupt). How have you wired the button and are you using the internal pullup resistor on the pin?
Be aware that this (waking from sleep mode) is an area where the ATtiny differs from the ATmega328p as used on the Uno etc. so you can't use a Uno for testing.

1 Like

Yes, I'm using that library, and I have the 2-pin push-button connected to GND and to PB0. I want to share this part of datasheet where I got confusion:

In the part Low Level Interrupt It says that "interrupt source can be used for waking the part also from sleep modes".

So I thought that only INT0 is the pin needed for waking up the MCU from deep sleep modes... but actually I've wired to PB2 that is a normal PCINTx pin.

Also I'm using INPUT_PULLUP for PB0

Hm, what's different between the wake mechanics on 328p and t85?

Both of them can wake only on CHANGE or LOWLEVEL interrupt from the external interrupt pins, or from a PCINT.

The t85 has only one external interrupt pin (PB2) but other than that they have the same constraints: If you're in power down sleep mode (the only one that really matters on classic AVR), there's no I/O clock. If there's no I/O clock, the pins can't detect whether an edge was rising or falling. It wasn't until parts released after the 2016 revolution that we've had parts with fully async pins that can wake without a clock (and the whole point of power down sleep is that it will turn off the clock, as that's one of the largest users of power)

Edit: Oh, interesting - no, it looks like according to a strict reading of the datasheet, the option to trigger an INTn-type interrupt on either edge wouldn't work for waking from power down sleep, only a low level would (This may not be universal, and I swear I've done it on some classic AVRs). I'm not certain that's how it ACTUALLY works

@Hyuma. Please show the schematic from which your PCB is derived. I presume you want a solution which works without heavy hacks to the board.

@DrAzzy. Positive edge triggered interrupts can wake an ATMEGA328P from power down sleep mode (despite what the data sheet says). However, this does not work with an ATTINY84/85 (empirical evidence - see post #5 for links). I'm not sure, however, if this is still applies to post 2016 parts.
Note: our posts have crossed.

Ah, so you're telling me that I can't wake up from sleep_pwr_dwn mode neither If I'm using PB2 with a push-button?

I don't have the old schematics because I've upgraded the PCBs without push-buttons but only with a normal on-off switch now. But I still have 10 of old pcbs with push-buttons and here you can see the gerbers where there is the push button connected to the PB0 (the red mark).

I'm sure that he is not saying that. PB2 is PCINT10 so can be configured with a pin change interrupt and can, therefore, wake the device from sleep_pwr_dwn mode.

In principle, any pin, which is configurable with pin change interrupts, can wake a device from sleep_pwr_dwn mode. That includes pins which are designated as external interrupt pins.
Because you are using a push button, pin change interrupts are perfectly valid. Some wake up sources (say an RTC) may have problems triggering a pin change interrupt but this is not your case.

Redraw the essential parts of your schematic to avoid further confusion but, in principle, you should be able to achieve your goal with zero changes to the PCB layout. But coding changes will be required.

Ah ok! On my code the essential parts for the interrupt are:

const int buttonPin = PB0; // push button connected to PB0

#define BUTTON_PRESSED LOW // 
#define INTERRUPT_TRIGGER_METHOD RISING // 

Then on my setup I have:

pinMode(buttonPin, INPUT_PULLUP);

// other suff....

attachInterrupt(digitalPinToInterrupt(buttonPin), ISR_buttonReleased, INTERRUPT_TRIGGER_METHOD);

EDIT: The fact is I tested the code with Arduino uno and it's ok... but when I change pin configuration for Attiny44a I have problems and it doesn't work anymore...

You can wake from a pushbutton on that pin just fine in two ways.

  1. Use an external interrupt. Have it trigger on low level. Then, as long as the button is pressed, the interrupt will be continually firing. But the interrupt can be an empty interrupt on a classic AVR.

I would do something like

sleep_cpu(); 
//Interrupt fires. Note that until the pin is released ther (albeit empty) ISR fires once per non interrupt instruction executed. Since that could mess things up later, you probably want to do like....
while(!digitalRead(BUTTON_PIN)); //wait until the pin goes high again. 
// Now you've woken from sleep, stay there waiting for the pin to go high as long as the button was held down, then proceed normally
  1. Use a PCINT. Again, the ISR can be an empty one.

The same construction as above is useful to avoid unexpected interrupts firing some time after the chip wakes and starts executing code (when the button is released. Again, this crude yet effective method is by no means optimal, but is simple and harder to botch the implementation of). I think this technique is used in consumer electronics - you know how many devices don't register a button press until you release it? It also makes it easier to implement a "long press" detection feature.

Yeah, infact my code should work on PCINT8 / PB0. The fact is with Arduino Uno works perfectly, but If i change some parameter for Attiny44a seems like doesnt read at all the pushing and nothing happens.

I've already said back in post #10 that the behaviour of the Uno, with its ATMega328P chip, is completely irrelevant to your edge triggered external interrupt experiments with the ATtiny series. For convenience, I'll repeat it here:

If you want to use PCINT8 / PB0 to wake the device from the Power Down sleep mode, you have to use pin change interrupts. That means, amongst other things, that the attachInterrupt() function cannot be used and you have to directly manipulate the port registers.