Arduino Forum

Using Arduino => Programming Questions => Topic started by: whoru on Jul 03, 2015, 12:30 am

Title: External RTC to wake Arduino up on interrupt
Post by: whoru on Jul 03, 2015, 12:30 am
Hi.

I have got RTC DS3231 working pretty well. I set my RTC to send interrupt signal on int.0 (pin2) every full minute. Was working great, I had the LED switch ON/OFF every minute. I assumed here that interrupts are working and I can use it as interrupt to wake an Arduino up. Well not so much.

Must mention here that I am using:
This (https://github.com/rocketscream/Low-Power) library for low power
and This (https://github.com/JChristensen/DS3232RTC) library for DS3231.

As provided in an example from library (https://github.com/rocketscream/Low-Power/blob/master/Examples/powerDownWakeExternalInterrupt/powerDownWakeExternalInterrupt.ino) and HERE (http://forum.arduino.cc/index.php/topic,37516.0.html) I am told that I can wake up Arduino when pin is low.

What I would like to achieve is obviously to wake Arduino up on interrupt from DS3231 every minute.
Here is my code. Would appreciate any help on that.

Code: [Select]
// Using JChristensen library

#include <DS3232RTC.h>
#include <Time.h>
#include <Wire.h>
#include "LowPower.h"

tmElements_t tm;

time_t cvt_date(char const *date, char const *time)
{
    char s_month[5];
    int year;
    tmElements_t t;
    static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";

    sscanf(date, "%s %hhd %d", s_month, &t.Day, &year);
    sscanf(time, "%2hhd %*c %2hhd %*c %2hhd", &t.Hour, &t.Minute, &t.Second);

    t.Month = (strstr(month_names, s_month) - month_names) / 3 + 1;
   
    /*
    if( year > 99)
      t.Year = year - 1970;
    else
      t.Year = year + 30;
    */
    t.Year = year - 1970;

    return makeTime(t);
}

int switchPin = 2;
int ledPin = 13;
boolean lastButton = LOW;
boolean ledOn = false;

void blink() {
  if (digitalRead(switchPin) == HIGH && lastButton == LOW) {
    ledOn = !ledOn;
    lastButton = HIGH;
  } else {
    lastButton = digitalRead(switchPin);
  }
  digitalWrite(ledPin, ledOn);
}

void pin2Interrupt(void)
{

}

void setup(void) {
  Serial.begin(9600);
  pinMode(ledPin,OUTPUT);
  pinMode(switchPin,INPUT);

  //attachInterrupt(0, pin2Interrupt, CHANGE);
 
  Serial.println(String("__DATE__ = ") + __DATE__);
  Serial.println(String("__TIME__ = ") + __TIME__);
 
  setTime(cvt_date(__DATE__, __TIME__));
  RTC.set(now());
  RTC.squareWave(SQWAVE_NONE);
  RTC.setAlarm(ALM2_EVERY_MINUTE,0,0,0);
  RTC.alarmInterrupt(ALARM_2, true);
 
  Serial.println(String("System date = ") + day() + "/" + month() + "/" + year() + " " + hour() + ":" + minute() + ":" + second() + "\n");

}

void loop(void) {
  //digitalClockDisplay(); //print time and date
  Serial.println("Entering sleep mode");
  delay(1000);
  attachInterrupt(0, pin2Interrupt, LOW);
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
  detachInterrupt(0);
}

void digitalClockDisplay(void)
{
  // digital clock display of the time
  RTC.read(tm);
  Serial.print(tm.Day,DEC);
  Serial.print('/');
  Serial.print(tm.Month, DEC);
  Serial.print('/');
  Serial.print(tm.Year+1970, DEC);
  Serial.print("   ");
  Serial.print(tm.Hour, DEC);
  Serial.print(':');
  Serial.print(tm.Minute, DEC);
  Serial.print(':');
  Serial.println(tm.Second, DEC);
 
  if (RTC.alarm(ALARM_2) ) {
    Serial.println("ALARM");
  }
}


I have 4.7k Ohm resistor between SQW and +5V.
Title: Re: External RTC to wake Arduino up on interrupt
Post by: nickgammon on Jul 03, 2015, 12:59 am
Code: [Select]
  attachInterrupt(0, pin2Interrupt, LOW);


You are better off using FALLING than LOW.

Quote
Well not so much.
What is the problem? It doesn't sleep? It doesn't wake?
Title: Re: External RTC to wake Arduino up on interrupt
Post by: whoru on Jul 03, 2015, 01:05 am
You are better off using FALLING than LOW.

What is the problem? It doesn't sleep? It doesn't wake?
MASSIVE EDIT : Wow. Nick you were right. Tried it with FALLING and it works like a charm. Thanks!

After Nick posted I got it working without 3rd party library like this but first code is neater:
Code: [Select]
#include <avr/sleep.h>
#include <avr/power.h>
#include <DS3232RTC.h>
#include <Time.h>
#include <Wire.h>

tmElements_t tm;

//CONVERT __DATE__ and __TIME__ to time_t
time_t cvt_date(char const *date, char const *time) {
    char s_month[5];
    int year;
    tmElements_t t;
    static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";

    sscanf(date, "%s %hhd %d", s_month, &t.Day, &year);
    sscanf(time, "%2hhd %*c %2hhd %*c %2hhd", &t.Hour, &t.Minute, &t.Second);

    t.Month = (strstr(month_names, s_month) - month_names) / 3 + 1;
   
    /*
    if( year > 99)
      t.Year = year - 1970;
    else
      t.Year = year + 30;
    */
    t.Year = year - 1970;

    return makeTime(t);
}

int pin2 = 2;

void pin2Interrupt(void) {

  detachInterrupt(0);
}

void enterSleep(void) {
 
  /* Setup pin2 as an interrupt and attach handler. */
  attachInterrupt(0, pin2Interrupt, LOW);
  delay(100);
 
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 
  sleep_enable();
 
  sleep_mode();
 
  /* The program will continue from here. */
 
  /* First thing to do is disable sleep. */
  sleep_disable();
}

void setup() {
  Serial.begin(9600);
 
  /* Setup the pin direction. */
  pinMode(pin2, INPUT);
 
  setTime(cvt_date(__DATE__, __TIME__));
  RTC.set(now());
  RTC.squareWave(SQWAVE_NONE);
  RTC.setAlarm(ALM2_EVERY_MINUTE,0,0,0);
  RTC.alarmInterrupt(ALARM_2, true);
 
  Serial.println(String("System date = ") + day() + "/" + month() + "/" + year() + " " + hour() + ":" + minute() + ":" + second() + "\n");
 
  Serial.println("Initialisation complete.");
}

int seconds = 0;

void loop() {
  delay(1000);
  seconds++;
 
  Serial.print("Awake for ");
  Serial.print(seconds, DEC);
  Serial.println(" second");
  //digitalClockDisplay(); //print time and date
 
  if(seconds == 3) {
    Serial.println("Entering sleep");
    digitalClockDisplay();
    delay(200);
    seconds = 0;
    enterSleep();
  }
 
}

//PRINT TIME FROM RDS3231
void digitalClockDisplay(void) {
  // digital clock display of the time
  RTC.read(tm);
  Serial.print(tm.Day,DEC);
  Serial.print('/');
  Serial.print(tm.Month, DEC);
  Serial.print('/');
  Serial.print(tm.Year+1970, DEC);
  Serial.print("   ");
  Serial.print(tm.Hour, DEC);
  Serial.print(':');
  Serial.print(tm.Minute, DEC);
  Serial.print(':');
  Serial.println(tm.Second, DEC);
 
  if(RTC.alarm(ALARM_2)) {
    Serial.println("ALARM");
  }
}
Title: Re: External RTC to wake Arduino up on interrupt
Post by: jboyton on Jul 03, 2015, 01:33 am
I read in the Atmega328 datasheet that for INT0 and INT1 only  a "level interrupt" will wake the processor. Why, then, is it waking on an edge interrupt?

(http://s13.postimg.org/6j3arz4sn/wakeup.jpg)
Title: Re: External RTC to wake Arduino up on interrupt
Post by: nickgammon on Jul 03, 2015, 02:08 am
See: http://www.gammon.com.au/interrupts (http://www.gammon.com.au/interrupts)

Confirmed by Atmel that the datasheet is 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: External RTC to wake Arduino up on interrupt
Post by: jboyton on Jul 03, 2015, 02:33 am
Nice!

edit: So why doesn't a level interrupt work for him?
Title: Re: External RTC to wake Arduino up on interrupt
Post by: nickgammon on Jul 05, 2015, 10:42 pm
Level interrupts are problematic because they continue firing. Unlike an edge interrupt it keeps calling the ISR while the level is still LOW. This could cause the sketch to run extremely slowly until the interrupt is disabled.
Title: Re: External RTC to wake Arduino up on interrupt
Post by: jboyton on Jul 06, 2015, 04:09 pm
How did you know I edited this thread?

Is there an edge interrupt for forum thread edits that you had enabled?
Title: Re: External RTC to wake Arduino up on interrupt
Post by: nickgammon on Jul 06, 2015, 11:32 pm
Under each post it tells you if someone edited it:

Quote
Re: External RTC to wake Arduino up on interrupt
Jul 03, 2015, 10:33 am Last Edit: Jul 04, 2015, 01:40 am by jboyton
Or did you not mean that?
Title: Re: External RTC to wake Arduino up on interrupt
Post by: jboyton on Jul 07, 2015, 12:45 am
No, I meant how did you know to go back and look at this thread when it hadn't been replied to since your last post? Is there a notification mechanism for threads where a post is edited?
Title: Re: External RTC to wake Arduino up on interrupt
Post by: nickgammon on Jul 07, 2015, 01:28 am
Ah, I see. As it happened I was searching for a thread that mentioned Manoraj Gnanadhas from Atmel, because of the issue of whether interrupts were triggered by a falling level or not. Having found this thread (for an unrelated reason to your edit) I noticed the edit and responded to it.