[SOLVED] DS3231 interrupt not working

Hello,

I try to wake up an arduino nano from power_off with a timed alarm from the ds3231 real time clock.
The ds3231 module int/sqw pin is connected to pin 2 on the arduino. The arduino is powered off but never wakes up.

Here is the code:

#include <avr/sleep.h>
#include <avr/power.h>
#include <DS3232RTC.h>
#include <Time.h>
#include <Wire.h>

int pin2 = 2;
int seconds = 0;

void pin2Interrupt(void)
{
  detachInterrupt(0);
}

void enterSleep(void)
{
  attachInterrupt(0, pin2Interrupt, FALLING);
  delay(100);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  sleep_mode();
  sleep_disable();
}


void setup()
{
  Serial.begin(9600);
  pinMode(pin2, INPUT_PULLUP);
  setSyncProvider(RTC.get);
  RTC.alarmInterrupt(ALARM_1, false);
  RTC.alarmInterrupt(ALARM_2, false);
  RTC.squareWave(SQWAVE_NONE);
  RTC.setAlarm(ALM1_MATCH_SECONDS, 10, 0, 0, dowSaturday);
  RTC.alarmInterrupt(ALARM_1, true);
  Serial.println(String("System date = ") + day() + "/" + month() + "/" + year() + " " + hour() + ":" + minute() + ":" + second() + "\n");
  Serial.println("Initialisation complete.");
}

void loop()
{
  delay(1000);
  seconds++;
  Serial.print("Awake for ");
  Serial.print(seconds, DEC);
  Serial.println(" second");

  if (seconds == 3)
  {
    Serial.println("Entering sleep");
    Serial.flush();
    seconds = 0;
    delay(200);
    enterSleep();
  }
}

Welcome,

Maybe you have ZS-042 module? If so, read this topic: DS3231 - No Alarm when powered Off. Why? - Programming Questions - Arduino Forum

Edit: also (on most arduinos and most interrupt pins) you cannot wake up from SLEEP_MODE_PWR_DOWN by edge-triggered interrupts. You must use another sleep mode, like SLEEP_MODE_IDLE.

guix:
Welcome,

Maybe you have ZS-042 module? If so, read this topic: DS3231 - No Alarm when powered Off. Why? - Programming Questions - Arduino Forum

Edit: also (on most arduinos and most interrupt pins) you cannot wake up from SLEEP_MODE_PWR_DOWN by edge-triggered interrupts. You must use another sleep mode, like SLEEP_MODE_IDLE.

Thanks guix,

Yes I have this ZS-042 module. According to the thread (and with the help of the pictures of Using a $1 DS3231 Real-time Clock Module with Arduino | Underwater Arduino Data Loggers I removed the resistors.
I also changed the code to

void enterSleep(void)
{
  attachInterrupt(0, pin2Interrupt, LOW);
  delay(100);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  sleep_mode();
  sleep_disable();
}

But the interrupt does not fire. When I set SLEEP_MODE_IDLE the arduino never goes to sleep.

Before you spend too much time looking at the clock module, can you try putting the Arduino in a power down mode and then manually change the state of the interrupt pin to wake it up ?

Edit:
I have also found that calling attachInterrupt can sometimes trigger the interrupt service routine one time which, in your case, would detach the interrupt, but I cannot explain this behaviour.

6v6gt:
Before you spend too much time looking at the clock module, can you try putting the Arduino in a power down mode and then manually change the state of the interrupt pin to wake it up ?

As you can imagine I have already spent several hours trying to solve that problem.
The sketch works when I manually connect pin2 to GND. Then the interrupt is triggered and the arduino wakes up.

The interrupt output of the DS3231 is open drain. You must have a pullup resistor on the connection for it to work.

jremington:
The interrupt output of the DS3231 is open drain. You must have a pullup resistor on the connection for it to work.

You mean that
pinMode(pin2, INPUT_PULLUP);is not sufficient?

INPUT_PULLUP might work.

Have you used an I2C scanner to verify that the ds3231 is wired correctly?

Pete

el_supremo:
Have you used an I2C scanner to verify that the ds3231 is wired correctly?

Pete

The DS3231 is detected at address 0x68, as it is expected.

Once the alarm is triggered you must reset a flag so that it can be triggered again. You can do that by calling RTC.alarm( ALARM_1 ). You normally use this function like this:

void loop()
{
    if ( RTC.alarm( ALARM_1 ) )
    {
      // do something when alarm is triggered
    }
}

I have wasted a lot of time getting this alarm thing to work and wake up my arduino. I'm almost certain you must use a FALLING interrupt for it to work correctly, but I could be wrong.

To add to what guix has said, you should attach the interrupt once in setup() (using RISING or FALLING) and not detach it again. Then use the code provided by guix to detect that the interrupt has occurred and reset the alarm. I don't know how to reset the alarm using that library but it must be in there somewhere.

If you would like to check that the interrupt is working at all try this code which starts the 1Hz square wave and the interrupt toggles the LED.

/*
  A simple sketch to test that a DS3231 RTC is interrupting
  using the 1Hz square wave output.
  The LED should blink on and off once per second.
  Pete (El_Supremo)
*/
#include <Wire.h>

// RTC interrupt (SQW) connected to this pin.
// The interrupt routine then toggles LED_PIN
// On my Teensy 2 it is pin 7
// On NANO it is pin 2
#define RTC_ALARM_PIN 2

volatile short outbit = 0;
volatile unsigned char interrupted = 0;
//=====================================
void rtc_interrupt(void)
{
  // Toggle the LED pin
  outbit ^= 1;
  digitalWrite(LED_BUILTIN, outbit);
}


//=====================================
void setup()
{
  Serial.begin(9600);

  Wire.begin();

  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  RTC_init();
}


void loop(void)
{
}

//=====================================
#define CLOCK_ADDRESS 0x68

#define RTC_CONTROL  0x0E
#define RTC_CTLSTAT  0x0F
#define RTC_CRYSTAL  0x10
//=====================================
void RTC_write_register(unsigned char reg,unsigned char value)
{
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(reg); 
  Wire.write(value);
  Wire.endTransmission();
}

//=====================================
void RTC_init(void)
{
  // Set up the RTC interrupt pin
  pinMode(RTC_ALARM_PIN, INPUT_PULLUP);
  // Attach the SQW interrupt
  attachInterrupt(digitalPinToInterrupt(RTC_ALARM_PIN), rtc_interrupt, FALLING);
  // Initialize control registers for SQW interrupt
  RTC_write_register(RTC_CONTROL,0x00);
  RTC_write_register(RTC_CTLSTAT,0x00);
}

Pete

1 Like

guix:
Once the alarm is triggered you must reset a flag so that it can be triggered again. You can do that by calling RTC.alarm( ALARM_1 ). You normally use this function like this:

void loop()

{
   if ( RTC.alarm( ALARM_1 ) )
   {
     // do something when alarm is triggered
   }
}

That works with LOW interrupt! Thanks.

walto:
As you can imagine I have already spent several hours trying to solve that problem.
The sketch works when I manually connect pin2 to GND. Then the interrupt is triggered and the arduino wakes up.

OK. In that case I would conclude that the pull down from the Clock Module is too soft for the Arduino to detect and would be thinking of slotting in a small one-shot (monostable Multivibrator) to condition the signal so it is not overlooked by the Arduino.

Edit: It looks like you have solved it in the meantime. I guess that is the end of a few frustrating hours of experimentation.

That works with LOW interrupt!

You need to use FALLING (not RISING or LOW). LOW will keep interrupting as long as the signal is LOW.
The clock ticks on the FALLING edge so that's the one to use with the DS3231.

Pete

Unless he detachInterrupt maybe? I realize I never tried this function... :slight_smile:

Unless he detachInterrupt maybe?

Probably.
I have always set attachinterrupt in setup() and let it interrupt at whatever rate is set and not use detachinterrupt at all. Then in loop(), detect that the interrupt has just occurred, one way or another, and clear the alarm (this isn't needed with the 1Hz square wave).

Pete

6v6gt:
OK. In that case I would conclude that the pull down from the Clock Module is too soft for the Arduino to detect

Highly unlikely. But would believe a wiring error, or maybe there is no pull up on the input. If you remove the pull up from the RTC module, you need one on the processor side.

aarg:
Highly unlikely. But would believe a wiring error, or maybe there is no pull up on the input. If you remove the pull up from the RTC module, you need one on the processor side.

The internal pull up is sufficient. (I also checked with external pull ups and found no difference to the internal pullup)

el_supremo:
Probably.
I have always set attachinterrupt in setup() and let it interrupt at whatever rate is set and not use detachinterrupt at all. Then in loop(), detect that the interrupt has just occurred, one way or another, and clear the alarm (this isn't needed with the 1Hz square wave).

Pete

Calling attachinterrupt only in setup loop does not work (for some reason I don't know).

You should design a simpler sketch to only test the interrupt hardware and software. Make sure that it works before you try applying it to the sleep.