ATtiny3217 1-series wake from sleep

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

It goes to sleep but it never wakes up.

Pin change interrupt works as expected if the sleep_cpu() line in the main loop is commented out.

It works as expected if the debugger is running but on it's own it does not wake on pin change or even on power cycle.

 

Main loop has:

		// enable pin change interrupt on falling edges
		PORTA.PIN7CTRL |= PORT_ISC_FALLING_gc;
		// set power down sleep mode and enable sleep
		set_sleep_mode(SLEEP_MODE_PWR_DOWN);
		cli();
		sleep_enable();
		led_off_all();
		sei();
		sleep_cpu();

ISR looks like:

 

ISR(PORTA_PORT_vect) { // assuming triggered by PA7 as it is the only one enabled
	uint16_t count=20000;
	
	// disable pin change interrupt
	PORTA.PIN7CTRL &= ~0x07;
        // do crude debounce
	while (--count && !(VPORTA_IN & PIN7_bm))
	{
		continue;
	}
	if (!count)
	{
		uart_puts_P(PSTR("Button"));
		uart_puts_P(strEOL);
	}
	// clear PA7 interrupt flag
	PORTA_INTFLAGS |= PORT_INT7_bm;
}  // ISR(PORTA_PORT_vect)

Urgent and desperate, of course.

 

Flame on!

Ian at WO

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

 

I don't know these new AVRs that well but when I look at:

 

 

that seems to say a "change" interrupt will wake from power down - I don't see it suggesting anything about an EDGE working for that?

 

(then again I don't really know the PORT capabilities of these either!)

 

PS just been reading the Sleep and PORT chapters in that datasheet - have to say these new AVR datasheets are utter crap compared to the original tiny/mega ones that made it much clearer about how sleep/wake worked!

 

Last Edited: Fri. Sep 6, 2019 - 01:02 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson, thanks for having a look.

 

I am finding the 1-series a pain, all my codebase for 0-series needs translating to match the new naming system.

 

This seems to say that you can select lots of options for the interrupt, I have tried rising edge, falling edge and low level.  As I said the interrupt works if I comment out the sleep_cpu() and weirdly it works when the debugger is running with the sleep_cpu() but won't work without debugging active????

 

Ian at WO

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


Yeah I saw that too (I am new to this!). So I don't really know how these new AVRs work but if you take a trip down memory lane and look at the way a traditional AVR (like the ubiquitous mega328P (Arduimno) processor) was then you see in that:

 

 

So from power down the only thing that can wake it (port related) are "pin change" or for INT0/INT1 (see footnote 3) you can't use rising edge/falling edge but only "level".

 

So I thought it might be the same for these new chips. But I can't find the equivalent of this kind of info in the sketchy/patchy 3217 datasheet.

 

So you may find that if you set the ISC bits in the PINCTRL to "LEVEL" (0x05) that it might work.

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

Good thought, tried "LEVEL" and it did not work.

 

Just tried it again and I can't even get "LEVEL" to trigger the ISR without the sleep_cpu(), at least my ISR triggers with "FALLING" without the sleep_cpu.

 

Without sleep_cpu(), LEVEL only works with debugger active!! ?? !! ??

Ian at WO

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

Does anyone have any thoughts on why "Start Debugging and Break" /  "Continue" makes my pin change interrupt work as expected but it does not work if I "Start Without Debugging"

Ian at WO

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

New test:

 

It works with

set_sleep_mode(SLEEP_MODE_IDLE);

but not with

set_sleep_mode(SLEEP_MODE_STANDBY);

and not with

set_sleep_mode(SLEEP_MODE_PWR_DOWN);

 

Is there some module/clock.... that I need to enable to make it work????

 

Ian at WO

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

Ian WO wrote:

New test:

 

It works with

set_sleep_mode(SLEEP_MODE_IDLE);

but not with

set_sleep_mode(SLEEP_MODE_STANDBY);

and not with

set_sleep_mode(SLEEP_MODE_PWR_DOWN);

 

Is there some module/clock.... that I need to enable to make it work????

 

Like Cliff, I have little experience with these new AVR's, but in the previous generation of mega's, Idle mode leaves the clocks running, while deeper modes turns off the clock, It may be when in debug mode, the clock must remain on for it to comm with the PC, perhaps that is why it works in debug mode, don't know. 

Try starting a smaller simpler complete program that tests only the wake/sleep functions to narrow down the problem and get a handle on sleep mode.

Post it here so others can follow and make suggestions.  Doing this may just lead you to your answer before you even post it.   Hope that helps.

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

Last Edited: Fri. Sep 6, 2019 - 02:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But this is the thing - the increasing levels of sleep stop more and more of the clocks. If you cut off the clock that is needed to make the wakeup event happen it won't. But even in the deepest power down that are some IO activity that *should* cause wake interrupts.

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

clawson wrote:

But this is the thing - the increasing levels of sleep stop more and more of the clocks. If you cut off the clock that is needed to make the wakeup event happen it won't. But even in the deepest power down that are some IO activity that *should* cause wake interrupts.

 

Exactly, what he said.

 

Ian at WO

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

Ok, here is my minimal test program complete.

It flashes the LED for 2 secs with button press only for set_sleep_mode(SLEEP_MODE_IDLE);

No LED with button for SLEEP_MODE_STANDBY or SLEEP_MODE_PWR_DOWN

 

/*
 * 1-series  sleep test.c
 *
 * Created: 7/09/2019 12:58:06 AM
 * Author : IanGregg
 */ 

#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <stdint.h>
#include <util/delay.h>

#define CLKCTRL_DIVBY_2_bm      (0<<1)      // Prescaler division by 2 mask.
#define CLKCTRL_DIVBY_4_bm      (0x01<<1)   // Prescaler division by 4 mask.
#define CLKCTRL_DIVBY_8_bm      (0x02<<1)   // Prescaler division by 8 mask.
#define CLKCTRL_DIVBY_16_bm     (0x03<<1)   // Prescaler division by 16 mask.

int main(void)
{
	// Set up the clock and prescaler for 4MHz as we only have 1V8
	// Assumes fuses set for 16 MHz, not 20 MHz
	CPU_CCP =  CCP_IOREG_gc;    // Disable pre-scaler edit lockout
	CLKCTRL_MCLKCTRLB = CLKCTRL_DIVBY_4_bm | CLKCTRL_PEN_bm;
	
	// set output for LED
	PORTA_DIR |= PIN3_bm;
	// input pullup and sense falling edge for switch input
	PORTA.PIN7CTRL |= PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc;
    while (1) 
    {
	    // LED on
		VPORTA_OUT |= PIN3_bm;
		_delay_ms(2000);
		// LED off
		VPORTA_OUT &= ~PIN3_bm;
	    // enable pin change interrupt on falling edges
	    PORTA.PIN7CTRL |= PORT_ISC_FALLING_gc;
	    // set power down sleep mode and enable sleep
	    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
	    cli();
	    sleep_enable();
		// make sure the interrupt flag is cleared
	    PORTA_INTFLAGS |= PORT_INT7_bm;
	    sei();
	    sleep_cpu();
    }  // while(1)
}  // main()

ISR(PORTA_PORT_vect) { // assuming triggered by PA7 as it is the only one enabled
	// disable pin change interrupt
	PORTA.PIN7CTRL &= ~0x07;
	// clear PA7 interrupt flag
	PORTA_INTFLAGS |= PORT_INT7_bm;
}  // ISR(PORTA_PORT_vect)

 

Ian at WO

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

>// enable pin change interrupt on falling edges

A synchronous pin can only use LEVEL and BOTHEDGES to wake from sleep. So the datasheet says, anyhow. I think maybe only Px2 and Px6 pins are asynchronous.

 

Not causing a problem at the moment, but you may want to think about how you are using |=. Clearing flags that way will cause a problem in the future, and setting a group of bits (isc in pinctrl) without first clearing that bit group may also cause problems later. Just need to watch out how flags get cleared (=) and how the _gc defines get used.

 

Simple example for a tiny416 (in c++, but you can decode, nothing much going on behind the scenes)-

//attiny416 nano board
#include "Port.hpp"
#include "Slpctrl.hpp"
#include "Delay.hpp"

PB5_OUTL_t led1;
PB4_INLPU_t sw1;

void blink(uint8_t n, uint32_t ms){
    for( n *= 2; n--; led1.tog(), Delay::wait( ms ) );
}

int main() {
    //3 long blinks for app start
    blink( 3, 250_ms );

    sw1.in_mode( Pins::BOTHEDGES );
    Cpuint::set_func( Cpuint::PORTB_INT, [](){ sw1.flagclr(); } );
    Cpuint::on( true );

    for(;;){
        Slpctrl::sleep( Slpctrl::POWERDOWN );
        //5 short blinks after wakeup
        blink( 5, 50_ms );
        //debounce sw1
        while( sw1.ison() );
        Delay::wait( 1_sec );
    }
}

I did also test FALLING, which does not wake as the datasheet says.

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

Thanks curtvm.

 

I just tried BOTHEDGES and did not get my pin change interrupt in Standby or Power Down sleep mode.  It works with Idle sleep mode

 

I thought that I was using asynchronous pin change.  I now see where the fine print says only Px2 and Px6 do asynch, will try wiring my switch to one of those.

 

 

Ian at WO

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

I also tried your code, which worked (a little cleaned up and I'm using pins on an attiny416 nano)-

 

#include <xc.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <stdint.h>
#define F_CPU 4000000ul
#include <util/delay.h>

#define CLKCTRL_DIVBY_4_bm (0x01<<1)

int main(void)
{
    CPU_CCP =  CCP_IOREG_gc;
    CLKCTRL_MCLKCTRLB = CLKCTRL_DIVBY_4_bm | CLKCTRL_PEN_bm;

    // set output for LED - PB5 (low is on)
    PORTB.DIRSET = PIN5_bm;
    PORTB.OUTSET = PIN5_bm;

    while (1)
    {
	PORTB.OUTCLR = PIN5_bm;
	_delay_ms(2000);
	PORTB.OUTSET = PIN5_bm;

        //sw on PB4
	PORTB.PIN4CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);
	cli();
	sleep_enable();
	sei();
	sleep_cpu();
    }
}

ISR(PORTB_PORT_vect) {
    PORTB_INTFLAGS = PORT_INT4_bm;
}

 

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

This may be helpful: Section 15.5.5 in the AVR0 data sheet says, for waking device from sleep:

From all interrupt sense configurations from sleep modes with Main Clock running. Only from

BOTHEDGES or LEVEL interrupt sense configuration from sleep modes with Main Clock stopped.

I have curiosity nano (w/ 4809) and working to see if I can get this demo going for that.

 

EDIT: oops, missed that someone noted this already

Last Edited: Sat. Sep 7, 2019 - 03:08 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

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

extronic.pl

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

I something working for the Curiosity Nano w/ atmega4809 (notably 0-series not 1-series).  This demo flashed the LED twice, then PWR_DOWN sleep, then repeat on button press.

 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#define sleep_cpu() __asm__ __volatile__ ( "sleep" "\n\t" :: )

ISR(PORTF_PORT_vect) {
  PORTF_INTFLAGS |= PORT_INT6_bm;	/* clear */
}

int main(void) {
  PORTF.DIRSET = PIN5_bm;		/* set LED/PF5 as output */
  PORTF.DIRCLR = PIN6_bm;		/* set SW0/PF6 as input */
  PORTF.PIN6CTRL |= PORT_ISC_LEVEL_gc;	/* switch will pull input low */

  //SLPCTRL.CTRLA |= SLEEP_MODE_IDLE;
  //SLPCTRL.CTRLA |= SLEEP_MODE_STANDBY;
  SLPCTRL.CTRLA |= SLEEP_MODE_PWR_DOWN;

  SLPCTRL.CTRLA |= SLEEP_ENABLED_gc;
  sei();

  for (;;) {
    for (uint8_t i = 0; i < 2; i++) {
      _delay_ms(250);
      PORTF.OUTCLR = PIN5_bm;
      _delay_ms(250);
      PORTF.OUTSET = PIN5_bm;
    }

    sleep_cpu();
  }
}

 

EDIT: removed variable "flag" which was used for pre-sleep build-up

Last Edited: Sun. Sep 8, 2019 - 04:23 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And there is a bug above.   Need to set sleep mode using:

  //SLPCTRL.CTRLA = SLEEP_MODE_IDLE;
  //SLPCTRL.CTRLA = SLEEP_MODE_STANDBY;
  SLPCTRL.CTRLA = SLEEP_MODE_PWR_DOWN;
  
  SLPCTRL.CTRLA |= SLEEP_ENABLED_gc; 

 

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

Many thanks to all, special mention to curtvm, I will buy you a drink next time you are in Brisbane.

It was a long night here but got it working just in time for my deadline.

 

What a dreadful datasheet.

 

One general questions:  Is there a reason to prefer the structure member PORTB.OUTSET or the direct define PORTB_OUTSET??

 

 

Ian at WO

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

It you're writing in C or C++ use PORTB.OUTSET, use PORTB_OUTSET if writing asm.

Letting the smoke out since 1978

 

 

 

 

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

And should I add F_CPU=4000000UL as a  compiler symbol in the project setup or should it be a #define somewhere.

 

It seems hard to get the #define recognised properly in all of the include files?

Ian at WO