DS3231 RTC module SQW pin: High/low for extended time?

Hi,
I wonder if anyone knows if it is possible to have alarm on the DS3231 RTC module that works by setting the SQW pin high and low for extended periods of time? I have used the DS3232RTC library to set interrupt alarms as talked about here Link and that worked just fine.

But that, I think, uses a short pulse to trigger an interrupt on the Uno. What I would like is to set the pin high for let's say a minute and then low for let's say an hour. I also need it to work when the power to the RTC is off (for that I think I need add a pull-up resistor to 5V on the SQW pin).

If it is not possible to customize the DS3231 this way, could you recommend an IC that uses minimal power that is a flip-flop/latch that can convert these short pulses to high-low values (each pulse makes it change state)?

Thank you!

Have you read the DS3231 data sheet?

It's my understanding that when an alarm is triggered, the INT/SQW pin goes low, and it stays that way until the appropriate register is cleared in the DS3231. If that's right, it's not a pulse, and it would be under your control as to when it goes back high, but you would have to issue that command.

If your module is the standard ZS-042, then INT/SQW already has a pullup resistor on the module. But if you power down the module, and Vcc goes to ground, then that becomes a pulldown resistor, so the pin is always low. You would need to cut the trace to that pullup resistor, and enable the internal pullup resistor on the Arduino GPIO pin used for the interrupt.

What are you doing with these pulses, and with the rest of the system? Without some context, it's hard to give useful advice because your ideas are basically non-starters.

aarg:
Have you read the DS3231 data sheet?

Great advice! I should have looked before asking here... Lesson learned. :slight_smile: Anyway, here is what I found with regards to this pin:

Active-Low Interrupt or Square-Wave Output. This open-drain pin requires an external pullup resistor connected to a supply at 5.5V or less. This multifunction pin is determined by the state of the INTCN bit in the Control Register (0Eh). When INTCN is set to logic 0, this pin outputs a square wave and its frequency is determined by RS2 and RS1 bits. When INTCN is set to logic 1, then a match between the timekeeping registers and either of the alarm registers activates the INT/SQW pin (if the alarm is enabled). Because the INTCN bit is set to logic 1 when power is first applied, the pin defaults to an interrupt output with alarms disabled. The pullup voltage can be up to 5.5V, regardless of the voltage on VCC. If not used, this pin can be left unconnected.

So, as mentioned in this thread, I think what I want to do is possible without the use of a latch which is great. The question now is how to code this.... Anyone have an example that could share?

The question now is how to code this

How to code what? The specification you gave us was extremely vague. You haven't explained what it is for, either. So far all that you've shown is that you can make a periodic pulse on the SQW pin. That's well documented but it seems you want to do more?

You ask for code, but you said the processor might be turned off. In that case there is no possibility of running code.

aarg:
What are you doing with these pulses, and with the rest of the system? Without some context, it's hard to give useful advice because your ideas are basically non-starters.

Good point. I should have explained the context.
I would like to turn the power on and off to my project (Uno and other modules) in regular intervals. I have a MOSFET that draws very little current that I plan on using as a switch for the 5V power. But I need an external timer to control the gate voltage to the MOSFET. At first I was thinking of using a CMOS 555 timer for this but since I have a DS3231 module in the project it seems that could be used instead. But as suggested here, I might have to modify the RTC module due to the pull-up resistor situation... I already modified my RTC module once as suggested in this forum to avoid charging the battery (non-chargable) when the RTC module has power. I know there are many ways of solving problems. One obvious alternative is to use another board like the Pro Mini, but I would like the option of having a power manager for the UNO that works this way.

Thus, as for example/programming, how do I program the DS3231 to work this way (what commands to use)? In particular, if the alarm sets the pin high, how do I set it low again?

Thanks again for all suggestions. Really appreciated!!

Thanks again for all your inputs. Really appreciated!!

You might find some answers in reading about the DS3231 library, DS3231 - Arduino Reference. You'll notice a link on that page, you'll want to follow that link, after reading the page. You'll be able to get to example code.

And if you want to get to the nitty and grit of the module you'd look at a spec sheet; https://datasheets.maximintegrated.com/en/ds/DS3231.pdf. I learned a lot by writing my own code to do the DS3231 this. Good luck and have fun.

Idahowalker:
You might find some answers in reading about the DS3231 library, DS3231 - Arduino Reference. You'll notice a link on that page, you'll want to follow that link, after reading the page. You'll be able to get to example code.

And if you want to get to the nitty and grit of the module you'd look at a spec sheet; https://datasheets.maximintegrated.com/en/ds/DS3231.pdf. I learned a lot by writing my own code to do the DS3231 this. Good luck and have fun.

Awesome! Thank for these links.
I just pulled out my oscilloscope to look at the signal on the SQW pin when I run the example that I had tried with the alarm/interrups (code given below).
The code has two alarms, one at '00' seconds (called Alarm_2) and and at '20' seconds (called Alarm_1). It works fine. Looking at the scope, the SQW pin is high (5V) at all times except when the alarms go off:

  • When alarm 2 goes off (00 seconds), the SQW pin stays low (0V) for 1.25ms before it goes back up to 5V.
  • When alarm 1 goes off (20 seconds) the SQW pin goes low (0V) and stays low for 0.75ms before it goes back up to 5V.

This behavior is very repeatable. I just need to figure out what is causing this (where the reset happens in the code). Here is the code:
#include <DS3232RTC.h> //GitHub - JChristensen/DS3232RTC: Arduino Library for Maxim Integrated DS3232 and DS3231 Real-Time Clocks
#include <Streaming.h> //http://arduiniana.org/libraries/streaming/
#include <Wire.h> //Wire - Arduino Reference
#define SQW_PIN 2
void setup(void)
{
Serial.begin(9600);
//setSyncProvider() causes the Time library to synchronize with the
//external RTC by calling RTC.get() every five minutes by default.
setSyncProvider(RTC.get);
Serial << "RTC Sync";
if (timeStatus() != timeSet){
Serial << " FAIL!";
}
Serial << endl;
printDateTime( RTC.get() );
Serial << " --> Current RTC time." << endl;
//Disable the default square wave of the SQW pin.
RTC.squareWave(SQWAVE_NONE);
//Attach an interrupt on the falling of the SQW pin.
//digitalWrite(SQW_PIN, HIGH); //redundant with the following line
pinMode(SQW_PIN, INPUT_PULLUP);
attachInterrupt(INT0, alarmIsr, FALLING);
//Set an alarm at every 20th second of every minute.
RTC.setAlarm(ALM1_MATCH_SECONDS, 20, 0, 0, 1); //daydate parameter should be between 1 and 7
RTC.alarm(ALARM_1); //ensure RTC interrupt flag is cleared
RTC.alarmInterrupt(ALARM_1, true);
//Set an alarm every minute.
RTC.setAlarm(ALM2_EVERY_MINUTE, 0, 0, 0, 1); //daydate parameter should be between 1 and 7
RTC.alarm(ALARM_2); //ensure RTC interrupt flag is cleared
RTC.alarmInterrupt(ALARM_2, true);
}
volatile boolean alarmIsrWasCalled = false;
void alarmIsr()
{
alarmIsrWasCalled = true;
}
void loop(void)
{
if (alarmIsrWasCalled){
if (RTC.alarm(ALARM_1)) {
printDateTime( RTC.get() );
Serial << " --> Alarm 1!" << endl;
}
if (RTC.alarm(ALARM_2)) {
printDateTime( RTC.get() );
Serial << " --> Alarm 2!" << endl;
}
alarmIsrWasCalled = false;
}
}
void printDateTime(time_t t)
{
Serial << ((day(t)<10) ? "0" : "") << _DEC(day(t)) << ' ';
Serial << monthShortStr(month(t)) << " " << _DEC(year(t)) << ' ';
Serial << ((hour(t)<10) ? "0" : "") << _DEC(hour(t)) << ':';
Serial << ((minute(t)<10) ? "0" : "") << _DEC(minute(t)) << ':';
Serial << ((second(t)<10) ? "0" : "") << _DEC(second(t));
}

Yea, the data sheet has a good description of how it works. https://datasheets.maximintegrated.com/en/ds/DS3231.pdf

The INT/SQW pin is always high until the alarm is triggered.

What's resetting the alarm in your example is the RTC library code. When you call the "alarm" function to see which alarm has been triggered, that function also clears the alarm flag, which lets the pin go back high. I probably wouldn't have coded it that way, and you can always modify the library to not do that if you like.

void loop(void)
{
    if (alarmIsrWasCalled){
        if (RTC.alarm(ALARM_1)) {            //<<<<<This one also clears the alarm
            printDateTime( RTC.get() );
            Serial << " --> Alarm 1!" << endl;
        }
        if (RTC.alarm(ALARM_2)) {            //<<<<< same here
            printDateTime( RTC.get() );
            Serial << " --> Alarm 2!" << endl;
        }
        alarmIsrWasCalled = false;
    }
}

If you find the alarm() function in the library .CPP file, the comments there make that clear.

Since the INT/SQW pin is open drain, you can connect it directly to the gate of a P-channel mosfet to control power to the processor. When the alarm triggers, it will bring the gate low, which will turn on the mosfet. Then when you are ready to shut down the power, you would set up the next alarm, and then as your final act you would clear the existing alarm. That would let the gate go back high, which would turn off the mosfet.

The problem is the 5.5V limit on the INT/SQW pin if your battery has a higher voltage than that. But a single lithium rechargeable at 4.2V would work fine, and it could directly power a 3.3V MCU such as a 3.3V 8MHz Arduino Pro Mini.

You would also need a pullup resistor on the mosfet gate.

I suggest putting the processor in sleep mode and turning it on with a pulse from the RTC, rather than powering it down entirely with a MOSFET. It will greatly simplify the RTC interface, eliminate a MOSFET circuit, and allow more flexibility in software.

Generally, you can use that approach to schedule a fixed periodic wake up, where you quickly update what you need to maintain a schedule, and then go back to sleep. For example you can wake every second and increment a count, when it reaches 30 do something. Because you've spent most of the time in sleep, it's equivalent to being asleep for 30 seconds... this shifts the burden of establishing time periods from the RTC to the processor where it's a lot more flexible.

You can't follow an approach like that if you are turning everything off, because then you can't maintain any variables to remember the states that control your schedule.

If you really have to turn everything off (for example if you can't turn peripherals power off under processor control) then you can just use the INT/SQW to turn on a MOSFET as outlined in the above posts, set it again when you want to shut down.

Great points with regards to the sleep mode. That, in addition to going with the Pro mini over an Uno would be the best solution by far. But I prefer the simplicity of the Uni/Nano with the integrated USB chip. In my particular situation I don't need to store any variables as I am writing the information to a microSD card.

I am also really thankful to ShermanP's reply that described the situation with the pull-up resistor! Thank you!

I find this forum really helpful and if anyone is reading this thread I just want to follow up with my latest findings with regards to the code and why I get a pulse. ShermanP already pointed this out (while I was typing this). Thank you again!!!

If we look in the main loop we see that it checks if the alarms went off (first alarm 1 then alarm 2) using this function:* RTC.alarm()*. And if we look in the source code for that function we see that this function checks the alarm and it has gone off it resets it on a line like this: statusReg &= ~mask;

This explains why I see a short pulse. It also explains why the pulse stays low longer when alarm 2 goes off as it checks alarm 1 first hence it takes longer for it to reset after it goes off. Thus, all is in order.

With this information I could modify the code to work the way I want (without the reset). BUT, like ShermanP pointed out, this will only work when the RTC is powered up. When power is off one has to cut the trace on the module for the pull-up (becomes pull-down) resistor. The other approach would be to use a CMOS 555 timer. Need to think about what is best. It is always good to have options!!

Thanks again for the input!!

Here's the schematic of the ZS-042 module showing what I would change. As you can see, if there's no power coming in on Vcc, there won't be any pullup on INT/SQW. So you need to cut that trace to prevent it from becoming a pulldown resistor. Then you can either use INT/SQW to turn on a mosfet, which will have its own pullup resistor, or you can use it to interrupt a sleeping Uno by configuring the Uno GPIO pin as INPUT_PULLUP. That way you can turn off the Vcc power to the module and save battery except when you need to communicate with the module over I2C.

Awesome! Thanks for that schematic!! That makes it easier to understand the situation. It also shows the other mods that are common with this module (one of which I have done already). Thanks again!

While I'm at it, this is a schematic of how one might use the DS3231 to control power.