The issue that I have is in INT0 service in which it doesn't perform properly when MCU is set in PowerDown mode. I declared a global variable as "counter" and put it inside INT0 ISR but its value doesn't change.
To make sure that the issue is coming from the Sleeping of the MCU, I commented-out "sleepNow();" inside Loop(), at line 156, and un-commented the following 3 lines and everything was working as expected and variable "counter" was changing correctly. I think I haven't constructed the sleeping part properly, which has caused this issue. I tried to play with the code and searched Google, but I couldn't find that much help. I also looked at the following topics, but those didn't help me either:
Waking up async the Arduino while it's sleeping periodically
Send out a short signal every 10 seconds to an arduino
Use lowpower-libary and still use serial connection and other things
How do interrupts work on the Arduino Uno and similar boards?
My simplified code is here:
#include <SoftwareSerial.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/power.h>
#define Voltage A7 // Analog Pin A7 | ADC7 - QFN pin 22
#define En_V A0 // Analog Pin A0 - PC0 -QFN pin 23 | Trigger pin to turn on MOSFETs
#define En_Sensors 9 // Digital Pin D9 - PB1 -QFN pin 13 | Trigger pin to turn on sensor
#define En_I2C2 3
#define En_Sigfox A1 // GPIO9 On Sigfox - It is Set to PULL UP by default in Sigfox module. Set to LOW for waking up
#define SF_rxPin 5 //Sigfox
#define SF_txPin 6 //Sigfox
boolean debug = true;
SoftwareSerial Sigfox (SF_rxPin, SF_txPin);
///////////////////////Interrupt changes////
const int interruptPin = 2; // INT0 - PD2 | INT1 - PD3
const uint8_t LED = A2;
volatile uint8_t counter = 0;
volatile bool IntFlag = false;
volatile bool WdtFlag = false;
////////////////////////////////////////////
uint8_t MCU_Sleep_Cycle = 4;
void wakeUp()
{
sleep_disable();
detachInterrupt(0);// INT0 - PD2 | INT1 - PD3
counter++;
IntFlag = true;
}
ISR (WDT_vect)
{
// WDIE & WDIF is cleared in hardware upon entering this ISR
wdt_disable();
WdtFlag = true;
}
void Sleep_Sigfox() {
digitalWrite(En_Sigfox, HIGH); // to go into DeepSleep mode
setPowerMode(2);
}
void setup() {
pinMode(Voltage, INPUT);
pinMode(En_V, OUTPUT);
pinMode(En_Sensors, OUTPUT);
pinMode(En_I2C2, OUTPUT);
pinMode(SF_rxPin, INPUT);
pinMode(SF_txPin, OUTPUT);
pinMode(En_Sigfox, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP);
if (debug) {
Serial.begin(9600);
}
Sigfox.begin(9600);
delay(3 * 500);
analogReference(EXTERNAL);
digitalWrite(En_I2C2, LOW);
if (debug) {
Serial.println(F("Hello"));
}
digitalWrite(En_Sensors, LOW);
Sleep_Sigfox();
delay(2 * 1000);
attachInterrupt(0, wakeUp, LOW);
}
uint8_t volt() {
uint16_t tmp = 0;
float v1, tmp2, tmp3;
uint8_t v;
delay(2 * 100);
tmp = analogRead(Voltage); //A7
if (tmp > 0) {
v1 = tmp * 3.3 / 1023;
tmp2 = v1 * 840 / 33; //10*(51+33)/33; to represent in 10*V, (51+33)/33 is a HW Voltage divider.
tmp3 = round(tmp2);
v = tmp3;
}
else {
v = 0;
}
return (v);
}
void loop() {
//delay(2 * 500);
if (WdtFlag) {
wdt_reset();
if (debug) {
Serial.println(F("\nI woke up"));
//Serial.print("IntFlag: ");
//Serial.println(IntFlag);
Serial.print(F("WdtFlag: "));
Serial.println(WdtFlag);
Serial.print(F("counter: "));
Serial.println(counter);
delay(500);
}
uint8_t rs = 0;
uint8_t v = 0;
char to_be_sent[12];
memset(to_be_sent, 0, sizeof(to_be_sent));
digitalWrite(En_V, HIGH);
delay(300);
v = volt();
rs = counter;
sprintf(to_be_sent, "%2X%02X", v, rs);
digitalWrite(En_V, LOW);
if (debug) {
Serial.print(F("Volt*10: "));
Serial.println(v);
Serial.print(F("RS-count: "));
Serial.print(rs);
Serial.println(F("\n"));
delay(1000);
}
///////////////////////////////// Send Values here
delay(1 * 50);
if (debug) {
Serial.print(F("Sending Message: "));
Serial.println(to_be_sent);
delay(20);
}
counter = 0;
}
if (debug) {
Serial.print(F("MCU is going into DeepSleep for "));
Serial.print(MCU_Sleep_Cycle);
Serial.println(F(" cycles."));
delay(40);
}
for (uint8_t i = 0; i < MCU_Sleep_Cycle ; i++) { //15 cycles = 2min | 6 cycles = 48sec
if (debug) {
Serial.print(F("."));
delay(10);
}
sleepNow();
//WdtFlag=true;
//attachInterrupt(0, wakeUp, LOW);
//delay(2*1000);
}
}
String setPowerMode(uint8_t mode) {
//0: Software reset
//1: sleep, send a break to wake up
//2: deep_sleep, toggle GPIO0 or Reset_N to wake up
if (debug) {
Serial.print("Sigfox Power mode: " + String(mode) + "\t");
//Serial.print(res);
switch (mode) {
case 0: Serial.println(F("Soft reset is done.\n")); break;
case 1: Serial.println(F("Module is in sleep mode. zZzZ\n")); break;
case 2: Serial.println(F("Module is in DeepSleep mode. zZzZ\n")); break;
}
delay(500);
}
Sigfox.print("AT$P=");
Sigfox.print(mode);
Sigfox.print("\r");
//String res = getData();
//return res;
}
void sleepNow() {
//cli(); //disable interrupts
EIFR |= (1 << INTF0); // Clearing INTF0 by setting this bit up. Int0 flag cleared.
EIMSK |= (1 << INT0); //enable INT0
byte adcsra_save = ADCSRA; //ADC backup
byte WDTCSR_save = WDTCSR; //WDT backup
WdtFlag = false;
IntFlag = false;
sleep_enable(); // enables the sleep bit in the mcucr register. so sleep is possible. just a safety pin
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
ADCSRA &= ~(1 << 7); //clear bit 7 of register ADCSRA and disable ADC
sleep_bod_disable();
//power_all_disable (); // turn off all modules
sei();//enable interrupts
attachInterrupt(0, wakeUp, LOW); //when pin 2 gets LOW, run function wakeUp() // INT0 - PD2 | INT1 - PD3
wdt_enable(WDTO_8S);
WDTCSR |= (1 << WDIE);
//sleep_mode();// here the device is actually put to sleep. THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
sleep_cpu ();
sleep_disable();
//power_all_enable (); // turn on all modules
sei();
ADCSRA |= (1 << 7); //Set bit 7 and Enable ADC
ADCSRA = adcsra_save; // Config ADC again as before
}
What MCU is used?
The MCU is an ATMEGA328P running on 3.3V at 8MHz
What I want to do?
I would like to put the MCU into deep sleep mode for a fixed period (e.g. 15 minutes, though in the code above I have reduced time to less than a minute), but monitor the number of times the external interrupt is happening. At the end of 15 minutes, when the MCU wakes up, I would like to get the interrupt count total from variable "counter", which should have been incremented by the INT0 ISR, once per external interrupt.
What is the issue?
The issue is that the variable "counter" is not increasing when the MCU is in sleep mode. When the MCU sleeps, the power consumption goes down. The WDT is also working. The interrupt INT0 wakes up the MCU, but value of the counter is not incrementing. I suspect that after the INT0 ISR executes, an MCU reset is happening, reinitializing the "counter" variable -- so that might be the reason why counter keeps staying at zero.
What did I do?
I tried to run the code while the MCU is not sleeping and in that case, variable "counter" works well. So, I suspect my sleeping instructions may not be correct. To do this, I commented line 156, sleepNow();, and un-commented lines 157-159 at the end of main void Loop(){}. Please see attached picture.
What do I expect?
I expect that, while MCU is in sleep mode, it can count the number of external interrupts.
What IDE, compiler and platform am I using?
Arduino IDE adjusted for board Arduino pro mini 3.3V - Windows 8 64bit
But the board that I have is not a genuine Arduino board. I just use the Arduino IDE adjusted for Arduino pro mini since it has the same settings and compilation is easier for me.
Thanks
counter = 0;
inside theloop()
block