Watchdog Timer Interrupt, need to disable WDE?

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi All,

I know there are TONS of tutorials for the watchdog timer. However, generally those tutorials use avr/WDC.h (or whatever the watchdog header file is.) It's generally pretty simple. I can get it to work, but I'm confused about a bit of wording in the datasheet. I'm working with a Tiny85. 

 

If you want to enable the interrupt, you have to set the WDIE bit in the WDTCR register. However, the manual says, and I quote: 

When this bit is written to one, WDE is cleared, and the I-bit in the Status Register is set, the Watchdog Time-out Interrupt is enabled. In this mode the corresponding interrupt is executed instead of a reset if a timeout in the Watchdog Timer occurs. 

I'm confused, does it mean that when this bit is set, WDE is cleared automatically, or YOU have to manually clear WDE? (WDE is the "watchdog enable" bit.) Why does WDE have to be disabled for this to work? Not an inch later in the datasheet, it says that if both WDE and WDIE are 1, then the interrupt is enabled, but that's contradictory to what it says above.  I guess I could simply set the watchdog fuse and not worry about the watchdog ever turning off, but I don't really NEED that. I simply want my program to continuously run the watchdog interrupt until the memory fills up then shut itself off. Easy enough, it's just getting the interrupt to constantly run which is a pain. The way I see it now, the code has to look something like this. Anything in "*" are code blocks that I didn't feel like writing out, but the general structure is there.

 

*watchdog setup including interrupt enable*
*enable watchdog*
*sleep mode pwr down*
while(*condition until memory fills up*)
{
    sleep_enable();
    sleep_cpu();
    //Deep sleep until Watchdog interrupt happens.
    *Enable WDE bit again?*
    *Enable WDIE bit*

}
*disable watchdog timer so that the MCU sleeps until I draw data from it*

ISR(WDT_vect)
{
    sleep_disable();
    *put data into memory*
    *increment memory position*
}

 

Alternatively I could go to debugging mode in avr studio (or whatever it's called now) and watch the bits, but I'm at work and can't do that now. :) Honestly I'm only asking this because I'm not home to experiment with it, as it'd probably take me only a few minutes to figure it out. 

Last Edited: Tue. Sep 16, 2014 - 03:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When I first used watchdog interrupt on Mega48 family, it did take some time to find the correct sequences.  I'm assuming from your post and the code that you want "interrupt only" and not "interrupt plus reset"?

 

>>If<< you can navigate the search feature on the new site, then you should be able to find prior discussions, and as I recall Tiny25 family was worked through as well.

 

I seem to recall that the GCC functions aren't quite right, or aren't really set up for "interrupt only".

 

FWIW here is the setup sequence from CodeVision Wizard for 8 second timeout, interrupt-only.  I'd have to dig into my projects to see if this is what I really use, so no warranty.

// Watchdog Timer initialization
// Watchdog Timer Prescaler: OSC/1024k
// Watchdog timeout action: Interrupt
#pragma optsize-
WDTCR=(0<<WDIF) | (0<<WDIE) | (1<<WDP3) | (1<<WDCE) | (0<<WDE) | (0<<WDP2) | (0<<WDP1) | (1<<WDP0);
WDTCR=(1<<WDIF) | (1<<WDIE) | (1<<WDP3) | (0<<WDCE) | (0<<WDE) | (0<<WDP2) | (0<<WDP1) | (1<<WDP0);
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the info! Yeah... google stopped directing to old threads of this site, so I gave up on searching. I find a relevant result on google and it just takes me to the home page. *I liked the old site better*

 

No worries about the code. It's interesting though. I can't tell if the watchdog fuse is set or not. If it is, then it almost makes sense because of the use of the WDCE bit to change the timing. If it isn't... then the watchdog isn't running after that. WDE would have to be 1. Unless the code is simply to set it up, and not start it. 

 

We'll see what happens when I get home.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I can't tell if the watchdog fuse is set or not.

???  Now you are confusing me.  It is your app.  You set the fuses.  You can read the fuses.  So why can't you tell? Aaah, yes, there are different chang considerations when WDTON is programmed--"safety level 2".

 

Or did you mean "Should the fuse be set"?  I've never set WDTON in any app.

 

I use the CV sequence, or similar, in every app.  It might also be useful to note that CV turns off the watchdog (and clears WDRF) at startup to avoid cascading watchdog resets.  AFAIK watchdog interrupt-only doesn't set WDRF.

 

Re "WDE would have to be 1" -- the setting to 0 is part of watchdog interrupt-only IIRC.

 

This datasheet excerpt seems pretty clear...

 

• Bit 6 – WDIE: Watchdog Timeout Interrupt Enable
When this bit is written to one, WDE is cleared, and the I-bit in the Status Register is set, the
Watchdog Time-out Interrupt is enabled. In this mode the corresponding interrupt is executed
instead of a reset if a timeout in the Watchdog Timer occurs.

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

corrado33 wrote:
When this bit is written to one, WDE is cleared, and the I-bit in the Status Register is set, the Watchdog Time-out Interrupt is enabled. In this mode the corresponding interrupt is executed instead of a reset if a timeout in the Watchdog Timer occurs.
It is an awkward phrasing, true.

 

To be clearer:

If ALL of the following are true...

  1. WDIE is 1
  2. WDE is 0
  3. interrupts are enabled (I-bit in SREG is 1)

... then the watchdog timeout interrupt will be enabled.

 

Quote:
Why does WDE have to be disabled for this to work?
This condition describes Interrupt Only mode.

Quote:
Not an inch later in the datasheet, it says that if both WDE and WDIE are 1...
This describes Interrupt-and-Reset mode.

Quote:
I guess I could simply set the watchdog fuse...
This will force Reset Only mode.  The watchdog interrupt cannot be enabled and will never fire.

 

Sounds like what you're looking for is Interrupt Only mode.

 

I can't include code for some reason because the code editor is (for me at least) totally broken.  Won't even show up.

 

I've attached a code snipped which should work for the ATtiny85.

 

EDIT: OK, whatever was wrong with the code editor (on my machine, or the site, or both) seems to have fixed itself.

 

#include <avr/wdt.h>

#define wdt_interrupt_enable(interval)                                    \
    __asm__ __volatile__ (                                                \
    /* Preserve SREG   */ "in     __tmp_reg__,  __SREG__          \n\t"   \
    /* Atomic          */ "cli                                    \n\t"   \
    /* reset WDT       */ "wdr                                    \n\t"   \
    /* WDCE & WDE      */ "out    %[wdtctr],    %[change]         \n\t"   \
    /* Restore SREG    */ "out    __SREG__, __tmp_reg__           \n\t"   \
    /* WDIE & interval */ "out    %[wdtctr],    %[enable]         \n\t"   \
                        :                                                 \
                        :                                                 \
    /* control reg     */ [wdtctr] "M" (_SFR_MEM_ADDR(WDTCR)),            \
    /* WDCE & WDE      */ [change] "r" ((uint8_t)((1<<WDCE) | (1<<WDE))), \
    /* IF/IE & intervl */ [enable] "r" ((uint8_t)((interval & 0x08 ?      \
                                                  (1<<WDP3) : 0x00) |     \
                                                  (1<<WDIF) | (1<<WDIE) | \
                                                  (interval & 0x07)) )    \
                        : "r0"                                            \
                         )

 

Attachment(s): 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Wed. Sep 17, 2014 - 03:15 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would recall that Interrupt and reset means:

The first wdt overflow causes interrupt, the subsequent overflows cause reset.

 

The table in the datasheet (2586Q–AVR–08/2013) should look like this:

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The table in the datasheet is accurate as it is.

 

An important piece of information required in order to understand how it all works is that if both WDE and WDIE are set, then when the wdt times out the interrupt is triggered and WDIE is cleared by hardware.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the help guys. I've my program works fine with interrupt only. I wasn't getting that I didn't have to "enable" the watchdog timer by setting WDE to 1. Enabling the interrupt effectively "enables" the timer as well. (I thought it was more of a "Enable timer using WDE, then enable interrupt by using WDIE")

 

Here's a tiny program that enables interrupt only and flashes a LED attached to Port B0 (bottom right of DIP package.) (Led cannot be attached during programming.)

 

Note: This program by no means uses good practices, but it demonstrates using the watchdog timer in C with interrupts only. This program works on my Tiny85, but it should work for the whole family (Tiny25, Tiny45, Tiny85)

#include <avr/io.h>
#include <avr/interrupt.h>

int main()
{

	SREG |= 0x80;	//Global interrupts
	WDTCR |= 0x04;	//Watchdog prescalers (how long it takes to go off)
	WDTCR |= 0x40;	//Enable watchdog by enabling interrupt only pin
	DDRB |=0x01;	//Set B0 to output
	while(1)
	{
	}
}


ISR(WDT_vect)
{
	PORTB ^= 0x01;	//Turn LED attached to B0 on and off.
}

For the sake of completeness, I have the tiny85 running at 8MHz with the Clkdiv8 fuse enabled (so it's really running at 1MHz). Main clock timing shouldn't affect the watchdog timing however. I'm also using the AVR-GCC compiler and AVR Studio 4 (I hate the new atmel studio.) The watchdog fuse is NOT enabled. All of the other fuses are default. (I believe the entire fuse set is what it is by default, but I just pointed out the most obvious ones for this application.) 

Last Edited: Wed. Sep 17, 2014 - 02:40 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
	WDTCR |= 0x04;	//Watchdog prescalers (how long it takes to go off)
	WDTCR |= 0x40;	//Enable watchdog by enabling interrupt only pin

1)  Perhaps it is just me, but I'd never do an |= for this work.  And in fact, doesn't WDCE need to be set somewhere in there?  (Your topic has been/is a bit confusing to me, even as an AVR veteran.  Luckily, there are only so many combinations...)

 

2)  Do the two lines need to be in a timed sequence?  Depending on e.g. optimization level, your sequence isn't guaranteed to meet the criterion.  Thus, the guru(s) posted the foolproof sequence in GCC ASM.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:

	WDTCR |= 0x04;	//Watchdog prescalers (how long it takes to go off)
	WDTCR |= 0x40;	//Enable watchdog by enabling interrupt only pin

1)  Perhaps it is just me, but I'd never do an |= for this work.  And in fact, doesn't WDCE need to be set somewhere in there?  (Your topic has been/is a bit confusing to me, even as an AVR veteran.  Luckily, there are only so many combinations...)

 

2)  Do the two lines need to be in a timed sequence?  Depending on e.g. optimization level, your sequence isn't guaranteed to meet the criterion.  Thus, the guru(s) posted the foolproof sequence in GCC ASM.

 

 

1) Agreed. The |= isn't the best of ideas, it's just what I do by default (didn't think about it here.) But by default that entire register is 0 so it works. As for WDCE, I don't think so. The way I read the datasheet made it seem like WDCE only needs to be set if you want to turn OFF the watchdog, or change the prescalers while the watchdog fuse is set. This is when I also think that I need to use a timed sequence. I could be wrong (you definitely know more than I do.) but you can be certain that the above program works. I've observed it in person.

 

2) Yes, you have to play with the optimization level for this to work. I don't think Os likes empty while loops. (Or any empty loops for that matter.) In my actual program I have things in the while loop so it works on more than just O0 optimization. 

Last Edited: Wed. Sep 17, 2014 - 02:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I wasn't getting that I didn't have to "enable" the watchdog timer by setting WDE to 1.

I've done more work on this with Mega48 family.  So I pulled up a recent datasheet for the '48PA as well as for the Tiny family.

 

It is interesting that the wording is a bit different for "WDE".  The '48 datasheet has

• Bit 3 – WDE: Watchdog System Reset Enable

...which then makes more sense, right?

 

Also, re the CV sequence and WDCE and so forth.  I thought about it a bit.  Suppose the program runs amok or otherwise ends up with the program counter at address 0.  The CV sequence at startup will turn off the watchdog first, so if it >>was enabled and running<< with some configuration it will then take on the desired configuration for the start of the AVR app.

 

Indeed, most or nearly all apps will have one watchdog configuration and stick with it.  But not always.  So at the expense of a couple flash words and AVR cycles the CV sequence covers the bases.  (I'm ignoring WDTON combinations.)

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

corrado33 wrote:
The way I read the datasheet made it seem like WDCE only needs to be set if you want to turn OFF the watchdog, or change the prescalers while the watchdog fuse is set. This is when I also think that I need to use a timed sequence.
There is actually no restriction for changing the prescaler even when the WDT is already running.  This is true regardless of whether the WDT is in interrupt mode, reset mode, or interrupt-and-reset mode.

 

This is 'safety-level-1' and is enabled by unprogramming the WDTON fuse.

 

Programming WDTON enables 'safety-level-2' which forces the WDT into reset mode.  The WDT cannot be disabled in this safety-level, and a timed sequence is required for changing the prescaler.

 

But beware that while this applies to the 85 and friends, not all WDT are created equally.  Always be sure to read the datasheet for your device.

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Wed. Sep 17, 2014 - 11:01 PM