In short: I have an Input Capture code and a Power-Saving code combined into one program. Both are adapted from Nick Gammon's examples that work fine independently. When I combined them into one code it only reads the data every other time a single pulse is sent to be captured every 20 seconds. The board sleeps during one idle cycle between the 20 second readings, then wakes up but misses the first reading, and then it stays awake during the next idle cycle and reads the pulse correctly at the 40 second mark for the second reading. And repeats. The references of these two Nick Gammon codes are listed in the program.
Details: Adafruit BlueFruit Feather 32u4 w/nrf51 in the Arduino 1.8.10 IDE. Using Nick Gammon's example for Input Capture an external incoming pulse of around 800 us (micro sec) long pulse is being measured by (ICP3) Input Capture #3 (rewritten from ICP1) on Pin D13 (PC7) (removed the LED). Works good.
Then I had a separate program that puts the board into deep-sleep and using INT0 (D3) to wake it up with an external interrupt signal. Since I was not able to figure out how to use the Input Capture as an ISR Interrupt to wake up the board, I ran the same external pulse signal also to the D3 (INT0) pin. So when the pulse hits both D3 (INT0) and D13 (ICP3) at the same time, and D3 wakes up the board via INT0 and then the ICP3 can capture the pulse and measure it. Then right after that, or several seconds later, can go back to sleep until the next pulse arrives on D13 (ICP3). I spaced the external 800us single pulses 20 seconds apart to make it easier to diagnose. If I remove the line that places the board into sleep "sleep_cpu ();" I get a nice single-shot signal pulse measurement every 20 seconds. Since I am not using the USB-detach and reconnect feature, after the board goes to sleep it disconnects, but I am monitoring the power usage via a Fluke mA meter and I can see when it sleep and when it wakes up, and also monitoring the external pulse going to D13 (ICP3) and D3 (INT0) on the Oscope.
Notes: The Input Capture is listed under the Interrupts, but at a much lower priority then INTo or INT1. I do not need an active USB during the readings or sleep, because using BLE to send the data. The code I posted has the BLE portion removed the make it simpler to troubleshoot. The 800us external single-shot pulse is rock solid I have it showing on the Oscope, at the proper magnitude (0 to 3.3V) and intervals. I am trying to have the CPU sleep between readings. Can be right after the reading or a few seconds later. Interrupts have to be alive and ready to capture in case the 20 seconds becomes 1 or 2 seconds intervals (in real life).
// Time the interval between two consecutive pulses.Frequency timer using input //capture unit #3 on 32u4
// Author: Nick Gammon
// Date: 31 August 2013 http://www.gammon.com.au/timers
// References: here: http://www.gammon.com.au/forum/?id=11504&reply=12#reply12 //and here: https://www.gammon.com.au/power Sketch J
// Info here: http://gammon.com.au/interrupts
//Freq (Hz) Per (µs)
// 8,000,000* 0.125us or 125ns per clock tick at 8mghz
#include "LowPower.h"
//part of work around for BOSD missing functionality in 32u4.
//Not needed for 328p MCUs for sleep.
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/interrupt.h>
#include "avr/io.h"
#include <math.h>
#include <Arduino.h>
// Input: Pin D13 (PC7, ICP3) adafruit 32u which is Timer3 Capture Input pin , //removed D13 LED by cutting trace or by removing resistor before LED13
const int wakeUpPin = 3;
volatile boolean first;
volatile boolean triggered;
volatile unsigned long overflowCount;
volatile unsigned long startTime;
volatile unsigned long finishTime;
volatile unsigned long elapsedTime;
//////START: ISR TIMER/COUNTER PULSE ROUTINE ON D13 INPUT-CAPTURE #3 on 32u4 ////
//https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html //http://medesign.seas.upenn.edu/index.php/Guides/MaEvArM-timer3
// timer overflows (every 65536 counts)
ISR (TIMER3_OVF_vect) //1 3
{
overflowCount++;
} // end of TIMER3_OVF_vect
ISR (TIMER3_CAPT_vect) // 1 3
{
// cancel sleep as a precaution (added here from Power Save)
sleep_disable();
// grab counter value before it changes any more
unsigned int timer3CounterValue;
timer3CounterValue = ICR3;
// see datasheet, page 117 (accessing 16-bit registers)
unsigned long overflowCopy = overflowCount;
// if just missed an overflow
if ((TIFR3 & bit (TOV3)) && timer3CounterValue < 0x7FFF) // 1 3 //http://medesign.seas.upenn.edu/index.php/Guides/MaEvArM-timer3
overflowCopy++;
// wait until we noticed last one
if (triggered)
return;
if (first)
{
startTime = (overflowCopy << 16) + timer3CounterValue;
first = false;
return;
}
finishTime = (overflowCopy << 16) + timer3CounterValue;
triggered = true;
TIMSK3 = 0; // no more interrupts for now // 1 3 //http://medesign.seas.upenn.edu/index.php/Guides/MaEvArM-timer3
} // end of TIMER3_CAPT_vect
/////////////////////////ENF OF: TIMER/COUNTER PULSE MEASURE ROUTINE////////////
////////PREPARE FOR INTERRUPTS ROUTINE FOR TIMER/COUNTER CAPTURE////////////////
void prepareForInterrupts ()
{
noInterrupts (); // protected code
first = true;
triggered = false; // re-arm for next time
// reset Timer 1
TCCR3A = 0; // 1 3
TCCR3B = 0; // 1 3
TIFR3 = bit (ICF3) | bit (TOV3); // clear flags so we don't get a bogus interrupt // 1 3
TCNT3 = 0; // Counter to zero // 1 3
overflowCount = 0; // Therefore no overflows yet
// Timer 3 - counts clock pulses
TIMSK3 = bit (TOIE3) | bit (ICIE3); // interrupt on Timer 3 overflow and input capture
// start Timer 1, no prescaler
TCCR3B = bit (CS30) | bit (ICES3);
// plus Input Capture Edge Select (rising on D13)
//TCCR1B &= ~(1<<ICES1);
//ICP set to trigger on falling/rising edge
// Bit 6 - ICES1: Input Capture Edge select Select edge detection for //input capture function. 0 = Capture on falling edge 1 = Capture on //rising edge
interrupts ();
} // end of prepare For Interrupts
///END OF: PREPARE FOR INTERRUPTS ROUTINE FOR TIMER/COUNTER////////////
///POWER SAVING -SIGNAL INTERRUPT WAKEUP ISR ON D3 on 32u4 or D2 on 328p///
void wakeUp ()
{
// cancel sleep as a precaution
sleep_disable();
// precautionary while we do other stuff
detachInterrupt(digitalPinToInterrupt(wakeUpPin));
//D3 for 32u4 and D2 for 328p (INT0)
} // end of wakeUp
////POWER SAVING ROUTINE - WAKEUP ISR-END/////////////////
////////SET UP VOID ///////////////////////////////////////////
void setup(void)
{
pinMode(wakeUpPin, INPUT); //this is pin D3 (INT0) on 32u4 and D2 (INT0) on 328p
digitalWrite (wakeUpPin, LOW);
// enable pull-down on D3 (on 32u4 D3 is INT0) for Wake INTERRUPT - PART OF //POWER SAVING ROUTINE WITH INT0 SIGNAL on D3 on 32u4 (or D2 on 328p)
Serial.begin(115200);
pinMode(13, INPUT);
//This is the input/measure pin (LED taken off or LED13 resistor removed)
analogWrite(13, LOW); //must pull up or down to stop noise and floating
// set up for interrupts
prepareForInterrupts ();
} // <= this is for the SET UP () ///////
////////////////////////END OF SETUP SEGMENT/////////////////
//////START OF MAIN LOOP/////////////
void loop(void)
{
// wait till we have a reading
if (!triggered) //if "triggered" is NOT TRUE (i.e. NOT TRIGGERED) then STOP HERE
return;
unsigned long elapsedTime = (finishTime - startTime);
//period count between start and stop times
Serial.print ("Start time: ");
Serial.print(startTime);
Serial.print (" counts. ");
Serial.print ("Finish time: ");
Serial.print(finishTime );
Serial.print (" counts. ");
Serial.print ("Elapsed time: ");
Serial.print (elapsedTime);
Serial.println (" counts. ");
// Delay before next measurement update
delayMicroseconds(1000) ;
prepareForInterrupts ();
// goes back up outside LOOP to RESET conditions for next INPUT CAPTURE ISR AND //OVERFLOW ISR TIMER/COUNTER reading, clear registers, etc
///START: POWER SAVING ROUTINE USING D3 (INT0) on 32u4 (D2 is INT0 on 328p) //INTERRUPT FROM PULSE OR USER SWITCH////////////
//delayMicroseconds(3000000) ;
// DELAY SO SLEEP ONLY CAN HAPPEN EVERY 3 sec => 3000000 us (micro sec)
delay(500);// MUST have delay to allow power down process to proceed
// disable ADC
ADCSRA = 0;
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
sleep_enable();
// Do not interrupt before we go to sleep, or the ISR will detach interrupts and we won't wake.
noInterrupts ();
// will be called when INT0 (pin D2 for 328p) or D3 for 32u4 goes HIGH//
attachInterrupt(digitalPinToInterrupt(wakeUpPin), wakeUp, RISING);
// [External Interrupts] //3 for 32u4 and 2 for 328p (INT0) Use RISING as //trigger for (INT0 on D2 for 328p and) INT0 on D3 on 32u4 from op AMP. Same //signal as the D13 INPUT CAPTURE TIMER from op Amp OUT
EIFR = bit (INTF0); // clear flag for interrupt 0
EIFR = bit (INTF1); // clear flag for interrupt 1
// added just for good measure to cover both D2 and D3 INT pins
// turn off brown-out enable in software, BODS does not work with 32u4, only //328p. Work around is to use "low-power.h" library, not implemented here
// BODS must be set to one and BODSE must be set to zero within four clock cycles
// MCUCR = bit (BODS) | bit (BODSE);
// The BODS bit is automatically cleared after three clock cycles
// MCUCR = bit (BODS);
//We are guaranteed that the sleep_cpu call will be done as the processor //executes the next instruction after interrupts are turned on.
interrupts (); // one cycle
// sleep_cpu (); // one cycle //*****DISABLED BECAUSE KEEPS DOUBLING
//DATA SEND TIME, AND ONLY WAKES UP HALF
//THE TIME
///////END OF POWER SAVING ROUTINE///////////////////////////////////////////////
}
///////////////////////END OF MAIN LOOP///////////////////