Test application for UV, IR, Light and Temperature sensors
[lpc82x] / core / watchdog.c
1 /****************************************************************************
2  *   core/watchdog.c
3  *
4  * Watchdog support
5  *
6  * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
7  *
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  *************************************************************************** */
24 /*
25  * This file implements support of the Windowed Watchdog (WWDT)
26  */
28 #include "core/system.h"
29 #include "core/watchdog.h"
33 /***************************************************************************** */
34 void watchdog_feed(void)
35 {
36         struct lpc_watchdog* wdt = LPC_WDT;
37         lpc_disable_irq();
38         wdt->feed_seqence = 0xAA;
39         wdt->feed_seqence = 0x55;
40         lpc_enable_irq();
41 }
43 static void (*wdt_callback)(void) = NULL;
46 /* With no callback, the watchdog interupt may be used to wake up by generating an interrupt */
47 void WDT_Handler(void)
48 {
49         struct lpc_watchdog* wdt = LPC_WDT;
50         wdt->mode |= LPC_WDT_INTR_FLAG;
51         /* Call user callback if the user registered one */
52         if (wdt_callback != NULL) {
53                 wdt_callback();
54         }
55 }
58 /* Lock the watchdog clock source power.
59  * Once locked, writes to the current watchdog clock power bits in powerdown_*_cfg will
60  *   have no effect.
61  * It is still possible to switch the watchdog clock source and turn of the clock if the
62  *   watchdog clock source has not been locked yet.
63  */
64 void watchdog_lock_clk_src_power(void)
65 {
66         struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
67         struct lpc_watchdog* wdt = LPC_WDT;
69         sys_config->powerdown_sleep_cfg &= ~(LPC_POWER_DOWN_WDT_OSC);
70         sys_config->powerdown_wake_cfg &= ~(LPC_POWER_DOWN_WDT_OSC);
72         wdt->mode |= LPC_WDT_CLK_POWER_LOCK;
73 }
75 /* Lock the watchdog timer value */
76 void watchdog_lock_timer_val(void)
77 {
78         struct lpc_watchdog* wdt = LPC_WDT;
79         wdt->mode |= LPC_WDT_TIMER_VAL_PROTECT;
80 }
82 /* Change the watchdog timer value, if not protected */
83 void watchdog_set_timer_val(uint32_t nb_clk)
84 {
85         struct lpc_watchdog* wdt = LPC_WDT;
87         if (!(wdt->mode & LPC_WDT_TIMER_VAL_PROTECT)) {
88                 wdt->timer_const = ((nb_clk >> 2) & LPC_WDT_TIMER_MAX);
89         }
90 }
92 /* Lock the watchdog and all related features.
93  * Calls all the other watchdog_lock_* functions (clk_src, clk_src_power, timer_val, enable).
94  */
95 void watchdog_lock_full(void)
96 {
97         watchdog_lock_timer_val();
98         watchdog_lock_clk_src_power();
99 }
101 /*
102  * Configure the watchdog.
103  * clk_sel is either 0 (IRC) or 1 (WDTCLK). The corresponding clock source will be powered on.
104  * Note : only WDTCLK is running in deep power down mode
105  * Note : protecting the clock source power will prevent turning off the IRC for power saving
106  *   if it is selected as main clock source.
107  */
108 void watchdog_config(const struct wdt_config* wd_conf)
110         struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
111         struct lpc_watchdog* wdt = LPC_WDT;
113         NVIC_DisableIRQ(WDT_IRQ);
114         /* Power wadchdog block before changing it's configuration */
115         subsystem_power(LPC_SYS_ABH_CLK_CTRL_Watchdog, 1);
116         /* Configure watchdog timeout for normal operation */
117         wdt->timer_const = ((wd_conf->nb_clk >> 2) & LPC_WDT_TIMER_MAX);
118         /* If intr_mode_only is set, a watchdog timeout will trigger an interrupt instead of a reset */
119         if (wd_conf->intr_mode_only == 1) {
120                 wdt->mode = LPC_WDT_EN;
121         } else {
122                 wdt->mode = LPC_WDT_EN | LPC_WDT_RESET_ON_TIMEOUT;
123         }
124         /* Register the callback for the interrupt */
125         wdt_callback = wd_conf->callback;
126         /* Power ON Watchdog clock */
127         sys_config->powerdown_run_cfg &= ~(LPC_POWER_DOWN_WDT_OSC);
128         /* Use the windows functionnality ? */
129         if (wd_conf->wdt_window > 0x100) {
130                 wdt->window_compare = (wd_conf->wdt_window & LPC_WDT_TIMER_MAX);
131         } else {
132                 wdt->window_compare = LPC_WDT_TIMER_MAX;
133         }
134         /* Warning interrupt ? */
135         if (wd_conf->wdt_warn != 0) {
136                 if (wd_conf->wdt_warn > LPC_WDT_WARNINT_MAXVAL) {
137                         wdt->warning_int_compare = LPC_WDT_WARNINT_MAXVAL;
138                 } else {
139                         wdt->warning_int_compare = wd_conf->wdt_warn;
140                 }
141         }
142         /* Protect any of the watchdog functions now ? */
143         if (wd_conf->locks != 0) {
144                 uint32_t mode = wdt->mode;
145                 if (wd_conf->locks & WDT_CLK_POWER_LOCK) {
146                         mode |= LPC_WDT_CLK_POWER_LOCK;
147                 }
148                 if (wd_conf->locks & WDT_TIMER_VAL_LOCK) {
149                         mode |= LPC_WDT_TIMER_VAL_PROTECT;
150                 }
151                 wdt->mode = mode;
152         }
153         /* Feed sequence to validate the configuration */
154         watchdog_feed();
155         NVIC_EnableIRQ(WDT_IRQ);
159 /*
160  * Stop the watchdog
161  * This function can be used during system operation to stop the watchdog if it has not
162  *   been locked or protected against clock source modification, for example when entering
163  *   sleep or deep sleep.
164  * Return 0 if a solution has been found to stop the watchdog, or -1 if watchdog is still
165  *   running after this call.
166  * TODO : Check this function
167  */
168 int stop_watchdog(void)
170         struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
171         struct lpc_watchdog* wdt = LPC_WDT;
173         if (wdt->mode & LPC_WDT_CLK_POWER_LOCK) {
174                 return -1;
175         }
176         NVIC_DisableIRQ(WDT_IRQ);
177         subsystem_power(LPC_SYS_ABH_CLK_CTRL_Watchdog, 1);
178         sys_config->powerdown_run_cfg |= LPC_POWER_DOWN_WDT_OSC;
179         subsystem_power(LPC_SYS_ABH_CLK_CTRL_Watchdog, 0);
180         return 0;
185 /*
186  * Disable the watchdog
187  * This function can be used upon system startup to disable watchdog operation
188  */
189 void startup_watchdog_disable(void)
191         struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
192         struct lpc_watchdog* wdt = LPC_WDT;
194         /* Power wadchdog block before changing it's configuration */
195         sys_config->sys_AHB_clk_ctrl |= LPC_SYS_ABH_CLK_CTRL_Watchdog;
196         /* Stop watchdog */
197         wdt->mode = 0;
198         watchdog_feed();
199         /* And power it down */
200         subsystem_power(LPC_SYS_ABH_CLK_CTRL_Watchdog, 0);
201         sys_config->powerdown_run_cfg |= LPC_POWER_DOWN_WDT_OSC;
202         NVIC_DisableIRQ(WDT_IRQ);