Problem setting watchdog prescaler on attiny88. [solved]

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

Hello, fellow AVR enthusiasts. I've got a bit of low-current, battery-powered code that's been running fine on tiny44s and tiny85s but refuses to set the watchdog's prescaler on tiny88s.

I've reduced the code to highlight the problem and protoboarded three MCUs each with a single activity LED. Both tiny44 and tiny85 blink at about 2Hz (250ms flips), which is correct, but the tiny88 flashes at around 30ish Hz (around 16ms) as if I hadn't set the prescaler (all WDP0-3 cleared).

Here's the code:

#include 
#include 

#ifdef SMCR
#define SLPREG SMCR
#else
#define SLPREG MCUCR
#endif

#ifdef WDTCR
#define WDREG WDTCR
#else
#define WDREG WDTCSR
#endif

ISR(WDT_vect) {
  PORTB ^= (1<<PB0);                    // Toggle activity LED.
}

int main(void) {
  uint8_t a,b;
  DDRB|=(1<<PB0);                       // Activity LED.
  PORTB |= (1<<PB0);
  sei();
  while(1) {
    __asm__ __volatile__ ( "wdr\n");   // WD timer reset.
    a=WDREG | (1<<WDCE) | (1<<WDIE);   // 1st: change & interrupt enable.
    b=WDREG | (1<<WDIE) | (1<<WDP2);   // 2nd: Int. Enable & prescaler @ 250ms.
    WDREG=a; WDREG=b;                  // Make changes inside of 4 cycles.
    SLPREG |= (1<<SM1) | (1<<SE);      // Sleep mode: power down, sleep enable.
    __asm__ __volatile__ ( "sleep\n"); // ZZZzzz...
    SLPREG &= ~(1<<SE);                // Disable sleep mode.
    WDREG &= ~(1<<WDIE);               // Disable WD interrupt.
  }
}

The defines work out which symbols are used depending on chip. I've verified that they indeed correspond to the correct registers holding the sleep mode and watchdog control bits.

I've tried setting the Watchdog Interrupt Enable and Prescaler bits seperately (each in two, less-than 4 cycles apart with change bit and without, passes) but that didn't help.

I've verified that the produced executable does indeed do the prescaler changes quickly:

    a=WDREG | (1<<WDCE) | (1<<WDIE);   // 1st: change & interrupt enable.
  6a: 90 91 60 00   lds r25, 0x0060
  6e: 90 65         ori r25, 0x50 ; 80
    b=WDREG | (1<<WDIE) | (1<<WDP2);   // 2nd: Int. Enable & prescaler @ 250ms.
  70: 80 91 60 00   lds r24, 0x0060
  74: 84 64         ori r24, 0x44 ; 68
    WDREG=a; WDREG=b;                  // Make changes inside of 4 cycles.
  76: 90 93 60 00   sts 0x0060, r25
  7a: 80 93 60 00   sts 0x0060, r24

I've been looking at this code and the datasheet to exhaustion. Have you guys any ideas where I've gone stupid?

Thanks.

odokemono. I try to entice electrons to do my bidding.

Last Edited: Sun. Oct 16, 2011 - 08:02 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My dad often said "When you're stuck on a problem, sleep on it, you'll see it from a fresh angle".

I can report that sleeping on microcontrollers is mighty uncomfortable. The DIP packages really bite into the skin.

However, enlightenment came. I've discovered that, unlike the 85s and 44s, the attiny88 only accepts watchdog prescaler changes when the WDE (Watchdog Enable) bit is set as well as the WDCE (change enable) bit.

This is different behaviour and is not documented in the datasheet.

So my updated code which works on all three mcus is:

    a=(1<<WDCE) | (1<<WDE);            // 1st: change & enable.
    b=(1<<WDIE) | (1<<WDP2);           // 2nd: Int. Enable & prescaler @ 250ms.
    WDREG=a; WDREG=b;                  // Make changes inside of 4 cycles.

odokemono. I try to entice electrons to do my bidding.

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

Quote:
This is different behaviour and is not documented in the datasheet.
Yes, it IS.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1