diff --git a/src/common/watchdog.c b/src/common/watchdog.c index 3c8091b..fc610af 100644 --- a/src/common/watchdog.c +++ b/src/common/watchdog.c @@ -6,103 +6,111 @@ void WDT_Enable(void) { Info("Enabling watchdog timer..."); - // WDTCR: Watchdog Timer Control Register + // WDTCSR: Watchdog Timer Control Register - // 7 6 5 4 3 2 1 0 - // – – - WDTOE WDE WDP2 WDP1 WDP0 + // 7 6 5 4 3 2 1 0 + // WDIF WDIE WDP3 WDCE WDE WDP2 WDP1 WDP0 - // When the WDE is written to logic one, the - // Watchdog Timer is enabled, and if the WDE is - // written to logic zero, the Watchdog Timer - // function is disabled. + // WDP3:0: Watchdog Timer Prescaler + // The WDP3:0 bits determine the Watchdog Timer + // prescaling when the Watchdog Timer is running. + // The different prescaling values and their + // corresponding time-out periods are - // WDP2, WDP1, WDP0: Watchdog Timer Prescaler - // The WDP2, WDP1, and WDP0 bits determine the - // Watchdog Timer prescaling when the Watchdog - // Timer is enabled. The different prescaling - // values and their corresponding Timeout - // Periods are: + // WDP3 WDP2 WDP1 WDP0 Cycles Timeout5V + // 0 0 0 0 2K 16ms + // 0 0 0 1 4K 32ms + // 0 0 1 0 8K 64ms + // 0 0 1 1 16K 125ms + // 0 1 0 0 32K 250ms + // 0 1 0 1 64K 500ms + // 0 1 1 0 128K 1000ms + // 0 1 1 1 256K 2000ms + // 1 0 0 0 512K 4000ms + // 1 0 0 1 1024K 8000ms - // WDP2 WDP1 WDP0 Cycles Timeout3V Timeout5V - // 0 0 0 16K 17.10ms 16.30ms - // 0 0 1 32K 34.30ms 32.50ms - // 0 1 0 64K 68.50ms 65.00ms - // 0 1 1 128K 0.14s 0.13s - // 1 0 0 256K 0.27s 0.26s - // 1 0 1 512K 0.55s 0.52s - // 1 1 0 1,024K 1.10s 1.00s - // 1 1 1 2,048K 2.20s 2.10s - - // WDTOE: Watchdog Turn-off Enable This bit must - // be set when the WDE bit is written to logic zero. - // Otherwise, the Watchdog will not be disabled. - // Once written to one, hardware will clear this - // bit after four clock cycles. + // 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. // 00001111: Watchdog enabled, 2sec timeout - WDTCR = BIT(WDE) | BIT(WDP2) | BIT(WDP1) | BIT(WDP0); + WDTCSR = BIT(WDE) | BIT(WDP2) | BIT(WDP1) | BIT(WDP0); } void WDT_SetTimeoutFlag(byte flag) { + // Currently only support for a maximum of 2 seconds + // timeout because there is no need for more and the + // bit location of WDP3 requires conditional logic. + + // The sequence for clearing WDE and changing timeout + // configuration is as follows: + + // 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. + + // 2. 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. + flag = CLAMP(flag, 7, 0); Info("Setting watchdog prescalar to %02X...", flag); - // Clear timer prescalar flags - WDTCR &= 0xF8; // 11111000 - - WDTCR |= flag; + // Disable interrupts + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + WDTCSR = BIT(WDCE) | BIT(WDE); + // Set new timer prescalar flag + WDTCSR = (WDTCSR & 0xC8) | flag; // C8=11001000 + } } +// XXX: COMMENTS UPDATED! bool WDT_HasTriggered(void) { bool isreset; // To make use of the Reset Flags to identify a reset // condition, the user should read and then reset the - // MCUCSR as early as possible in the program. If the + // MCUSR as early as possible in the program. If the // register is cleared before another reset occurs, // the source of the reset can be found by examining // the Reset Flags. - // MCUCSR: MCU Control and Status Register - // The MCU Control and Status Register provides - // information on which reset source caused an MCU - // Reset. + // MCUSR: MCU Status Register + // The MCU Status Register provides information on + // which reset source caused an MCU reset. - // 7 6 5 4 3 2 1 0 - // JTD ISC2 – JTRF WDRF BORF EXTRF PORF + // 7 6 5 4 3 2 1 0 + // - - – JTRF WDRF BORF EXTRF PORF // Is watchdog reset flag set? - isreset = ((MCUCSR & BIT(WDRF)) != 0); + isreset = ((MCUSR & BIT(WDRF)) != 0); // XXX: Reset flag detection should be a separate // module to handle the different types. - MCUCSR = 0; + MCUSR = 0; return isreset; } void WDT_Disable(void) { - // WDE can only be cleared if the WDTOE bit has - // logic level one. To disable an enabled watchdog - // timer, the following procedure must be followed: + // See WDT_SetTimeoutFlag for an explanation of the + // necessary sequence for clearing WDE and changing + // timeout configuration. - // 1. In the same operation, write a logic one to - // WDTOE and WDE. A logic one must be written to WDE - // even though it is set to one before the disable - // operation starts. - - // 2. Within the next four clock cycles, write a - // logic 0 to WDE. This disables the watchdog. - - // No interrupts while we set WDTCR; + // Disable interrupts ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - WDTCR = BIT(WDTOE) | BIT(WDE); - WDTCR = 0; + WDTCSR = BIT(WDCE) | BIT(WDE); + WDTCSR = 0; } } diff --git a/src/common/watchdog.h b/src/common/watchdog.h index 9c55baa..0efcb40 100644 --- a/src/common/watchdog.h +++ b/src/common/watchdog.h @@ -8,7 +8,7 @@ #define WDT1000 0x6 // 1000 ms #define WDT500 0x5 // 500 ms #define WDT250 0x4 // 250 ms -#define WDT100 0x3 // 100 ms +#define WDT125 0x3 // 125 ms #define WDT64 0x2 // 64 ms #define WDT32 0x1 // 32 ms #define WDT16 0x0 // 16 ms