Contiki 2.5
watchdog.c
1 /*
2  * Copyright (c) 2005, Swedish Institute of Computer Science
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 
33 /* Watchdog routines for the AVR */
34 
35 /* The default timeout of 2 seconds works on most MCUs.
36  * It should be disabled during sleep (unless used for wakeup) since
37  * it draws significant current (~5 uamp on 1284p, 20x the MCU consumption).
38  *
39  * Note the wdt is not properly simulated in AVR Studio 4 Simulator 1:
40  * On many devices calls to wdt_reset will have no effect, and a wdt reboot will occur.
41  * The MCUSR will not show the cause of a wdt reboot.
42  * A 1MHz clock is assumed; at 8MHz timeout occurs 8x faster than it should.
43  * Simulator 2 is supposed to work on supported devices (not atmega128rfa1),
44  * but neither it nor Studio 5 beta do any resets on the 1284p.
45  *
46  * Setting WATCHDOG_CONF_TIMEOUT -1 will disable the WDT.
47  */
48 //#define WATCHDOG_CONF_TIMEOUT -1
49 
50 #ifndef WATCHDOG_CONF_TIMEOUT
51 #define WATCHDOG_CONF_TIMEOUT WDTO_2S
52 #endif
53 
54  /* While balancing start and stop calls is a good idea, an imbalance will cause
55  * resets that can take a lot of time to track down.
56  * Some low power protocols may cause this.
57  * The default is no balance; define WATCHDOG_CONF_BALANCE 1 to override.
58  */
59 #ifndef WATCHDOG_CONF_BALANCE
60 #define WATCHDOG_CONF_BALANCE 0
61 #endif
62 
63 #include "dev/watchdog.h"
64 #include <avr/wdt.h>
65 #include <avr/interrupt.h>
66 
67 /* Keep address over reboots */
68 void *watchdog_return_addr __attribute__ ((section (".noinit")));
69 
70 //Not all AVR toolchains alias MCUSR to the older MSUSCR name
71 //#if defined (__AVR_ATmega8__) || defined (__AVR_ATmega8515__) || defined (__AVR_ATmega16__)
72 #if !defined (MCUSR) && defined (MCUCSR)
73 #warning *** MCUSR not defined, using MCUCSR instead ***
74 #define MCUSR MCUCSR
75 #endif
76 
77 #if WATCHDOG_CONF_BALANCE && WATCHDOG_CONF_TIMEOUT >= 0
78 static int stopped = 0;
79 #endif
80 
81 /*---------------------------------------------------------------------------*/
82 void
83 watchdog_init(void)
84 {
85 /* Clear startup bit and disable the wdt, whether or not it will be used.
86  Random code may have caused the last reset.
87  */
88  watchdog_return_addr = 0;
89  MCUSR&=~(1<<WDRF);
90  wdt_disable();
91 #if WATCHDOG_CONF_BALANCE && WATCHDOG_CONF_TIMEOUT >= 0
92  stopped = 1;
93 #endif
94 }
95 /*---------------------------------------------------------------------------*/
96 void
97 watchdog_start(void)
98 {
99 #if WATCHDOG_CONF_TIMEOUT >= 0
100 #if WATCHDOG_CONF_BALANCE
101  stopped--;
102  if(!stopped)
103 #endif
104  {
105  wdt_enable(WATCHDOG_CONF_TIMEOUT);
106 #if defined (__AVR_ATmega1284P__)
107  WDTCSR |= _BV(WDIE);
108 #endif
109  }
110 #endif
111 }
112 /*---------------------------------------------------------------------------*/
113 void
114 watchdog_periodic(void)
115 {
116 #if WATCHDOG_CONF_TIMEOUT >= 0
117 #if WATCHDOG_CONF_BALANCE
118  if(!stopped)
119 #endif
120  wdt_reset();
121 #endif
122 }
123 /*---------------------------------------------------------------------------*/
124 void
125 watchdog_stop(void)
126 {
127 #if WATCHDOG_CONF_TIMEOUT >= 0
128 #if WATCHDOG_CONF_BALANCE
129  stopped++;
130 #endif
131  wdt_disable();
132 #if defined (__AVR_ATmega1284P__)
133  WDTCSR &= ~_BV(WDIE);
134 #endif
135 #endif
136 }
137 /*---------------------------------------------------------------------------*/
138 void
139 watchdog_reboot(void)
140 {
141  cli();
142  wdt_enable(WDTO_15MS); //wd on,250ms
143  while(1); //loop
144 }
145 /*---------------------------------------------------------------------------*/
146 /* Not all AVRs implement the wdt interrupt */
147 #if defined (__AVR_ATmega1284P__)
148 ISR(WDT_vect)
149 {
150  /* The address is given in words (16-bit), but all GNU tools use bytes
151  * so we need to multiply with 2 here. */
152  watchdog_return_addr = (void *)((unsigned int)__builtin_return_address(0)<<1);
153 }
154 #endif