user13749: Desired behaviour:

Go to IDLE sleep mode.
When PB2 (blue trace) goes low wake up and give a 10 ms HIGH on PB1 pulling a pull-up low (yellow trace on Figure 1).
Go to 1.

What I get:

Figure 1. (1) The input triggers, (2) the CPU wakes from sleep, (3) the CPU goes back to sleep and wakes up repeatedly until (9) the input goes high again.
I want one 10 ms low pulse and then go back to sleep until the next negative going edge on PB2 regardless of how long PB2 is held low.
Even though I set MCUCR to falling edge of INT0 the device seems to wake repeatedly when PB2 is held low. My code below attempts to solve this by switching to rising edge interrupt if the input is low and falling edge interrupt if the input is high. The result is shown in Figure 1.
void setup(){
  ADCSRA &= ~_BV(ADEN);               // ADC off. ADC not used.
  pinMode(reedPin, INPUT);
}

void loop(){
  system_sleep();                     // Go straigth to sleep.
  // ---- System woken up by interrupt. ---------
  if (!digitalRead(reedPin)) {        // Check that input is low.
    pinMode(outPin, OUTPUT);          // Enable output.
    digitalWrite(outPin, HIGH);       // Pull motor sensor input low by MOSFET.
    delay(pulseTime);                 // Pulse time.
    digitalWrite(outPin, LOW);        // Pulse off.
  }  
}

// From http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/
void system_sleep() {
  MCUCR |= _BV(ISC01);                    // Required for both rising and falling edge interrupt.
  if(digitalRead(reedPin)) {              // Input is high so set interrupt for detecting low.
    MCUCR &= ~_BV(ISC00);                 // Clear MCUCR bit 0 for falling edge interrupt.
  } else {                                // Input is low so set interrupt for detecting high.
    MCUCR |= _BV(ISC00);                  // Set MCUCR bit 0 for rising edge interrupt.
  }
  GIMSK |= _BV(INT0);                     // Enable Pin Change Interrupts
  set_sleep_mode(SLEEP_MODE_IDLE);        // Leaves the clock running for elapsedMillis.
  sleep_enable();                         // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
  sei();                                  // Enable interrupts
  sleep_cpu();                            // sleep
  // ZZZZZZZZZZZzzzzzzzzzzz .......
  // ------- CPU is now asleep and awaiting interrupt. ----------------------
  cli();                                  // Disable interrupts on wake up.
  sleep_disable();                        // Clear SE bit.
}

ISR(INT0_vect){                           // Wake up.
  GIMSK = 0;                              // Disable external interrupts. (Only need one to wake up.)
}

Can anyone guide me through this?
Many thanks.

user7508: The Arduino core configures a timer to deliver a periodic interrupt.
This interrupt is used to implement millis(), delay(), etc. Your
code assumes the external interrupt is the only one the microcontroller
can receive. I guess the timer interrupts may be the cause of the
observed behavior.
I suggest configuring the interrupt for falling edges and leaving it
always on. The ISR can take care of starting the pulse, and setting a
flag to let the main loop know the pulse is active. The main loop can
then stop the pulse when it has been on for long enough:
volatile bool pulse_active;     // whether the pulse is on
volatile uint32_t pulse_start;  // time when it started

ISR(INT0_vect) {
    // Start the pulse.
    digitalWrite(outPin, HIGH);
    pulse_active = true;
    pulse_start = millis();
}

void loop() {
    // End the pulse if it's time to do so.
    if (pulse_active && millis() - pulse_start >= pulseTime) {
        digitalWrite(outPin, LOW);
        pulse_active = false;
    }

    // Take a little nap.
    sleep_mode();
}

Note that the little nap in the code above can be interrupted by either
the external interrupt or the timer interrupt.

13749: <p>Desired behaviour:</p>
<ol>
<li>Go to IDLE sleep mode.</li>
<li>When PB2 (blue trace) goes low wake up and give a 10 ms HIGH on PB1 pulling a pull-up low (yellow trace on Figure 1).</li>
<li>Go to 1.</li>
</ol>
<p>What I get:</p>
<p><a href="https://i.stack.imgur.com/uQSsr.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/uQSsr.png" alt="Oscilloscope view." /></a></p>
<p><em>Figure 1. (1) The input triggers, (2) the CPU wakes from sleep, (3) the CPU goes back to sleep and wakes up repeatedly until (9) the input goes high again.</em></p>
<p>I want one 10 ms low pulse and then go back to sleep until the next negative going edge on PB2 regardless of how long PB2 is held low.</p>
<p>Even though I set MCUCR to falling edge of INT0 the device seems to wake repeatedly when PB2 is held low. My code below attempts to solve this by switching to rising edge interrupt if the input is low and falling edge interrupt if the input is high. The result is shown in Figure 1.</p>
<pre class="lang-cpp prettyprint-override"><code>void setup(){
  ADCSRA &amp;= ~_BV(ADEN);               // ADC off. ADC not used.
  pinMode(reedPin, INPUT);
}

void loop(){
  system_sleep();                     // Go straigth to sleep.
  // ---- System woken up by interrupt. ---------
  if (!digitalRead(reedPin)) {        // Check that input is low.
    pinMode(outPin, OUTPUT);          // Enable output.
    digitalWrite(outPin, HIGH);       // Pull motor sensor input low by MOSFET.
    delay(pulseTime);                 // Pulse time.
    digitalWrite(outPin, LOW);        // Pulse off.
  }  
}

// From http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/
void system_sleep() {
  MCUCR |= _BV(ISC01);                    // Required for both rising and falling edge interrupt.
  if(digitalRead(reedPin)) {              // Input is high so set interrupt for detecting low.
    MCUCR &amp;= ~_BV(ISC00);                 // Clear MCUCR bit 0 for falling edge interrupt.
  } else {                                // Input is low so set interrupt for detecting high.
    MCUCR |= _BV(ISC00);                  // Set MCUCR bit 0 for rising edge interrupt.
  }
  GIMSK |= _BV(INT0);                     // Enable Pin Change Interrupts
  set_sleep_mode(SLEEP_MODE_IDLE);        // Leaves the clock running for elapsedMillis.
  sleep_enable();                         // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
  sei();                                  // Enable interrupts
  sleep_cpu();                            // sleep
  // ZZZZZZZZZZZzzzzzzzzzzz .......
  // ------- CPU is now asleep and awaiting interrupt. ----------------------
  cli();                                  // Disable interrupts on wake up.
  sleep_disable();                        // Clear SE bit.
}

ISR(INT0_vect){                           // Wake up.
  GIMSK = 0;                              // Disable external interrupts. (Only need one to wake up.)
}
</code></pre>
<p>Can anyone guide me through this?</p>
<p>Many thanks.</p>
 7508: <p>The Arduino core configures a timer to deliver a periodic interrupt.
This interrupt is used to implement <code>millis()</code>, <code>delay()</code>, etc. Your
code assumes the external interrupt is the only one the microcontroller
can receive. I guess the timer interrupts may be the cause of the
observed behavior.</p>
<p>I suggest configuring the interrupt for falling edges and leaving it
always on. The ISR can take care of starting the pulse, and setting a
flag to let the main loop know the pulse is active. The main loop can
then stop the pulse when it has been on for long enough:</p>
<pre class="lang-cpp prettyprint-override"><code>volatile bool pulse_active;     // whether the pulse is on
volatile uint32_t pulse_start;  // time when it started

ISR(INT0_vect) {
    // Start the pulse.
    digitalWrite(outPin, HIGH);
    pulse_active = true;
    pulse_start = millis();
}

void loop() {
    // End the pulse if it's time to do so.
    if (pulse_active &amp;&amp; millis() - pulse_start &gt;= pulseTime) {
        digitalWrite(outPin, LOW);
        pulse_active = false;
    }

    // Take a little nap.
    sleep_mode();
}
</code></pre>
<p>Note that the little nap in the code above can be interrupted by either
the external interrupt or the timer interrupt.</p>
