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  */
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
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
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  {
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