AVR mega48 problem getting watchdog interrupt mode to work

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

Hi

I apologize I am sure there is a thread out there that covers this but I could not find it.

I would like to use the watchdog as a 1 second repeating timer interrupt (interrupt mode).

I am using avr studio + gcc compiler.

Does anyone know of a working example of how to successfully do this?

I have tried all sorts of combinations of wdt_enable(); etc and don't appear to be getting anywhere

Thanks in advance

John

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

Quote:

I am sure there is a thread out there that covers this but I could not find it.

;) Forum search for "mega48 watchdog interrupt" (all words) uncovers on the third hit "Mega48 Watchdog not generating an interrupt".
https://www.avrfreaks.net/index.p...
which should help quite a bit. Ensure that the timed sequences aren't being stretched (with -O0 the timing criteria may not be met, but I think the library sequences are forced to be correct). Also scan the results for other prior discussions, and also try with "mega88 watchdog interrupt".

Note that AVRStudio simulator may not support this.

Lee

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

Many thanks - I think the problem is with the gcc compiler as - I guess this is too many cycles

  7c:	f8 94       	cli
  7e:	a8 95       	wdr
  80:	e0 e6       	ldi	r30, 0x60	; 96
  82:	f0 e0       	ldi	r31, 0x00	; 0
  84:	8e e1       	ldi	r24, 0x1E	; 30
  86:	80 83       	st	Z, r24
  88:	e0 e6       	ldi	r30, 0x60	; 96
  8a:	f0 e0       	ldi	r31, 0x00	; 0
  8c:	86 e4       	ldi	r24, 0x46	; 70
  8e:	80 83       	st	Z, r24
  90:	78 94       	sei

is produced from

	WDTCSR =  0x1E; //WDCE | WDE | WDP2 | WDP1;
	WDTCSR = 0x46;  //WDIE | WDP2 | WDP1; // 1second
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To follow up I change the optimization settings to -01 was (-00)(what ever that means) and code became

cli
  72:	a8 95       	wdr
  74:	e0 e6       	ldi	r30, 0x60	; 96
  76:	f0 e0       	ldi	r31, 0x00	; 0
  78:	8e e1       	ldi	r24, 0x1E	; 30
  7a:	80 83       	st	Z, r24
  7c:	86 e4       	ldi	r24, 0x46	; 70
  7e:	80 83       	st	Z, r24
  80:	78 94       	sei

and hey presto - it works!

I really need a more stable way to generate the code - but I don't fancy learning AVR asm - any ideas?

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

-O0 means no optimization at all. Don't use this setting unless there's a very good reason to do so. When starting a new project, I always start by setting -Os which is a good all-round setting in most cases. Typically the code size will be much smaller as well with -Os compared to -O0.

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

@John

These days both the Mfile template and a new GCC project in Studio default a project to -Os so if you had -O0 being used it suggests that you might be using an old version (unless this project was created a while back when Studio used to default to -O0?). Your experience above is part of the reason for FAQ#4 below...

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

Use the watchdog macros in wdt.h to take care of it, then it doesn't matter what optimization settings you use.

wdt_enable(WDTO_1S);
WDTCSR |=  (1<<WDIE);

The WDIE bit cannot be set using the macro, but you can set that separately as it has no change enable restriction on setting that bit (if I'm reading the datasheet correctly- page 54 'Bit 4 - WDCE').

Also be aware of the note on page 51. You should clear the WDRF early in your startup code (or set the watchdog early) to prevent another watchdog reset after a 'real' watchdog reset.

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

Quote:

but you can set that separately as it has no change enable restriction on setting that bit (if I'm reading the datasheet correctly- page 54 'Bit 4 - WDCE').

??? Have you tried it? A reading of the WDIE might imply differently, as WDE >>needs to be clear<<:
Quote:
• Bit 6 - WDIE: Watchdog Interrupt Enable
When this bit is written to one and the I-bit in the Status Register is set, the Watchdog Interrupt is
enabled. If WDE is cleared in combination with this setting, the Watchdog Timer is in Interrupt Mode, and the corresponding interrupt is executed if time-out 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

No I have not tried it, that's why I said 'if I'm reading the datasheet correctly'.

Quote:
Bit 4 - WDCE: Watchdog Change Enable
This bit is used in timed sequences for changing WDE and prescaler bits. To clear the WDE bit, and/or change the prescaler bits, WDCE must be set. Once written to one, hardware will clear WDCE after four clock cycles.
which looks to me like its talking about WDE and the prescale bits.

The part you quoted seems to me to say if the WDIE bit is set and the WDE bit is clear, you are in 'Interrupt Mode'. Nothing more.

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

Quote:

The part you quoted seems to me to say if the WDIE bit is set and the WDE bit is clear, you are in 'Interrupt Mode'. Nothing more.

Exactly. Your proposed sequence does not have WDE cleared, so how can it enable interrupt mode?

The combinations can drive a sane person to the edge; just think of what it does to the likes of me. I struggled with this as well in my first WDT-as-wakeuptimer app, but with the aid of the CodeVision Wizard and discussions here I know that the sequence in the thread I linked to works for "interrupt-only".

Lee

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

Quote:
Exactly. Your proposed sequence does not have WDE cleared, so how can it enable interrupt mode?
You are right. I am missing the fact that WDE is still on, so it would then be in 'Interrupt + System Reset Mode'.

2nd attempt-

WDTCSR = (1<<WDE)|(1<<WDCE);
WDTCSR = (1<<WDIE) | 6; //1S, IRQ Mode

(about the same thing as OP's original)
output with -O0-

WDTCSR = (1<<WDE)|(1<<WDCE);
  72:	88 e1       	ldi	r24, 0x18
  74:	80 93 60 00 	sts	0x0060, r24
WDTCSR = (1<<WDIE) | 6; //1S, IRQ Mode
  78:	86 e4       	ldi	r24, 0x46
  7a:	80 93 60 00 	sts	0x0060, r24

(also have not tested this, as I'm not by my 'stuff' rihgt now).

I will have to do some testing on this, as now I'm also not clear if SETTING WDE require WDCE, as both the 'Bit 4' I quoted and this-

Quote:
The sequence for clearing WDE and changing time-out configuration is as follows:
seem to say that setting WDE (assuming prescale bits are what you want already) does not require the WDCE.

I guess some testing will tell me.[/code]

Last Edited: Wed. Jan 23, 2008 - 04:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Many thanks everyone

Lee is correct

I tried using

wdt_enable(WDTO_1S);
WDTCSR |=  (1<<WDIE); 

and various other combinations early on and could never figure out why I always got an interrupt followed by a watchdog reset.

With Lee's code ( and the right compiler setting) everything works

Cheers

John

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

Quote:
With Lee's code
I too would like to use his code but am having trouble finding it (I'm probably looking right at it).

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

Quote:

I too would like to use his code but am having trouble finding it (I'm probably looking right at it).

Quote:

I know that the sequence in the thread I linked to works for "interrupt-only".

Earlier in this thread:
https://www.avrfreaks.net/index.p... which has
theusch wrote:
A couple of things based on the original code posted:

--Heed the datasheet about the first write to WDTCSR:

Quote:
1. In the same operation, write a logic one to the Watchdog change enable bit
(WDCE) and WDE. A logic one must be written to WDE regardless of the previous
value of the WDE bit.

So I've got a sequence like this (that I know works):

WDTCSR = BIT_WDTCSR_WDCE | BIT_WDTCSR_WDE | WDT_8_SEC;
WDTCSR = BIT_WDTCSR_WDIE | WDT_8_SEC;

But it may not work for you as-is (well, after you make the bit defines). Why? 'Cause your compiler may be optimizing the sequence, or otherwise manipulating it. With my compiler I'm turning off the optimizations around this code block. You will need to examine the output of your compiler and ensure that both operations are indeed carried out in separate instructions, and within 4 cycles.

Lee

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
WDTCSR = (1<<WDE)|(1<<WDCE);
WDTCSR = (1<<WDIE) | 6; //1S, IRQ Mode
WDTCSR = BIT_WDTCSR_WDCE | BIT_WDTCSR_WDE | WDT_8_SEC;
WDTCSR = BIT_WDTCSR_WDIE | WDT_8_SEC;

So it looks the same as my 2nd attempt, except setting the prescale bits in the first op, which are not needed (no effect I presume), but do not hurt.

It looks like gcc could use some updates to the wdt.h header to include setting the watchdog to the other 2 modes available on some avr's. (I'm looking at the latest libc, but do not see anything different in wdt.h).

(I'm not sure why OP's compiled code is using the Z pointer instead of sts, I suppose -O0 can produce 'anything' even though mine produces sts with -O0).

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

Quote:

...except setting the prescale bits in the first op, which are not needed (no effect I presume), but do not hurt.

Well, you >>are<< setting the pre-scale bits in the first op, as 000 is a valid selection for the shortest timeout period. And you need WDCE set to >>change<< the prescaler. So AFAIK your sequence won't work. [I remember struggling to get this to work as well, with many combinations as OP mentioned, and I'll bet you a cold one that if you indeed want 1 second it needs to be in the first op. Whether it needs to be in the second op, ???. I know that my sequence works in practice.]

Lee

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

Quote:
and I'll bet you a cold one that if you indeed want 1 second it needs to be in the first op
I'll take you up on that.

That first op may indeed write those prescale bits (I don't know yet if they 'stick', will need to do some testing), but the second instruction is where 'it happens'.

Quote:
Within the next four clock cycles, write the WDE and Watchdog prescaler bits (WDP) as desired, but with the WDCE bit cleared. This must be done in one operation

If writing the prescale bits is required in the first op, why does gcc produce this code-

wdt_enable(WDTO_1S);
  72:	88 e1       	ldi	r24, 0x18	; 24
  74:	90 e0       	ldi	r25, 0x00	; 0
  76:	2e e0       	ldi	r18, 0x0E	; 14
  78:	0f b6       	in	r0, 0x3f	; 63
  7a:	f8 94       	cli
  7c:	a8 95       	wdr
  7e:	80 93 60 00 	sts	0x0060, r24
  82:	0f be       	out	0x3f, r0	; 63
  84:	20 93 60 00 	sts	0x0060, r18

its only setting the prescale bits on the second op.

I will get my Dragon fired up and run some tests (along with the 'analog' port tests I now need to do).

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

Quote:

why does gcc produce this code...

Good question: Does it work?

Quote:

(along with the 'analog' port tests I now need to do)

LOL Me too. ;) I have nearly all "real" boards so I have to probably cut a track to check.

Lee

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

Quote:
why does gcc produce this code

Because of this maybe?

#define _wdt_write(value)   \
    __asm__ __volatile__ (  \
        "in __tmp_reg__,__SREG__" "\n\t"    \
        "cli" "\n\t"    \
        "wdr" "\n\t"    \
        "sts %0,%1" "\n\t"  \
        "out __SREG__,__tmp_reg__" "\n\t"   \
        "sts %0,%2" \
        : /* no outputs */  \
        : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \
        "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \
        "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | \
            _BV(WDE) | (value & 0x07)) ) \
        : "r0"  \
    )

(point being that this was not arbritary code generated by the compiler but hand crafted inline asm from the author of wdt.h, probably Marek Michalkiewicz or maybe our own Eric)

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

results- (AVR Dragon & mega88 on a STK500 with winavr20060421)

#include 
#include 
#include 

ISR(WDT_vect){
    //result= we get here every 1S
}

int main(void){

//test for prescale 'stickiness'
WDTCSR = WDTO_1S;
//result= nothing changes (prescale bits not set)

//test for prescale 'stickiness' with WDCE&WDE
WDTCSR = (WDTO_1S)|(1<<WDE)|(1<<WDCE);
//result= prescale bits not set,but WDE 'sticks'

//4cycles to prevent corrupting next test
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");

//test if WDIE can be set
WDTCSR = (1<<WDIE);
//result= WDIE is set

//test if WDIE can be cleared
WDTCSR &= ~(1<<WDIE);
//result= WDIE is cleared

//test if WDCE needed to set WDE
WDTCSR = (1<<WDE); 
//result= WDE bit is set (WDCE not needed to set WDE)

//test clearing WDE
WDTCSR &= ~(1<<WDE);
//result= no clearing (we already knew that)

//test setting irq mode
WDTCSR = (1<<WDE)|(1<<WDCE);
WDTCSR = (1<<WDIE) | WDTO_1S; //1S, IRQ Mode
//result= it works, I'm thirsty
 
sei();
while(1);
}

If I'm missing some test, let me know.

The prescale bits DO NOT change unless inside the 4cycles AFTER WDCE and WDE are set.

The WDE bit CAN be SET without using WDCE (but not cleared of course).

The WDIE bit can be changed without WDCE.

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

While waiting for my 'cold one' to arrive, I tried to modify wdt.h to accept the other 2 watchdog modes- (wrong forum, but same subject)-

//wdt.h modification testing
//testing watchdog irq mode and
//irq_reset mode

//need to move these up by 1 bit
//to keep WDE out of the way of the
//timeout values in the defines
#if defined (WDIE)
#define WDTO_1S_IRQ     (WDTO_1S|0x80)
#define WDTO_1S_IRQ_RST (WDTO_1S|0x90)
#endif

//undefine for testing purposes
#undef  _wdt_write
#define _wdt_write(value)                   \
__asm__ __volatile__ (                      \
"in __tmp_reg__,__SREG__"       "\n\t"      \
"cli"                           "\n\t"      \
"wdr"                           "\n\t"      \
"sts %0,%1"                     "\n\t"      \
"out __SREG__,__tmp_reg__"      "\n\t"      \
"sts %0,%2"                                 \
: /* no outputs */                          \
: "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)),     \
"r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)),       \
"r" ((uint8_t)(                             \
    (value & 0x08 ? _WD_PS3_MASK : 0x00) |  \
    (value & 0x80 ? (value >> 1) & 0x48 : _BV(WDE)) | \
    (value & 7)                             \
    ))                                      \
: "r0"                                      \
)

There may already be something in libc to do this, but I can't find it.

I have only briefly tested this, and only touched the macro code needed for a mega88. So, 2 more defines per timeout value, and a change in the wd change macro would seem to cover it. But I may be missing something obvious (like WDIE not at the same bit location for every avr- I would have to do a quick search on that).

update- WDE and WDIE is the same bit location (3 and 6) for all avr's in the latest avr studio inc's.

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

I bought my own 'cold one' and charged it to Lee (they said they knew who you were).

my revised wdt.h for using normal,irq, or irq+reset mode
http://www.mtcnet.net/~henryvm/wdt/

I'm sure its not finished (nothing ever is).

(I am using an alternate method to determine whether to use sts or out, so all those avr models don't have to be listed, and new models 'should' be covered. At least that's the idea)

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

Quote:

I bought my own 'cold one' and charged it to Lee (they said they knew who you were).

LOL--I'll get it back; don't you worry about that.

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

Quote:
I'll get it back
Probably many times over. I may want to just PayPal you some $ now, so I can stay ahead of it.

Maybe you could just take over my previous debt. I think I owe somebody on this forum a cookie.

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

curtvm wrote:
I think I owe somebody on this forum a cookie.

That's a bit sad - for me the forum is always ofering to DELIVER cookies to me ?!?

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

my new version of wdt.h (new and improved, maybe just new)
http://www.mtcnet.net/~henryvm/wdt/

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

Curt,

If you think you have made a significant improvement here then consider opening an item on the avr-libc bug list to get this considered for future inclusion

http://savannah.nongnu.org/bugs/...

(you could see your name in lights!)

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

Give me another 6 months to tweak on it (I already changed it again), then give me another 6 months to figure out how the documentation inside the header works.

If I ever see my name in lights, I'll know I'm on the wrong planet.