Can get DS3231 wakeup despite using trick of ShermanP

Hi,
I'm using the trick proposed by ShermanP to reduce power consumption of a battery powered project.

For those whose do not know the trick, it consists to cut the wire between the SQW pin and the pullup resistor; and then it is possible to power the RTC module only when you want to communicate with it.

I did everything adviced on the post (october 2020 - sorry I don't know how-to re add a reference to this post) but once I stop the power of the RTC, it will not wakeup.

If I do not stop the power (by calling "return;" at the very first line of the rtcPowerOff function, the program works correctly..

I checked with ohm-meter and the wire between the SQW pin and the resistor is cut

Below is the program (testing code)

any idea what you have a look at ? or did I do an error ?

thanks

Vincent

#include <TimeLib.h>        // https://github.com/PaulStoffregen/Time
#include <DS3232RTC.h>      // https://github.com/JChristensen/DS3232RTC
#include <Wire.h>           // https://arduino.cc/en/Reference/Wire
#include <Streaming.h>      // https://github.com/janelia-arduino/Streaming
#include <Wire.h>
#include <LowPower.h>
#include <avr/power.h>

#include "RTClib.h"
#include "DS3231Functions.h"

// LEDs and switchs
const byte ledPin1 = LED_BUILTIN ;
const byte buttonPin1 = 12;
 
// Booleans for input states
volatile bool D12_state = LOW;

volatile bool rtcAlarm {false};         // ISR flag
DS3232RTC myRTC;

constexpr uint32_t ledInterval {10};    // seconds to leave the LED on after an alarm
// set current date time to RTC
// year is assumed to be tenths only (i.e. 20 means 2020)

const uint8_t do_rtcPower=6;

void rtcPowerOn()
{ 
  pinMode(do_rtcPower, OUTPUT);
  delay(100);
  digitalWrite(do_rtcPower,HIGH);
  delay(100);
  myRTC.begin();//Wire.begin();
}

void rtcPowerOff()
{ 
  //return;          
  Wire.end();
  digitalWrite(do_rtcPower,LOW);
  delay(100);
  pinMode(do_rtcPower, INPUT);       // high-z, turn off power to the rtc
}

void setup() 
{
 Serial.begin(115200);
 Serial << F("> Setup()\n");

  // Set LEDs as outputs
  pinMode(ledPin1, OUTPUT);
  digitalWrite(ledPin1,LOW);
   
  // Set switches as inputs with pullups
  pinMode(buttonPin1, INPUT_PULLUP);
 
  // Enable PCIE2 Bit0 = 1 (Port B) & Bit2 (Port D)
  PCICR |= B00000001;
  
  // Enable interrupt on D12  (D12-PB4-PCINT4)
  PCMSK0 |= B00010000;

  rtcPowerOn();

  Serial << F("Sketch start "); 
  printTime(myRTC.get());

  // initialize the alarms to known values, clear the alarm flags, clear the alarm interrupt flags
  myRTC.setAlarm(DS3232RTC::ALM1_MATCH_DATE, 0, 0, 0, 1);
  myRTC.alarm(DS3232RTC::ALARM_1);
  myRTC.alarmInterrupt(DS3232RTC::ALARM_1, false);
  myRTC.squareWave(DS3232RTC::SQWAVE_NONE);   // assert INT/SQW pin on alarm
  
  Serial << F("now= "); printTime(myRTC.get());
  Serial << F("< Setup()\n");
  rtcPowerOff();
}

const uint8_t wakeInterval=10;
void loop()
{
  rtcPowerOn();
  
  time_t wake = myRTC.get()+wakeInterval;
      
  Serial << F("Setting alarm for ");   
  printTime(wake);
  myRTC.setAlarm(DS3232RTC::ALM1_MATCH_DATE, second(wake), minute(wake), hour(wake), day(wake));
  myRTC.alarmInterrupt(DS3232RTC::ALARM_1, true);

  Serial << F("Going to sleep at "); 
  printTime(myRTC.get()); Serial.flush(); 

//  interrupts();
  rtcPowerOff();
  goToSleep();
  
  //noInterrupts();
  Serial << F("Alarm at "); 
  
  rtcPowerOn();
  printTime(myRTC.get());
  myRTC.alarm(DS3232RTC::ALARM_1);    // clear alarm flag
  myRTC.alarmInterrupt(DS3232RTC::ALARM_1, false);
  
}

// RTC interrupt handler
ISR (PCINT0_vect)
{
  rtcAlarm= (digitalRead(buttonPin1)==LOW);
}

// format and print a time_t value

void printTime(time_t t)
{
    char buf[25];
    memset(buf,0,25);
    sprintf(buf, "%.4d.%.2d.%.2d-%.2d:%.2d:%.2d",
        year(t),month(t), day(t) ,hour(t), minute(t), second(t));
    Serial.println(buf);
}

void goToSleep()
{
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);            
  power_all_enable();
}

Why don't you ask @ShermanP what's wrong?

Hello,
Just on thing: I did not remove the led on the ds3231 shield.. I don't think this is the cause of the trouble but maybe I'm wrong

The link to the @ShermanP post you are referencing is
https://forum.arduino.cc/t/ds3231-rtc-module-sqw-pin-high-low-for-extended-time/683859/3?

Are you using an actual DS3231 or similar or the problematic ZS-042. I have both the raw DS3231 chip as well as my fav RTC board the Chronodot V2 here are some relevant links NOTE the MaceTech site has 3 versions of Chronodot plus a special Pi version. I just noticed the chip is now up to DS3234. I don't know what is different, most of mine Chronodot V2.1
https://amz.cx/3DTZ
https://amz.cx/3DTa
https://docs.macetech.com/doku.php/chronodot_v3.0

Disconnecting the SWQ pin from its pullup resistor on the RTC module does let you turn off the power to that module except for I2C traffic. But SQW is an open drain output, so it has to have a pullup resistor somewhere. You can add an external resistor on your Arduino, or you can just make the pinMode() of the pin receiving the interrupt from SQW INPUT_PULLUP. But if buttonpin is that pin, then it looks like you've done everything to set it up.

What is the voltage on D12 when you're waiting for the interrupt?

I'm not up to speed on your libraries, but are you clearing the alarm flag in the RTC after setting the alarm time? SQW will not go back high until you do that.

One other thing, although not specifically related to your question. I think you should set the PCI mask register just before you shut down power to the RTC. Then clear it in the ISR. This is a pin change interrupt, and you want it to interrupt only when SWQ goes low at the alarm time, but not when it goes back high when you clear the alarm flag bit. So the mask register should be clear when you clear the alarm bit so no interrupt will be generated at that time.

Hey,
I'm using the ZS-042 shield
V

Do your research, or spend a couple bucks on a real DS3231, i.e. The Chronodot.

There are a few traces to be cut. I never heard of the SQW trick, it's not needed with a real DS3231. Good luck.

@sonofcy hello, no sadly i do not have the part you mentionned.

@ShermanP thank you for your advices. I'll give then a try as soon I can.

I see that you are clearing the alarm flag after wakeup. As far as I can see you're doing everything right.

Is the chip the DS3231SN or the DS3231M? If it's the M chip, then you have to be sure the BBSQW bit is set. That's bit 6 of the control register. So in setup() it would be:

writeRTC(0x0E, (readRTC(0x0E) | 0x40);

Edit: Yes, you said it works if you don't turn off the power to the RTC. That's a good indication the BBSQW bit is the problem. This is from the DS3231M errata:

  1. BBSQW BIT FUNCTION IS NOT IDENTICAL TO DS3231
    Description:
    DS3231 BBSQW bit (if = 1) enables SQW when operating on VBAT supply.
    DS3231M BBSQW bit (if = 1) enables SQW and RTC alarm interrupt when operating on VBAT supply.

Workaround:
Write BBSQW = 1 if user desires an RTC alarm interrupt during battery operation

@ShermanP you got it, setting bit BBSQW to 1 makes the rtc to wakeup when not powered.

Thx for your help !!
Best

It's nice when things work. :slight_smile:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.