Start implementing watchdog timer
This commit is contained in:
@@ -140,6 +140,22 @@ int I2C_Stop(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void I2C_Reset(void)
|
||||||
|
{
|
||||||
|
unsigned char TWBRold = TWBR;
|
||||||
|
unsigned char TWARold = TWAR;
|
||||||
|
|
||||||
|
// TODO: Handle timeouts and reset TWI if necessary,
|
||||||
|
// fatal error after multiple attempts and then bring
|
||||||
|
// system to a safe stop.
|
||||||
|
|
||||||
|
// TWI_Disable();
|
||||||
|
// TWI_Init();
|
||||||
|
|
||||||
|
TWAR = TWARold;
|
||||||
|
TWBR = TWBRold;;
|
||||||
|
}
|
||||||
|
|
||||||
int I2C_SetChannel(int channel)
|
int I2C_SetChannel(int channel)
|
||||||
{
|
{
|
||||||
unsigned char crb;
|
unsigned char crb;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef MAD_CORE_COMMON_H
|
#ifndef MAD_CORE_COMMON_H
|
||||||
#define MAD_CORE_COMMON_H
|
#define MAD_CORE_COMMON_H
|
||||||
|
|
||||||
|
#include "common/watchdog.h"
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|||||||
112
src/common/watchdog.c
Normal file
112
src/common/watchdog.c
Normal 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
12
src/common/watchdog.h
Normal 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
|
||||||
20
src/main.c
20
src/main.c
@@ -33,6 +33,24 @@ int Init(void)
|
|||||||
|
|
||||||
Info("Initializing...");
|
Info("Initializing...");
|
||||||
|
|
||||||
|
// The watchdog timer is clocked from a separate
|
||||||
|
// on-chip oscillator which runs at 1MHz. Eight
|
||||||
|
// different clock cycle periods can be selected
|
||||||
|
// to determine the reset period. If the reset
|
||||||
|
// period expires, the chip resets and executes
|
||||||
|
// from the reset vector.
|
||||||
|
|
||||||
|
// The update loop must call WDT_Reset to reset
|
||||||
|
// the timer, kind of like a dead man's switch
|
||||||
|
// allowing us to detect infinite loops and any
|
||||||
|
// other error that halts execution.
|
||||||
|
|
||||||
|
if (WDT_HasTriggered())
|
||||||
|
Info("Unexpected system reset.");
|
||||||
|
|
||||||
|
// WDT_Enable();
|
||||||
|
// WDT_SetTimeout(7);
|
||||||
|
|
||||||
// There is a possiblity to use interrupt signals
|
// There is a possiblity to use interrupt signals
|
||||||
// for I2C communication but only as one large
|
// for I2C communication but only as one large
|
||||||
// branching routine for the whole I2C system.
|
// branching routine for the whole I2C system.
|
||||||
@@ -80,6 +98,8 @@ void Update(void)
|
|||||||
float temp[3], rhum[3];
|
float temp[3], rhum[3];
|
||||||
short raw[4];
|
short raw[4];
|
||||||
|
|
||||||
|
WDT_Reset(); // Reset watchdog
|
||||||
|
|
||||||
Info("Reading sensor values...");
|
Info("Reading sensor values...");
|
||||||
|
|
||||||
I2C_SetChannel(AHT01);
|
I2C_SetChannel(AHT01);
|
||||||
|
|||||||
Reference in New Issue
Block a user