Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using interrupt with sleepDelay in pwrDownMode #16

Open
divya0056 opened this issue Jan 25, 2017 · 4 comments
Open

Using interrupt with sleepDelay in pwrDownMode #16

divya0056 opened this issue Jan 25, 2017 · 4 comments

Comments

@divya0056
Copy link

Hello, trying to keep Arduino in sleep mode until one of the two events have occurred
1 if the desired time has passed , Arduino wakes up does its thing. OR if the time has NOT passed but interrupt pin becomes active Arduino wakes up.
Is this possible?
Thanks for you help.

@divya0056
Copy link
Author

Found closed issue by DimMedvedev and your input. Modified the .CPP file with your input , Having issues to get the code complied. Could you please make changes to the library. I can test it and let you know . Thanks.

@divya0056
Copy link
Author

Ok, was able to compile modified .cpp and .h files with code from n0m1.
When abortCycle is true, arduino stays in sleep until interrupt button is pressed. But it does not wake up by itself if the "sleepTime " has passed.
When abortCycle is false, arduino does not wake up even if the interrupt button is pressed until sleepTime has passed ( mandatory sleep). After sleepTime has passed arduino will wake up only if interrupt button is pressed.

My goal : if interrupt button is pressed regardless of time passed wakeup. if no interrupt button is pressed wake up if time has passed.

/************************************************************************************
*

  • Name : Sleep_n0m1.h
  • Author : Noah Shibley / NoMi Design
  • Date : July 10th 2011
  • Version : 0.1
  • Notes : Some of this code comes from "Cloudy" on the arduino forum
  •  	  http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1292898715
    
  •      Sleep_n0m1 is free software: you can redistribute it and/or modify
    
  •      it under the terms of the GNU General Public License as published by
    
  •      the Free Software Foundation, either version 3 of the License, or
    
  •      (at your option) any later version.
    
  •      Sleep_n0m1 is distributed in the hope that it will be useful,
    
  •      but WITHOUT ANY WARRANTY; without even the implied warranty of
    
  •      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    
  •      GNU General Public License for more details.
    
  •      You should have received a copy of the GNU General Public License
    
  •      along with Sleep_n0m1.  If not, see <http://www.gnu.org/licenses/>.
    

***********************************************************************************/

#include "Sleep_n0m1.h"

Sleep* Sleep::pSleep = 0;

Sleep::Sleep()
{
pSleep = this; //the ptr points to this object
timeSleep = 0; // total time due to sleep
calibv = 1.0; // ratio of real clock with WDT clock
byte isrcalled = 0; // WDT vector flag
sleepCycleCount = 0;
sleepCycleInterval = 100;

}

/********************************************************************
*

  • setSleepMode

********************************************************************/
void Sleep::setSleepMode(int mode)
{
sleepMode_ = mode;
}

/********************************************************************
*

  • calibrateTime

********************************************************************/
void Sleep::calibrateTime(unsigned long sleepTime, boolean &abortCycle) {
// timer0 continues to run in idle sleep mode
set_sleep_mode(SLEEP_MODE_IDLE);
long tt1=millis();
sleepWDT(sleepTime,abortCycle);
long tt2=millis();

calibv = (float) sleepTime/(tt2-tt1);

//Serial.println(calibv);
}

/********************************************************************
*

  • WDTMillis

********************************************************************/
unsigned long Sleep::WDTMillis() {
return millis()+timeSleep;
}

/********************************************************************
*

  • sleepInterrupt [Deprecated]

********************************************************************/
void Sleep::sleepInterrupt(int interrupt,int mode) {

if(mode == FALLING || mode == LOW)
{
   int pin = interrupt + 2; //will fail on the mega
   pinMode (pin, INPUT);
   digitalWrite (pin, HIGH);
}

set_sleep_mode(sleepMode_);
sleep_enable();
attachInterrupt(interrupt,sleepHandler,mode);
sei(); //make sure interrupts are on!
sleep_mode();
 //----------------------------- ZZZZZZ sleeping here----------------------
sleep_disable(); //disable sleep, awake now
detachInterrupt(interrupt);

}

/********************************************************************
*

  • sleepPinInterrupt

********************************************************************/
void Sleep::sleepPinInterrupt(int interruptPin,int mode) {

int intNum = digitalPinToInterrupt(interruptPin);

if(mode == FALLING || mode == LOW)
{
   pinMode (interruptPin, INPUT);
   digitalWrite (interruptPin, HIGH);
}

set_sleep_mode(sleepMode_);
sleep_enable();
attachInterrupt(intNum,sleepHandler,mode);
sei(); //make sure interrupts are on!
sleep_mode();
 //----------------------------- ZZZZZZ sleeping here----------------------
sleep_disable(); //disable sleep, awake now
detachInterrupt(intNum);

}

/********************************************************************
*

  • sleepDelay

********************************************************************/
void Sleep::sleepDelay(unsigned long sleepTime){

boolean abortCycle = false;

sleepDelay(sleepTime,abortCycle);

}

/********************************************************************
*

  • sleepDelay

********************************************************************/
void Sleep::sleepDelay(unsigned long sleepTime, boolean &abortCycle) {
ADCSRA &= ~(1<<ADEN); // adc off
// PRR = 0xEF; // modules off

++sleepCycleCount;
sleepCycleCount = sleepCycleCount % sleepCycleInterval; //recalibrate every interval cycles
if(sleepCycleCount == 1)
{
calibrateTime(sleepTime,abortCycle);
}
else
{
set_sleep_mode(sleepMode_);
int trem = sleepWDT(sleepTime*calibv,abortCycle);
timeSleep += (sleepTime-trem);
}
// PRR = 0x00; //modules on
ADCSRA |= (1<<ADEN); // adc on
}

/********************************************************************
*

  • sleepWDT

********************************************************************/
int Sleep::sleepWDT(unsigned long remainTime, boolean &abortCycle) {

#if defined(WDP3)
byte WDTps = 9; // WDT Prescaler value, 9 = 8192ms
#else
byte WDTps = 7; // WDT Prescaler value, 7 = 2048ms
#endif

isrcalled = 0;
sleep_enable();
while(remainTime > 0) {
//work out next prescale unit to use
while ((0x10<<WDTps) > remainTime && WDTps > 0) {
WDTps--;
}
// send prescaler mask to WDT_On
WDT_On((WDTps & 0x08 ? (1<<WDP3) : 0x00) | (WDTps & 0x07));
isrcalled=0;
while (isrcalled==0 && abortCycle == false) {

  #if defined(__AVR_ATmega328P__)
  // turn bod off
  MCUCR |= (1<<BODS) | (1<<BODSE);
  MCUCR &= ~(1<<BODSE);  // must be done right before sleep
  #endif
  sleep_cpu();  // sleep here
}
// calculate remaining time
remainTime -= (0x10<<WDTps);
if ((long) remainTime < 0 ) {remainTime = 0;} //check for unsigned underflow, by converting to signed

}
sleep_disable();
return remainTime;
}

/********************************************************************
*

  • WDT_On

*******************************************************************/
void Sleep::WDT_On(byte psMask)
{
// prepare timed sequence first
byte ps = (psMask | (1<<WDIE)) & ~(1<<WDE);
cli();
wdt_reset();
/
Clear WDRF in MCUSR */
MCUSR &= ~(1<<WDRF);
// start timed sequence
WDTCSR |= (1<<WDCE) | (1<<WDE);
// set new watchdog timeout value
WDTCSR = ps;
sei();
}

/********************************************************************
*

  • WDT_Off

*******************************************************************/
void Sleep::WDT_Off() {
cli();
wdt_reset();
/
Clear WDRF in MCUSR /
MCUSR &= ~(1<<WDRF);
/
Write logical one to WDCE and WDE /
/
Keep old prescaler setting to prevent unintentional time-out /
WDTCSR |= (1<<WDCE) | (1<<WDE);
/
Turn off WDT */
WDTCSR = 0x00;
sei();
}

/********************************************************************
*

  • sleepHandler ISR

********************************************************************/
void sleepHandler(void)
{

}

/********************************************************************
*

  • WDT ISR

********************************************************************/
ISR(WDT_vect) {
Sleep::pSleep->WDT_Off();
Sleep::pSleep->isrcalled=1;
}

/********************************************************************
*

  • NEW_SLEEP

********************************************************************/

void Sleep::newSleep(unsigned long sleepTime, boolean &abortCycle, int interruptPin, int mode) {

int intNum = digitalPinToInterrupt(interruptPin);

if(mode == FALLING || mode == LOW)
{
pinMode (interruptPin, INPUT);
digitalWrite (interruptPin, HIGH);
}

ADCSRA &= ~(1<<ADEN); // adc off
// PRR = 0xEF; // modules off

++sleepCycleCount;
sleepCycleCount = sleepCycleCount % sleepCycleInterval; //recalibrate every interval cycles
if(sleepCycleCount == 1)
{
calibrateTime(sleepTime,abortCycle);
}
else
{
set_sleep_mode(sleepMode_);
int trem = sleepWDT(sleepTime*calibv,abortCycle);
timeSleep += (sleepTime-trem); }
sleep_enable();
attachInterrupt(intNum,sleepHandler,mode);
sei(); //make sure interrupts are on
sleep_mode();
sleep_disable();
detachInterrupt(intNum);

}
// PRR = 0x00; //modules on
ADCSRA |= (1<<ADEN); // adc on
}

/************************************************************************************
*

  • Name : Sleep_n0m1.h
  • Author : Noah Shibley / NoMi Design
  • Date : July 10th 2011
  • Version : 0.1
  • Notes : Some of this code comes from "Cloudy" on the arduino forum
  •    http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1292898715
    
  •    Sleep_n0m1 is free software: you can redistribute it and/or modify
    
  •    it under the terms of the GNU General Public License as published by
    
  •    the Free Software Foundation, either version 3 of the License, or
    
  •    (at your option) any later version.
    
  •    Sleep_n0m1 is distributed in the hope that it will be useful,
    
  •    but WITHOUT ANY WARRANTY; without even the implied warranty of
    
  •    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    
  •    GNU General Public License for more details.
    
  •    You should have received a copy of the GNU General Public License
    
  •    along with Sleep_n0m1.  If not, see <http://www.gnu.org/licenses/>.
    

***********************************************************************************/

#ifndef SLEEP_H
#define SLEEP_H

#include <avr/sleep.h>
#include <avr/wdt.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

extern "C" void WDT_vect(void) attribute ((signal));
extern "C" void sleepHandler(void) attribute ((signal));

class Sleep {

public:

friend void WDT_vect(void);
friend void sleepHandler(void);

Sleep();

/* modes of sleep
SLEEP_MODE_IDLE
SLEEP_MODE_ADC
SLEEP_MODE_PWR_SAVE
SLEEP_MODE_EXT_STANDBY
SLEEP_MODE_STANDBY
SLEEP_MODE_PWR_DOWN
*/

//------------------------------------------------------
// Description: sets the Arduino into idle Mode sleep,
// the least power saving, The idle mode stops the MCU
// but leaves peripherals and timers running.
//------------------------------------------------------
void idleMode() { setSleepMode(SLEEP_MODE_IDLE);}

//------------------------------------------------------
// Description: sets the Arduino into adc Mode sleep,
// This mode makes the MCU enter ADC Noise Reduction mode,
// stopping the CPU but allowing the ADC, the external interrupts,
// the 2-wire Serial Interface address watch, Timer/Counter2
// and the Watchdog to continue operating.
//------------------------------------------------------
void adcMode() {setSleepMode(SLEEP_MODE_ADC);}

//------------------------------------------------------
// Description: sets the Arduino into power Save Mode sleep,
// The timer crystal will continue to operate in this mode,
// Timer2 still active.
//------------------------------------------------------
void pwrSaveMode() {setSleepMode(SLEEP_MODE_PWR_SAVE);}

//------------------------------------------------------
// Description: sets the Arduino into extStandby Mode sleep,
// This mode is identical to Power-save with the exception
// that the Oscillator is kept running for fast wake up
//------------------------------------------------------
void extStandbyMode(){setSleepMode(SLEEP_MODE_EXT_STANDBY);}

//------------------------------------------------------
// Description: sets the Arduino into standby Mode sleep,
// This mode is identical to Power-down with the exception
// that the Oscillator is kept running for fast wake up
//------------------------------------------------------
void standbyMode(){setSleepMode(SLEEP_MODE_STANDBY);}

//------------------------------------------------------
// Description: sets the Arduino into power Down Mode sleep,
// The most power saving, all systems are powered down
// except the watch dog timer and external reset
//------------------------------------------------------
void pwrDownMode(){setSleepMode(SLEEP_MODE_PWR_DOWN);}

//------------------------------------------------------
// Description: Works like the Arduino delay function, sets the
// Arduino into sleep mode for a specified time.
// Parameters: (unsigned long) time in ms of the sleep cycle
//------------------------------------------------------
void sleepDelay(unsigned long sleepTime);

//------------------------------------------------------
// Description: Works like the Arduino delay function, sets the
// Arduino into sleep mode for a specified time.
// Parameters: (unsigned long) time in ms of the sleep cycle
// (boolean) prevents the Arduino from entering sleep
//------------------------------------------------------
void sleepDelay(unsigned long sleepTime,boolean &abortCycle);

//------------------------------------------------------
// Description: the WDT needs to be calibrated against timer 0
// periodically to keep the sleep time accurate. Default calibration
// occurs every 100 wake/sleep cycles. recalibrate too often will
// waste power and too rarely will make the sleep time inaccurate.
// Parameters: (int) set the # of wake/sleep cycles between calibrations
//------------------------------------------------------
void setCalibrationInterval(int interval){ sleepCycleInterval = interval; }

//------------------------------------------------------
// Deprecated, please use sleepPinInterrupt()
// Description: set the Arduino into sleep mode until an interrupt is
// triggered. The interrupts are passed in as parameters
// Parameters: (int) interrupt value, 0, 1, etc, see attachinterrupt()
// (int) mode of trigger, HIGH,LOW,RISING,CHANGE
//------------------------------------------------------
void sleepInterrupt(int interruptPin,int mode) attribute ((deprecated));

//------------------------------------------------------
// Description: set the Arduino into sleep mode until an interrupt is
// triggered. The interrupt pin is passed in as parameter
// Parameters: (int) interrupt pin value, 2, 3, etc, see attachinterrupt()
// (int) mode of trigger, HIGH,LOW,RISING,CHANGE
//------------------------------------------------------
void sleepPinInterrupt(int interrupt,int mode);

void newSleep(unsigned long sleepTime, boolean &abortCycle, int interruptPin, int mode) ;

private:

int sleepMode_;
unsigned long timeSleep;
float calibv;
volatile byte isrcalled;
static Sleep* pSleep; //static ptr to Sleep class for the ISR
int sleepCycleCount;
int sleepCycleInterval;

void setSleepMode(int mode);
void WDT_Off();
void WDT_On(byte psMask);
int sleepWDT(unsigned long remainTime,boolean &abortCycle);
void calibrateTime(unsigned long sleepTime,boolean &abortCycle); //calibrate the time keeping difference between WDT and Timer0
unsigned long WDTMillis(); // Estimated millis is real clock + calibrated sleep time

};

#endif

// any help greatly appreciated.

@veer5551
Copy link

Hello!
I have the same issue. Any update or help regarding the same is greatly appreciated.
Thank you.

@nullboundary
Copy link
Collaborator

Hmmm, as the library is now there isn't any simple way to do this. However the sleepPinInterrupt library function could be rewritten to pass in a function for the sleep interrupt handler. Something like this:

void Sleep::sleepPinInterrupt(int interruptPin,int mode, std::function<void()> handler){

int intNum = digitalPinToInterrupt(interruptPin);

if(mode == FALLING || mode == LOW)
{
   pinMode (interruptPin, INPUT);
   digitalWrite (interruptPin, HIGH);
}

set_sleep_mode(sleepMode_);
sleep_enable();
attachInterrupt(intNum,handler,mode);
sei(); //make sure interrupts are on!
sleep_mode();
 //----------------------------- ZZZZZZ sleeping here----------------------
sleep_disable(); //disable sleep, awake now
detachInterrupt(intNum);
}

Then define that handler function in your sketch before you pass it into the sleepPinInterrupt function. Or use a C++11 lambda function (similar to a anonymous function in javascript) like so:

sleep.sleepPinInterrupt(intPin,LOW,[](){ 
    //do interrupt handler stuff here
});

I haven't tested any of this stuff, but if you can make it work and make a pull request I'll be sure to add it in to the library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants