1 /***************************************************************************//**
2  * @file
3  * @brief Watchdog (WDOG) peripheral API
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 
31 #ifndef EM_WDOG_H
32 #define EM_WDOG_H
33 
34 #include "em_device.h"
35 #if defined(WDOG_COUNT) && (WDOG_COUNT > 0)
36 
37 #include <stdbool.h>
38 
39 #ifdef __cplusplus
40 extern "C" {
41 #endif
42 
43 /***************************************************************************//**
44  * @addtogroup wdog
45  * @{
46  ******************************************************************************/
47 
48 /*******************************************************************************
49  *******************************   DEFINES   ***********************************
50  ******************************************************************************/
51 
52 /** Default WDOG instance for deprecated functions. */
53 #if !defined(DEFAULT_WDOG)
54 #if defined(WDOG0)
55 #define DEFAULT_WDOG WDOG0
56 #elif defined(WDOG)
57 #define DEFAULT_WDOG WDOG
58 #endif
59 #endif
60 
61 /*******************************************************************************
62  ********************************   ENUMS   ************************************
63  ******************************************************************************/
64 
65 /** Watchdog clock selection. */
66 #if defined(_WDOG_CTRL_CLKSEL_MASK)
67 typedef enum {
68   wdogClkSelULFRCO = _WDOG_CTRL_CLKSEL_ULFRCO,   /**< Ultra low frequency (1 kHz) clock */
69   wdogClkSelLFRCO  = _WDOG_CTRL_CLKSEL_LFRCO,    /**< Low frequency RC oscillator */
70   wdogClkSelLFXO   = _WDOG_CTRL_CLKSEL_LFXO      /**< Low frequency crystal oscillator */
71 } WDOG_ClkSel_TypeDef;
72 #endif
73 
74 /** Watchdog period selection. */
75 typedef enum {
76   wdogPeriod_9    = 0x0, /**< 9 clock periods */
77   wdogPeriod_17   = 0x1, /**< 17 clock periods */
78   wdogPeriod_33   = 0x2, /**< 33 clock periods */
79   wdogPeriod_65   = 0x3, /**< 65 clock periods */
80   wdogPeriod_129  = 0x4, /**< 129 clock periods */
81   wdogPeriod_257  = 0x5, /**< 257 clock periods */
82   wdogPeriod_513  = 0x6, /**< 513 clock periods */
83   wdogPeriod_1k   = 0x7, /**< 1025 clock periods */
84   wdogPeriod_2k   = 0x8, /**< 2049 clock periods */
85   wdogPeriod_4k   = 0x9, /**< 4097 clock periods */
86   wdogPeriod_8k   = 0xA, /**< 8193 clock periods */
87   wdogPeriod_16k  = 0xB, /**< 16385 clock periods */
88   wdogPeriod_32k  = 0xC, /**< 32769 clock periods */
89   wdogPeriod_64k  = 0xD, /**< 65537 clock periods */
90   wdogPeriod_128k = 0xE, /**< 131073 clock periods */
91   wdogPeriod_256k = 0xF  /**< 262145 clock periods */
92 } WDOG_PeriodSel_TypeDef;
93 
94 #if defined(_WDOG_CTRL_WARNSEL_MASK) \
95   || defined(_WDOG_CFG_WARNSEL_MASK)
96 /** Select watchdog warning timeout period as percentage of timeout. */
97 typedef enum {
98   wdogWarnDisable   = 0,
99   wdogWarnTime25pct = 1,
100   wdogWarnTime50pct = 2,
101   wdogWarnTime75pct = 3,
102 } WDOG_WarnSel_TypeDef;
103 #endif
104 
105 #if defined(_WDOG_CTRL_WINSEL_MASK) \
106   || defined(_WDOG_CFG_WINSEL_MASK)
107 /**  Select watchdog illegal window limit. */
108 typedef enum {
109   wdogIllegalWindowDisable     = 0,
110   wdogIllegalWindowTime12_5pct = 1,
111   wdogIllegalWindowTime25_0pct = 2,
112   wdogIllegalWindowTime37_5pct = 3,
113   wdogIllegalWindowTime50_0pct = 4,
114   wdogIllegalWindowTime62_5pct = 5,
115   wdogIllegalWindowTime75_0pct = 6,
116   wdogIllegalWindowTime87_5pct = 7,
117 } WDOG_WinSel_TypeDef;
118 #endif
119 
120 /*******************************************************************************
121  *******************************   STRUCTS   ***********************************
122  ******************************************************************************/
123 
124 /** Watchdog initialization structure. */
125 typedef struct {
126   /** Enable watchdog when initialization completed. */
127   bool                   enable;
128 
129   /** Counter keeps running during debug halt. */
130   bool                   debugRun;
131 
132   /** Counter keeps running when in EM2. */
133   bool                   em2Run;
134 
135   /** Counter keeps running when in EM3. */
136   bool                   em3Run;
137 
138   /** Block EMU from entering EM4. */
139   bool                   em4Block;
140 
141   /** Block SW from disabling LFRCO/LFXO oscillators. */
142 #if defined(_WDOG_CTRL_SWOSCBLOCK_MASK)
143   bool                   swoscBlock;
144 #endif
145 
146   /** Block SW from modifying the configuration (a reset is needed to reconfigure). */
147   bool                   lock;
148 
149   /** Clock source to use for watchdog. */
150 #if defined(_WDOG_CTRL_CLKSEL_MASK)
151   WDOG_ClkSel_TypeDef    clkSel;
152 #endif
153 
154   /** Watchdog timeout period. */
155   WDOG_PeriodSel_TypeDef perSel;
156 
157 #if defined(_WDOG_CTRL_WARNSEL_MASK) \
158   || defined(_WDOG_CFG_WARNSEL_MASK)
159   /** Select warning time as % of the watchdog timeout */
160   WDOG_WarnSel_TypeDef   warnSel;
161 #endif
162 
163 #if defined(_WDOG_CTRL_WINSEL_MASK) \
164   || defined(_WDOG_CFG_WINSEL_MASK)
165   /** Select illegal window time as % of the watchdog timeout */
166   WDOG_WinSel_TypeDef    winSel;
167 #endif
168 
169 #if defined(_WDOG_CTRL_WDOGRSTDIS_MASK) \
170   || defined(_WDOG_CFG_WDOGRSTDIS_MASK)
171   /** Disable watchdog reset output if true */
172   bool                   resetDisable;
173 #endif
174 } WDOG_Init_TypeDef;
175 
176 /** Suggested default configuration for WDOG initialization structure. */
177 #if defined(_WDOG_CFG_MASK)
178 #define WDOG_INIT_DEFAULT                                                       \
179   {                                                                             \
180     true,                     /* Start watchdog when initialization is done. */ \
181     false,                    /* WDOG is not counting during debug halt. */     \
182     false,                    /* WDOG is not counting when in EM2. */           \
183     false,                    /* WDOG is not counting when in EM3. */           \
184     false,                    /* EM4 can be entered. */                         \
185     false,                    /* Do not lock WDOG configuration. */             \
186     wdogPeriod_256k,          /* Set longest possible timeout period. */        \
187     wdogWarnDisable,          /* Disable warning interrupt. */                  \
188     wdogIllegalWindowDisable, /* Disable illegal window interrupt. */           \
189     false                     /* Do not disable reset. */                       \
190   }
191 #elif defined(_WDOG_CTRL_WARNSEL_MASK)   \
192   && defined(_WDOG_CTRL_WDOGRSTDIS_MASK) \
193   && defined(_WDOG_CTRL_WINSEL_MASK)
194 #define WDOG_INIT_DEFAULT                                                       \
195   {                                                                             \
196     true,                     /* Start watchdog when initialization is done. */ \
197     false,                    /* WDOG is not counting during debug halt. */     \
198     false,                    /* WDOG is not counting when in EM2. */           \
199     false,                    /* WDOG is not counting when in EM3. */           \
200     false,                    /* EM4 can be entered. */                         \
201     false,                    /* Do not block disabling LFRCO/LFXO in CMU. */   \
202     false,                    /* Do not lock WDOG configuration. */             \
203     wdogClkSelLFRCO,          /* Select 32.768 kHZ WDOG oscillator. */          \
204     wdogPeriod_256k,          /* Set longest possible timeout period. */        \
205     wdogWarnDisable,          /* Disable warning interrupt. */                  \
206     wdogIllegalWindowDisable, /* Disable illegal window interrupt. */           \
207     false                     /* Do not disable reset. */                       \
208   }
209 #else
210 #define WDOG_INIT_DEFAULT                                                       \
211   {                                                                             \
212     true,                     /* Start watchdog when initialization is done. */ \
213     false,                    /* WDOG is not counting during debug halt. */     \
214     false,                    /* WDOG is not counting when in EM2. */           \
215     false,                    /* WDOG is not counting when in EM3. */           \
216     false,                    /* EM4 can be entered. */                         \
217     false,                    /* Do not block disabling LFRCO/LFXO in CMU. */   \
218     false,                    /* Do not lock WDOG configuration. */             \
219     wdogClkSelLFRCO,          /* Select 32.768 kHz WDOG oscillator. */          \
220     wdogPeriod_256k           /* Set longest possible timeout period. */        \
221   }
222 #endif
223 
224 /*******************************************************************************
225  *****************************   PROTOTYPES   **********************************
226  ******************************************************************************/
227 
228 void WDOGn_Enable(WDOG_TypeDef *wdog, bool enable);
229 void WDOGn_Feed(WDOG_TypeDef *wdog);
230 void WDOGn_Init(WDOG_TypeDef *wdog, const WDOG_Init_TypeDef *init);
231 void WDOGn_Lock(WDOG_TypeDef *wdog);
232 void WDOGn_SyncWait(WDOG_TypeDef *wdog);
233 void WDOGn_Unlock(WDOG_TypeDef *wdog);
234 
235 #if defined(_WDOG_IF_MASK)
236 /***************************************************************************//**
237  * @brief
238  *   Clear one or more pending WDOG interrupts.
239  *
240  * @param[in] wdog
241  *   Pointer to WDOG peripheral register block.
242  *
243  * @param[in] flags
244  *   WDOG interrupt sources to clear. Use a set of interrupt flags OR-ed
245  *   together to clear multiple interrupt sources.
246  ******************************************************************************/
WDOGn_IntClear(WDOG_TypeDef * wdog,uint32_t flags)247 __STATIC_INLINE void WDOGn_IntClear(WDOG_TypeDef *wdog, uint32_t flags)
248 {
249 #if defined(WDOG_HAS_SET_CLEAR)
250   wdog->IF_CLR = flags;
251 #else
252   wdog->IFC = flags;
253 #endif
254 }
255 
256 /***************************************************************************//**
257  * @brief
258  *   Disable one or more WDOG interrupts.
259  *
260  * @param[in] wdog
261  *   Pointer to WDOG peripheral register block.
262  *
263  * @param[in] flags
264  *   WDOG interrupt sources to disable. Use a set of interrupt flags OR-ed
265  *   together to disable multiple interrupt.
266  ******************************************************************************/
WDOGn_IntDisable(WDOG_TypeDef * wdog,uint32_t flags)267 __STATIC_INLINE void WDOGn_IntDisable(WDOG_TypeDef *wdog, uint32_t flags)
268 {
269 #if defined(WDOG_HAS_SET_CLEAR)
270   wdog->IEN_CLR = flags;
271 #else
272   wdog->IEN &= ~flags;
273 #endif
274 }
275 
276 /***************************************************************************//**
277  * @brief
278  *   Enable one or more WDOG interrupts.
279  *
280  * @note
281  *   Depending on the use, a pending interrupt may already be set prior to
282  *   enabling the interrupt. To ignore a pending interrupt, consider using
283  *   WDOG_IntClear() prior to enabling the interrupt.
284  *
285  * @param[in] wdog
286  *   Pointer to WDOG peripheral register block.
287  *
288  * @param[in] flags
289  *   WDOG interrupt sources to enable. Use a set of interrupt flags OR-ed
290  *   together to set multiple interrupt.
291  ******************************************************************************/
WDOGn_IntEnable(WDOG_TypeDef * wdog,uint32_t flags)292 __STATIC_INLINE void WDOGn_IntEnable(WDOG_TypeDef *wdog, uint32_t flags)
293 {
294 #if defined(WDOG_HAS_SET_CLEAR)
295   wdog->IEN_SET = flags;
296 #else
297   wdog->IEN |= flags;
298 #endif
299 }
300 
301 /***************************************************************************//**
302  * @brief
303  *   Get pending WDOG interrupt flags.
304  *
305  * @note
306  *   The event bits are not cleared by the use of this function.
307  *
308  * @param[in] wdog
309  *   Pointer to WDOG peripheral register block.
310  *
311  * @return
312  *   Pending WDOG interrupt sources. Returns a set of interrupt flags OR-ed
313  *   together for the interrupt sources set.
314  ******************************************************************************/
WDOGn_IntGet(WDOG_TypeDef * wdog)315 __STATIC_INLINE uint32_t WDOGn_IntGet(WDOG_TypeDef *wdog)
316 {
317   return wdog->IF;
318 }
319 
320 /***************************************************************************//**
321  * @brief
322  *   Get enabled and pending WDOG interrupt flags.
323  *
324  * @details
325  *   Useful for handling more interrupt sources in the same interrupt handler.
326  *
327  * @param[in] wdog
328  *   Pointer to WDOG peripheral register block.
329  *
330  * @return
331  *   Pending and enabled WDOG interrupt sources. Returns a set of interrupt
332  *   flags OR-ed together for the interrupt sources set.
333  ******************************************************************************/
WDOGn_IntGetEnabled(WDOG_TypeDef * wdog)334 __STATIC_INLINE uint32_t WDOGn_IntGetEnabled(WDOG_TypeDef *wdog)
335 {
336   uint32_t tmp;
337 
338   tmp = wdog->IEN;
339 
340   /* Bitwise AND of pending and enabled interrupt flags. */
341   return wdog->IF & tmp;
342 }
343 
344 /***************************************************************************//**
345  * @brief
346  *   Set one or more pending WDOG interrupts from SW.
347  *
348  * @param[in] wdog
349  *   Pointer to WDOG peripheral register block.
350  *
351  * @param[in] flags
352  *   WDOG interrupt sources to set to pending. Use a set of interrupt flags
353  *   (WDOG_IFS_nnn).
354  ******************************************************************************/
WDOGn_IntSet(WDOG_TypeDef * wdog,uint32_t flags)355 __STATIC_INLINE void WDOGn_IntSet(WDOG_TypeDef *wdog, uint32_t flags)
356 {
357 #if defined(WDOG_HAS_SET_CLEAR)
358   wdog->IF_SET = flags;
359 #else
360   wdog->IFS = flags;
361 #endif
362 }
363 #endif
364 
365 /***************************************************************************//**
366  * @brief
367  *   Get enabled status of the watchdog.
368  *
369  * @param[in] wdog
370  *   Pointer to WDOG peripheral register block.
371  *
372  * @return
373  *   True if watchdog is enabled.
374  ******************************************************************************/
WDOGn_IsEnabled(WDOG_TypeDef * wdog)375 __STATIC_INLINE bool WDOGn_IsEnabled(WDOG_TypeDef *wdog)
376 {
377 #if defined(_WDOG_EN_MASK)
378   return (wdog->EN & _WDOG_EN_EN_MASK) == WDOG_EN_EN;
379 #else
380   return (wdog->CTRL & _WDOG_CTRL_EN_MASK) == WDOG_CTRL_EN;
381 #endif
382 }
383 
384 /***************************************************************************//**
385  * @brief
386  *   Get locked status of the watchdog.
387  *
388  * @param[in] wdog
389  *   Pointer to WDOG peripheral register block.
390  *
391  * @return
392  *   True if watchdog is locked.
393  ******************************************************************************/
WDOGn_IsLocked(WDOG_TypeDef * wdog)394 __STATIC_INLINE bool WDOGn_IsLocked(WDOG_TypeDef *wdog)
395 {
396 #if defined(_WDOG_STATUS_MASK)
397   return (wdog->STATUS & _WDOG_STATUS_LOCK_MASK) == WDOG_STATUS_LOCK_LOCKED;
398 #else
399   return (wdog->CTRL & _WDOG_CTRL_LOCK_MASK) == WDOG_CTRL_LOCK;
400 #endif
401 }
402 
403 /***************************************************************************//**
404  * @brief
405  *   Enable/disable the watchdog timer.
406  *
407  * @deprecated
408  *   Deprecated function. New code should use @ref WDOGn_Enable().
409  *   This function uses @ref DEFAULT_WDOG.
410  *
411  * @param[in] enable
412  *   Set to true to enable watchdog, false to disable. Watchdog cannot be
413  *   disabled if watchdog has been locked.
414  ******************************************************************************/
WDOG_Enable(bool enable)415 __STATIC_INLINE void WDOG_Enable(bool enable)
416 {
417   WDOGn_Enable(DEFAULT_WDOG, enable);
418 }
419 
420 /***************************************************************************//**
421  * @brief
422  *   Feed the watchdog.
423  *
424  * @deprecated
425  *   Deprecated function. New code should use @ref WDOGn_Feed().
426  *   This function uses @ref DEFAULT_WDOG.
427  ******************************************************************************/
WDOG_Feed(void)428 __STATIC_INLINE void WDOG_Feed(void)
429 {
430   WDOGn_Feed(DEFAULT_WDOG);
431 }
432 
433 /***************************************************************************//**
434  * @brief
435  *   Initialize watchdog (assuming the watchdog configuration has not been
436  *   locked).
437  *
438  * @deprecated
439  *   Deprecated function. New code should use @ref WDOGn_Init().
440  *   This function uses @ref DEFAULT_WDOG.
441  *
442  * @param[in] init
443  *   Structure holding watchdog configuration. A default setting
444  *   #WDOG_INIT_DEFAULT is available for initialization.
445  ******************************************************************************/
WDOG_Init(const WDOG_Init_TypeDef * init)446 __STATIC_INLINE void WDOG_Init(const WDOG_Init_TypeDef *init)
447 {
448   WDOGn_Init(DEFAULT_WDOG, init);
449 }
450 
451 /***************************************************************************//**
452  * @brief
453  *   Lock the watchdog configuration.
454  *
455  * @deprecated
456  *   Deprecated function. New code should use @ref WDOGn_Lock().
457  *   This function uses @ref DEFAULT_WDOG.
458  ******************************************************************************/
WDOG_Lock(void)459 __STATIC_INLINE void WDOG_Lock(void)
460 {
461   WDOGn_Lock(DEFAULT_WDOG);
462 }
463 
464 /***************************************************************************//**
465  * @brief
466  *   Get enabled status of the watchdog.
467  *
468  * @deprecated
469  *   Deprecated function. New code should use @ref WDOGn_IsEnabled().
470  *   This function uses @ref DEFAULT_WDOG.
471  *
472  * @return
473  *   True if watchdog is enabled.
474  ******************************************************************************/
WDOG_IsEnabled(void)475 __STATIC_INLINE bool WDOG_IsEnabled(void)
476 {
477   return WDOGn_IsEnabled(DEFAULT_WDOG);
478 }
479 
480 /***************************************************************************//**
481  * @brief
482  *   Get locked status of the watchdog.
483  *
484  * @deprecated
485  *   Deprecated function. New code should use @ref WDOGn_IsLocked().
486  *   This function uses @ref DEFAULT_WDOG.
487  *
488  * @return
489  *   True if watchdog is locked.
490  ******************************************************************************/
WDOG_IsLocked(void)491 __STATIC_INLINE bool WDOG_IsLocked(void)
492 {
493   return WDOGn_IsLocked(DEFAULT_WDOG);
494 }
495 
496 /** @} (end addtogroup wdog) */
497 
498 #ifdef __cplusplus
499 }
500 #endif
501 
502 #endif /* defined(WDOG_COUNT) && (WDOG_COUNT > 0) */
503 #endif /* EM_WDOG_H */
504