#ifndef _AVR_WDT_H_
#define _AVR_WDT_H_
#include <avr/io.h>
#include <stdint.h>
#define wdt_reset() __asm__ __volatile__ ("wdr")
#ifndef __DOXYGEN__
#if defined(WDP3)
# define _WD_PS3_MASK _BV(WDP3)
#else
# define _WD_PS3_MASK 0x00
#endif
#if defined(WDTCSR)
# define _WD_CONTROL_REG WDTCSR
#elif defined(WDTCR)
# define _WD_CONTROL_REG WDTCR
#else
# define _WD_CONTROL_REG WDT
#endif
#if defined(WDTOE)
#define _WD_CHANGE_BIT WDTOE
#else
#define _WD_CHANGE_BIT WDCE
#endif
#endif
#if defined(__AVR_XMEGA__)
#if defined (WDT_CTRLA) && !defined(RAMPD)
#define wdt_enable(timeout) \
do { \
uint8_t temp; \
__asm__ __volatile__ ( \
"wdr" "\n\t" \
"out %[ccp_reg], %[ioreg_cen_mask]" "\n\t" \
"lds %[tmp], %[wdt_reg]" "\n\t" \
"sbr %[tmp], %[wdt_enable_timeout]" "\n\t" \
"sts %[wdt_reg], %[tmp]" "\n\t" \
"1:lds %[tmp], %[wdt_status_reg]" "\n\t" \
"sbrc %[tmp], %[wdt_syncbusy_bit]" "\n\t" \
"rjmp 1b" "\n\t" \
: [tmp] "=r" (temp) \
: [ccp_reg] "I" (_SFR_IO_ADDR(CCP)), \
[ioreg_cen_mask] "r" ((uint8_t)CCP_IOREG_gc), \
[wdt_reg] "n" (_SFR_MEM_ADDR(WDT_CTRLA)), \
[wdt_enable_timeout] "M" (timeout), \
[wdt_status_reg] "n" (_SFR_MEM_ADDR(WDT_STATUS)), \
[wdt_syncbusy_bit] "I" (WDT_SYNCBUSY_bm) \
); \
} while(0)
#define wdt_disable() \
do { \
uint8_t temp; \
__asm__ __volatile__ ( \
"wdr" "\n\t" \
"out %[ccp_reg], %[ioreg_cen_mask]" "\n\t" \
"lds %[tmp], %[wdt_reg]" "\n\t" \
"cbr %[tmp], %[timeout_mask]" "\n\t" \
"sts %[wdt_reg], %[tmp]" "\n\t" \
: [tmp] "=r" (temp) \
: [ccp_reg] "I" (_SFR_IO_ADDR(CCP)), \
[ioreg_cen_mask] "r" ((uint8_t)CCP_IOREG_gc), \
[wdt_reg] "n" (_SFR_MEM_ADDR(WDT_CTRLA)),\
[timeout_mask] "I" (WDT_PERIOD_gm) \
); \
} while(0)
#else
#define wdt_enable(timeout) \
do { \
uint8_t temp; \
__asm__ __volatile__ ( \
"in __tmp_reg__, %[rampd]" "\n\t" \
"out %[rampd], __zero_reg__" "\n\t" \
"out %[ccp_reg], %[ioreg_cen_mask]" "\n\t" \
"sts %[wdt_reg], %[wdt_enable_timeout]" "\n\t" \
"1:lds %[tmp], %[wdt_status_reg]" "\n\t" \
"sbrc %[tmp], %[wdt_syncbusy_bit]" "\n\t" \
"rjmp 1b" "\n\t" \
"out %[rampd], __tmp_reg__" "\n\t" \
: [tmp] "=r" (temp) \
: [rampd] "I" (_SFR_IO_ADDR(RAMPD)), \
[ccp_reg] "I" (_SFR_IO_ADDR(CCP)), \
[ioreg_cen_mask] "r" ((uint8_t)CCP_IOREG_gc), \
[wdt_reg] "n" (_SFR_MEM_ADDR(WDT_CTRL)), \
[wdt_enable_timeout] "r" ((uint8_t)(WDT_CEN_bm | WDT_ENABLE_bm | timeout)), \
[wdt_status_reg] "n" (_SFR_MEM_ADDR(WDT_STATUS)), \
[wdt_syncbusy_bit] "I" (WDT_SYNCBUSY_bm) \
: "r0" \
); \
} while(0)
#define wdt_disable() \
__asm__ __volatile__ ( \
"in __tmp_reg__, %[rampd]" "\n\t" \
"out %[rampd], __zero_reg__" "\n\t" \
"out %[ccp_reg], %[ioreg_cen_mask]" "\n\t" \
"sts %[wdt_reg], %[disable_mask]" "\n\t" \
"out %[rampd], __tmp_reg__" "\n\t" \
: \
: [rampd] "I" (_SFR_IO_ADDR(RAMPD)), \
[ccp_reg] "I" (_SFR_IO_ADDR(CCP)), \
[ioreg_cen_mask] "r" ((uint8_t)CCP_IOREG_gc), \
[wdt_reg] "n" (_SFR_MEM_ADDR(WDT_CTRL)), \
[disable_mask] "r" ((uint8_t)((~WDT_ENABLE_bm) | WDT_CEN_bm)) \
: "r0" \
);
#endif
#elif defined(__AVR_TINY__)
#define wdt_enable(value) \
__asm__ __volatile__ ( \
"in __tmp_reg__,__SREG__" "\n\t" \
"cli" "\n\t" \
"wdr" "\n\t" \
"out %[CCPADDRESS],%[SIGNATURE]" "\n\t" \
"out %[WDTREG],%[WDVALUE]" "\n\t" \
"out __SREG__,__tmp_reg__" "\n\t" \
: \
: [CCPADDRESS] "I" (_SFR_IO_ADDR(CCP)), \
[SIGNATURE] "r" ((uint8_t)0xD8), \
[WDTREG] "I" (_SFR_IO_ADDR(_WD_CONTROL_REG)), \
[WDVALUE] "r" ((uint8_t)((value & 0x08 ? _WD_PS3_MASK : 0x00) \
| _BV(WDE) | (value & 0x07) )) \
: "r16" \
)
#define wdt_disable() \
do { \
uint8_t temp_wd; \
__asm__ __volatile__ ( \
"in __tmp_reg__,__SREG__" "\n\t" \
"cli" "\n\t" \
"wdr" "\n\t" \
"out %[CCPADDRESS],%[SIGNATURE]" "\n\t" \
"in %[TEMP_WD],%[WDTREG]" "\n\t" \
"cbr %[TEMP_WD],%[WDVALUE]" "\n\t" \
"out %[WDTREG],%[TEMP_WD]" "\n\t" \
"out __SREG__,__tmp_reg__" "\n\t" \
: \
: [CCPADDRESS] "I" (_SFR_IO_ADDR(CCP)), \
[SIGNATURE] "r" ((uint8_t)0xD8), \
[WDTREG] "I" (_SFR_IO_ADDR(_WD_CONTROL_REG)), \
[TEMP_WD] "d" (temp_wd), \
[WDVALUE] "n" (1 << WDE) \
: "r16" \
); \
}while(0)
#elif defined(CCP)
static __inline__
__attribute__ ((__always_inline__))
void wdt_enable (const uint8_t value)
{
if (!_SFR_IO_REG_P (CCP) && !_SFR_IO_REG_P (_WD_CONTROL_REG))
{
__asm__ __volatile__ (
"in __tmp_reg__,__SREG__" "\n\t"
"cli" "\n\t"
"wdr" "\n\t"
"sts %[CCPADDRESS],%[SIGNATURE]" "\n\t"
"sts %[WDTREG],%[WDVALUE]" "\n\t"
"out __SREG__,__tmp_reg__" "\n\t"
:
: [CCPADDRESS] "n" (_SFR_MEM_ADDR(CCP)),
[SIGNATURE] "r" ((uint8_t)0xD8),
[WDTREG] "n" (_SFR_MEM_ADDR(_WD_CONTROL_REG)),
[WDVALUE] "r" ((uint8_t)((value & 0x08 ? _WD_PS3_MASK : 0x00)
| _BV(WDE) | (value & 0x07) ))
: "r0"
);
}
else if (!_SFR_IO_REG_P (CCP) && _SFR_IO_REG_P (_WD_CONTROL_REG))
{
__asm__ __volatile__ (
"in __tmp_reg__,__SREG__" "\n\t"
"cli" "\n\t"
"wdr" "\n\t"
"sts %[CCPADDRESS],%[SIGNATURE]" "\n\t"
"out %[WDTREG],%[WDVALUE]" "\n\t"
"out __SREG__,__tmp_reg__" "\n\t"
:
: [CCPADDRESS] "n" (_SFR_MEM_ADDR(CCP)),
[SIGNATURE] "r" ((uint8_t)0xD8),
[WDTREG] "I" (_SFR_IO_ADDR(_WD_CONTROL_REG)),
[WDVALUE] "r" ((uint8_t)((value & 0x08 ? _WD_PS3_MASK : 0x00)
| _BV(WDE) | (value & 0x07) ))
: "r0"
);
}
else if (_SFR_IO_REG_P (CCP) && !_SFR_IO_REG_P (_WD_CONTROL_REG))
{
__asm__ __volatile__ (
"in __tmp_reg__,__SREG__" "\n\t"
"cli" "\n\t"
"wdr" "\n\t"
"out %[CCPADDRESS],%[SIGNATURE]" "\n\t"
"sts %[WDTREG],%[WDVALUE]" "\n\t"
"out __SREG__,__tmp_reg__" "\n\t"
:
: [CCPADDRESS] "I" (_SFR_IO_ADDR(CCP)),
[SIGNATURE] "r" ((uint8_t)0xD8),
[WDTREG] "n" (_SFR_MEM_ADDR(_WD_CONTROL_REG)),
[WDVALUE] "r" ((uint8_t)((value & 0x08 ? _WD_PS3_MASK : 0x00)
| _BV(WDE) | (value & 0x07) ))
: "r0"
);
}
else
{
__asm__ __volatile__ (
"in __tmp_reg__,__SREG__" "\n\t"
"cli" "\n\t"
"wdr" "\n\t"
"out %[CCPADDRESS],%[SIGNATURE]" "\n\t"
"out %[WDTREG],%[WDVALUE]" "\n\t"
"out __SREG__,__tmp_reg__" "\n\t"
:
: [CCPADDRESS] "I" (_SFR_IO_ADDR(CCP)),
[SIGNATURE] "r" ((uint8_t)0xD8),
[WDTREG] "I" (_SFR_IO_ADDR(_WD_CONTROL_REG)),
[WDVALUE] "r" ((uint8_t)((value & 0x08 ? _WD_PS3_MASK : 0x00)
| _BV(WDE) | (value & 0x07) ))
: "r0"
);
}
}
static __inline__
__attribute__ ((__always_inline__))
void wdt_disable (void)
{
if (!_SFR_IO_REG_P (CCP) && !_SFR_IO_REG_P(_WD_CONTROL_REG))
{
uint8_t temp_wd;
__asm__ __volatile__ (
"in __tmp_reg__,__SREG__" "\n\t"
"cli" "\n\t"
"wdr" "\n\t"
"sts %[CCPADDRESS],%[SIGNATURE]" "\n\t"
"lds %[TEMP_WD],%[WDTREG]" "\n\t"
"cbr %[TEMP_WD],%[WDVALUE]" "\n\t"
"sts %[WDTREG],%[TEMP_WD]" "\n\t"
"out __SREG__,__tmp_reg__" "\n\t"
:
: [CCPADDRESS] "n" (_SFR_MEM_ADDR(CCP)),
[SIGNATURE] "r" ((uint8_t)0xD8),
[WDTREG] "n" (_SFR_MEM_ADDR(_WD_CONTROL_REG)),
[TEMP_WD] "d" (temp_wd),
[WDVALUE] "n" (1 << WDE)
: "r0"
);
}
else if (!_SFR_IO_REG_P (CCP) && _SFR_IO_REG_P(_WD_CONTROL_REG))
{
uint8_t temp_wd;
__asm__ __volatile__ (
"in __tmp_reg__,__SREG__" "\n\t"
"cli" "\n\t"
"wdr" "\n\t"
"sts %[CCPADDRESS],%[SIGNATURE]" "\n\t"
"in %[TEMP_WD],%[WDTREG]" "\n\t"
"cbr %[TEMP_WD],%[WDVALUE]" "\n\t"
"out %[WDTREG],%[TEMP_WD]" "\n\t"
"out __SREG__,__tmp_reg__" "\n\t"
:
: [CCPADDRESS] "n" (_SFR_MEM_ADDR(CCP)),
[SIGNATURE] "r" ((uint8_t)0xD8),
[WDTREG] "I" (_SFR_IO_ADDR(_WD_CONTROL_REG)),
[TEMP_WD] "d" (temp_wd),
[WDVALUE] "n" (1 << WDE)
: "r0"
);
}
else if (_SFR_IO_REG_P (CCP) && !_SFR_IO_REG_P(_WD_CONTROL_REG))
{
uint8_t temp_wd;
__asm__ __volatile__ (
"in __tmp_reg__,__SREG__" "\n\t"
"cli" "\n\t"
"wdr" "\n\t"
"out %[CCPADDRESS],%[SIGNATURE]" "\n\t"
"lds %[TEMP_WD],%[WDTREG]" "\n\t"
"cbr %[TEMP_WD],%[WDVALUE]" "\n\t"
"sts %[WDTREG],%[TEMP_WD]" "\n\t"
"out __SREG__,__tmp_reg__" "\n\t"
:
: [CCPADDRESS] "I" (_SFR_IO_ADDR(CCP)),
[SIGNATURE] "r" ((uint8_t)0xD8),
[WDTREG] "n" (_SFR_MEM_ADDR(_WD_CONTROL_REG)),
[TEMP_WD] "d" (temp_wd),
[WDVALUE] "n" (1 << WDE)
: "r0"
);
}
else
{
uint8_t temp_wd;
__asm__ __volatile__ (
"in __tmp_reg__,__SREG__" "\n\t"
"cli" "\n\t"
"wdr" "\n\t"
"out %[CCPADDRESS],%[SIGNATURE]" "\n\t"
"in %[TEMP_WD],%[WDTREG]" "\n\t"
"cbr %[TEMP_WD],%[WDVALUE]" "\n\t"
"out %[WDTREG],%[TEMP_WD]" "\n\t"
"out __SREG__,__tmp_reg__" "\n\t"
:
: [CCPADDRESS] "I" (_SFR_IO_ADDR(CCP)),
[SIGNATURE] "r" ((uint8_t)0xD8),
[WDTREG] "I" (_SFR_IO_ADDR(_WD_CONTROL_REG)),
[TEMP_WD] "d" (temp_wd),
[WDVALUE] "n" (1 << WDE)
: "r0"
);
}
}
#else
static __inline__
__attribute__ ((__always_inline__))
void wdt_enable (const uint8_t value)
{
if (_SFR_IO_REG_P (_WD_CONTROL_REG))
{
__asm__ __volatile__ (
"in __tmp_reg__,__SREG__" "\n\t"
"cli" "\n\t"
"wdr" "\n\t"
"out %0, %1" "\n\t"
"out __SREG__,__tmp_reg__" "\n\t"
"out %0, %2" "\n \t"
:
: "I" (_SFR_IO_ADDR(_WD_CONTROL_REG)),
"r" ((uint8_t)(_BV(_WD_CHANGE_BIT) | _BV(WDE))),
"r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) |
_BV(WDE) | (value & 0x07)) )
: "r0"
);
}
else
{
__asm__ __volatile__ (
"in __tmp_reg__,__SREG__" "\n\t"
"cli" "\n\t"
"wdr" "\n\t"
"sts %0, %1" "\n\t"
"out __SREG__,__tmp_reg__" "\n\t"
"sts %0, %2" "\n \t"
:
: "n" (_SFR_MEM_ADDR(_WD_CONTROL_REG)),
"r" ((uint8_t)(_BV(_WD_CHANGE_BIT) | _BV(WDE))),
"r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) |
_BV(WDE) | (value & 0x07)) )
: "r0"
);
}
}
static __inline__
__attribute__ ((__always_inline__))
void wdt_disable (void)
{
if (_SFR_IO_REG_P (_WD_CONTROL_REG))
{
uint8_t register temp_reg;
__asm__ __volatile__ (
"in __tmp_reg__,__SREG__" "\n\t"
"cli" "\n\t"
"wdr" "\n\t"
"in %[TEMPREG],%[WDTREG]" "\n\t"
"ori %[TEMPREG],%[WDCE_WDE]" "\n\t"
"out %[WDTREG],%[TEMPREG]" "\n\t"
"out %[WDTREG],__zero_reg__" "\n\t"
"out __SREG__,__tmp_reg__" "\n\t"
: [TEMPREG] "=d" (temp_reg)
: [WDTREG] "I" (_SFR_IO_ADDR(_WD_CONTROL_REG)),
[WDCE_WDE] "n" ((uint8_t)(_BV(_WD_CHANGE_BIT) | _BV(WDE)))
: "r0"
);
}
else
{
uint8_t register temp_reg;
__asm__ __volatile__ (
"in __tmp_reg__,__SREG__" "\n\t"
"cli" "\n\t"
"wdr" "\n\t"
"lds %[TEMPREG],%[WDTREG]" "\n\t"
"ori %[TEMPREG],%[WDCE_WDE]" "\n\t"
"sts %[WDTREG],%[TEMPREG]" "\n\t"
"sts %[WDTREG],__zero_reg__" "\n\t"
"out __SREG__,__tmp_reg__" "\n\t"
: [TEMPREG] "=d" (temp_reg)
: [WDTREG] "n" (_SFR_MEM_ADDR(_WD_CONTROL_REG)),
[WDCE_WDE] "n" ((uint8_t)(_BV(_WD_CHANGE_BIT) | _BV(WDE)))
: "r0"
);
}
}
#endif
#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
#if defined(__DOXYGEN__) || defined(WDP3)
#define WDTO_4S 8
#define WDTO_8S 9
#endif
#endif