Start implementing watchdog timer

This commit is contained in:
2024-09-05 15:19:36 +02:00
parent 14e12cdd03
commit d1a25c4bd3
5 changed files with 162 additions and 0 deletions

112
src/common/watchdog.c Normal file
View File

@@ -0,0 +1,112 @@
#include "common.h"
#include <util/atomic.h>
void WDT_Enable(void)
{
Info("Enabling watchdog timer...");
// WDTCR: Watchdog Timer Control Register
// 7 6 5 4 3 2 1 0
// - WDTOE 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.
// 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:
// 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.
// 00001111: Watchdog enabled, 2sec timeout
WDTCR = BIT(WDE) | BIT(WDP2) | BIT(WDP1) | BIT(WDP0);
}
void WDT_SetTimeout(unsigned char time)
{
time = CLAMP(time, 7, 0);
Info("Setting watchdog prescalar to %d...", time);
// Clear timer prescalar flags
WDTCR &= 0xF8; // 11111000
WDTCR |= time;
}
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
// 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.
// 7 6 5 4 3 2 1 0
// JTD ISC2 JTRF WDRF BORF EXTRF PORF
// Is power-on reset flag not set?
isreset = ((MCUCSR & BIT(0)) == 0);
// XXX: Reset flag detection should be a separate
// module to handle the different types.
MCUCSR = 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:
// 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;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
WDTCR = BIT(WDTOE) | BIT(WDE);
WDTCR = 0;
}
}
void WDT_Reset(void)
{
// TODO: Reset watchdog timer
}

12
src/common/watchdog.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef MAD_CORE_COMMON_WATCHDOG_H
#define MAD_CORE_COMMON_WATCHDOG_H
#include <stdbool.h>
void WDT_Enable(void);
void WDT_SetTimeout(unsigned char time);
bool WDT_HasTriggered(void);
void WDT_Disable(void);
void WDT_Reset(void);
#endif // MAD_CORE_COMMON_WATCHDOG_H