watchdog timer flag doesn't reset with servo on attiny85

I’m using a ATTiny85 at 1 mhz internal clock.

My code uses a wdt to sleep and repeatedly wake up until a watchdog counter hits a target value, then operates a servo and resets that watchdog counter to wait the same amount of time before operating the servo again.

During loop, it sleeps for 8 sec, and wdt wakes it up. if it has been waken up 4 times (wd_target is the var that stores this value), then the servo is supposed to spin once.

The problem is the servo never stops moving after the wd_target reaches 4. This variable is supposed to be set back to 0 right after my feedTheFish function (Which makes the servo move). It’s like resetting wd_target to 0 didn’t work.

If I change my feedTheFish function for flashing a LED however, everything works fine and it flashes every 4 x 8 seconds. It looks like SoftwareServo doesn’t like working with wdt? How can I stop the servo from moving once feedTheFish is triggered? thanks!

/**************************************************************************************************************************************************************/
////LIBRARIES
/**************************************************************************************************************************************************************/

#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <SoftwareServo.h>



/**************************************************************************************************************************************************************/
////PINS
/**************************************************************************************************************************************************************/


#define switchPin  2
#define ledPin  1
#define voltagePin  4


/**************************************************************************************************************************************************************/
////VARIABLES
/**************************************************************************************************************************************************************/

//WDT variables
volatile int watchDog_counter;
int wd_target = 4; //target for wd counter

//PC interrupt variables
volatile int buttonFlag;
unsigned long last_interrupt_time;
int voltage;

// values are set depending on resistor values. Common resistor is 10k
#define minNb  190 //175 to 185 based on a 4.7k resistor value for UP arrow button
#define maxNb  205
#define minSize  210 //189 to 220 based on a 1k resistor value for DOWN arrow button
#define maxSize  220
#define minReset  175 //120 to 166 based on a 10k resistor value for SELECT button
#define maxReset  189


//Food Data variables

//amount of meals per day
byte meal_nb = 1;
#define max_meal_nb 3

//amount of cylinder spins (meal size)
byte meal_size = 1;
#define max_meal_size 5


//Servo variables
byte pos = 0;


/**************************************************************************************************************************************************************/
////OBJECTS
/**************************************************************************************************************************************************************/ 
SoftwareServo feederServo;      // creates feederServo as object to control a servo


/**************************************************************************************************************************************************************/
////SETUP
/**************************************************************************************************************************************************************/

void setup() {

  watchDog_counter = 0;

  //SoftwareServo setup
  feederServo.attach(0);                        // attaches the servo on pin 0 to the servo object


  //pins setup
  DDRB &= ~(1 << switchPin);
  PORTB |= (1 << switchPin);
  DDRB |= (1 << ledPin);




  //Watchdog timer setup
  //This order of commands is important and cannot be combined
  MCUSR &= ~(1 << WDRF); //Clear the watch dog reset
  WDTCR |= (1 << WDCE) | (1 << WDE); //Set WD_change enable, set WD enable
  WDTCR = 0B100001; //Set prescaler to 8 sec (see p.46 of datasheet to change prescaler), and OVERWRITE WDTCR value ( dont just use |= )
  WDTCR |= _BV(WDIE); //Set the interrupt enable, this will keep unit from resetting after each int



  //Pin Change interrupt setup
  //Enable interrupts
  GIMSK |= (1 << PCIE);
  PCMSK |= _BV(PCINT2);
  sei();



 
  sleep_enable();
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
}



/**************************************************************************************************************************************************************/
////LOOP
/**************************************************************************************************************************************************************/


void loop() {

  ADCSRA &= ~_BV(ADEN);      //Turn ADC off, saves ~230uA
  sleep_cpu();
  ADCSRA |= _BV(ADEN);        //will ADC need to be turned on after sleep?

  PORTB |= (1 << ledPin);
  delay(100);
  PORTB ^= (1 << ledPin);

  //  delay(500);



  if (watchDog_counter >= wd_target) {
    feedTheFish();
    watchDog_counter = 0;
  }
}


/**************************************************************************************************************************************************************/
////FUNCTIONS
/**************************************************************************************************************************************************************/




  ISR(PCINT0_vect) { //NOT PCINT0_vect!
    if (!(PINB & (1 << PB2))) buttonFlag = 1; //tell the arduino a button was pressed, not released
  }




  ISR(WDT_vect) {
    watchDog_counter++;
  }


void feedTheFish() {



  for (int s = 0; s < meal_size; s++) {
    for (pos = 0; pos <= 180; pos += 1)       // goes from 0 degrees to 180 degrees
    { // in steps of 1 degree
      feederServo.write(pos);                     // tell servo to go to position in variable 'pos'
      delay(15);                              // waits 15 milliseconds for the servo to reach the position
      SoftwareServo::refresh();               // required by SoftwareServo Library to sweep correctly
    }
    delay (20);                               // required by SoftwareServo Library to sweep correctly



    for (pos = 180; pos >= 0; pos -= 1)       // goes from 180 degrees to 0 degrees
    {
      feederServo.write(pos);                     // tell servo to go to position in variable 'pos'
      delay(15);                              // waits 15 milliseconds for the servo to reach the position
      SoftwareServo::refresh();               // required by SoftwareServo Library to sweep correctly
    }
    delay(20);                                // required by SoftwareServo Library to sweep correctly
  }
}

how about changing

if (watchDog_counter >= wd_target) {
    feedTheFish();
    watchDog_counter = 0;
  }

to

if (!(watchDog_counter% wd_target)) {
    feedTheFish();
  }

and maybe change watchDog_counter to an Unsigned int (or a byte for that matter) and start it of as 1, I can’t explain it not working the way you (and i) expect to, but if you want it feeding the fish every 4 (or maybe it’s 5 ?) times it wakes up, this is a way.

Deva_Rishi:
how about changing

if (watchDog_counter >= wd_target) {

feedTheFish();
    watchDog_counter = 0;
  }


to


if (!(watchDog_counter% wd_target)) {
    feedTheFish();
  }


and maybe change watchDog_counter to an Unsigned int (or a byte for that matter) and start it of as 1, I can't explain it not working the way you (and i) expect to, but if you want it feeding the fish every 4 (or maybe it's 5 ?) times it wakes up, this is a way.

Thanks! even though your code is cleaner than mine (I will use it your way), the Servo still keeps spinning. After trying a bunch of things, I realized the program is not even stopping the Servo.write lines.

I first thought it finished moving the servo, and then could not get back to sleep and kept cycling through feedTheFish(), but it is not even doing that. If I add delays and turn on my LED at various spots in feedTheFish(), my ATTiny doesn't follow my commands and keeps trying to infinitely write to the servo.

This makes me think it might be a problem linked to the delay() periods between each servo.write? like they are too short or too quick for ATTiny85 with the given clock speed of 1Mhz? I tried changing them from 15 to 50 ms but it didn't change anything. I really wonder what is going on.

can the servo only move taking 1 degree steps ? and/or is the position really an absolute value in degrees ?
I would start out with a sample sketch for just controlling the servo, and given the current situation i would go back to that. Then afterwards we can see if sleeping causes any issues.

Deva_Rishi:
can the servo only move taking 1 degree steps ? and/or is the position really an absolute value in degrees ?
I would start out with a sample sketch for just controlling the servo, and given the current situation i would go back to that. Then afterwards we can see if sleeping causes any issues.

Thanks to everyone who helped me!!

I ended up going one step at a time, like you said, and finally understood. There seems to be more than one problematic element in my original post. In order to make it work, I ended up putting my watchdog setup in the loop, right before going to sleep. I also switched my pos variable from byte to int. Both these seemed to do the trick. Here is my final code: (I can wake up the IC with a button, or wait for the WDT to wake it up):

/**************************************************************************************************************************************************************/
////LIBRARIES
/**************************************************************************************************************************************************************/

#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <SoftwareServo.h>



/**************************************************************************************************************************************************************/
////PINS
/**************************************************************************************************************************************************************/

#define switchPin  2
#define ledPin  1
#define voltagePin  4


/**************************************************************************************************************************************************************/
////VARIABLES
/**************************************************************************************************************************************************************/

//WDT variables
volatile int watchDog_counter;
int wd_target = 2; //target for wd counter

//PC interrupt variables
volatile int buttonFlag;
unsigned long last_interrupt_time;
int voltage;

// values are set depending on resistor values. Common resistor is 10k
#define minNb  190 //175 to 185 based on a 4.7k resistor value for UP arrow button
#define maxNb  205
#define minSize  210 //189 to 220 based on a 1k resistor value for DOWN arrow button
#define maxSize  220
#define minReset  175 //120 to 166 based on a 10k resistor value for SELECT button
#define maxReset  189


//Food Data variables

//amount of meals per day
int meal_nb = 1;
#define max_meal_nb 3

//amount of cylinder spins (meal size)
int meal_size = 1;
#define max_meal_size 5


//Servo variables
int pos = 0; //NEEDS TO BE AN INT, NOT A BYTE


/**************************************************************************************************************************************************************/
////OBJECTS
/**************************************************************************************************************************************************************/
SoftwareServo feederServo;      // creates feederServo as object to control a servo


/**************************************************************************************************************************************************************/
////SETUP
/**************************************************************************************************************************************************************/

void setup() {

  // watchDog_counter = 0;

  //SoftwareServo setup
  feederServo.attach(0);                        // attaches the servo on pin 0 to the servo object


  //pins setup
  DDRB &= ~(1 << switchPin);
  PORTB |= (1 << switchPin);
  DDRB |= (1 << ledPin);




  //Pin Change interrupt setup
  //Enable interrupts
  GIMSK |= (1 << PCIE);
  PCMSK |= _BV(PCINT2);
  sei();

  //EXT INTERRUPT STUFF
  //IMSK |= (1 << PCIE);
  //set low lvl trigger (keeps triggering while button not released)
  //MCUCR &= ~(1 << ISC01);
  //TRYING TO PUT THIS INSTEAD!! (FOR FALLING EDGE):  MCUCR |= (1 << ISC01);
  //MCUCR |= (1 << ISC00);



  sleep_enable();
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
}



/**************************************************************************************************************************************************************/
////LOOP
/**************************************************************************************************************************************************************/


void loop() {
  //Watchdog timer setup  //Putting this in setup causes a problem when servo writing
  //This order of commands is important and cannot be combined
  MCUSR &= ~(1 << WDRF); //Clear the watch dog reset
  WDTCR |= (1 << WDCE) | (1 << WDE); //Set WD_change enable, set WD enable
  WDTCR = 0B100001; //Set prescaler to 8 sec (see p.46 of datasheet to change prescaler), and OVERWRITE WDTCR value ( dont just use |= )
  WDTCR |= _BV(WDIE); //Set the interrupt enable, this will keep unit from resetting after each int

  ADCSRA &= ~_BV(ADEN);      //Turn ADC off, saves ~230uA
  sleep_cpu();
  ADCSRA |= _BV(ADEN);        //will ADC need to be turned on after sleep?

  PORTB |= (1 << ledPin);
  delay(100);
  PORTB ^= (1 << ledPin);
  delay(100);


  if (!(watchDog_counter % wd_target)) {
    feedTheFish();
  }


  if (buttonFlag) {
    //  buttonsAction();
    buttonFlag = 0;
  }


}


/**************************************************************************************************************************************************************/
////FUNCTIONS
/**************************************************************************************************************************************************************/




ISR(PCINT0_vect) { //NOT PCINT0_vect!
  if (!(PINB & (1 << PB2))) buttonFlag = 1; //tell the arduino a button was pressed, not released
}




ISR(WDT_vect) {
  watchDog_counter++;
}

what happened to void feedTheFish() {} ? it is not in your code anymore.