Edge triggered interrupts -- can they be lost?

If I use the interrupt mode rising, falling, or changing, is there any chance of the interrupt being lost?
For example, if interrupts happen to be turned off right when the change happens, will the interrupt be queued, or will it be lost?
Also, is there a good way of blocking and re-awakening the loop() function, while still allowing interrupt handlers to execute?
Specifically, I'd like to "kick" the loop function in response to the rising edge of an input square wave (from a timer chip) tied to pin 2, and also on the user pressing any of my 4 input buttons (I'll have to rig some logic for this to generate a change on pin 3).

Here's the pseudo-code I want:

void int_pin_2()
{
    interrupted = true;
    source2 = true;
    kick_main_loop();
}

void int_pin_3()
{
    interrupted = true;
    source3 = true;
    kick_main_loop();
}

void loop()
{
    int sources = 0;
    if (!interrupted) {
        wait_for_kick();
        uint8_t sreg = SREG;
        cli();
        if (source2) sources |= 1;
        if (source3) sources |= 2;
        source2 = source3 = interrupted = false;
        SREG = sreg;
    }
    do_stuff(sources);
}

This is pseudo-code, but I hope the intention is clear. If this were running on battery, a low-power state in wait_for_kick() would save battery, although "power off" is not needed -- this will actually run on wall wart, and I'm only trying to write code the way I feel it "should" be written.

Speaking of which: is this structure even a useful desired on the AVR? Is it worth it trying to "do nothing" when I know nothing is happening? Or should I just run loop() full bore and it won't harm or wear out anything? (Assuming I don't actually do anything other than return if there is no input).
I guess a third option is to put in delay(10) in the main loop, rather than wait_for_kick(), but that would increase my worst-case interrupt latency a smidgen -- again, probably doesn't matter for this application, but I don't want to go with "dirty" habits.

jwatte:
If I use the interrupt mode rising, falling, or changing, is there any chance of the interrupt being lost?
For example, if interrupts happen to be turned off right when the change happens, will the interrupt be queued, or will it be lost?

If interrupts happen to be off then any pending interrupt is queued (the queue being one long per interrupt).

There is a priority of interrupts (as described in the manual) - reset being the highest followed by int0 and int1 (and so on).

Once interrupts are on, and if the interrupt condition is met, then it will be serviced in priority order. From page 14 of the manual:

If an interrupt condition occurs while the corresponding interrupt enable bit is cleared, the Interrupt Flag will be set and remembered until the interrupt is enabled, or the flag is cleared by software. Similarly, if one or more interrupt conditions occur while the Global Interrupt Enable bit is cleared, the corresponding Interrupt Flag(s) will be set and remembered until the Global Interrupt Enable bit is set, and will then be executed by order of priority.

Or should I just run loop() full bore and it won't harm or wear out anything?

There is no particular harm in doing that apart from power consumption, which won't matter if you are running off some source other than batteries.

You can put the processor to sleep to save power, however only some interrupts will work then (and depending on the level of sleep). For example, external low interrupts are serviced, but not rising, falling or change.

I think your pseudo-code is unnecessarily complicated. An interrupt should really just set a flag, and a tight loop in the "loop" function will notice it soon enough. You don't need to "kick" it. Testing a couple of booleans will happen quite fast. So really this would do:

volatile boolean source2, source3;

void int_pin_2()
{
    source2 = true;
}

void int_pin_3()
{
    source3 = true;
}

void loop()
{
   if (source2)
     foo ();
   if (source3)
     bar ();
}

Of course, foo and bar should clear the appropriate flag ready for next time.

And the time taken in those functions should be low enough that they are ready to service the next interrupt.

... is there any chance of the interrupt being lost?

The interrupt would be lost if two happened before you could service the first one. So tight coding may be required, depending on how quickly the interrupts arrive, and how much you want to do when they do.

I don't see any particular point in clearing interrupts (ie calling cli) unless you have a clear reason to do so.

Thanks for taking the time to answer! Some follow-up questions if you don't mind:

From page 14 of the manual:

Which manual is that? Is there an official Arduino manual? (My kit didn't come with one) Or are you talking about the AVR datasheet or programmer's manual?

In general, I would be interested in a reference-type document that explains what parts of the environment are Ardunio tools/library, what parts are AVR tools/library, and what parts are hardware, so if something like that exists, I'd love a pointer! (I find the Wiki and docs to be too fragmented -- I'd love one big page with everything if possible...)

I think your pseudo-code is unnecessarily complicated. An interrupt should really just set a flag, and a tight loop in the "loop" function will notice it soon enough. You don't need to "kick" it.

I understand that, if I do not sleep the CPU, then I don't need to "kick" it (wake it up). However, if I just suspend code execution in the main loop, then I imagine I would need to un-suspend it as part of the interrupt. If un-suspend is automatic when returning from the ISR, there's a possible race with the main loop putting the CPU to sleep, too!

I should perhaps preface this that I come at this project from a background where I have done systems development (device drivers, etc) for higher-end chips with features like multi-threading and multi-processing, so some of my habits WRT interrupts and power management come from requirements that probably just aren't there on a single microcontroller with a single thread of execution.

I don't see any particular point in clearing interrupts (ie calling cli) unless you have a clear reason to do so.

I agree that things that have no reason should not be done! However, in the interrupt routines, I set two variables; interrupted and source. In order to test them and clear them in a consistent state, I need to do so without risking a race with the interrupt handlers. The "interrupted" flag is needed only if I want to go the CPU sleep route, which seems to be rather more complex than I necessarily need, as I will be running on wall wart power.

That being said, this project is a learning exercise, and if I want to do batteries the next time, it would be good to understand these things. If there's good documentation about how interrupts and power states/sleep interact, and how to avoid the test-interrupt-sleep race condition, I'd love a pointer!

Again, thanks for your time and reply; I really appreciate it!

Which manual is that?

The Atmega328 datasheet. At over 440 pages I tend to think of it as a manual rather than a sheet.

Reading it is quite helpful, if you find something about (say) SPI being implemented in hardware then you can guess that the libraries just make it easier to use. But something like the 1-wire protocol is implemented entirely in software.

... if I do not sleep the CPU, ...

I did a post about sleeping and waking using the watchdog timer:

Also here, where I demonstrate using a LOW interrupt to wake the CPU from a low level signal on pin 2:

http://arduino.cc/forum/index.php/topic,71748.0.html

That also discusses the issue of where to disable interrupts. Doing it in the wrong place can cost you quite a few clock cycles.

In order to test them and clear them in a consistent state, I need to do so without risking a race with the interrupt handlers.

You are right to be concerned about race conditions, and indeed getting the instruction sequence right can be a challenge at times. I think this works reasonably well:

volatile boolean interrupted;
volatile long counter;

void myISR ()
  {
  if (! interrupted) 
    {
    interrupted = true;
    counter++;
    }  // if not already have an interrupt
  }  // end of myISR

void loop ()
  {
  if (interrupted)
    {

    // do something with counter

    interrupted = false;
    }  // end of if
  } // end of loop

This makes the ISR test to see whether it recently raised a flag (which loop hasn't yet cleared) and if so, it does nothing. That way the ISR doesn't change counter while it is being used.

Of course, you may miss interrupts, but either you can handle them fast enough, or not.

Then in loop you test the flag, and clear it last thing so it doesn't matter if the flag is set the instruction after you cleared it.

Thanks again for your pointers! I'm reading them now.

I think there is a race condition in this code, though:

[quote]void loop ()
  {
  if (interrupted)
    {

    // do something with counter
// <-- interrupt happens here
    interrupted = false;
    }  // end of if
  } // end of loop

If the interrupt happens during the marked line, then the program will be in a state where:

  1. The counter has incremented
    but
  2. the interrupted flag is false, and thus the program will not pay attention to the incremented counter (until perhaps the next time an interrupt comes in).

Also, if the counter is non-atomic (16 bits or more), I believe the AVR will actually break that into multiple cycles, and thus the read of that counter could be interrupted.

In most cases when using more than one byte, I really do think disabling interrupts is necessary to avoid all possible races.

I read that power-saving article, and it shows pretty well how to use the power saving registers.
However, that circuit didn't have to respond to external interrupts, only internal interrupts. Especially when some of those external interrupts are user-generated, things become less predictable.

So, here's the problem I'm thinking about:

  1. My ISR can wake the chip up from sleep.
  2. My main loop can do whatever it wants to do, and then put itself to sleep.
  3. However, if I take an interrupt (say the user presses a button) RIGHT before I call the "go to sleep" function, then the ISR will "wake up" the chip, but the chip (which is already awake) will go right into sleep.

It feels as if, to solve this problem, I really need the ability to "go to sleep and re-enable interrupts" in a single, atomic instruction/call. That way, I can disable interrupts, poll for work to do, and if there's nothing to do, go to sleep and re-enable interrupts without any risk of racing and being stuck in sleep.

Is there some AVR magic to solve this problem?

jwatte:
I think there is a race condition in this code, though: ...

No, because of the way the ISR is written:

void myISR ()
  {
  if (! interrupted) 
    {
    interrupted = true;
    counter++;
    }  // if not already have an interrupt
  }  // end of myISR

An interrupt, while interrupted is true, is discarded. That may not be optimal, but as I said, either your design keeps up with the rate at which interrupts occur, or not.

jwatte:
3) However, if I take an interrupt (say the user presses a button) RIGHT before I call the "go to sleep" function, then the ISR will "wake up" the chip, but the chip (which is already awake) will go right into sleep.

See page 15 of the "manual":

When using the SEI instruction to enable interrupts, the instruction following SEI will be executed before any pending interrupts, as shown in this example.

sei ; set Global Interrupt Enable

sleep; enter sleep, waiting for interrupt
; note: will enter sleep before any pending interrupt(s)

So, you could clear interrupts while setting up for sleep, and then execute the above code. The processor will not process the interrupt after re-enabling interrupts but before sleeping, so you won't sleep directly after the keypress (you'll sleep before).

either your design keeps up with the rate at which interrupts occur, or not.

When I have more than one interrupt source, then there's basically no way that I can guarantee that. I can keep up with the rate from any one source just fine, but two interrupts from different sources may come in at basically arbitrarily close times. Losing the interrupt from the second source just because I'm processing the first source is not OK in this case.

When using the SEI instruction to enable interrupts, the instruction following SEI will be executed before any pending interrupts, as shown in this example.

That's great! That solves exactly the question I had. Thanks for the detailed pointer, too!

jwatte:
When I have more than one interrupt source, then there's basically no way that I can guarantee that. I can keep up with the rate from any one source just fine, but two interrupts from different sources may come in at basically arbitrarily close times.

You mean int0 and int1? They could have different ISRs and different flags, so that shouldn't be a problem.

I'd just like to follow up with a thank you for your considered answers and good pointers. At this point, I think I'm making good progress in the right direction, and I appreciate your time!