Intermittent external interrupts with MKR 1010 and DS3231 RTC

Hi,

I have been building a data logger and have it running on a bare bones Arduino - it goes to sleep and is woken by an interrupt from a DS3231 to take a measurement from a voltage divider. That works successfully and I am now trying to replicate the same functionality on a MKR 1010, currently on a breadboard. I have attached photos below (I have an external pull-up resistor between VCC and pin 7 though I did not need one on the bare bones Arduino).

I am trying to get the external interrupt working when the alarm goes off however I find that the interrupt triggers sporadically and not every minute as expected. A capture of the output from the serial monitor is below;

11:37:44.404 -> Turn off alarms initially
11:37:44.444 -> Set alarm clock time
11:37:44.444 -> Turn on alarm
11:37:44.444 -> Attach pin interrupt
11:37:44.444 -> Pin interrupt attached on 7
11:38:02.643 -> 2020/5/31,10:38,0.0010,26.75
11:39:02.670 -> 2020/5/31,10:39,0.0010,26.75
11:43:02.670 -> 2020/5/31,10:43,0.0010,26.50
11:45:02.657 -> 2020/5/31,10:45,0.0015,26.50
11:50:02.660 -> 2020/5/31,10:50,0.0015,26.25
11:51:02.637 -> 2020/5/31,10:51,0.0015,26.25
11:52:02.654 -> 2020/5/31,10:52,0.0015,26.25
11:53:02.679 -> 2020/5/31,10:53,0.0015,26.25
11:55:02.640 -> 2020/5/31,10:55,0.0015,26.25
11:59:02.670 -> 2020/5/31,10:59,0.0010,26.25

Steps to investigate are;

  1. Tried different DS3231 RTC - didn't resolve
  2. Changed jumper wire from SQW pin to MKR 1010 (bad connection?) - didn't resolve
  3. Tried running RTC on 3.3V - didn't resolve
  4. Tried on pins A0 and 0 separately - didn't resolve
  5. I have been testing on pins A1 and 0 while RTC has been powered at 5V. Tried running on pin 7 with RTC only at 3.3V - didn't resolve
  6. Put 4.7k ohm pull up resistor between VCC and 7 - didn't resolve
  7. Put 10k ohm pull up resistor between VCC and 7 - didn't resolve

I can't work out where the problem is though. I have added my code below but I am getting the feeling this is related to the external pull up resistors, my understanding is that I need one to keep the pin high as the interupt is triggered when the SQW signal is falling.

At the moment though I can't figure it out so any suggestions would be gratefully received.

Many thanks.

#include <DS3231.h> //v1.0.2 https://github.com/NorthernWidget/DS3231
#include <Wire.h>

DS3231 Clock;
bool Century = false;
bool h12; s
bool PMT;
//byte ADay, AHour, AMinute, ASecond, ABits;
//bool ADy, A12h, APMT;

#define ALRM1_MATCH_EVERY_SEC  0b1111  // once a second
#define ALRM1_MATCH_SEC        0b1110  // when seconds match
//#define ALRM1_MATCH_MIN_SEC    0b1100  // when minutes and seconds match
//#define ALRM1_MATCH_HR_MIN_SEC 0b1000  // when hours, minutes, and seconds match
byte ALRM1_SET = ALRM1_MATCH_SEC;

//Variables for voltage calculation START
int value = 0;
int var;
int loops = 5;
float voltage;
const float referenceVoltage = 1;
//Variables for voltage calculation END

//Variables for RTC START
byte timeComponent, clockYear, clockMonth, clockDay,
     clockHour, clockMinute;
//const byte rtcTimerIntPin = 3;
const float kelvin = 273.15;
bool alarmflag = false;
//Variables for RTC END

void setup() {
  // Start the I2C interface
  Wire.begin();
  // Start the serial interface
  Serial.begin(9600);

  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB
  }

  Serial.println("Turn off alarms initially");
  Clock.turnOffAlarm(1);
  Clock.turnOffAlarm(2);

  Serial.println("Set alarm clock time");
  Clock.setA1Time(0, 0, 0, 1, ALRM1_SET, true, false, false);

  Serial.println("Turn on alarm");
  Clock.turnOnAlarm(1);

  Serial.println("Attach pin interrupt");
  // Attach interrupt
  pinMode (7, INPUT_PULLUP);
  digitalWrite(7, HIGH);
  attachInterrupt (digitalPinToInterrupt (7), clockTrigger, FALLING);
  Serial.println(F("Pin interrupt attached on 7"));
}

void loop() {
  // send what's going on to the serial monitor.

  //if (alarmflag = true)
  if (Clock.checkIfAlarm(1))
  {
    Clock.checkIfAlarm(1);
    var = 0;
    while (var < loops) {
      value = value + analogRead(A1);
      delay(5);
      var++;
    }
    value = value / loops;

    float temperature;
    temperature = ((Clock.getTemperature()) / 4);


    voltage = value * referenceVoltage / 2046; //1023;
    //calculate voltage reading

    clockYear = Clock.getYear();
    delay(10);
    clockMonth = Clock.getMonth(Century);
    delay(10);
    clockDay = Clock.getDate();
    delay(10);
    clockHour = Clock.getHour(h12, PMT);
    delay(10);
    clockMinute = Clock.getMinute();
    delay(10);

    // Start with the year
    Serial.print("20");
    Serial.print(clockYear);
    Serial.print("/");
    // then the month
    //extraZero(clockMonth);
    Serial.print(clockMonth);
    Serial.print("/");
    // then the date
    //extraZero(clockDay);
    Serial.print(clockDay);
    Serial.print(",");
    // Finally the hour, minute, and second
    //extraZero(clockHour);
    Serial.print(clockHour);
    Serial.print(":");
    //extraZero(clockMinute);
    Serial.print(clockMinute);
    // Display the temperature
    Serial.print(",");
    Serial.print(voltage, 4);
    Serial.print(",");
    Serial.println(Clock.getTemperature(), 2);
  }
}

void extraZero(byte value)
{
  if (value < 10) {
    Serial.print("0");
  }
}

void clockTrigger()
{
  //don't do any other processing in this subroutine
}

You should not need an external pull-up resistor if you have enabled the internal pull-up resistor.

I'd start by simplifying the code

#include <DS3231.h> //v1.0.2 https://github.com/NorthernWidget/DS3231
#include <Wire.h>

DS3231 Clock;
bool Century = false;
bool h12; s
bool PMT;
//byte ADay, AHour, AMinute, ASecond, ABits;
//bool ADy, A12h, APMT;

#define ALRM1_MATCH_EVERY_SEC  0b1111  // once a second
#define ALRM1_MATCH_SEC        0b1110  // when seconds match
//#define ALRM1_MATCH_MIN_SEC    0b1100  // when minutes and seconds match
//#define ALRM1_MATCH_HR_MIN_SEC 0b1000  // when hours, minutes, and seconds match
byte ALRM1_SET = ALRM1_MATCH_SEC;


//Variables for RTC START
volatile bool alarmflag = false;
//Variables for RTC END

void setup() {
  // Start the I2C interface
  Wire.begin();
  // Start the serial interface
  Serial.begin(9600);

  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB
  }

  Serial.println("Turn off alarms initially");
  Clock.turnOffAlarm(1);
  Clock.turnOffAlarm(2);

  Serial.println("Set alarm clock time");
  Clock.setA1Time(0, 0, 0, 1, ALRM1_SET, true, false, false);

  Serial.println("Turn on alarm");
  Clock.turnOnAlarm(1);

  Serial.println("Attach pin interrupt");
  // Attach interrupt
  pinMode (7, INPUT_PULLUP);
  digitalWrite(7, HIGH);
  attachInterrupt (digitalPinToInterrupt (7), clockTrigger, FALLING);
  Serial.println(F("Pin interrupt attached on 7"));
}

void loop() {
  // send what's going on to the serial monitor.

  if (alarmflag == true) {
    Serial.println( "AlarmFlag is true" );
    alarmflag = false;
  }
  if (Clock.checkIfAlarm(1)) {
    Serial.println( "checkIfAlarm(1) is true" );
  }
}

void clockTrigger()
{
  alarmflag = true;
}

To see what you get on the Serial monitor (with timestamps turned on)

I did notice that your 'alarmflag' was not declared volatile which is required if it will be used in the ISR. You also had your if() statement with an assignment '=' vs. a compare '=='

blh64:
You should not need an external pull-up resistor if you have enabled the internal pull-up resistor.

...

I did notice that your 'alarmflag' was not declared volatile which is required if it will be used in the ISR. You also had your if() statement with an assignment '=' vs. a compare '=='

Hi,

Thanks for getting back to me so soon, external resistor is now gone.

I ran the code you supplied and got back;

20:22:54.943 -> Turn off alarms initially
20:22:54.943 -> Set alarm clock time
20:22:54.943 -> Turn on alarm
20:22:54.943 -> Attach pin interrupt
20:22:54.943 -> Pin interrupt attached on 7
20:23:01.483 -> checkIfAlarm(1) is true
20:23:01.483 -> AlarmFlag is true
20:24:01.490 -> checkIfAlarm(1) is true
20:24:01.490 -> AlarmFlag is true
20:25:01.474 -> checkIfAlarm(1) is true
20:25:01.474 -> AlarmFlag is true
20:26:01.467 -> checkIfAlarm(1) is true
20:26:01.467 -> AlarmFlag is true
20:27:01.467 -> AlarmFlag is true
20:28:01.487 -> AlarmFlag is true
20:29:01.487 -> checkIfAlarm(1) is true
20:29:01.487 -> AlarmFlag is true
20:30:01.497 -> checkIfAlarm(1) is true
20:30:01.497 -> AlarmFlag is true
20:31:01.497 -> AlarmFlag is true
20:32:01.467 -> AlarmFlag is true
20:33:01.477 -> checkIfAlarm(1) is true
20:33:01.477 -> AlarmFlag is true
20:34:01.487 -> AlarmFlag is true
20:35:01.497 -> AlarmFlag is true
20:36:01.487 -> AlarmFlag is true
20:37:01.486 -> checkIfAlarm(1) is true
20:37:01.486 -> AlarmFlag is true
20:38:01.497 -> AlarmFlag is true
20:39:01.497 -> AlarmFlag is true
20:40:01.487 -> checkIfAlarm(1) is true
20:40:01.487 -> AlarmFlag is true
20:41:01.467 -> checkIfAlarm(1) is true
20:41:01.467 -> AlarmFlag is true
20:42:01.467 -> AlarmFlag is true
20:43:01.477 -> AlarmFlag is true
20:44:01.500 -> checkIfAlarm(1) is true
20:44:01.500 -> AlarmFlag is true
20:45:01.483 -> checkIfAlarm(1) is true
20:45:01.483 -> AlarmFlag is true
20:46:01.513 -> checkIfAlarm(1) is true
20:46:01.513 -> AlarmFlag is true
20:47:01.503 -> AlarmFlag is true
20:48:01.496 -> AlarmFlag is true

Looking at this am I right in thinking the following?

  1. The external interrupt is working correctly as 'alarmflag is true' appears in the serial monitor every minute (I had messed up my attempt at doing this)
  2. checkIfAlarm is not evaluating to true after the external interrupt triggers and not reliably identifying that the alarm is going off(?). As I was using this as the basis on whether to print the date/voltage/temp to serial this is why I was not getting the expected measurement every minute.

Therefore could I just rely on alarmflag and forget checkIfAlarm?

I had been using the DS3232 library but on installing the SAMD core it seems to have been moved into an 'incompatible' folder. I had been using the equivalent of checkIfAlarm there but I think there may be a problem when I call it in this library.

Many thanks,

Dave

I am wondering why you are using an external rtc(ds3231) when the MKR series boards all have a built in rtc?

RoomForImprovement:

  1. The external interrupt is working correctly as 'alarmflag is true' appears in the serial monitor every minute (I had messed up my attempt at doing this)

Iwould agree with that conclusion

  1. checkIfAlarm is not evaluating to true after the external interrupt triggers and not reliably identifying that the alarm is going off(?). As I was using this as the basis on whether to print the date/voltage/temp to serial this is why I was not getting the expected measurement every minute.

This method does appear unreliable. If you look at the code for this function, it is reading some register/bits on the RTC and then resetting them. I don't know enough about the RTC to know if those bits stay set until reset or automatically get reset upon read or ????

Therefore could I just rely on alarmflag and forget checkIfAlarm?

That would be my path forward