Nut/OS  4.10.3
API Reference
wdt.c
Go to the documentation of this file.
00001 
00035 /*
00036  * $Log: wdt.c,v $
00037  *
00038  */
00039 
00040 #include <sys/timer.h>
00041 #include <dev/watchdog.h>
00042 #include <arch/avr32.h>
00043 
00044 #include <avr32/io.h>
00045 
00046 // AP7000 includes lack this define, even though they are the same as UC30512
00047 #if !defined(AVR32_WDT_KEY_VALUE)
00048 #define AVR32_WDT_KEY_VALUE                            0x00000055
00049 #endif
00050 
00055 
00056 static ureg_t nested;
00057 
00058 static void wdt_set_ctrl(unsigned long ctrl)
00059 {
00060     AVR32_WDT.ctrl = ctrl | (AVR32_WDT_KEY_VALUE << AVR32_WDT_CTRL_KEY_OFFSET);
00061     AVR32_WDT.ctrl = ctrl | ((~AVR32_WDT_KEY_VALUE << AVR32_WDT_CTRL_KEY_OFFSET) & AVR32_WDT_CTRL_KEY_MASK);
00062 }
00063 
00064 static long long wdt_get_us_timeout_period(void)
00065 {
00066     unsigned int slowclock = NutArchClockGet(NUT_HWCLK_SLOW_CLOCK);
00067     // Read CTRL.PSEL and translate it into us.
00068     return (AVR32_WDT.ctrl & AVR32_WDT_CTRL_EN_MASK) ?
00069         ((1ULL << (((AVR32_WDT.ctrl & AVR32_WDT_CTRL_PSEL_MASK) >> AVR32_WDT_CTRL_PSEL_OFFSET) + 1)) *
00070          1000000 + slowclock / 2) / slowclock : -1;
00071 }
00072 
00079 uint32_t Avr32WatchDogStart(uint32_t ms)
00080 {
00081     unsigned long long int timeout = ms * 1000;
00082 
00083     unsigned int slowclock = NutArchClockGet(NUT_HWCLK_SLOW_CLOCK);
00084 
00085     Avr32WatchDogDisable();
00086 
00087 #define MIN_US_TIMEOUT_PERIOD  \
00088         (((1ULL <<  1 ) * 1000000 + slowclock / 2) / slowclock)
00089 #define MAX_US_TIMEOUT_PERIOD  \
00090         (((1ULL << (1 << AVR32_WDT_CTRL_PSEL_SIZE)) * 1000000 + slowclock / 2) / slowclock)
00091 
00092     // Set the CTRL.EN bit and translate the us timeout to fit in CTRL.PSEL using
00093     // the formula wdt = 2pow(PSEL+1) / fRCosc in useconds.
00094     if (timeout < MIN_US_TIMEOUT_PERIOD)
00095         timeout = MIN_US_TIMEOUT_PERIOD;
00096     else if (timeout > MAX_US_TIMEOUT_PERIOD)
00097         timeout = MAX_US_TIMEOUT_PERIOD;
00098 
00099     wdt_set_ctrl(AVR32_WDT_CTRL_EN_MASK |
00100                  ((32 - __builtin_clz(((((timeout * slowclock + 500000) / 1000000) << 1) - 1) >> 1) -
00101                    1) << AVR32_WDT_CTRL_PSEL_OFFSET));
00102 
00103     Avr32WatchDogRestart();
00104     nested = 1;
00105 
00106     // Return the actual wdt period in us.
00107     return wdt_get_us_timeout_period() / 1000;
00108 }
00109 
00116 void Avr32WatchDogRestart(void)
00117 {
00118     wdt_set_ctrl(AVR32_WDT.ctrl | AVR32_WDT_CTRL_EN_MASK);
00119     AVR32_WDT.clr = 0;
00120 }
00121 
00128 void Avr32WatchDogDisable(void)
00129 {
00130     if (nested) {
00131         nested++;
00132     }
00133     wdt_set_ctrl(AVR32_WDT.ctrl & ~AVR32_WDT_CTRL_EN_MASK);
00134 }
00135 
00142 void Avr32WatchDogEnable(void)
00143 {
00144     if (nested > 1 && --nested == 1) {
00145         Avr32WatchDogRestart();
00146     }
00147 }
00148