[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[avr-libc-dev] [bug #44140] wdt_disable() macro clobbers prescaller bits

From: anonymous
Subject: [avr-libc-dev] [bug #44140] wdt_disable() macro clobbers prescaller bits and can cause unexpected resets
Date: Sat, 31 Jan 2015 17:05:10 +0000
User-agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0


                 Summary: wdt_disable() macro clobbers prescaller bits and can
cause unexpected resets
                 Project: AVR C Runtime Library
            Submitted by: None
            Submitted on: Sat 31 Jan 2015 05:05:09 PM UTC
                Category: Library
                Severity: 3 - Normal
                Priority: 5 - Normal
              Item Group: None
                  Status: None
        Percent Complete: 100%
             Assigned to: None
        Originator Email: address@hidden
             Open/Closed: Open
         Discussion Lock: Any
                 Release: Any
           Fixed Release: None



The wdt_disable() macro in wdt.h overwrites the prescaler bits as an
unintended side effect when setting the watchdog change enable bit.

The relevant line in wdt_disable() macro looks like this (expanded for


IN safely level 1 (WatchDog fuse not set), the above code writes 0's to the
WDTCSR register's lower 3 bits,  which contain a prescaler for the counter.
When changing to a lower prescaler, it is possible to trigger an unintended
reset if the new prescaler has already expired.

The data sheet specially mentions this possibility in the comments for the
example code to disable the watchdog, and uses an OR to set the relevant bits
and preserve the prescaler bits...

; Write logical one to WDCE and WDE
; Keep old prescaler setting to prevent unintentional Watchdog Reset
in r16, WDTCSR
orir16, (1<<WDCE)|(1<<WDE)
out WDTCSR, r16

The problem can also be fixed with only one extra instruction/cycle and no
extra register use by placing a watchdog reset before the assignment. Since
interrupts are already disabled, this ensures that the new prescaler will not
have already tripped. Note that the watchdog is reset when it is disabled
anyway, so this should not have any side effects. 

New macro with the reset strategy would look like...

__asm__ __volatile__ ( \
"in __tmp_reg__, __SREG__" "\n\t" \
"cli" "\n\t" \
"wdr" "\n\r" \
"out %0, %1" "\n\t" \
"out %0, __zero_reg__" "\n\t" \
"out __SREG__,__tmp_reg__" "\n\t" \
: /* no outputs */ \
"r" ((uint8_t)(_BV(_WD_CHANGE_BIT) | _BV(WDE))) \
: "r0" \

I have only tested this on an ATTINY84A, but the watchdog function is the same
in every 8-bit AVR I've checked. 

Let me know if you have any questions.




Reply to this item at:


  Message sent via/by Savannah

reply via email to

[Prev in Thread] Current Thread [Next in Thread]