Contiki-Inga 3.x
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 <avr/io.h>
64 #include <avr/wdt.h>
65 #include <avr/interrupt.h>
66 #include <dev/watchdog.h>
67 
68 // This is needed because AVR libc does not support WDT yet
69 #ifdef __AVR_XMEGA__
70 #ifndef wdt_disable
71 #define wdt_disable() \
72  CCP = CCP_IOREG_gc; \
73  WDT.CTRL = (WDT.CTRL & ~WDT_ENABLE_bm) | WDT_CEN_bm;
74 #endif
75 #endif
76 
77 
78 /* Keep address over reboots */
79 void *watchdog_return_addr __attribute__ ((section (".noinit")));
80 
81 //Not all AVR toolchains alias MCUSR to the older MSUSCR name
82 //#if defined (__AVR_ATmega8__) || defined (__AVR_ATmega8515__) || defined (__AVR_ATmega16__)
83 #if !defined (MCUSR) && defined (MCUCSR)
84 #warning *** MCUSR not defined, using MCUCSR instead ***
85 #define MCUSR MCUCSR
86 #endif
87 
88 #if WATCHDOG_CONF_BALANCE && WATCHDOG_CONF_TIMEOUT >= 0
89 static int stopped = 0;
90 #endif
91 
92 /* Only required if we want to examine reset source later on. */
93 uint8_t mcusr_mirror __attribute__ ((section (".noinit")));
94 
95 /*
96  * Watchdog may remain activated with cleared prescaler (fastest) after reset.
97  * Thus disabling the watchdog during init is required!!
98  */
99 void get_mcusr(void) \
100  __attribute__((naked)) \
101  __attribute__((section(".init3")));
102 void get_mcusr(void)
103 {
104  mcusr_mirror = MCUSR;
105  MCUSR &= ~(1 << WDRF);
106  wdt_disable();
107 }
108 
109 /*---------------------------------------------------------------------------*/
110  void
111 watchdog_init(void)
112 {
113  watchdog_return_addr = 0;
114 
115 #if WATCHDOG_CONF_BALANCE && WATCHDOG_CONF_TIMEOUT >= 0
116  stopped = 1;
117 #endif
118 }
119 /*---------------------------------------------------------------------------*/
120  void
121 watchdog_start(void)
122 {
123 #if WATCHDOG_CONF_TIMEOUT >= 0
124 #if WATCHDOG_CONF_BALANCE
125  stopped--;
126  if(!stopped)
127 #endif
128  {
129 #ifdef __AVR_XMEGA__
130  // enable watchdog
131  CCP = CCP_IOREG_gc;
132  WDT.CTRL = WATCHDOG_CONF_TIMEOUT | WDT_CEN_bm | WDT_ENABLE_bm;
133 #else
134  wdt_enable(WATCHDOG_CONF_TIMEOUT);
135 #endif
136 
137  // Enable WDT Interrupt
138 #if defined (__AVR_ATmega1284P__)
139  WDTCSR |= _BV(WDIE);
140 #endif
141  }
142 #endif
143 }
144 /*---------------------------------------------------------------------------*/
145  void
147 {
148 #if WATCHDOG_CONF_TIMEOUT >= 0
149 #if WATCHDOG_CONF_BALANCE
150  if(!stopped)
151 #endif
152 
153 #ifdef __AVR_XMEGA__
154  // reset watchdog
155  CCP = CCP_IOREG_gc;
156  WDT.CTRL = (RST.CTRL & ~WDT_ENABLE_bm) | WDT_CEN_bm;
157  CCP = CCP_IOREG_gc;
158  WDT.CTRL = WATCHDOG_CONF_TIMEOUT | WDT_CEN_bm | WDT_ENABLE_bm;
159 #else
160  wdt_reset();
161 #endif
162 
163 #endif
164 }
165 /*---------------------------------------------------------------------------*/
166  void
167 watchdog_stop(void)
168 {
169 #if WATCHDOG_CONF_TIMEOUT >= 0
170 #if WATCHDOG_CONF_BALANCE
171  stopped++;
172 #endif
173  wdt_disable();
174  // Disable WDT Interrupt
175 #if defined (__AVR_ATmega1284P__)
176  WDTCSR &= ~_BV(WDIE);
177 #endif
178 #endif
179 }
180 /*---------------------------------------------------------------------------*/
181 void
182 watchdog_reboot(void)
183 {
184  cli();
185  wdt_enable(WDTO_15MS); //wd on,250ms
186  while(1); //loop until watchdog resets
187 }
188 /*---------------------------------------------------------------------------*/
189 /* Not all AVRs implement the wdt interrupt */
190 #if defined (__AVR_ATmega1284P__)
191 ISR(WDT_vect)
192 {
193  /* The address is given in words (16-bit), but all GNU tools use bytes
194  * so we need to multiply with 2 here. */
195  watchdog_return_addr = (void *)((unsigned int)__builtin_return_address(0)<<1);
196 }
197 #endif