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