forked from forks/qmk_firmware
160 lines
5.4 KiB
C
160 lines
5.4 KiB
C
|
/* This is from http://www.mtcnet.net/~henryvm/wdt/ */
|
||
|
#ifndef _AVR_WD_H_
|
||
|
#define _AVR_WD_H_
|
||
|
|
||
|
#include <avr/io.h>
|
||
|
|
||
|
/*
|
||
|
Copyright (c) 2009, Curt Van Maanen
|
||
|
|
||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||
|
purpose with or without fee is hereby granted, provided that the above
|
||
|
copyright notice and this permission notice appear in all copies.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||
|
|
||
|
|
||
|
include usage-
|
||
|
#include "wd.h" //if in same directory as project
|
||
|
#include <avr/wd.h> //if wd.h is in avr directory
|
||
|
|
||
|
set watchdog modes and prescale
|
||
|
|
||
|
usage-
|
||
|
WD_SET(mode,[timeout]); //prescale always set
|
||
|
|
||
|
modes-
|
||
|
WD_OFF disabled
|
||
|
WD_RST normal reset mode
|
||
|
WD_IRQ interrupt only mode (if supported)
|
||
|
WD_RST_IRQ interrupt+reset mode (if supported)
|
||
|
|
||
|
timeout-
|
||
|
WDTO_15MS default if no timeout provided
|
||
|
WDTO_30MS
|
||
|
WDTO_60MS
|
||
|
WDTO_120MS
|
||
|
WDTO_250MS
|
||
|
WDTO_500MS
|
||
|
WDTO_1S
|
||
|
WDTO_2S
|
||
|
WDTO_4S (if supported)
|
||
|
WDTO_8S (if supported)
|
||
|
|
||
|
examples-
|
||
|
WD_SET(WD_RST,WDTO_1S); //reset mode, 1s timeout
|
||
|
WD_SET(WD_OFF); //watchdog disabled (if not fused on)
|
||
|
WD_SET(WD_RST); //reset mode, 15ms (default timeout)
|
||
|
WD_SET(WD_IRQ,WDTO_120MS); //interrupt only mode, 120ms timeout
|
||
|
WD_SET(WD_RST_IRQ,WDTO_2S); //interrupt+reset mode, 2S timeout
|
||
|
|
||
|
|
||
|
for enhanced watchdogs, if the watchdog is not being used WDRF should be
|
||
|
cleared on every power up or reset, along with disabling the watchdog-
|
||
|
WD_DISABLE(); //clear WDRF, then turn off watchdog
|
||
|
|
||
|
*/
|
||
|
|
||
|
//reset registers to the same name (MCUCSR)
|
||
|
#if !defined(MCUCSR)
|
||
|
#define MCUCSR MCUSR
|
||
|
#endif
|
||
|
|
||
|
//watchdog registers to the same name (WDTCSR)
|
||
|
#if !defined(WDTCSR)
|
||
|
#define WDTCSR WDTCR
|
||
|
#endif
|
||
|
|
||
|
//if enhanced watchdog, define irq values, create disable macro
|
||
|
#if defined(WDIF)
|
||
|
#define WD_IRQ 0xC0
|
||
|
#define WD_RST_IRQ 0xC8
|
||
|
#define WD_DISABLE() do{ \
|
||
|
MCUCSR &= ~(1<<WDRF); \
|
||
|
WD_SET(WD_OFF); \
|
||
|
}while(0)
|
||
|
#endif
|
||
|
|
||
|
//all watchdogs
|
||
|
#define WD_RST 8
|
||
|
#define WD_OFF 0
|
||
|
|
||
|
//prescale values
|
||
|
#define WDTO_15MS 0
|
||
|
#define WDTO_30MS 1
|
||
|
#define WDTO_60MS 2
|
||
|
#define WDTO_120MS 3
|
||
|
#define WDTO_250MS 4
|
||
|
#define WDTO_500MS 5
|
||
|
#define WDTO_1S 6
|
||
|
#define WDTO_2S 7
|
||
|
|
||
|
//prescale values for avrs with WDP3
|
||
|
#if defined(WDP3)
|
||
|
#define WDTO_4S 0x20
|
||
|
#define WDTO_8S 0x21
|
||
|
#endif
|
||
|
|
||
|
//watchdog reset
|
||
|
#define WDR() __asm__ __volatile__("wdr")
|
||
|
|
||
|
//avr reset using watchdog
|
||
|
#define WD_AVR_RESET() do{ \
|
||
|
__asm__ __volatile__("cli"); \
|
||
|
WD_SET_UNSAFE(WD_RST); \
|
||
|
while(1); \
|
||
|
}while(0)
|
||
|
|
||
|
/*set the watchdog-
|
||
|
1. save SREG
|
||
|
2. turn off irq's
|
||
|
3. reset watchdog timer
|
||
|
4. enable watchdog change
|
||
|
5. write watchdog value
|
||
|
6. restore SREG (restoring irq status)
|
||
|
*/
|
||
|
#define WD_SET(val,...) \
|
||
|
__asm__ __volatile__( \
|
||
|
"in __tmp_reg__,__SREG__" "\n\t" \
|
||
|
"cli" "\n\t" \
|
||
|
"wdr" "\n\t" \
|
||
|
"sts %[wdreg],%[wden]" "\n\t" \
|
||
|
"sts %[wdreg],%[wdval]" "\n\t" \
|
||
|
"out __SREG__,__tmp_reg__" "\n\t" \
|
||
|
: \
|
||
|
: [wdreg] "M" (&WDTCSR), \
|
||
|
[wden] "r" ((uint8_t)(0x18)), \
|
||
|
[wdval] "r" ((uint8_t)(val|(__VA_ARGS__+0))) \
|
||
|
: "r0" \
|
||
|
)
|
||
|
|
||
|
/*set the watchdog when I bit in SREG known to be clear-
|
||
|
1. reset watchdog timer
|
||
|
2. enable watchdog change
|
||
|
5. write watchdog value
|
||
|
*/
|
||
|
#define WD_SET_UNSAFE(val,...) \
|
||
|
__asm__ __volatile__( \
|
||
|
"wdr" "\n\t" \
|
||
|
"sts %[wdreg],%[wden]" "\n\t" \
|
||
|
"sts %[wdreg],%[wdval]" "\n\t" \
|
||
|
: \
|
||
|
: [wdreg] "M" (&WDTCSR), \
|
||
|
[wden] "r" ((uint8_t)(0x18)), \
|
||
|
[wdval] "r" ((uint8_t)(val|(__VA_ARGS__+0))) \
|
||
|
)
|
||
|
|
||
|
|
||
|
//for compatibility with avr/wdt.h
|
||
|
#define wdt_enable(val) WD_SET(WD_RST,val)
|
||
|
#define wdt_disable() WD_SET(WD_OFF)
|
||
|
|
||
|
|
||
|
#endif /* _AVR_WD_H_ */
|