Problem with RTClib and DS3231 Interrupt management

Arduino ver. 1.8.19 - Hardware see the attached images.

Problem with interrupt handling of RTClib and DS3231.
I used two ESP32, one that I need for the project is the 38 Pin ESP32, the other for any tests is the ESP32-TTGO.
I would like to use the RTClib with the DS3231 with alarms.
For this reason I used the SQW pin, connecting it to the free Pins, which in the case of the ESP32-TTGO are all, while in the case of the ESP32-38PIN they are only some.
Unfortunately every time I try to use one the ESP32 crashes, sometimes without the alarm being enabled but immediately after loading the program. At this point I excluded all the Pins that gave this problem imagining that the use of that Pin as an interrupt was not suitable.
The problem is that every time the alarm is started (even if I still don't understand how it works) the ESP32 crashes again.
Surely I must have done something wrong in the test program, but I don't understand where I made the mistake.

// Date and time functions using a DS3231 RTC connected via I2C and Wire lib
#include "RTClib.h"

RTC_DS3231 rtc;

// the pin that is connected to SQW
#define CLOCK_INTERRUPT_PIN 36

/*
  DS3231 Alarm modes for alarm 1 ***********

  DS3231_A1_PerSecond = 0x0F,
  DS3231_A1_Second = 0x0E,
  DS3231_A1_Minute = 0x0C,
  DS3231_A1_Hour = 0x08,
  DS3231_A1_Date = 0x00,
  DS3231_A1_Day = 0x10

  DS3231 Alarm modes for alarm 2 ***********

  DS3231_A2_PerMinute = 0x7,
  DS3231_A2_Minute = 0x6,
  DS3231_A2_Hour = 0x4,
  DS3231_A2_Date = 0x0,
  DS3231_A2_Day = 0x8
*/
    
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
int yy=0;
int MM=0;
int dd=0;
int hh=0;
int mm=0;
int ss=0;

bool Aa = false;

void setup () {
  
    Serial.begin(115200);
    delay(1000);

    if (! rtc.begin()) {
      Serial.println("Couldn't find RTC");
      Serial.flush();
      while (1) delay(10);
    }
    
    //we don't need the 32K Pin
    rtc.disable32K();
    
    // Making it so, that the alarm will trigger an interrupt
    pinMode(CLOCK_INTERRUPT_PIN, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN), onAlarm, FALLING);

    // set alarm 1, 2 flag to false (so alarm 1, 2 didn't happen so far)
    // if not done, this easily leads to problems, as both register aren't reset on reboot/recompile
    rtc.clearAlarm(1);
    rtc.clearAlarm(2);

    // stop oscillating signals at SQW Pin
    // otherwise setAlarm1 will fail
    rtc.writeSqwPinMode(DS3231_OFF);
    
    // if (rtc.lostPower()) {
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // }
  
    DateTime now = rtc.now();
    yy = now.year();
    MM = now.month();
    dd = now.day();
    hh = now.hour();
    mm = now.minute();
    ss = now.second();

    // rtc.adjust(DateTime(yy, MM, dd, hh, mm, ss));
  
}

void loop () {

    DateTime now = rtc.now();

    Serial.print("Adesso = ");
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);

    Serial.print(" - ");
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();

    setAlarm();
    
    // the stored alarm value + mode
    DateTime alarm2 = rtc.getAlarm2();
    Ds3231Alarm2Mode alarm2mode = rtc.getAlarm2Mode();
    char alarm2Date[12] = "DD hh:mm:ss";
    alarm2.toString(alarm2Date);
    Serial.print(" [Alarm2: ");
    Serial.print(alarm2Date);
    Serial.print(", Mode: ");
    switch (alarm2mode) {
      case DS3231_A2_PerMinute: Serial.print("PerMinute"); break;
      case DS3231_A2_Minute: Serial.print("Minute"); break;
      case DS3231_A2_Hour: Serial.print("Hour"); break;
      case DS3231_A2_Date: Serial.print("Date"); break;
      case DS3231_A2_Day: Serial.print("Day"); break;
    }
    Serial.println();
    delay(1000);
}

void setAlarm() {
  
 if (Aa == false) {
  rtc.clearAlarm(2);
  rtc.writeSqwPinMode(DS3231_OFF);

  if (!rtc.setAlarm2( rtc.now() + TimeSpan( 1 ), DS3231_A2_PerMinute )) {
     Serial.println("Error, alarm wasn't set!");
  } else {
    Serial.println("Alarm will happen every 1 minute!");
  }
 }
 Aa = true;
}

void onAlarm() {
    Serial.println("Alarm occured!");
    rtc.clearAlarm(2);
    Serial.println("** Alarm cleared");
}


 [Alarm2: 18 10:22:00, Mode: PerMinute
Alarm occured!
uru Meditation Error: Core  1 panic'ed (Interrupt wdt timeout on CPU1). 

Core  1 register dump:
PC      : 0x4008afe6  PS      : 0x00060735  A0      : 0x80089f5e  A1      : 0x3ffbf08c  
A2      : 0x3ffb8d90  A3      : 0x3ffbce64  A4      : 0x00000004  A5      : 0x00060723  
A6      : 0x00060723  A7      : 0x00000001  A8      : 0x3ffbce64  A9      : 0x00000019  
A10     : 0x3ffbce64  A11     : 0x00000019  A12     : 0x3ffc2cdc  A13     : 0x00060723  
A14     : 0x007bf388  A15     : 0x003fffff  SAR     : 0x0000001c  EXCCAUSE: 0x00000006  
EXCVADDR: 0x00000000  LBEG    : 0x400861f8  LEND    : 0x4008620e  LCOUNT  : 0x00000000  
Core  1 was running in ISR context:
EPC1    : 0x400dd96f  EPC2    : 0x00000000  EPC3    : 0x00000000  EPC4    : 0x00000000


Backtrace: 0x4008afe3:0x3ffbf08c |<-CORRUPTED


Core  0 register dump:
PC      : 0x4008b17b  PS      : 0x00060035  A0      : 0x80089b87  A1      : 0x3ffbeaac  
A2      : 0x3ffbf388  A3      : 0xb33fffff  A4      : 0x0000abab  A5      : 0x00060023  
A6      : 0x00060021  A7      : 0x0000cdcd  A8      : 0x0000abab  A9      : 0xffffffff  
A10     : 0x3ffc2af8  A11     : 0x00000000  A12     : 0x3ffc2af4  A13     : 0x00000007  
A14     : 0x007bf388  A15     : 0x003fffff  SAR     : 0x0000001d  EXCCAUSE: 0x00000006  
EXCVADDR: 0x00000000  LBEG    : 0x00000000  LEND    : 0x00000000  LCOUNT  : 0x00000000  


Backtrace: 0x4008b178:0x3ffbeaac |<-CORRUPTED




ELF file SHA256: 4cd5a81964b129d5


bool sqwAlarm;
void onAlarm() {
   sqwAlarm = true;
}

The rest to be done at loop level.

Now works !!
Thanks, but there are two things I don't understand, the first is that the alarm minutes are always equal to the minutes of the current time and are not ahead of 1 minute as the alarm should be set (at the start).
The second is how come it works now, eliminating the Print ?
Takes too long to print and gets messed up?

Adesso = 2023/3/18 - 10:41:56
[Alarm2: 18 10:40:00, Mode: PerMinute
Adesso = 2023/3/18 - 10:41:57
[Alarm2: 18 10:40:00, Mode: PerMinute
Adesso = 2023/3/18 - 10:41:58
[Alarm2: 18 10:40:00, Mode: PerMinute
Adesso = 2023/3/18 - 10:41:59
[Alarm2: 18 10:40:00, Mode: PerMinute
Adesso = 2023/3/18 - 10:42:0
[Alarm2: 18 10:40:00, Mode: PerMinute
Alarm occured!
** Alarm cleared
Adesso = 2023/3/18 - 10:42:1
[Alarm2: 18 10:40:00, Mode: PerMinute
Adesso = 2023/3/18 - 10:42:2
[Alarm2: 18 10:40:00, Mode: PerMinute
Adesso = 2023/3/18 - 10:42:3
[Alarm2: 18 10:40:00, Mode: PerMinute
Adesso = 2023/3/18 - 10:42:4
[Alarm2: 18 10:40:00, Mode: PerMinute
Adesso = 2023/3/18 - 10:42:5
[Alarm2: 18 10:40:00, Mode: PerMinute

I think the problem may be that the ESP32 is running internally at 3.3V, so its GPIO pins are expecting 3.3V. But you are powering the RTC with 5V, so on the INT line you are effectively powering an ESP32 pin with a 4.7K pullup resistor to 5V, which the ESP32 may not like. There may be other problems, but the RTC Vcc pin should be powered with 3.3V, not 5V.

It actually runs on 3.3V since I didn't have a long cable to power it on 5V.
I thought the "PerMinute" alarm was set to repeat every 1 or 5 minutes, but I found it's always for 1 minute.
I have to activate a fan for a variable time from 1 hour to 3 hours and make it work for a variable time from 1 to 5 minutes, but I don't understand how to do it.

When the alarm goes off read the current time, update with the interval, and reset the alarm. Adjust as needed for the library you used. You also need to set up the interrupt handler, etc.

// default sample interval 
const uint16_t DEFAULT_MINUTE_INTERVAL = 120;

// Real time clock
#include <RtcDS3231.h>    // from "Rtc by Makuna" in library manager
RtcDS3231<TwoWire> Rtc(Wire);  // Construct RTC object

/* interval between readings
 *  input the interval in minutes (1-1440) so the interface 
 *  doesn't have to deal with hours and minutes - particularly
 *  when readings interval is an hour or less 
 */
// number of minutes between readings
uint16_t minuteInterval = DEFAULT_MINUTE_INTERVAL;  
uint16_t minuteMatch;      // minute count to match
uint8_t minutePart;       // minute part of interval
uint8_t hourPart;         // hour part of interval


/********************************************************************
*
* set alarm 1 for next sample time 
* 
* ********************************************************************/ 
void SetNextSampleTime(){ 
   // set next timer interrupt
   RtcDateTime present;
   present = Rtc.GetDateTime(); //get the current date-time 
  // round next time up to a multiple of match interval
  minuteMatch = (((present.Hour()*60+present.Minute()) / minuteInterval) +1 )*minuteInterval;
  // split interval into minutes and hours
  minutePart = minuteMatch%60;
  hourPart = (minuteMatch/60)%24; // keep within a day            
  // set next data collection interrupt time 
  DS3231AlarmOne alarm1(
      0,           // day - don't care
      hourPart,
      minutePart,
      0,          // seconds
  DS3231AlarmOneControl_HoursMinutesSecondsMatch);  // interrupt at (h,m,s)
  Rtc.SetAlarmOne(alarm1);
}

Ti ringrazio per l'esempio ed il suggerimento :slight_smile:

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