TinyAVR Series 1 e.g. ATtiny1614 wake up from interrupt

This is a new variant of the various tales that have been told regarding the older AVR series where, for example, it was possible to wake an ATmega328P using an edge trigger interrupt whereas on, for example, on an ATTiny84 this was not possible and a level change interrupt had to be specified. Much research was done by @NickGammon, @JChristensen especially in identifying mismatches between observed behaviour and data sheets.

Anyway, in this new case some pins can be used to get an edge trigger to force a wake up of a sleeping MCU. Other pins can do so only by a level change. The information is somewhat scattered about in the data sheet.

The properties of the pins (sense control) can be seen here:

So, for example, if you want to set up pin PA4 (Arduino pin D0 for an ATtiny1614) for a level change interrupt and add a pull-up resistor, you'd do something like this:

PORTA.PIN4CTRL = (PORTA.PIN4CTRL & ~PORT_ISC_gm) | PORT_ISC_LEVEL_gc | PORT_PULLUPEN_bm ;

Configuring an edge trigger on another pin, this time PA6 (Arduino pin D2 for an ATtiny1614) could look like this:

PORTA.PIN6CTRL = (PORTA.PIN6CTRL & ~PORT_ISC_gm) | PORT_ISC_FALLING_gc | PORT_PULLUPEN_bm ;

However, you have got to know on which pin(s) an edge trigger is allowed. A level change trigger can be used on (mostly?) all pins.

So, there it is and described as "full asynchronus detection". Pin 2 and pin 6 only on each port can be used as an edge trigger interrupt for the purposes of waking a sleeping MCU.

Any external interrupt can wake up a sleeping MCU in IDLE mode. The "full asynchronous detection" I think pertains to the deepest of all sleep mode.

I believe "full asynchronous detection" is referring to when the main clock is not running, which could also be in standby mode:

This is the test I used:

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

// button on PA6 (arduino D2)  can wake from sleep on falling edge
// button on PA4 (arduino D0)  must wake from sleep on level change 
const uint8_t ledPin = 7 ; // PB0 (arduino D7)



ISR(PORTA_PORT_vect)
{
  PORTA.INTFLAGS = PIN4_bm | PIN6_bm ;  // clear interrupt  **
}

ISR(RTC_CNT_vect)
{
  RTC.INTFLAGS = RTC_OVF_bm | RTC_CMP_bm ;
}

void setup() {
  Serial.begin( 115200 );

  pinMode( ledPin, OUTPUT ) ;
  digitalWrite( ledPin, HIGH ) ;
  delay(1000) ;
  digitalWrite( ledPin, LOW ) ;

  // set up PA6 (D2) for falling interrupts
  //PORTA.PIN6CTRL = (PORTA.PIN6CTRL & ~PORT_ISC_gm) | PORT_ISC_FALLING_gc | PORT_PULLUPEN_bm ;
  
  // OR
  
  // set up PA4 (D0) for LEVEL change interrupts
  PORTA.PIN4CTRL = (PORTA.PIN4CTRL & ~PORT_ISC_gm) | PORT_ISC_LEVEL_gc | PORT_PULLUPEN_bm ;

  // set up RTC
  while (RTC.STATUS > 0) {} // Wait for all register to be synchronized
  cli() ;
  // see http://ww1.microchip.com/downloads/en/AppNotes/TB3213-Getting-Started-with-RTC-90003213A.pdf
  RTC.CLKSEL = RTC_CLKSEL_INT1K_gc; // 32KHz divided by 32, i.e run at 1.024kHz
  RTC.CTRLA = RTC_PRESCALER_DIV1_gc // NO Prescaler
              | RTC_RTCEN_bm         // Enable RTC
              | RTC_RUNSTDBY_bm;     // Run in standby
  RTC.CNT = 0;
  RTC.PER = 4096UL ; // 4 seconds
  set_sleep_mode(SLEEP_MODE_STANDBY);
  RTC.INTCTRL =   RTC_OVF_bm ;   
  sei() ;

}


void loop() {
  digitalWrite( ledPin, HIGH ) ;
  delay( 500 ) ;
  digitalWrite( ledPin, LOW ) ;
  delay( 500 ) ;
  
  cli() ;
  RTC.CNT = 0;
  sei() ;

  sleep_enable();
  sleep_cpu();  
  // wake here
}
1 Like

That's my understanding, yeah, when the main clock is stopped,, they can stay choosy about whether a transition is rising or falling while most pins can only wake on "change" or level, not specific direction of change.. It's like this on all new parts since the 2016 revolution.

The fully async pins' low level int can also be triggered by pulses shorter than one system clock, there is no 3 clock cooldown after reti before it can retrigger - Not sure how that works exactly. The datasheet does provide a side-by-side comparison of the two types of pins in either interrupt or port chapter.

Being able to detect ultra short pulses sounds great, until you realize that noise from the environment causes spurious interrupts on async pins :wink: (of course the usual countermeasures work, they're just more sensitive. also if a pin is connected to nothing and you set it to pull up and enable low level int, it can and often will trigger immediately, while a normal pin usually won't (This was discovered empirically with a pin being used as ersatz reset on tiny 0-series. normal pins worked, using an async one it would sit there continually resetting itself.)

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.