ATtiny85 Watchdog Timer with Millis Calculation

Hi,

I am trying to use an ATtiny85 to transmit time data with an IR LED, but only every 10 seconds, which is more than the maximum time for the watchdog timer you can configure with the watchdog timer prescaler bits. The ATtiny also needs to be in ADC Noise Reduction mode to keep the internal clock running.

In the code at the bottom, I'm having trouble with the if statement calculating the time elapsed with the millis() function. The IR LED will blink if I just say something like if(current_time_ms) or if(last_transmit_time), but if I say if((current_time_ms-last_transmit_time)>0), the IR LED does not blink.

I took the watchdog timer code from an example online, and I don't really understand what each line is doing so I'm not sure how it's working. Is it possible the watchdog timer is interfering with the clock the millis() function uses? Ideally the watchdog timer triggers an interrupt and not a reset.

/*

  The connections to the ATTiny are as follows:
  ATTiny    Arduino    Info
  Pin  1  - 5
  Pin  2  - 3 / A3     
  Pin  3  - 4 / A2     
  Pin  4  -            GND
  Pin  5  - 0          IR LED (PWM)
  Pin  6  - 1
  Pin  7  - 2 / A1
  Pin  8  -   +Vcc

*/


// include IR library
#include <IRremote.hpp>
#include <avr/sleep.h>

// Routines to set and clear bits (used in the sleep code)
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

// define pins
const int IR_LED_PIN = 0;

// declare variables
uint32_t time_command = 0;     // variable to store time, sending as raw data
uint8_t sRepeats = 0;
unsigned long current_time_ms;    // time in ms
unsigned long last_transmit_time;
int time_between_transmissions = 10;    // time in seconds between transmissions

// sleep variables
volatile boolean f_wdt = 1;

void setup()
{
  // Set up IO pins
  pinMode(IR_LED_PIN, OUTPUT);

  IrSender.begin(IR_LED_PIN, ENABLE_LED_FEEDBACK);

  delay(100);

  last_transmit_time = millis();
}

void loop() {
  setup_watchdog(7);            // sleep time defined in setup_watchdog
  system_sleep();               // send the unit to sleep

  if (f_wdt == 1) { // wait for timed out watchdog / flag is set when a watchdog timeout occurs
    // watchdog timer interrupt

    f_wdt = 0;     // reset flag

    current_time_ms = millis();
    if (( (current_time_ms - last_transmit_time) / 1000) > time_between_transmissions) {
      time_command = 2678400;   // test 31 days = 2678400 seconds
      IrSender.sendNECRaw(time_command, sRepeats);    // time is too big to send as address-command, send as raw data
      last_transmit_time = millis();
    }
  }
}

void system_sleep() {
  // set system into the sleep state
  // system wakes up when watchdog is timed out

  pinMode(IR_LED_PIN, INPUT);   // set the ports to be inputs - saves more power

  cbi(ADCSRA, ADEN);                   // switch Analog to Digitalconverter OFF

  set_sleep_mode(SLEEP_MODE_ADC);      // sleep mode is set here

  sleep_enable();

  sleep_mode();                        // System actually sleeps here

  sleep_disable();                     // System continues execution here when watchdog timed out

  sbi(ADCSRA, ADEN);                   // switch Analog to Digitalconverter ON

  pinMode(IR_LED_PIN, OUTPUT);  // set the ports to be output again

}

void setup_watchdog(int ii) {
  // 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
  // 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec

  byte bb;
  int ww;
  if (ii > 9 ) ii = 9;
  bb = ii & 7;
  if (ii > 7) bb |= (1 << 5);
  bb |= (1 << WDCE);
  ww = bb;

  MCUSR &= ~(1 << WDRF);
  // start timed sequence
  WDTCR |= (1 << WDCE) | (1 << WDE);
  // set new watchdog timeout value
  WDTCR = bb;
  WDTCR |= _BV(WDIE);
}

ISR(WDT_vect) {
  // Watchdog Interrupt Service / is executed when watchdog timed out
  f_wdt = 1; // set global flag
}

Use the watchdog with 1 second wakeups, and transmit every 10th wakeup. Timing is approximate.

Is it possible the watchdog timer is interfering with the clock the millis() function uses?

millis() does not run at all during deep sleep.

I guess that could work, thanks for the idea. So even though the sleep mode is ADC Noise Reduction, that's still considered deep sleep and millis() still doesn't work even though the internal clock is still running?


What I read in the datasheet is that also during ADC noise reduction all clocks except the ADC clock are halted. So I suspect millis also stops then.

millis() requires the CPU clock to be running.

Ahhh, I was confusing the CPU clock with the oscillator and misunderstood "Main Clock Source Enabled". Thank you all very much for your responses, this is very helpful. And thank you mrburnette for that post, I hadn't come across that when I was looking around.

I'm still a little confused as to why mills isn't working after the watchdog timer wakes up the microcontroller. Shouldn't the attiny be awake, meaning the CPU clock is on? I see in mrburnette's sketch you added the line power_all_enable ();, maybe that's what turns the clock and other peripherals back on?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.