Hello community,
I've spent ~10 hrs and still unable to get my code to workable state and need some help.
Short: I have deep sleep (PWR_DOWN) in my Attiny85 code. The wake trigger is external interrupt or pin change interrupt. When I'm trying to use watchdog for power-efficient time counting, it's not working.
However, it's working when I add delays in function which enables watchdog.
Setup:
- ATTINY85 at Digispark dev board;
- running at 1 MHz;
- pin 3 is connected to shake sensor;
- pin 2 is connected to button;
- 2 and 3 is in INPUT_PULLUP, other sides are connected to GND.
Workflow:
-
ShakeSensor producing PC interrupt, setting the flag. If this flag is set, payload inside loop is executed and loop counter will be reset.
-
If flag is not set, watchdog timer is being started for 120 ms. After that loop counter will be incremented.
-
If loop counter exceeds constant, MCU will fall into deep sleep.
-
Button will generate external interrupt which will reset duty cycle.
-
If I'll have delay(60) in WDT setup, it's working.
-
If I'll replace WDT sleep by delay(120), it's working.
-
I left some commented lines with alternatives which I've checked and they didn't work too.
What's wrong with my code?(below)
Code:
#include <Arduino.h>
#include <avr/wdt.h>
#include <avr/sleep.h>
#include <avr/power.h>
#define led1 0 //1
#define led2 1 //2
#define led3 4 //4
#define shakeSensor 3
#define buttonPin 2
const int brightness = 64;
int count = 50;
int time = 500;
volatile int idlecycles = 0;
volatile bool blockInterrupted = false;
volatile bool interrupted = false;
const int cyclesCuttOff = 50;
int target;
//workers
void roll();
void showSequence(int, int, int);
void blinkNumber(int, int);
void showNumber(int, int);
void fadeNumber(int);
//sleep, wdt, interrupts
void fallasleep();
void letTheDogOut();
void setup()
{
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(led3, OUTPUT);
pinMode(shakeSensor, INPUT_PULLUP);
pinMode(buttonPin, INPUT_PULLUP);
pinMode(5, INPUT);
cli();
GIMSK = _BV(INT0) | _BV(PCIE); //INT0, PCINT0
PCMSK = _BV(PCINT3);
sei();
ADCSRA &= ~(1 << ADEN);
power_adc_disable();
blinkNumber(5, 250);//ready
}
bool getInterrupted()
{
return interrupted && !blockInterrupted;
}
void fallasleep()
{
blinkNumber(6, 250); //show that we're going to sleep
cli();
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
// Turn off ADC
ADCSRA = 0;
// diable all modules availables
power_all_disable(); // power off ADC, Timer 0 and 1, serial interface
//configure interrupts
GIMSK = _BV(INT0); //external only
sleep_enable();
sei();
sleep_cpu();
sleep_disable();
power_all_enable(); // power everything back on
cli();
GIMSK |= _BV(PCIE); //both
sei();
blinkNumber(1, 250); //exiting sleep
}
void letTheDogOut()
{
//delay(60); //Suddenly working OK with delays
//blinkNumber(3, 50);
/*cli();
MCUSR = 0;
WDTCR = _BV(WDCE) | _BV(WDE) | bit(WDIF); //enable editing, disable reset, clean old int flag (?!)
WDTCR = _BV(WDIE) | _BV(WDP1) | (WDP0); //run dog for ~125ms*/
wdt_reset();
wdt_enable(WDTO_120MS);
WDTCR |= _BV(WDIE);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sei();
sleep_cpu();
sleep_disable();
//delay(60); //Suddenly working OK with delays
//blinkNumber(4, 50);
}
//interrupt handlers
ISR(PCINT0_vect)
{
interrupted = true;
}
ISR(INT0_vect)
{
}
ISR(WDT_vect)
{
wdt_disable();
idlecycles++;
}
//main loop
void loop()
{
if (interrupted || digitalRead(shakeSensor) == 0) //pulled down by shaking
{
interrupted = false;//clear flag
idlecycles = 0;//reset idle counter
roll();
fadeNumber(target);
}
//delay(120);idlecycles++ //working with delay instead of watchdog
letTheDogOut();//handler will increment cycles count
if (idlecycles >= cyclesCuttOff)//going into deep sleep
{
blockInterrupted = true;
fallasleep();
interrupted = false;
//delay(500);
fadeNumber(target); //showing last number after pressing the button
idlecycles = 0;
blockInterrupted = false;
}
}
//LED routines below
....