Hi all,
I'm hoping to ask for some advice on how to recover from a false trigger on an external interrupt pin.
I've been working on an Ardunio weather station project that will operate for long periods of time in remote areas. It's a relatively simple design, based on the Adafruit Pro Trinket 3V and DS3231 Precision RTC Breakout.
I have connected the SQW/INT pin of the DS3231 to the external interrupt pin (D3) of the Pro Trinket. I am using Jack Christensen's DS3232RTC library to set alarms to wake the Trinket from sleep every 5 minutes, at which point measurements from a thermistor and anemometer will be recorded. I am using RocketScream's LowPower.h library to put the Trinket to sleep inbetween measurements.
I have spent a considerable amount of time studying both the DS3232RTC library and the DS3231 datasheet, but I am struggling to understand to how best deal with false triggers (or why they happen).
Using the code below, I have observed that if there is a significant source of noise, or I manually trigger the external interrupt by momentarily connecting pin D3 to GND, the Trinket will wake and execute the main loop, but the alarm flag will not reset and the external interrupt pin is permanently brought LOW. This effectively means that the Trinket will never wake again. I am very curious as to what could be causing this to happen.
I've included an oscilloscope screenshot below that should help to illustrate my problem. While one should always ensure their design is free of noise and other possible sources that could cause false triggers, I am hoping there may be a programmatic solution that would be able to deal with such an event.
I would greatly appreciate any feedback or thoughts on how to improve overall operation.
Cheers,
Adam
#include <DS3232RTC.h> // https://github.com/JChristensen/DS3232RTC
#include <LowPower.h> // https://github.com/rocketscream/Low-Power
#define RTC_ALARM_PIN 3
time_t t, alarmTime;
time_t alarmInterval = 10; // Alarm interval in seconds.
void setup()
{
Serial.begin(9600);
pinMode(RTC_ALARM_PIN, INPUT_PULLUP); // Enable internal pull-up resistor.
RTC.setAlarm(ALM1_MATCH_SECONDS, 0, 0, 0, 1); // Set initial alarm 1 to occur at the next instance of 00 seconds.
RTC.alarm(ALARM_1); // Ensure RTC interrupt flag is cleared.
RTC.alarm(ALARM_2); // Ensure RTC interrupt flag is cleared.
RTC.squareWave(SQWAVE_NONE); // Configure INT/SQW pin for interrupt operation. Disable default square wave.
RTC.alarmInterrupt(ALARM_1, true); // Enable interrupt output for alarm 1.
RTC.alarmInterrupt(ALARM_2, false); // Disable interrupt output for alarm 2.
}
void loop()
{
sleepNow(); // Sleep.
/*
Read sensors, etc., upon wake.
*/
RTC.alarm(ALARM_1); // Reset alarm 1 flag.
t = RTC.get(); // Read date and time from RTC.
alarmTime = t + alarmInterval; // Calculate next alarm.
RTC.setAlarm(ALM1_MATCH_DATE, second(alarmTime), minute(alarmTime), hour(alarmTime), day(alarmTime)); // Set alarm 1.
}
// Enable sleep until RTC alarm interrupt is generated.
void sleepNow()
{
noInterrupts(); // Disable interrupts before entering sleep.
attachInterrupt(digitalPinToInterrupt(RTC_ALARM_PIN), wakeUpNowISR, FALLING); // Wake on falling edge of RTC_ALARM_PIN.
interrupts(); // Enable interrupts to ensure next instruction is executed.
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); // Enter sleep and await external interrupt.
}
// RTC alarm interrupt service routine.
void wakeUpNowISR()
{
detachInterrupt(digitalPinToInterrupt(RTC_ALARM_PIN)); // Disable interrupts on RTC_ALARM_PIN
}