Arduino Forum

Using Arduino => Microcontrollers => Topic started by: JChristensen on Jul 29, 2013, 01:10 am

Title: Which external interrupt to wake 328P?
Post by: JChristensen on Jul 29, 2013, 01:10 am
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):
(https://lh6.googleusercontent.com/--ynpOnSqFLw/UfWg5ngiU8I/AAAAAAAAJEc/3LYFDmunXHk/s800/sec_10_1.png)

Note that edge-triggered interrupts require clkIO, which is inactive in power-down mode:
(https://lh5.googleusercontent.com/-IgllOb7OF88/UfWjkr5x0LI/AAAAAAAAJEw/AM0qtUmFgTo/s800/sec_13.png)

(https://lh5.googleusercontent.com/-yLDzPG08KWI/UfWjlnftBeI/AAAAAAAAJE4/sGWpKc3754w/s800/sec_13_2.png)

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)
}
Title: Re: Which external interrupt to wake 328P?
Post by: CrossRoads on Jul 29, 2013, 01:13 am
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.
Title: Re: Which external interrupt to wake 328P?
Post by: JChristensen on Jul 29, 2013, 01:21 am

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.
Title: Re: Which external interrupt to wake 328P?
Post by: nickgammon on Jul 29, 2013, 01:35 am
I can reproduce your results, but not explain them. :)
Title: Re: Which external interrupt to wake 328P?
Post by: JChristensen on Jul 29, 2013, 01:48 am

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


I appreciate that!  :D
Title: Re: Which external interrupt to wake 328P?
Post by: nickgammon on Jul 29, 2013, 07:30 am
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.
Title: Re: Which external interrupt to wake 328P?
Post by: larryd on Jul 29, 2013, 07:38 am
Jack seems to be finding a lot of weird stuff lately.
Title: Re: Which external interrupt to wake 328P?
Post by: JChristensen on Jul 29, 2013, 06:21 pm

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
Title: Re: Which external interrupt to wake 328P?
Post by: nickgammon on Jul 29, 2013, 11:58 pm

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.
Title: Re: Which external interrupt to wake 328P?
Post by: larryd on Jul 30, 2013, 12:10 am
Quote
my code had INT1 configured for a falling edge


If the i/p bounces what would happen?
Title: Re: Which external interrupt to wake 328P?
Post by: nickgammon on Jul 30, 2013, 12:15 am
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.
Title: Re: Which external interrupt to wake 328P?
Post by: JChristensen on Jul 30, 2013, 12:20 am

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.
Title: Re: Which external interrupt to wake 328P?
Post by: JChristensen on Sep 18, 2013, 10:36 pm
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.
Title: Re: Which external interrupt to wake 328P?
Post by: nickgammon on Sep 19, 2013, 12:53 am

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


Perhaps they should contact the supplier. :P
Title: Re: Which external interrupt to wake 328P?
Post by: fungus on Sep 19, 2013, 02:33 am


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.


Title: Re: Which external interrupt to wake 328P?
Post by: oric_dan on Sep 20, 2013, 06:42 pm
Quote
explicitly state that edge-triggered interrupts are detected asynchronously without the I/O clock, and so will wake the MCU from power-down.

I believe this is usually done using an edge-triggered flip-flop that does not have a connection from the system clock, so it will trigger at any time at all, and hold its output until reset - usually by the ISR clearing it in s.w.

Jack, I like your code [will try it myself since I am setting up some battery-operated nodes], but FWIW, I don't think this would work properly with Mega chips, for reasons brought out on other threads recently [ie, interrupts being remapped on those chips],
Code: [Select]
    EIMSK = _BV(INT1);             //enable INT1
Title: Re: Which external interrupt to wake 328P?
Post by: JChristensen on Sep 20, 2013, 07:05 pm

Jack, I like your code [will try it myself since I am setting up some battery-operated nodes], but FWIW, I don't think this would work properly with Mega chips, for reasons brought out on other threads recently [ie, interrupts being remapped on those chips],
Code: [Select]
    EIMSK = _BV(INT1);             //enable INT1


@oric_dan, give me a little more on that please, or maybe links to some of those other threads, I'm not following...
Title: Re: Which external interrupt to wake 328P?
Post by: oric_dan on Sep 20, 2013, 07:20 pm
Check reply #2, etc,
http://forum.arduino.cc/index.php?topic=187600.0

See also the final note on Nick's page,
http://www.gammon.com.au/forum/?id=11488
Quote
Reply #8 on Sat 27 Jul 2013 12:41 AM (UTC)
Interrupt names to pin mappings
Title: Re: Which external interrupt to wake 328P?
Post by: JChristensen on Sep 20, 2013, 07:35 pm
Ah OK, thanks. I wasn't concerned with portability between MCUs or pin mapping. I'm strictly working with the 328P. For whatever reason, I never much got into using Arduino's interrupt functions, I prefer to just code the ISRs and set the registers as needed.

I you do try that code, I'd be very interested in your results. Nick was able to duplicate my results, and I have informed Atmel that my results were independently verified by one person, but the more the merrier. Thanks!
Title: Re: Which external interrupt to wake 328P?
Post by: oric_dan on Sep 20, 2013, 07:40 pm
Yeah, I just thought I'd mention it. If I saw your sketch, and I were using a Mega board, I'd immediately try it of course, since Arduino code is reputed to be so "transportable" across processors, lol. Now, back to work.
Title: Re: Which external interrupt to wake 328P?
Post by: JChristensen on Sep 24, 2013, 03:23 pm
Atmel has reproduced the behavior, and has escalated the issue. I asked whether it might just be a documentation error (reply #12 above).
Title: Re: Which external interrupt to wake 328P?
Post by: SirNickity on Sep 24, 2013, 10:05 pm
Good catch there Jack.  :-)
Title: Re: Which external interrupt to wake 328P?
Post by: nickgammon on Sep 24, 2013, 11:40 pm

Atmel has reproduced the behavior, and has escalated the issue. I asked whether it might just be a documentation error (reply #12 above).


So that's Jack, myself, and Atmel. :)

Well at least we aren't going mad.
Title: Re: Which external interrupt to wake 328P?
Post by: JChristensen on Sep 25, 2013, 12:44 am

Well at least we aren't going mad.


I know! That's what I always think in these situations!  :D
Title: Re: Which external interrupt to wake 328P?
Post by: JChristensen on Nov 18, 2013, 12:02 am
The final word from Atmel:

Quote
From: <avr@atmel.com>
Date: Fri, Oct 11, 2013 at 1:04 AM
Subject: (ATTicket:751590) External interrupt to wake ATmega328P from power-down
To: jack.christensen

Dear Jack,

You are correct, both edge and level based interrupt are waking up the device and the issue have verified with the internal resource. As you mention this has to be updated in the document and this will be updated in the upcoming release.
Thanks for your valuable inputs.
Sorry for the delay in response and Kevin is on leave so the ticket has assinged to me

Best Regards,
Vincent Christopher
Atmel Technical Support Team
Title: Re: Which external interrupt to wake 328P?
Post by: nickgammon on Nov 18, 2013, 04:44 am

You are correct, both edge and level based interrupt are waking up the device and the issue have verified with the internal resource.


It's strangely vague about whether this is by design, or just happens on the chips that are tested.

It would be nice if they had said it is designed to do it.
Title: Re: Which external interrupt to wake 328P?
Post by: JChristensen on Nov 18, 2013, 05:18 am


You are correct, both edge and level based interrupt are waking up the device and the issue have verified with the internal resource.


It's strangely vague about whether this is by design, or just happens on the chips that are tested.

It would be nice if they had said it is designed to do it.


I thought the same thing which is why I asked one final question, that was not answered (below).  Assuming they were diligent about the whole thing, and also assuming that the update to the datasheet will make it read like the other ATmega datasheets, then I can only conclude that the observed behavior is by design.

Quote
From: Jack Christensen
Date: Fri, Oct 11, 2013 at 7:54 AM
Subject: Re: (ATTicket:751590) External interrupt to wake ATmega328P from power-down
To: avr@atmel.com

Hello Vincent,

No problem, thanks for the update.  Just to be clear, the device is operating as designed, and the issue was with the documentation, correct?

Best regards,
Jack Christensen

Title: Re: Which external interrupt to wake 328P?
Post by: SirNickity on Nov 20, 2013, 02:24 am
Ticket Status:  Confirmed Bug Feature
Title: Re: Which external interrupt to wake 328P?
Post by: JChristensen on Nov 20, 2013, 02:38 am

Ticket Status:  Confirmed Bug Feature


I really do think the chip is working as designed, and it was just a documentation error.

What was that old saying?  Something like "A bug is a problem with the code, an error is a problem with the documentation." ??
Title: Re: Which external interrupt to wake 328P?
Post by: ari_jasberg on Aug 27, 2014, 01:02 pm
I have been searching this forum / other forums for an explanation to my findings on m328p, and finally I see this thread. Thanx Jack!

I can confirm wake-up of m328p from power-down on rising/falling edge on INT0 pin. I used a minimalist setup running with 8Mhz internal oscillator on a breadboard, and the triggering edge was generated by a master m328p. After the wake-up, the slave m328p sent a digital signal back to the master that measured the start-up delay to be max  90 microseconds (BOD was disabled on power-down, and according to atmel's documentation this creates a start-up delay of 60us)

I also measured the supply current to the slave m328. In active mode current was 6-7mA, and on entering sleep the current drop to 0.2uA, which confirms that m328p entered power-down mode.

Title: Re: Which external interrupt to wake 328P?
Post by: nickgammon on Jan 08, 2015, 09:00 pm
Atmel has reproduced the behavior, and has escalated the issue. I asked whether it might just be a documentation error (reply #12 above).
Have you got a link to your report, Jack? I submitted my own one yesterday and got this response (the implication being it was news to them)  :

Quote
Commented by Manoraj Gnanadhas (Atmel)
2015-01-08 11:27:32 GMT
[Recipients: Nick Gammon]

Hello Nick,

Thank you for contacting Atmel Technical Support.

It looks like a mistake in the datasheet. We tested here and also able to reproduce the same behavior here. If you refer "Section - 13. External Interrupts (Page-70)", you can read the following information.

"Low level interrupts and the edge interrupt on INT2:0 are detected asynchronously. This implies that these interrupts can be used for waking the part also from sleep modes other than Idle mode."

This is contradicting with the 'Note-3' mentioned under Table 10-1. Therefore I need to confirm this with the concerned team. I will get back to you once I receive any valid update from the design team.

Best Regards,
Manoraj Gnanadhas

Title: Re: Which external interrupt to wake 328P?
Post by: nickgammon on Jan 20, 2015, 08:44 pm
I got this confirmation today that the datasheet was wrong:

Quote
Commented by Manoraj Gnanadhas (Atmel)
2015-01-20 06:23:36 GMT
(Recipients: Nick Gammon)

Hello Nick,

Our design team has confirmed that "Note-3 mentioned under Table 10-1" is a datasheet bug. So you can use any type of interrupt (Rising edge/ Falling edge / Low level / Any logical change) to wake up from sleep mode. Sorry for the inconvenience caused.

Best Regards,
Manoraj Gnanadhas
Title: Re: Which external interrupt to wake 328P?
Post by: ChilliTronix on Jan 20, 2015, 11:20 pm
Well done for getting that out of them Nick!
Title: Re: Which external interrupt to wake 328P?
Post by: nickgammon on Jan 20, 2015, 11:29 pm
Thanks! I've amended my Interrupts page (http://www.gammon.com.au/interrupts) to mention this altered information.
Title: Re: Which external interrupt to wake 328P?
Post by: ChilliTronix on Jan 21, 2015, 12:09 am
Good, because that is where I would look if I were checking!

It is also good to note that almost any form of interrupt would work.
Title: Re: Which external interrupt to wake 328P?
Post by: Charly86 on Apr 09, 2015, 02:53 am
Humm,

This is an interessting post, to be honest, I was using interrupt like that (and worked) without really have read the datasheet on this point. It looked to me so logical (and worked) that I missed this one, good catch.

By the way, while on interrupt post, I would like if possible to ask you guys on your high level of expertise on interrupt. I read all Nick dedicated post about interrupt on his forum (my godness this site is my most technical reference bible) and still have a interrogation due to strange thing happening on my ULPNode  (http://hallard.me/category/ulpnode/)prototypes with IRQ and sleep mode.

Let's say I have this code (I simplified it from my lib)

Code: [Select]


// blah blah configure IRQ that could wake us (in my case INT0 and a Pin change)

volatile uint8_t counter = 0;

// we don't want to be waked by the watchdog, so be
// sure to disable it by changing the config
WDTCSR = _BV(WDCE) | _BV(WDE);
WDTCSR = 0;    

set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
  
// turn off BOD (sequenced order see datasheet)
// Don't change anything before we're waked
MCUCR = _BV(BODS) | _BV(BODSE);
MCUCR = _BV(BODS);
sei();          
sleep_cpu();  
  
// ...........
// ZZZZZZZZZZZ
// ...........
  
// Waked !!!
counter++;
nop(); // be sure to avoid compiler optimization changing 3*+1 counter increment to 1*3
counter++;
nop(); // be sure to avoid compiler optimization changing 3*+1 counter increment to 1*3
counter++;
  


I think while reading this code, your mind is already anticipating my question  ;)

So my question is : what is the 1st instruction executed after wake up ? If I check counter in my IRQ which should have been the 1st instruction executed (well after the IRQ push stack overhead of course) I should always read it to 0 or is there a change that the IRQ trigger was delayed due to wake up and counter incremented before my IRQ was triggered ?

Really thanks for your help


Title: Re: Which external interrupt to wake 328P?
Post by: Coding Badly on Apr 09, 2015, 03:33 am
So my question is : what is the 1st instruction executed after wake up ?
Call to the interrupt service routine vector which is nearly always a jump to the interrupt service routine.  In your case, the vector for the watchdog.

Title: Re: Which external interrupt to wake 328P?
Post by: Charly86 on Apr 12, 2015, 01:55 pm
Hey,

Thank you for your answer, that's what I thought, but sometimes, I saw strange things just like if my code was executed just before entering into my IRQ (the one who wake up me). But I have so much IRQ stuff in my project that it can be another thing. I think I will need to isolate one and write a small sketch with only this config and one IRQ. Then stress it with a switch push button to verify.