1 /***************************************************************************//**
2  * @file
3  * @brief Backup Real Time Counter (BURTC) Peripheral API
4  * @author Energy Micro AS
5  * @version 3.0.0
6  *******************************************************************************
7  * @section License
8  * <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
9  *******************************************************************************
10  *
11  * Permission is granted to anyone to use this software for any purpose,
12  * including commercial applications, and to alter it and redistribute it
13  * freely, subject to the following restrictions:
14  *
15  * 1. The origin of this software must not be misrepresented; you must not
16  *    claim that you wrote the original software.
17  * 2. Altered source versions must be plainly marked as such, and must not be
18  *    misrepresented as being the original software.
19  * 3. This notice may not be removed or altered from any source distribution.
20  *
21  * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
22  * obligation to support this Software. Energy Micro AS is providing the
23  * Software "AS IS", with no express or implied warranties of any kind,
24  * including, but not limited to, any implied warranties of merchantability
25  * or fitness for any particular purpose or warranties against infringement
26  * of any proprietary rights of a third party.
27  *
28  * Energy Micro AS will not be liable for any consequential, incidental, or
29  * special damages, or any other relief, or for any claim by any third party,
30  * arising from your use of this Software.
31  *
32  ******************************************************************************/
33 #include "em_part.h"
34 #if defined(BURTC_PRESENT)
35 #include "em_burtc.h"
36 
37 #include "em_assert.h"
38 #include "em_bitband.h"
39 
40 /***************************************************************************//**
41  * @addtogroup EM_Library
42  * @{
43  ******************************************************************************/
44 
45 /***************************************************************************//**
46  * @addtogroup BURTC
47  * @brief Backup Real Time Counter (BURTC) Peripheral API
48  * @{
49  ******************************************************************************/
50 
51 /*******************************************************************************
52  *******************************   DEFINES   ***********************************
53  ******************************************************************************/
54 
55 /*******************************************************************************
56  **************************   LOCAL FUNCTIONS   ********************************
57  ******************************************************************************/
58 
59 /***************************************************************************//**
60  * @brief Convert dividend to prescaler logarithmic value. Only works for even
61  *        numbers equal to 2^n
62  * @param[in] div Unscaled dividend,
63  * @return Base 2 logarithm of input, as used by fixed prescalers
64  ******************************************************************************/
BURTC_DivToLog2(uint32_t div)65 __STATIC_INLINE uint32_t BURTC_DivToLog2(uint32_t div)
66 {
67   uint32_t log2;
68 
69   /* Prescaler accepts an argument of 128 or less, valid values being 2^n */
70   EFM_ASSERT((div > 0) && (div <= 32768));
71 
72   /* Count leading zeroes and "reverse" result, Cortex-M3 intrinsic */
73   log2 = (31 - __CLZ(div));
74 
75   return log2;
76 }
77 
78 
79 /*******************************************************************************
80  **************************   GLOBAL FUNCTIONS   *******************************
81  ******************************************************************************/
82 
83 /***************************************************************************//**
84  * @brief Initialize BURTC
85  *
86  * @details
87  *    Configures the BURTC peripheral.
88  *
89  * @note
90  *   Before initialization, BURTC module must first be enabled by clearing the
91  *   reset bit in the RMU, i.e.
92  * @verbatim
93  *   RMU_ResetControl(rmuResetBU, false);
94  * @endverbatim
95  *   Compare channel 0 must be configured outside this function, before
96  *   initialization if enable is set to true. The counter will always be reset.
97  *
98  * @param[in] burtcInit
99  *   Pointer to BURTC initialization structure
100  ******************************************************************************/
BURTC_Init(const BURTC_Init_TypeDef * burtcInit)101 void BURTC_Init(const BURTC_Init_TypeDef *burtcInit)
102 {
103   uint32_t ctrl;
104   uint32_t presc;
105 
106   /* Check initializer structure integrity */
107   EFM_ASSERT(burtcInit != (BURTC_Init_TypeDef *) 0);
108   /* Clock divider must be between 1 and 128, really on the form 2^n */
109   EFM_ASSERT((burtcInit->clkDiv >= 1) && (burtcInit->clkDiv <= 128));
110   /* Ignored compare bits during low power operation must be less than 7 */
111   /* Note! Giant Gecko revision C errata, do NOT use LPCOMP=7 */
112   EFM_ASSERT(burtcInit->lowPowerComp <= 6);
113   /* You cannot enable the BURTC if mode is set to disabled */
114   EFM_ASSERT((burtcInit->enable == false) ||
115              ((burtcInit->enable == true) && (burtcInit->mode != burtcModeDisable)));
116   /* Low power mode is only available with LFRCO or LFXO as clock source */
117   EFM_ASSERT((burtcInit->clkSel != burtcClkSelULFRCO) ||
118              ((burtcInit->clkSel == burtcClkSelULFRCO) && (burtcInit->lowPowerMode == burtcLPDisable)));
119 
120   /* Calculate prescaler value from clock divider input */
121   /* Note! If clock select (clkSel) is ULFRCO, a non-zero clkDiv will select */
122   /* 1kHz clock source, while any other value will use a 2kHz ULFRCO clock */
123   presc = BURTC_DivToLog2(burtcInit->clkDiv);
124 
125   /* Make sure all registers are updated simultaneously */
126   if (burtcInit->enable)
127   {
128     BURTC_FreezeEnable(true);
129   }
130 
131   /* Configure low power mode */
132   BURTC->LPMODE = (uint32_t)(burtcInit->lowPowerMode);
133 
134   /* New configuration */
135   ctrl = ((BURTC_CTRL_RSTEN) |
136           (burtcInit->mode) |
137           (burtcInit->debugRun << _BURTC_CTRL_DEBUGRUN_SHIFT) |
138           (burtcInit->compare0Top << _BURTC_CTRL_COMP0TOP_SHIFT) |
139           (burtcInit->lowPowerComp << _BURTC_CTRL_LPCOMP_SHIFT) |
140           (presc << _BURTC_CTRL_PRESC_SHIFT) |
141           (burtcInit->clkSel) |
142           (burtcInit->timeStamp << _BURTC_CTRL_BUMODETSEN_SHIFT));
143 
144   /* Clear interrupts */
145   BURTC->IFC = 0xFFFFFFFF;
146 
147   /* Set new configuration */
148   BURTC->CTRL = ctrl;
149 
150   /* Enable BURTC and counter */
151   if (burtcInit->enable)
152   {
153     /* To enable BURTC counter, we need to disable reset */
154     BURTC_Enable(true);
155 
156     /* Clear freeze */
157     BURTC_FreezeEnable(false);
158 
159     /* Await synchronization into low frequency domain */
160     while (BURTC->SYNCBUSY) ;
161   }
162 }
163 
164 
165 /***************************************************************************//**
166  * @brief Set BURTC compare channel
167  *
168  * @param[in] comp Compare channel index, must be 0 for Giant / Leopard Gecko
169  *
170  * @param[in] value New compare value
171  ******************************************************************************/
BURTC_CompareSet(unsigned int comp,uint32_t value)172 void BURTC_CompareSet(unsigned int comp, uint32_t value)
173 {
174   EFM_ASSERT(comp == 0);
175 
176   /* Configure compare channel 0 */
177   BURTC->COMP0 = value;
178 
179   /* Check if freeze or RSTEN is active, if not wait for synchronization of register */
180   if (BURTC->FREEZE & BURTC_FREEZE_REGFREEZE_FREEZE)
181   {
182     return;
183   }
184   /* Check if mode is enabled */
185   if ((BURTC->CTRL & _BURTC_CTRL_MODE_MASK) == BURTC_CTRL_MODE_DISABLE)
186   {
187     return;
188   }
189 
190   while (BURTC->SYNCBUSY & BURTC_SYNCBUSY_COMP0) ;
191 }
192 
193 
194 /***************************************************************************//**
195  * @brief Get BURTC compare value
196  *
197  * @param[in] comp Compare channel index value, must be 0 for Giant/Leopard.
198  *
199  * @return Currently configured value for this compare channel
200  ******************************************************************************/
BURTC_CompareGet(unsigned int comp)201 uint32_t BURTC_CompareGet(unsigned int comp)
202 {
203   EFM_ASSERT(comp == 0);
204 
205   return BURTC->COMP0;
206 }
207 
208 
209 /***************************************************************************//**
210  * @brief Reset counter
211  *
212  * @param[in] mode New mode of operation, after clearing
213  ******************************************************************************/
BURTC_CounterReset(void)214 void BURTC_CounterReset(void)
215 {
216   /* Set and clear reset bit */
217   BITBAND_Peripheral(&BURTC->CTRL, _BURTC_CTRL_RSTEN_SHIFT, 1);
218   BITBAND_Peripheral(&BURTC->CTRL, _BURTC_CTRL_RSTEN_SHIFT, 0);
219 }
220 
221 
222 /***************************************************************************//**
223  * @brief
224  *   Restore BURTC to reset state
225  * @note
226  *   Before accessing the BURTC, BURSTEN in RMU->CTRL must be cleared.
227  *   LOCK will not be reset to default value, as this will disable access
228  *   to core BURTC registers.
229  ******************************************************************************/
BURTC_Reset(void)230 void BURTC_Reset(void)
231 {
232   /* Verify RMU BURSTEN is disabled */
233   EFM_ASSERT((RMU->CTRL & RMU_CTRL_BURSTEN) == 0);
234 
235   /* Restore all essential BURTC registers to default config */
236   BURTC->CTRL      = _BURTC_CTRL_RESETVALUE;
237   BURTC->IEN       = _BURTC_IEN_RESETVALUE;
238   BURTC->LPMODE    = _BURTC_LPMODE_RESETVALUE;
239   BURTC->LFXOFDET  = _BURTC_LFXOFDET_RESETVALUE;
240   BURTC->POWERDOWN = _BURTC_POWERDOWN_RESETVALUE;
241   BURTC->FREEZE    = _BURTC_FREEZE_RESETVALUE;
242 }
243 
244 
245 /** @} (end addtogroup BURTC) */
246 /** @} (end addtogroup EM_Library) */
247 
248 #endif /* BURTC_PRESENT */
249