1 /***************************************************************************//**
2  * @file
3  * @brief Watchdog (WDOG) peripheral API
4  *   devices.
5  * @author Energy Micro AS
6  * @version 3.0.0
7  *******************************************************************************
8  * @section License
9  * <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
10  *******************************************************************************
11  *
12  * Permission is granted to anyone to use this software for any purpose,
13  * including commercial applications, and to alter it and redistribute it
14  * freely, subject to the following restrictions:
15  *
16  * 1. The origin of this software must not be misrepresented; you must not
17  *    claim that you wrote the original software.
18  * 2. Altered source versions must be plainly marked as such, and must not be
19  *    misrepresented as being the original software.
20  * 3. This notice may not be removed or altered from any source distribution.
21  *
22  * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
23  * obligation to support this Software. Energy Micro AS is providing the
24  * Software "AS IS", with no express or implied warranties of any kind,
25  * including, but not limited to, any implied warranties of merchantability
26  * or fitness for any particular purpose or warranties against infringement
27  * of any proprietary rights of a third party.
28  *
29  * Energy Micro AS will not be liable for any consequential, incidental, or
30  * special damages, or any other relief, or for any claim by any third party,
31  * arising from your use of this Software.
32  *
33  ******************************************************************************/
34 #include "em_wdog.h"
35 #include "em_bitband.h"
36 
37 /***************************************************************************//**
38  * @addtogroup EM_Library
39  * @{
40  ******************************************************************************/
41 
42 /***************************************************************************//**
43  * @addtogroup WDOG
44  * @brief Watchdog (WDOG) Peripheral API
45  * @{
46  ******************************************************************************/
47 
48 /*******************************************************************************
49  **************************   GLOBAL FUNCTIONS   *******************************
50  ******************************************************************************/
51 
52 /***************************************************************************//**
53  * @brief
54  *   Enable/disable the watchdog timer.
55  *
56  * @note
57  *   This function modifies the WDOG CTRL register which requires
58  *   synchronization into the low frequency domain. If this register is modified
59  *   before a previous update to the same register has completed, this function
60  *   will stall until the previous synchronization has completed.
61  *
62  * @param[in] enable
63  *   true to enable watchdog, false to disable. Watchdog cannot be disabled if
64  *   watchdog has been locked.
65  ******************************************************************************/
WDOG_Enable(bool enable)66 void WDOG_Enable(bool enable)
67 {
68   if (!enable)
69   {
70     /* Wait for any pending previous write operation to have been completed in */
71     /* low frequency domain */
72     while (WDOG->SYNCBUSY & WDOG_SYNCBUSY_CTRL)
73       ;
74   }
75   BITBAND_Peripheral(&(WDOG->CTRL), _WDOG_CTRL_EN_SHIFT, (unsigned int)enable);
76 }
77 
78 
79 /***************************************************************************//**
80  * @brief
81  *   Feed the watchdog.
82  *
83  * @details
84  *   When the watchdog is activated, it must be fed (ie clearing the counter)
85  *   before it reaches the defined timeout period. Otherwise, the watchdog
86  *   will generate a reset.
87  ******************************************************************************/
WDOG_Feed(void)88 void WDOG_Feed(void)
89 {
90   /* If a previous clearing is being synchronized to LF domain, then there */
91   /* is no point in waiting for it to complete before clearing over again. */
92   /* This avoids stalling the core in the typical use case where some idle loop */
93   /* keeps clearing the watchdog. */
94   if (WDOG->SYNCBUSY & WDOG_SYNCBUSY_CMD)
95     return;
96 
97   WDOG->CMD = WDOG_CMD_CLEAR;
98 }
99 
100 
101 /***************************************************************************//**
102  * @brief
103  *   Initialize watchdog (assuming the watchdog configuration has not been
104  *   locked).
105  *
106  * @note
107  *   This function modifies the WDOG CTRL register which requires
108  *   synchronization into the low frequency domain. If this register is modified
109  *   before a previous update to the same register has completed, this function
110  *   will stall until the previous synchronization has completed.
111  *
112  * @param[in] init
113  *   Structure holding watchdog configuration. A default setting
114  *   #WDOG_INIT_DEFAULT is available for init.
115  ******************************************************************************/
WDOG_Init(const WDOG_Init_TypeDef * init)116 void WDOG_Init(const WDOG_Init_TypeDef *init)
117 {
118   uint32_t setting;
119 
120   if (init->enable)
121   {
122     setting = WDOG_CTRL_EN;
123   }
124   else
125   {
126     setting = 0;
127   }
128 
129   if (init->debugRun)
130   {
131     setting |= WDOG_CTRL_DEBUGRUN;
132   }
133 
134   if (init->em2Run)
135   {
136     setting |= WDOG_CTRL_EM2RUN;
137   }
138 
139   if (init->em3Run)
140   {
141     setting |= WDOG_CTRL_EM3RUN;
142   }
143 
144   if (init->em4Block)
145   {
146     setting |= WDOG_CTRL_EM4BLOCK;
147   }
148 
149   if (init->swoscBlock)
150   {
151     setting |= WDOG_CTRL_SWOSCBLOCK;
152   }
153 
154   setting |= ((uint32_t)(init->clkSel) << _WDOG_CTRL_CLKSEL_SHIFT) |
155              ((uint32_t)(init->perSel) << _WDOG_CTRL_PERSEL_SHIFT);
156 
157   /* Wait for any pending previous write operation to have been completed in */
158   /* low frequency domain */
159   while (WDOG->SYNCBUSY & WDOG_SYNCBUSY_CTRL)
160     ;
161 
162   WDOG->CTRL = setting;
163 
164   /* Optional register locking */
165   if (init->lock)
166   {
167     if (init->enable)
168     {
169       WDOG_Lock();
170     }
171     else
172     {
173       BITBAND_Peripheral(&(WDOG->CTRL), _WDOG_CTRL_LOCK_SHIFT, 1);
174     }
175   }
176 }
177 
178 
179 /***************************************************************************//**
180  * @brief
181  *   Lock the watchdog configuration.
182  *
183  * @details
184  *   This prevents errors from overwriting the watchdog configuration, possibly
185  *   disabling it. Only a reset can unlock the watchdog config, once locked.
186  *
187  *   If the LFRCO or LFXO clocks are used to clock the watchdog, one should
188  *   consider using the option of inhibiting those clocks to be disabled,
189  *   please see the WDOG_Enable() init structure.
190  *
191  * @note
192  *   This function modifies the WDOG CTRL register which requires
193  *   synchronization into the low frequency domain. If this register is modified
194  *   before a previous update to the same register has completed, this function
195  *   will stall until the previous synchronization has completed.
196  ******************************************************************************/
WDOG_Lock(void)197 void WDOG_Lock(void)
198 {
199   /* Wait for any pending previous write operation to have been completed in */
200   /* low frequency domain */
201   while (WDOG->SYNCBUSY & WDOG_SYNCBUSY_CTRL)
202     ;
203 
204   /* Disable writing to the control register */
205   BITBAND_Peripheral(&(WDOG->CTRL), _WDOG_CTRL_LOCK_SHIFT, 1);
206 }
207 
208 
209 /** @} (end addtogroup WDOG) */
210 /** @} (end addtogroup EM_Library) */
211