1 /***************************************************************************//**
2 * \file cy_wdt.h
3 * \version 1.30.1
4 *
5 * This file provides constants and parameter values for the WDT driver.
6 *
7 ********************************************************************************
8 * \copyright
9 * Copyright 2016-2020 Cypress Semiconductor Corporation
10 * SPDX-License-Identifier: Apache-2.0
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *
24 *******************************************************************************/
25
26 /**
27 * \addtogroup group_wdt
28 * \{
29 *
30 * The Watchdog timer (WDT) has a 16-bit free-running up-counter.
31 *
32 * The functions and other declarations used in this driver are in cy_wdt.h.
33 * You can include cy_pdl.h to get access to all functions
34 * and declarations in the PDL.
35 *
36 * The WDT can issue counter match interrupts, and a device reset if its interrupts are not
37 * handled. Use the Watchdog timer for two main purposes:
38 *
39 * The <b> First use case </b> is recovering from a CPU or firmware failure.
40 * A timeout period is set up in the Watchdog timer, and if a timeout occurs, the
41 * device is reset (WRES). <br>
42 * The <b>Second use case</b> is to generate periodic interrupts.
43 * It is strongly recommended not to use the WDT for periodic interrupt
44 * generation. However, if absolutely required, see information below.
45 *
46 * A "reset cause" register exists, and the firmware should check this register
47 * at a start-up. An appropriate action can be taken if a WRES reset is detected.
48 *
49 * The user's firmware periodically resets the timeout period (clears or "feeds"
50 * the watchdog) before a timeout occurs. If the firmware fails to do so, that is
51 * considered to be a CPU crash or a firmware failure, and the reason for a
52 * device reset.
53 * The WDT can generate an interrupt instead of a device reset. The Interrupt
54 * Service Routine (ISR) can handle the interrupt either as a periodic interrupt,
55 * or as an early indication of a firmware failure and respond accordingly.
56 * However, it is not recommended to use the WDT for periodic interrupt
57 * generation. The Multi-counter Watchdog Timers (MCWDT) can be used to generate
58 * periodic interrupts if such are presented in the device.
59 *
60 * <b> Functional Description </b>
61 *
62 * The WDT generates an interrupt when the count value in the counter equals the
63 * configured match value.
64 *
65 * Note that the counter is not reset on a match. In such case the WDT
66 * reset period is:
67 * WDT_Reset_Period = ILO_Period * (2*2^(16-IgnoreBits) + MatchValue);
68 * When the counter reaches a match value, it generates an interrupt and then
69 * keeps counting up until it overflows and rolls back to zero and reaches the
70 * match value again, at which point another interrupt is generated.
71 *
72 * To use a WDT to generate a periodic interrupt, the match value should be
73 * incremented in the ISR. As a result, the next WDT interrupt is generated when
74 * the counter reaches a new match value.
75 *
76 * You can also reduce the entire WDT counter period by
77 * specifying the number of most significant bits that are ignored in the WDT
78 * counter. For example, if the Cy_WDT_SetIgnoreBits() function is called with
79 * parameter 3, the WDT counter becomes a 13-bit free-running up-counter.
80 *
81 * <b> Power Modes </b>
82 *
83 * WDT can operate in all possible low power modes.
84 * Operation during Hibernate mode is possible because the logic and
85 * high-voltage internal low oscillator (ILO) are supplied by the external
86 * high-voltage supply (Vddd). The WDT can be configured to wake the device from
87 * Hibernate mode.
88 *
89 * In CPU Active mode, an interrupt request from the WDT is sent to the
90 * CPU. In CPU Sleep, CPU Deep Sleep mode, the CPU subsystem
91 * is powered down, so the interrupt request from the WDT is sent directly to the
92 * WakeUp Interrupt Controller (WIC) which will then wake up the CPU. The
93 * CPU then acknowledges the interrupt request and executes the ISR.
94 *
95 * <b> Clock Source </b>
96 *
97 * The WDT is clocked by the ILO. The WDT must be disabled before disabling
98 * the ILO. According to the device datasheet, the ILO accuracy is +/-30% over
99 * voltage and temperature. This means that the timeout period may vary by 30%
100 * from the configured value. Appropriate margins should be added while
101 * configuring WDT intervals to make sure that unwanted device resets do not
102 * occur on some devices.
103 *
104 * Refer to the device datasheet for more information on the oscillator accuracy.
105 *
106 * <b> Register Locking </b>
107 *
108 * You can prevent accidental corruption of the WDT configuration by calling
109 * the Cy_WDT_Lock() function. When the WDT is locked, any writing to the WDT_*,
110 * CLK_ILO_CONFIG, CLK_SELECT.LFCLK_SEL, and CLK_TRIM_ILO_CTL registers is
111 * ignored.
112 * Call the Cy_WDT_Unlock() function to allow registers modification, mentioned
113 * above.
114 *
115 * Note that the WDT lock state is not retained during system Deep Sleep. After
116 * the wakeup from system Deep Sleep the WDT is locked.
117 *
118 * <b> Clearing WDT </b>
119 *
120 * The ILO clock is asynchronous to the SysClk. Therefore it generally
121 * takes three ILO cycles for WDT register changes to come into effect. It is
122 * important to remember that a WDT should be cleared at least four cycles
123 * (3 + 1 for sure) before a timeout occurs, especially when small
124 * match values / low-toggle bit numbers are used.
125 *
126 * \warning It may happen that a WDT reset can be generated
127 * faster than a device start-up. To prevent this, calculate the
128 * start-up time and WDT reset time. The WDT reset time should be always greater
129 * than device start-up time.
130 *
131 * <b> Reset Detection </b>
132 *
133 * Use the Cy_SysLib_GetResetReason() function to detect whether the WDT has
134 * triggered a device reset.
135 *
136 * <b> Interrupt Configuration </b>
137 *
138 * If the WDT is configured to generate an interrupt, pending
139 * interrupts must be cleared within the ISR (otherwise, the interrupt will be
140 * generated continuously).
141 * A pending interrupt to the WDT block must be cleared by calling the
142 * Cy_WDT_ClearInterrupt() function. The call to the function will clear the
143 * unhandled WDT interrupt counter.
144 *
145 * Use the WDT ISR as a timer to trigger certain actions
146 * and to change a next WDT match value.
147 *
148 * Ensure that the interrupts from the WDT are passed to the CPU to avoid
149 * unregistered interrupts. Unregistered WDT interrupts result in a continuous
150 * device reset. To avoid this, call Cy_WDT_UnmaskInterrupt().
151 * After that, call the WDT API functions for interrupt
152 * handling/clearing.
153 *
154 * \section group_wdt_configuration Configuration Considerations
155 *
156 * To start the WDT, make sure that ILO is enabled.
157 * After the ILO is enabled, ensure that the WDT is unlocked and disabled by
158 * calling the Cy_WDT_Unlock() and Cy_WDT_Disable() functions. Set the WDT match
159 * value by calling Cy_WDT_SetMatch() with the required match value. If needed,
160 * set the ignore bits for reducing the WDT counter period by calling
161 * Cy_WDT_SetIgnoreBits() function. After the WDT configuration is set,
162 * call Cy_WDT_Enable().
163 *
164 * \note Enable a WDT if the power supply can produce
165 * sudden brownout events that may compromise the CPU functionality. This
166 * ensures that the system can recover after a brownout.
167 *
168 * When the WDT is used to protect against system crashes, the
169 * WDT interrupt should be cleared by a portion of the code that is not directly
170 * associated with the WDT interrupt.
171 * Otherwise, it is possible that the main firmware loop has crashed or is in an
172 * endless loop, but the WDT interrupt vector continues to operate and service
173 * the WDT. The user should:
174 * * Feed the watchdog by clearing the interrupt bit regularly in the main body
175 * of the firmware code.
176 *
177 * * Guarantee that the interrupt is cleared at least once every WDT period.
178 *
179 * * Use the WDT ISR only as a timer to trigger certain actions and to change the
180 * next match value.
181 *
182 * \section group_wdt_section_more_information More Information
183 *
184 * For more information on the WDT peripheral, refer to the technical reference
185 * manual (TRM).
186 *
187 * \section group_wdt_changelog Changelog
188 * <table class="doxtable">
189 * <tr><th>Version</th><th>Changes</th><th>Reason for Change</th></tr>
190 * <tr>
191 * <td>1.30.1</td>
192 * <td>Minor documentation updates.</td>
193 * <td>Removed MISRA 2004 compliance details and verified MISRA 2012 complaince.</td>
194 * </tr>
195 * <tr>
196 * <td rowspan="2">1.30</td>
197 * <td>Updated the following functions for the PSoC 64 devices: \ref Cy_WDT_ClearInterrupt(),
198 * \ref Cy_WDT_MaskInterrupt(), and \ref Cy_WDT_UnmaskInterrupt().</td>
199 * <td>Added PSoC 64 device support.</td>
200 * </tr>
201 * <tr>
202 * <td>Minor documentation updates.</td>
203 * <td>Documentation enhancement.</td>
204 * </tr>
205 * <tr>
206 * <td>1.20</td>
207 * <td>Added a new API function \ref Cy_WDT_IsEnabled() </td>
208 * <td>Enhancement based on usability feedback.</td>
209 * </tr>
210 * <tr>
211 * <td>1.10.1</td>
212 * <td>Added info that the WDT lock state is not retained during
213 * system Deep Sleep power mode.
214 * </td>
215 * <td>Documentation updates.</td>
216 * </tr>
217 * <tr>
218 * <td rowspan="4">1.10</td>
219 * <td>Flattened the organization of the driver source code into the single
220 * source directory and the single include directory.
221 * </td>
222 * <td>Driver library directory-structure simplification.</td>
223 * </tr>
224 * <tr>
225 * <td> Removed critical section usage in the following functions:
226 * - \ref Cy_WDT_Init()
227 * - \ref Cy_WDT_Lock()
228 * - \ref Cy_WDT_Unlock()
229 * </td>
230 * <td>Driver functions simplification</td>
231 * </tr>
232 * <tr>
233 * <td>Updated the \ref Cy_WDT_Init(), \ref Cy_WDT_Enable() to clear WDT interrupt.</td>
234 * <td>Corner case reliability improvements</td>
235 * </tr>
236 * <tr>
237 * <td>Added register access layer. Use register access macros instead
238 * of direct register access using dereferenced pointers.</td>
239 * <td>Makes register access device-independent, so that the PDL does
240 * not need to be recompiled for each supported part number.</td>
241 * </tr>
242 * <tr>
243 * <td>1.0.2</td>
244 * <td>Minor documentation updates</td>
245 * <td>Corrected info about a reset generation</td>
246 * </tr>
247 * <tr>
248 * <td>1.0.1</td>
249 * <td>General documentation updates</td>
250 * <td>Added info about periodic interrupt generation use case</td>
251 * </tr>
252 * <tr>
253 * <td>1.0</td>
254 * <td>Initial version</td>
255 * <td></td>
256 * </tr>
257 * </table>
258 *
259 * \defgroup group_wdt_macros Macros
260 * \defgroup group_wdt_functions Functions
261 *
262 */
263
264 #if !defined(CY_WDT_H)
265 #define CY_WDT_H
266
267 #include "cy_device.h"
268
269 #if defined (CY_IP_MXS28SRSS) || defined (CY_IP_MXS40SRSS ) || defined (CY_IP_MXS40SSRSS )
270
271 #include <stdint.h>
272 #include <stdbool.h>
273 #include "cy_syslib.h"
274 #if defined(CY_DEVICE_SECURE)
275 #include "cy_pra.h"
276 #endif /* defined(CY_DEVICE_SECURE) */
277
278
279 #if defined(__cplusplus)
280 extern "C" {
281 #endif
282
283
284 /*******************************************************************************
285 * Function Constants
286 *******************************************************************************/
287
288 /**
289 * \addtogroup group_wdt_macros
290 * \{
291 */
292
293 /** The driver major version */
294 #define CY_WDT_DRV_VERSION_MAJOR 1
295
296 /** The driver minor version */
297 #define CY_WDT_DRV_VERSION_MINOR 30
298
299 /** The internal define for the first iteration of WDT unlocking */
300 #define CY_SRSS_WDT_LOCK_BIT0 ((uint32_t)0x01U << 30U)
301
302 /** The internal define for the second iteration of WDT unlocking */
303 #define CY_SRSS_WDT_LOCK_BIT1 ((uint32_t)0x01U << 31U)
304
305 /** The WDT default match value */
306 #define CY_SRSS_WDT_DEFAULT_MATCH_VALUE ((uint32_t) 4096U)
307
308 /** The default match value of the WDT ignore bits */
309 #define CY_SRSS_WDT_DEFAULT_IGNORE_BITS (0U)
310
311 /** The default match value of the WDT ignore bits */
312 #define CY_SRSS_WDT_LOCK_BITS (3U)
313
314 /** The WDT driver identifier */
315 #define CY_WDT_ID CY_PDL_DRV_ID(0x34U)
316
317 /** \} group_wdt_macros */
318
319 /** \cond Internal */
320
321 /** The WDT maximum match value */
322 #define WDT_MAX_MATCH_VALUE (0xFFFFuL)
323
324 /** The WDT maximum match value */
325 #define WDT_MAX_IGNORE_BITS (0xFuL)
326
327 /* Internal macro to validate match value */
328 #define CY_WDT_IS_MATCH_VAL_VALID(match) ((match) <= WDT_MAX_MATCH_VALUE)
329
330 /* Internal macro to validate match value */
331 #define CY_WDT_IS_IGNORE_BITS_VALID(bitsNum) ((bitsNum) <= WDT_MAX_IGNORE_BITS)
332
333 /** \endcond */
334
335
336 /*******************************************************************************
337 * Function Prototypes
338 *******************************************************************************/
339 /**
340 * \addtogroup group_wdt_functions
341 * @{
342 */
343 /* WDT API */
344 void Cy_WDT_Init(void);
345 __STATIC_INLINE void Cy_WDT_Enable(void);
346 __STATIC_INLINE void Cy_WDT_Disable(void);
347 void Cy_WDT_Lock(void);
348 void Cy_WDT_Unlock(void);
349 bool Cy_WDT_Locked(void);
350 __STATIC_INLINE uint32_t Cy_WDT_GetCount(void);
351 void Cy_WDT_SetMatch(uint32_t match);
352 __STATIC_INLINE uint32_t Cy_WDT_GetMatch(void);
353 void Cy_WDT_SetIgnoreBits(uint32_t bitsNum);
354 __STATIC_INLINE uint32_t Cy_WDT_GetIgnoreBits(void);
355 __STATIC_INLINE void Cy_WDT_MaskInterrupt(void);
356 __STATIC_INLINE void Cy_WDT_UnmaskInterrupt(void);
357 void Cy_WDT_ClearInterrupt(void);
358 void Cy_WDT_ClearWatchdog(void);
359
360
361 /*******************************************************************************
362 * Function Name: Cy_WDT_Enable
363 ****************************************************************************//**
364 *
365 * Enables the Watchdog timer.
366 *
367 * \sideeffect
368 * This function clears the WDT interrupt.
369 *
370 *******************************************************************************/
Cy_WDT_Enable(void)371 __STATIC_INLINE void Cy_WDT_Enable(void)
372 {
373 SRSS_WDT_CTL |= _VAL2FLD(SRSS_WDT_CTL_WDT_EN, 1U);
374 Cy_WDT_ClearInterrupt();
375 }
376
377
378 /*******************************************************************************
379 * Function Name: Cy_WDT_Disable
380 ****************************************************************************//**
381 *
382 * Disables the Watchdog timer. The Watchdog timer should be unlocked before being
383 * disabled. Call the Cy_WDT_Unlock() API to unlock the WDT.
384 *
385 *******************************************************************************/
Cy_WDT_Disable(void)386 __STATIC_INLINE void Cy_WDT_Disable(void)
387 {
388 SRSS_WDT_CTL &= ((uint32_t) ~(_VAL2FLD(SRSS_WDT_CTL_WDT_EN, 1U)));
389 }
390
391
392 /*******************************************************************************
393 * Function Name: Cy_WDT_IsEnabled
394 ****************************************************************************//**
395 *
396 * Reports an enable/disable state of the Watchdog timer.
397 *
398 * \return
399 * - true - if the timer is enabled
400 * - false - if the timer is disabled
401 *
402 *******************************************************************************/
Cy_WDT_IsEnabled(void)403 __STATIC_INLINE bool Cy_WDT_IsEnabled(void)
404 {
405 return _FLD2BOOL(SRSS_WDT_CTL_WDT_EN, SRSS_WDT_CTL);
406 }
407
408
409 /*******************************************************************************
410 * Function Name: Cy_WDT_GetMatch
411 ****************************************************************************//**
412 *
413 * Reads the WDT counter match comparison value.
414 *
415 * \return The counter match value.
416 *
417 *******************************************************************************/
Cy_WDT_GetMatch(void)418 __STATIC_INLINE uint32_t Cy_WDT_GetMatch(void)
419 {
420 return ((uint32_t) _FLD2VAL(SRSS_WDT_MATCH_MATCH, SRSS_WDT_MATCH));
421 }
422
423
424 /*******************************************************************************
425 * Function Name: Cy_WDT_GetCount
426 ****************************************************************************//**
427 *
428 * Reads the current WDT counter value.
429 *
430 * \return A live counter value.
431 *
432 *******************************************************************************/
Cy_WDT_GetCount(void)433 __STATIC_INLINE uint32_t Cy_WDT_GetCount(void)
434 {
435 return ((uint32_t) _FLD2VAL(SRSS_WDT_CNT_COUNTER, SRSS_WDT_CNT));
436 }
437
438
439 /*******************************************************************************
440 * Function Name: Cy_WDT_GetIgnoreBits
441 ****************************************************************************//**
442 *
443 * Reads the number of the most significant bits of the Watchdog timer that are
444 * not checked against the match.
445 *
446 * \return The number of the most significant bits.
447 *
448 *******************************************************************************/
Cy_WDT_GetIgnoreBits(void)449 __STATIC_INLINE uint32_t Cy_WDT_GetIgnoreBits(void)
450 {
451 return((uint32_t) _FLD2VAL(SRSS_WDT_MATCH_IGNORE_BITS, SRSS_WDT_MATCH));
452 }
453
454
455 /*******************************************************************************
456 * Function Name: Cy_WDT_MaskInterrupt
457 ****************************************************************************//**
458 *
459 * After masking interrupts from the WDT, they are not passed to the CPU.
460 * This function does not disable the WDT-reset generation.
461 *
462 *******************************************************************************/
Cy_WDT_MaskInterrupt(void)463 __STATIC_INLINE void Cy_WDT_MaskInterrupt(void)
464 {
465 #if CY_CPU_CORTEX_M4 && defined(CY_DEVICE_SECURE)
466 CY_PRA_REG32_CLR_SET(CY_PRA_INDX_SRSS_SRSS_INTR_MASK, SRSS_SRSS_INTR_MASK_WDT_MATCH, 0U);
467 #else
468 SRSS_SRSS_INTR_MASK &= (uint32_t)(~ _VAL2FLD(SRSS_SRSS_INTR_MASK_WDT_MATCH, 1U));
469 #endif /* CY_CPU_CORTEX_M4 && defined(CY_DEVICE_SECURE) */
470 }
471
472
473 /*******************************************************************************
474 * Function Name: Cy_WDT_UnmaskInterrupt
475 ****************************************************************************//**
476 *
477 * After unmasking interrupts from the WDT, they are passed to CPU.
478 * This function does not impact the reset generation.
479 *
480 *******************************************************************************/
Cy_WDT_UnmaskInterrupt(void)481 __STATIC_INLINE void Cy_WDT_UnmaskInterrupt(void)
482 {
483 #if CY_CPU_CORTEX_M4 && defined(CY_DEVICE_SECURE)
484 CY_PRA_REG32_CLR_SET(CY_PRA_INDX_SRSS_SRSS_INTR_MASK, SRSS_SRSS_INTR_MASK_WDT_MATCH, 1U);
485 #else
486 SRSS_SRSS_INTR_MASK |= _VAL2FLD(SRSS_SRSS_INTR_MASK_WDT_MATCH, 1U);
487 #endif /* CY_CPU_CORTEX_M4 && defined(CY_DEVICE_SECURE) */
488 }
489 /** \} group_wdt_functions */
490
491 #if defined(__cplusplus)
492 }
493 #endif
494
495 #endif /* CY_IP_MXS28SRSS, CY_IP_MXS40SRSS */
496
497 #endif /* CY_WDT_H */
498
499 /** \} group_wdt */
500
501
502 /* [] END OF FILE */
503