| Xmega IEC60730 Class B Library 1.0 |

All Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
classb_wdt_test.c
Go to the documentation of this file.
1 /* This file has been prepared for Doxygen automatic documentation generation.*/
2 /**
3 * \file
4 *
5 * \brief
6 * Watchdog timer self-diagnostic routine.
7 *
8 * \par Application note:
9 * AVR1610: Guide to IEC60730 Class B compliance with XMEGA
10 *
11 * \par Documentation
12 * For comprehensive code documentation, supported compilers, compiler
13 * settings and supported devices see readme.html
14 *
15 * \author
16 * Atmel Corporation: http://www.atmel.com \n
17 * Support email: avr@atmel.com
18 *
19 * Copyright (C) 2012 Atmel Corporation. All rights reserved.
20 *
21 * \page License
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions are met:
25 *
26 * 1. Redistributions of source code must retain the above copyright notice,
27 * this list of conditions and the following disclaimer.
28 *
29 * 2. Redistributions in binary form must reproduce the above copyright notice,
30 * this list of conditions and the following disclaimer in the documentation
31 * and/or other materials provided with the distribution.
32 *
33 * 3. The name of Atmel may not be used to endorse or promote products derived
34 * from this software without specific prior written permission.
35 *
36 * 4. This software may only be redistributed and used in connection with an
37 * Atmel AVR product.
38 *
39 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
40 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
41 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
42 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
43 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
44 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
45 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
46 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
48 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
49 * DAMAGE.
50 */
51
52 #include "classb_wdt_test.h"
53
54 //! \addtogroup classb_wdt
55 //@{
56
57 //! \cond INTERNAL
58
59 //! \internal \name Non-initialized Variables
60 //! \brief These variables need to be preserved between resets.
61 //@{
62
63 //! \internal \brief Test state.
64 //! This variable is not initialized and, therefore, can be used across resets.
65 NO_INIT volatile classb_preinit_teststate_t classb_wdt_teststate;
66
67 //! \internal \brief Number of RTC periods in a WDT period.
68 //! This variable is not initialized and, therefore, can be used across resets.
69 NO_INIT volatile uint16_t classb_rtc_count;
70 //@}
71
72 //! \endcond
73
74 //@}
75
76
77 /**
78 * \brief This is the watchdog timer (WDT) self-diagnostic test.
79 *
80 * Basically this functions tests the following:
81 * -# WDT issues a system reset after timeout.
82 * -# WDT timing and that it can be reset.
83 * -# WDT issues a system reset if it is untimely reset (WDT window mode).
84 * If any of these tests should fail, \ref CLASSB_ERROR_HANDLER_WDT() would be called.
85 * By default the device will simply hang.
86 *
87 * The expected (error-free) execution flow is as follows:
88 * -# Power-on or external reset has occurred.
89 * -# Check that WDT can issue a system reset. Set test state 1 and system reset.
90 * -# Check that WDT can be reset. Set test state 2 and system reset.
91 * -# Check that window mode works correctly. Set test state 3 and system reset.
92 * -# Set up WDT in windows mode with periods CLASSB_WDT_WPER and CLASSB_WDT_PER.
93 * Set test state "ok" and continue to main().
94 *
95 * The real time counter (RTC) is used as an independent clock source, which is
96 * used to check the timing of the oscillator used by the WDT.
97 *
98 * The reset cause is used to decide which actions to take. The user can configure
99 * how to process a reset caused by the watchdog when the test is in the "ok" state,
100 * i.e. \ref CLASSB_ACTIONS_WDT_RUNTIME_FAILURE(), or what to do for brown-out or
101 * software reset, i.e. \ref CLASSB_ACTIONS_WDT_OTHER_FAILURE().
102 *
103 * \note This test is executed before the main function. The method to achieve this
104 * depends on the specific compiler that is used.
105 *
106 */
107 classb_wdt_test (void)
108 {
109
110 // This variable is used to count RTC periods
111 register uint16_t counter;
112
113 // Check reset cause.
114 //
115 // If a power-on, external or debug reset has occurred the first part of the test
116 // is executed. This checks that WDT issues a system reset on timeout.
117 if ( RST.STATUS & (RST_PORF_bm | RST_EXTRF_bm | RST_PDIRF_bm) ) {
118
119 // Firstly clear reset flags
120 RST.STATUS = (RST_PORF_bm | RST_EXTRF_bm | RST_PDIRF_bm);
121 // Set the next state of the test
122 classb_wdt_teststate = TEST_WDT_1;
123
124 // Configure the RTC, which is used as an independent time source.
125 // In this section we are going to measure the number of RTC periods
126 // before the WDT timeout issues a system reset.
127 #ifdef RTC32
128 // If we use a device with RTC32 module, the VBAT system must be
129 // initialized before we use the RTC module. This sets a 1024 Hz RTC32
130 // from the 32.768 kHz crystal oscillator
131 vbat_init();
132 #else
133 // Use the RTC with 1024 Hz from internal 32.768 kHz RC oscillator
134 OSC.CTRL |= OSC_RC32KEN_bm;
135 while (!(OSC.STATUS & OSC_RC32KRDY_bm));
136 CLK.RTCCTRL = CLK_RTCSRC_RCOSC_gc | CLK_RTCEN_bm;
137 #endif
138 // In order to have a good estimate, CLASSB_WDT_RTC_PER should be small.
139 RTC_TEST.PER = CLASSB_WDT_RTC_PER;
140 // Wait until RTC is ready.
141 while( rtc_is_busy() );
142 // Start RTC timer
143 RTC_TEST.CTRL = RTC_TEST_START_bm;
144
145 // WDT Configuration:
146 // First write to Configuration Change Protection register
147 CCP = CCP_IOREG_gc;
148 // Then enable WDT with a configurable period. This requires setting
149 // the Change Enabled bit.
150 WDT.CTRL = WDT_ENABLE_bm | CLASSB_WDT_PER | WDT_CEN_bm;
151
152 // Count number of RTC periods until a WDT timeout.
153 // There is a configurable maximum number of RTC periods before
154 // an error in the WDT is assumed.
155 // Recall that the CLASSB_WDT_RTC_PER gives the value of the register
156 // that is compared against the timer value, so the real period is
157 // CLASSB_WDT_RTC_PER+1
158 classb_rtc_count = 0;
159 counter = CLASSB_WDT_MAX / (CLASSB_WDT_RTC_PER+1);
160 while(counter--){
161 classb_rtc_count ++;
162 while( !(RTC_TEST.INTFLAGS & RTC_TEST_OVFIF_bm) );
163 RTC_TEST.INTFLAGS = RTC_TEST_OVFIF_bm;
164 }
165 // This should only be executed if there is an error in the WDT,
166 // i.e. if the WDT did not timeout before the maximum number of
167 // RTC periods was exceeded.
168 classb_wdt_teststate = FAULT_WDT;
169 }
170
171 // If a watchdog reset has occurred, this is not the first iteration.
172 else if ( RST.STATUS & RST_WDRF_bm ) {
173
174 // Firstly clear the flag for WDT reset.
175 RST.STATUS = RST_WDRF_bm;
176
177 // Handle the different test stages.
178 switch (classb_wdt_teststate) {
179
180 // test WDT timing and that WDT can be reset
181 // small RTC test
182 case TEST_WDT_1:
183
184 // Assume watchdog fault for now.
185 classb_wdt_teststate = FAULT_WDT;
186
187 // Make sure that the estimated WDT period is also higher than expected
188 if( classb_rtc_count >= CLASSB_WDT_MIN / (CLASSB_WDT_RTC_PER+1) ){
189
190 // The real time counter is used as an independent time source.
191 #ifdef RTC32
192 // If we use a device with RTC32 module, the VBAT system must be initialized before we use the RTC module
193 // This sets a 1024 Hz RTC32 from the 32.768 kHz crystal oscillator
194 vbat_init();
195 #else
196 // Use the RTC with 1024 Hz from internal 32.768 kHz RC oscillator
197 CLK.RTCCTRL = CLK_RTCSRC_RCOSC_gc | CLK_RTCEN_bm;
198 #endif
199 // Set RTC period
200 RTC_TEST.PER = CLASSB_WDT_RTC_PER;
201 // Wait until RTC is ready.
202 while( rtc_is_busy() );
203 // Start RTC timer
204 RTC_TEST.CTRL = RTC_TEST_START_bm;
205
206 // WDT Configuration
207 // Enable WDT with configurable period.
208 // First write to Configuration Change Protection register
209 CCP = CCP_IOREG_gc;
210 // Then enable WDT with desired period, which requires setting
211 // the Change Enabled bit.
212 WDT.CTRL = WDT_ENABLE_bm | CLASSB_WDT_PER | WDT_CEN_bm;
213
214 // Wait approximately 0.75 * T_WDT, where T_WDT is the estimated
215 // WDT period, before a WDT reset. This checks that the WDT does
216 // not expires earlier than expected.
217 counter = classb_rtc_count;
218 counter += (classb_rtc_count >> 1);
219 counter >>= 1;
220 while(counter--){
221 while( !(RTC_TEST.INTFLAGS & RTC_TEST_OVFIF_bm) );
222 RTC_TEST.INTFLAGS = RTC_TEST_OVFIF_bm;
223 }
224 watchdog_reset();
225 // Wait again approximately 0.75 * T_WDT
226 counter = classb_rtc_count;
227 counter += (classb_rtc_count >> 1);
228 counter >>= 1;
229 while(counter--){
230 while( !(RTC_TEST.INTFLAGS & RTC_TEST_OVFIF_bm) );
231 RTC_TEST.INTFLAGS = RTC_TEST_OVFIF_bm;
232 }
233
234 // This should only occur if WDT reset worked, otherwise there would
235 // have been a system reset before this point (this would be
236 // executed approximately 1.5*T_WDT after the WDT was initially set).
237 // Note that in that case the state would still be |FAULT_WDT|.
238 // Set next state and wait for the WDT to issue a system reset.
239 // That should approximately happen in approx 0.25*T_WDT
240 classb_wdt_teststate = TEST_WDT_2;
241 // Wait approx 0.5*T_WDT
242 counter = (classb_rtc_count >> 1);
243 while(counter--){
244 while( !(RTC_TEST.INTFLAGS & RTC_TEST_OVFIF_bm) );
245 RTC_TEST.INTFLAGS = RTC_TEST_OVFIF_bm;
246 }
247 }
248 // Set error flag if WDT has not issued a reset.
249 classb_wdt_teststate = FAULT_WDT;
250 break;
251
252
253 // test WDT with window mode.
254 case TEST_WDT_2:
255
256 // Assume watchdog fault for now.
257 classb_wdt_teststate = FAULT_WDT;
258
259 // The real time counter is used as an independent time source.
260 #ifdef RTC32
261 // If we use a device with RTC32 module, the VBAT system must be initialized before we use the RTC module
262 // This sets a 1024 Hz RTC32 from the 32.768 kHz crystal oscillator
263 vbat_init();
264 #else
265 // Use the RTC with 1024 Hz from internal 32.768 kHz RC oscillator
266 CLK.RTCCTRL = CLK_RTCSRC_RCOSC_gc | CLK_RTCEN_bm;
267 #endif
268 // Set RTC period
269 RTC_TEST.PER = CLASSB_WDT_RTC_PER;
270 // Wait until RTC is ready.
271 while( rtc_is_busy() );
272 // Start RTC timer
273 RTC_TEST.CTRL = RTC_TEST_START_bm;
274
275 // Enable WDT with window mode enabled.
276 // Set Normal period (when WDT can be reset)
277 CCP = CCP_IOREG_gc;
278 WDT.CTRL = WDT_ENABLE_bm | CLASSB_WDT_PER | WDT_CEN_bm;
279 // Wait until WDT Synchronized
280 while( WDT.STATUS & WDT_SYNCBUSY_bm );
281 // Set Closed period (when WDT cannot be reset)
282 CCP = CCP_IOREG_gc;
283 WDT.WINCTRL = WDT_WEN_bm | CLASSB_WDT_WPER | WDT_WCEN_bm;
284 // Wait until WDT Synchronized
285 while( WDT.STATUS & WDT_SYNCBUSY_bm );
286
287 // Set next test state and do a reset of the WDT immediately.
288 // This should issue a system reset with any window mode settings.
289 classb_wdt_teststate = TEST_WDT_3;
290 watchdog_reset();
291
292 // If there was a problem with the WDT in window mode, this would be executed.
293 // Wait for 0.25 * T_WDT just to avoid timing issues with reset vs execution of instructions
294 // then set fault state if WDT module has not reset the device as expected.
295 counter = classb_rtc_count >> 2;
296 while(counter--){
297 while( !(RTC_TEST.INTFLAGS & RTC_TEST_OVFIF_bm) );
298 RTC_TEST.INTFLAGS = RTC_TEST_OVFIF_bm;
299 }
300 // Set error flag if WDT has not issued a reset.
301 classb_wdt_teststate = FAULT_WDT;
302 break;
303
304 // After the test the WDT should be left enabled for the main application.
305 case TEST_WDT_3:
306 /* WDT configuration for the main application: WDT in normal mode */
307 CCP = CCP_IOREG_gc;
308 WDT.CTRL = WDT_ENABLE_bm | CLASSB_WDT_PER | WDT_CEN_bm ;
309 /* Wait until WDT Synchronized */
310 while( WDT.STATUS & WDT_SYNCBUSY_bm );
311 /* Set Closed period (when WDT cannot be reset) */
312 CCP = CCP_IOREG_gc;
313 WDT.WINCTRL = WDT_WEN_bm | CLASSB_WDT_WPER | WDT_WCEN_bm;
314 /* Wait until WDT Synchronized */
315 while( WDT.STATUS & WDT_SYNCBUSY_bm );
316 classb_error = 0;
317
318 //The test of the WDT is finished and there was no error
319 classb_wdt_teststate = TEST_WDT_OK;
320 break;
321
322 // Handle WDT reset under normal operation. If the program reaches
323 // this point is because the main application did not update the
324 // WDT correctly and this led to system reset. Note that the WDT
325 // needs to be setup again.
326 case TEST_WDT_OK:
327 // Configurable actions
328 CLASSB_ACTIONS_WDT_RUNTIME_FAILURE();
329 break;
330
331 // Otherwise assume error
332 default:
333 classb_wdt_teststate = FAULT_WDT;
334 break;
335
336 }
337 }
338 // Handle other reset reasons, i.e. software or brown-out.
339 else
340 {
341 // Configurable actions
342 CLASSB_ACTIONS_WDT_OTHER_FAILURE();
343 }
344
345 // Actions to take if there was an error.
346 // The test would be on fault state because:
347 // - WDT could not be reset
348 // - WDT did not issue a system reset on either timeout or untimely reset (window mode)
349 if (classb_wdt_teststate == FAULT_WDT)
350 {
351 CLASSB_ERROR_HANDLER_WDT();
352 }
353
354
355 // IAR has a low level pre-init prototype that needs a return value.
356 #if defined(__ICCAVR__)
357 return 1;
358 #endif
359 }
360