Hi all,
I have an Arduino Pro Mini (it is one of those botched 5V versions with 8MHz external oscillator but the VR is irrelevant - I run it directly off the VCC pin) for a project that I need to run off battery for long periods - how long before the battery is charged is out of my control. Thus, when the system is on battery only, it will be in sleep (power down mode) until it is interrupted from a sensor, or when power is connected. When the battery is detected to be low, the interrupt for the sensor is disabled and the system only wakes on power on. To achieve this, I initially used the two external interrupts available INT0 and INT1 on pins 2 & 3. The sensor is a simple microswitch which shorts to ground when actuated.
This works flawlessly when I ran the Pro Mini on 5V, but when it was running at 3.3V, it started waking from sleep due to fluctuations in the sensor pin values. It wakes without triggering any ISR, I debugged using the BAD_ISR vector to check if there was any interrupt triggering unintentionally. However, it wakes and goes straight to executing straight after the call to sleep. The fluctuations need to be fast (The microswitch bounces rapidly when clicked, which is how the problem was discovered), in the order of milliseconds (reproducible by hand by sticking a wire from a GPIO pin to GND and out rapidly, but more difficult than using the bouncing switch). However, on further probing, I discovered that it wakes not only due to fluctuations on pins with the external interrupt, but any GPIO pin. I did this by connecting identical microswitches to random input pins. To further troubleshoot, I changed to use pin change interrupts, which did not change anything about the problem. Once I disable all interrupts, this issue disappears and the Arduino will be stuck in an infinite deep sleep. However, as long as any external interrupts or pin change interrupts are enabled, pins that are masked away or from different pin change interrupts can trigger this wake behavior without causing any ISR to be fired. Below are 2 snippets of code that can reproduce the problem highlighted:
Summary/TLDR: Pin changes without interrupts enabled on them wake ATmega328P only when running on 3.3v and only when interrupts to other pins are enabled, no ISR triggered.
Edit:
Oh yes, I forgot to include the question... Does anyone know why this is happening or can reproduce this problem? Thank you!!
#include <avr/power.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
volatile enum opmodes{sleep, interrupt}opmode;
ISR(INT0_vect){
//Disable all Interrupts
EIMSK = 0;
opmode = interrupt;
Serial.println("INT0");
}
ISR(INT1_vect){
//Disable all Interrupts
EIMSK = 0;
opmode = interrupt;
Serial.println("INT1");
}
ISR(BADISR_vect){
Serial.println("Whut");
}
void setup() {
Serial.begin(9600);
pinMode(2, INPUT_PULLUP);
pinMode(12, INPUT);
}
void loop() {
opmode = sleep;
Serial.println("Sleep");
Serial.flush();
delay(20);
EIFR = bit(INTF0); // clear flag for interrupt 0
EIMSK = bit(INT0); // enable interrupt 0
power_adc_disable();
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
cli();
if (opmode == sleep){
sleep_enable();
sei();
sleep_cpu();
sleep_disable();
}
sei();
power_adc_enable();
}
#include <avr/power.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
volatile enum opmodes{sleep, interrupt}opmode;
ISR(PCINT0_vect){
//Disable all Interrupts
PCICR = 0;
opmode = interrupt;
Serial.println("PCINT0");
}
ISR(PCINT2_vect){
//Disable all Interrupts
PCICR = 0;
opmode = interrupt;
Serial.println("PCINT2");
}
ISR(BADISR_vect){
Serial.println("Whut");
}
void setup() {
Serial.begin(9600);
pinMode(2, INPUT_PULLUP);
pinMode(12, INPUT);
PCMSK0 = bit(PCINT4); //enable pcinterrupt 0 on pin 12
PCMSK2 = bit(PCINT18); //enable pcinterrupt 2 on pin 2
PCICR = 0;
PCICR = bit(PCIE0); // enable pcinterrupt 0
}
void loop() {
opmode = sleep;
Serial.println("Sleep");
Serial.flush();
delay(20);
PCIFR = bit(PCIF0); // clear flag for pcinterrupt 0
PCICR = bit(PCIE0); // enable pcinterrupt 0 only
power_adc_disable();
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
cli();
if (opmode == sleep){
sleep_enable();
sei();
sleep_cpu();
sleep_disable();
}
sei();
power_adc_enable();
}