SpenceKonde / ATTinyCore

Arduino core for ATtiny 1634, 828, x313, x4, x41, x5, x61, x7 and x8
Other
1.6k stars 311 forks source link

ATtiny85: Timer 0 is messing up watchdog interrupt #881

Closed NikolaiRadke closed 1 month ago

NikolaiRadke commented 1 month ago

Hi everybody!

I encountered a problem with the usage of watchdog interrupt after a single timer operation. The sketch uses pin change with a button and watchdog interrupt after 8 seconds:

cli(); // Stop all interrupts. An interrupt can ruin the timed sequence GIMSK |= (1 << PCIE); // Turn on pin change interrupt PCMSK |= (1 << PCINT1); // Turn on interrupt on PB1 button MCUSR &= ~(1 << WDRF); // No watchdog reset WDTCR |= (1 << WDCE) | (1 << WDE); // Watchdog change enable WDTCR = (1 << WDP0) | (1 << WDP3); // Set prescaler to 8 s sei(); // Start interrupts

The ATiny85 goes to sleep and waits for pin change interrupt. Watchdog isn't enabled yet:

sleep_mode(); // Sleep until button is pressed to "turn on" TCCR0A = 0x00; // Set timer 0 to normal mode TCCR0B = (1 << CS00); // Set prescaler to 1 to start the timer while (!(PINB & (1 << BUTTON))); // Wait until button is released randomSeed(TCNT0); // Get a time count as seed

The short time between wake up and releasing the button is enough for a quite good random seed, better than any AnalogRead readings. Later, the main loop starts, in which the ATtiny should go to sleep for 8 seconds OR until a key is pressed:

WDTCR |= (1 << WDIE); // Set watchdog interrupt sleep_mode(); // Sleep 8 s or wake when button is pressed WDTCR &= ~(1 << WDIE); // Stop watchdog interrupt

But the watchdog does not wake the ATtiny. When i use millis() instead of timer 0 for the random seed, everything is working fine:

sleep_mode(); // Sleep until button is pressed to "turn on" while (!(PINB & (1 << BUTTON))); // Wait until button is released randomSeed(millis()); // Time passed is used for random numbers

I tried to avoid millis() to save flash and encountered the problem. I know that timer 0 gets turned of after reading from register TCNT0. Using timer 1 caused the same error. After three days of searching the internet i wasn't able to find someone with the same problem or even someone using both timer and watchdog. So maybe it's a bug and timer is messing up watchdog in your core? Or even a hardware issue? Or PERHAPS a mistake by myself? ;-)

You can find the complete sketch here: https://github.com/NikolaiRadke/Schimpfolino/blob/main/src/Schimpfolino_new/Schimpfolino_new.ino

Of course i am using ISRs:

ISR(PCINT0_vect) { // Interrupt routine for pin change awake = true; // Set awake flag when button is pressed } ISR(WDT_vect) {} // Interrupt routine for watchdog. Unused but mandatory

Thank you for the great core!

Best regards, Nikolai

NikolaiRadke commented 1 month ago

Note: I am using core 1.5.2. and tried 2.0.0-dev too.

hmeijdam commented 1 month ago

Are you sure the Watchdog Interrupt can wakeup the device?

What I read in the datasheet is that a Watchdog Reset can do that, amongst others, but I don't see the Watchdog Interrupt as wakeup source. I admit I have not explored the sleep function much. image

NikolaiRadke commented 1 month ago

Yes, with ATtiny25/45/85 it is possible. See 8.4 in the Datasheet:

8.4 Watchdog Timer The Watchdog Timer is clocked from an On-chip Oscillator which runs at 128 kHz. By controlling the Watchdog Timer prescaler, the Watchdog Reset interval can be adjusted as shown in Table 8-3 on page 46. The WDR – Watchdog Reset – instruction resets the Watchdog Timer. The Watchdog Timer is also reset when it is disabled and when a Chip Reset occurs. Ten different clock cycle periods can be selected to determine the reset period. If the reset period expires without another Watchdog Reset, the ATtiny25/45/85 resets and executes from the Reset Vector. For timing details on the Watchdog Reset, refer to Table 8-3 on page 46.

The Wathdog [sic!] Timer can also be configured to generate an interrupt instead of a reset. This can be very helpful when using the Watchdog to wake-up from Power-down.

Watchdog interrupt works fine as long as i don't use one of the timers.

NikolaiRadke commented 1 month ago

Hey there,

surely it was my mistake. And certainly a stupid stupid stupid mistake with an additional sleep mode call at the wrong place. Timer and Watchdog are working fine. If anyone is interested in a timer generated random seed, feel free to harvest my code :-)

Thank you and sorry for the issue.