Go Down

Topic: Which external interrupt to wake 328P? (Read 3161 times) previous topic - next topic

Jack Christensen

Hoping someone can point out where I'm misinterpreting or making an error here. I was innocently reading the datasheet when I realized that some code I had previously written shouldn't work.

From the following sections of the datasheet, my interpretation is that an external interrupt (INT0 or 1, I'm using INT1) will only wake the MCU from power-down mode when configured for a level-based interrupt, not a falling or rising edge. And here's the problem, my code had INT1 configured for a falling edge and it was working. See the test code below, it works either for a low-level interrupt (ISC11=ISC10=0) or for falling edge (ISC11=1, ISC10=0).

Thanks in advance. Not sure which is worse, something that should work but doesn't, or something that shouldn't work but does :smiley-eek:

Notice Note (3):


Note that edge-triggered interrupts require clkIO, which is inactive in power-down mode:




Code: [Select]
/*----------------------------------------------------------------------*
* Sleep demo for ATmega328P.                                           *
* Wire a button from pin D2 (INT0) to ground.                          *
* Wire an LED with an appropriate dropping resistor from pin D13 to    *
* ground.                                                              *
* Pushing the button wakes the MCU.                                    *
* After waking, the MCU flashes the LED, then waits 10 seconds before  *
* going back to sleep.                                                 *
*                                                                      *
* Jack Christensen 07May2013                                           *
*                                                                      *
* Developed with Arduino 1.0.4 and an Arduino Uno.                     *
* Test conditions for all results below:                               *
*   5V regulated power supply, fed to the Vin pin                      *
*   16MHz system clock                                                 *
*   Fuse bytes (L/H/E): 0xFF / 0xDE / 0x05                             *
*   Optiboot bootloader                                                *
*                                                                      *
* Uno R1                                                               *
*   38mA active, 26mA with MCU in power-down mode.                     *
*                                                                      *
* Uno SMD edition                                                      *
*   42mA active, 31mA power-down.                                      *
*                                                                      *
* Adafruit Boarduino                                                   *
*   Power select jumper set to "USB", USB (FTDI) not connected.        *
*   15mA active, 3mA power-down.                                       *
*                                                                      *
* Adafruit Boarduino without power LED                                 *
*   12mA active, 0.1µA power-down.                                     *
*                                                                      *
* Breadboarded ATmega328P-PU                                           *
*   12mA active, 0.1µA power-down.                                     *
*                                                                      *
* This work is licensed under the Creative Commons Attribution-        *
* ShareAlike 3.0 Unported License. To view a copy of this license,     *
* visit http://creativecommons.org/licenses/by-sa/3.0/ or send a       *
* letter to Creative Commons, 171 Second Street, Suite 300,            *
* San Francisco, California, 94105, USA.                               *
*----------------------------------------------------------------------*/

#include <avr/sleep.h>

#define LED LED_BUILTIN            //LED on pin 13
#define KEEP_RUNNING 10000         //milliseconds

void setup(void)
{
    //to minimize power consumption while sleeping, output pins must not source
    //or sink any current. input pins must have a defined level; a good way to
    //ensure this is to enable the internal pullup resistors.

    for (byte i=0; i<20; i++) {    //make all pins inputs with pullups enabled
        pinMode(i, INPUT_PULLUP);
    }

    pinMode(LED, OUTPUT);          //make the led pin an output
    digitalWrite(LED, LOW);        //drive it low so it doesn't source current
}

void loop(void)
{
    goToSleep();
    for (byte i=0; i<5; i++) {     //flash the LED
        digitalWrite(LED, HIGH);
        delay(100);
        digitalWrite(LED, LOW);
        delay(100);
    }
    delay(KEEP_RUNNING);           //opportunity to measure active supply current
}

void goToSleep(void)
{
    byte adcsra, mcucr1, mcucr2;

    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();

//  >>>--> either of the following two lines work!
    EICRA = _BV(ISC11);            //interrupt on falling edge
//    EICRA = 0x00;                  //interrupt on low level

    EIFR = _BV(INTF1);             //ensure interrupt flag is cleared (setting ISCnn can cause an interrupt)
    EIMSK = _BV(INT1);             //enable INT1
    adcsra = ADCSRA;               //save the ADC Control and Status Register A
    ADCSRA = 0;                    //disable ADC
    cli();                         //stop interrupts to ensure the BOD timed sequence executes as required
    mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE);  //turn off the brown-out detector while sleeping
    mcucr2 = mcucr1 & ~_BV(BODSE);
    MCUCR = mcucr1;                //timed sequence
    MCUCR = mcucr2;                //BODS stays active for 3 cycles, sleep instruction must be executed while it's active
    sei();                         //ensure interrupts enabled so we can wake up again
    sleep_cpu();                   //go to sleep
    sleep_disable();               //wake up here
    ADCSRA = adcsra;               //restore ADCSRA
}

//external interrupt 1 wakes the MCU
ISR(INT1_vect)
{
    EIMSK = 0;                     //disable external interrupts (only need one to wake up)
}
MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

CrossRoads

Table 10-1 Note 3 says Level for INT0, 1. That's what I have used.
Maybe your Falling was interpreted as a Level eventually.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Jack Christensen


Maybe your Falling was interpreted as a Level eventually.


I was thinking that with clkIO shut down, it would not be possible to detect a falling edge, so the interrupt should not trigger. And even though the level is held low after the falling edge, the interrupt is not configured to respond to that.

I did some more testing and found that any of the four possible ISC11/ISC10 configurations wake the MCU with the test code.
MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

Nick Gammon

I can reproduce your results, but not explain them. :)
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Jack Christensen


I can reproduce your results, but not explain them. :)


I appreciate that!  :D
MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

Nick Gammon

Further testing reveals that not only does the processor wake up, but it executes the ISR. I had thought maybe it would wake but realize that the "falling" condition was not satisfied.

It's hard to know where to go. Do we have faulty chips? (both of us)

Is the documentation wrong? It seems pretty explicit that it shouldn't be waking.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

LarryD

#6
Jul 29, 2013, 07:38 am Last Edit: Jul 30, 2013, 12:07 am by LarryD Reason: 1
Jack seems to be finding a lot of weird stuff lately.
The way you have it in your schematic isn't the same as how you have it wired up!

Jack Christensen


Further testing reveals that not only does the processor wake up, but it executes the ISR. I had thought maybe it would wake but realize that the "falling" condition was not satisfied.


Thanks again, I did not actually test that.

Quote

It's hard to know where to go. Do we have faulty chips? (both of us)


That's always last on my list. In my case it would be multiple chips, both -AU and -PU packages, so I'd have to rule it out completely. (My chips came from Mouser, not eBay or whatever.)

Quote

Is the documentation wrong? It seems pretty explicit that it shouldn't be waking.


Maybe I should ask Atmel!


Jack seems to be find a lot of weird stuff lately.


I've been accused of that before!  :D :D
MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

Nick Gammon


Maybe I should ask Atmel!


Please do. My experience is the bigger the company, the more they ignore technical queries.

My guess is that the hardware must have some sort of "wake up when the pin changes" built into it, otherwise how do pin change interrupts work? Even with the clock off. However that contradicts the datasheet.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

LarryD

Quote
my code had INT1 configured for a falling edge


If the i/p bounces what would happen?
The way you have it in your schematic isn't the same as how you have it wired up!

Nick Gammon

Yes I suppose it is hard to get a single contact when touching wires together, but still it shouldn't have fired if it was configured for falling (or rising, or change) when it isn't supposed to.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Jack Christensen


Quote
my code had INT1 configured for a falling edge


If the i/p bounces what would happen?


I suppose we get some extra edges for free ;)  I was using a tactile button switch in my test circuit so it was almost certainly bouncing, although note that the first (and only) thing the ISR does is to disable the interrupt. In my real application circuit, the signal is the alarm from an RTC so should be a clean transition. In both circuits the MCU wakes with the interrupt configured for falling edge.
MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

Jack Christensen

Update: I did contact Atmel, this was keeping me up nights. They're looking for an ATmega328P to test the code on :smiley-eek:  In the meantime, in reading datasheets for other ATmega MCUs, I see that some explicitly state that edge-triggered interrupts are detected asynchronously without the I/O clock, and so will wake the MCU from power-down. Depending on the MCU, this does not necessarily apply to all external interrupts.

So this may be a documentation issue. I hope so because I like the ability to wake the MCU with edge-triggered interrupts.

I also experimented with a couple ATtinys (45, 84) and edge-triggered interrupts do not wake the MCU from power-down, but this behavior matches their datasheets.

Should be interesting. Hope to have more soon.
MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

Nick Gammon


They're looking for an ATmega328P to test the code on ...


Perhaps they should contact the supplier. :P
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

fungus



They're looking for an ATmega328P to test the code on ...


Perhaps they should contact the supplier. :P


Request a free sample? See if it makes it past the sample-approvers.


No, I don't answer questions sent in private messages (but I do accept thank-you notes...)

Go Up