Resetting / Rebooting ATTiny85 with Watchdog Timer (WDT)

I was expecting this to be a no-brainer. I use WDT on Arduinos w/o any trouble. The code for Arduino would roughly be:

#include <arv/wdt.h>

...
wdt_enable(WDTO_1s);
while (true) {}

After one second, the arduino reboots because of the WDT.

That does not work for the ATTiny85. It wants to call the WDT_vect ISR instead and somehow (at least for me) hangs up such that I have to remove power from the ATTiny85 to get it running again.

After hours of banging my head against the wall and searching every source repeatedly I finally was able to put together the following code which correctly reboots the ATTiny85:

#include <avr/wdt.h>

void reboot(
    ) {

cli();
WDTCR = 0xD8 | WDTO_1S;
sei();

wdt_reset();
while (true) {}

} //reboot

void setup (
    ) {

    wdt_disable();

    }

In this example, the WDIE bit is set to 1 which is necessary to get the MCU to reset. Evidently wdt_enable() is not doing that for the ATTiny85. The other possibility is that the wdt_enable() procedure is not fast enough as the ATTiny85 requires everything be set properly in 4 clock cycles.

Note: You MUST include wdt_disable() as the first instruction in setup(). I tried going without this and it hangs under that condition as well.

Either way, this code is working for me, so after 2 evenings of frustration, I can proceed with my project!

This entry was posted in c-tinys and tagged . Bookmark the permalink.

5 Responses to Resetting / Rebooting ATTiny85 with Watchdog Timer (WDT)

  1. mahesh says:

    hi, your code didn’t work for my ATtiny85 (programmed using an Arduino Uno as ISP) but the following did. the main difference is that MCUSR &= ~(1<<WDRF) needs to be set before wdt_disable() in your setup code, so it's the first thing that's executed.

    void setup() {
    MCUSR &= ~(1<<WDRF); // reset status flag
    wdt_disable();
    //… other stuff
    }

    void loop() {
    if (some-condition) reboot2();
    }

    void reboot2() {
    wdt_enable(WDTO_2S);
    while(1){};
    }

  2. Tom Hansen says:

    I’m using an Adafruit Trinket Pro 3V. Here’s my variation that works for me:

    #include

    void reboot() {
    wdt_reset();
    wdt_enable(WDTO_15MS);
    while (true) {}
    } //reboot

    void setup () {
    wdt_disable();
    }

  3. CShannon says:

    The Mahesh method worked for me as well. I’m using the TinyAVR programmer from Sparkfun and USBtinyISP programmer with Arduino 1.8.1 IDE with ATTiny85.

  4. Matthew says:

    There are four or five different versions or avr/wdt.h floating around depending upon your toolchain. The ATTinyx5’s were neglected in the definitions of wdt_enable(). The datasheet is obsessed more with disabling the WDT and less with setting it up. You may also want to redefine WDTO_4S and WDTO_8S as 0x20 and 0x21 so the “bitwise or” works without (messy ternary?) “if” statements. Mahesh is correct and Spence Konde has also noted this in his core with the same syntax. All the wdt.h header files include a commented function to similarly deal with MCUSR including copying it.

  5. Joe H says:

    Many thanks Dan for your blog! You saved me many hours of painful work trying to figure out why a simple program to reboot the ATtiny85 when wdt was reset in time wouldn’t work. My application of the attiny was as an external watchdog timer for a Raspberry Pi 0 which will be at a remote location (more than 4 hours from my home here in Dublin). Basically the attiny is set to reboot the RPi0 if it doesn’t receive a reset signal from the RPi0 within 12 hours. I already lost many hours on Friday last trying to figure out why my simple program (without the attiny’s internal wdt at this point) wouldn’t work as I was using INT0 to reset the countdown timer every 15 mins (using a few seconds for testing purposes) from the RPi0 (which also checks for an internet connection before it resets the ext wdt). After many frustrating hours, I realised my simple ISR which only had a single line pulseCheck = millis(); wasn’t simple as millis() is a function call. Bad, bad, bad idea to call a function (particualrly one I haven’t written myself) within an ISR as I have now found it as it sometimes worked and often didn’t with very erratic behaviour. I presumed it was grounding issues, RFI etc etc and wondered why others didn’t report such flaky behaviour in the attiny INT0 function. I changed it to setting a reset flag in the ISR and resetting the counter then in the main program loop with the same line if the flag was set. It was as solid as a rock after that change! An important lesson learnt for me as I had thought it was working fine when it worked in the simulide simulator – which is also an important lesson as they are never reality replicators.

    As the attiny has its own internal wdt I thought I would use it as well to make sure my ext wdt didn’t freeze either and become non-functional. I thought it was simple but like you found that the attiny didn’t reboot properly (testing program had a long flash in the setup section and a constant quick flash in the main loop). When the int wdt reset the tiny the led flashed very very rapidly (I think it was constantly rebooting the attiny but am not sure.) I googled the problem and very luckily found your blog.

    As per Mahesh above I just added in the two lines MCUSR &= ~(1<<WDRF); and wdt_disable(); as the first 2 lines in setup and then turned on the int wdt as before at the end of the setup section with wdt_reset() called in the main loop. This worked properly then fully rebooting the attiny. Many thanks. Joe

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.