1

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

  • i do not have time to examine your code in detail, but i see counter = 0; inside the loop() block – jsotola Jan 29 at 19:26
  • @jsotola that part is after reading and printing its value. Moreover, before reaching that line, its value will be copied to variable "rs". – Nima Sajedi Jan 29 at 19:31
  • perhaps the compiler has somehow optimized it out of existence ... what happens if you assign a value other than 0 at the variable declaration – jsotola Jan 29 at 19:37
  • @ jsotola, I already tried that one with not giving it an initial value in declaration and still it was zero in readings. After triggering external interrupt, MCU resets and everything starts from "Setup()" and it might be the reason that "counter" is zero. Triggering Ex.Int is not supposed to reset MCU. When I tried without putting MCU in PowerDown mode, everything is fine and external interrupt works as expected. The issue occurs when it is in PowerDown mode. – Nima Sajedi Jan 29 at 19:46
  • you may have to use an external counter – jsotola Jan 29 at 23:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.