1 /***************************************************************************//**
2 * @file
3 * @brief Real Time Counter (RTC) 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_rtc.h"
34 #include "em_assert.h"
35 #include "em_bitband.h"
36
37 /***************************************************************************//**
38 * @addtogroup EM_Library
39 * @{
40 ******************************************************************************/
41
42 /***************************************************************************//**
43 * @addtogroup RTC
44 * @brief Real Time Counter (RTC) Peripheral API
45 * @{
46 ******************************************************************************/
47
48 /*******************************************************************************
49 ******************************* DEFINES ***********************************
50 ******************************************************************************/
51
52 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
53
54 /** Validation of valid comparator register for assert statements. */
55 #define RTC_COMP_REG_VALID(reg) (((reg) <= 1))
56
57 /** @endcond */
58
59
60 /*******************************************************************************
61 ************************** LOCAL FUNCTIONS ********************************
62 ******************************************************************************/
63
64 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
65
66 #if defined(_EFM32_GECKO_FAMILY)
67 /***************************************************************************//**
68 * @brief
69 * Wait for ongoing sync of register(s) to low frequency domain to complete.
70 *
71 * @note
72 * This only applies to the Gecko Family, see the reference manual
73 * chapter about Access to Low Energy Peripherals (Asynchronos Registers)
74 * for details. For Tiny Gecko and Giant Gecko, the RTC supports immediate
75 * updates of registers, and will automatically hold the bus until the
76 * register has been updated.
77 *
78 * @param[in] mask
79 * Bitmask corresponding to SYNCBUSY register defined bits, indicating
80 * registers that must complete any ongoing synchronization.
81 ******************************************************************************/
RTC_Sync(uint32_t mask)82 __STATIC_INLINE void RTC_Sync(uint32_t mask)
83 {
84 /* Avoid deadlock if modifying the same register twice when freeze mode is */
85 /* activated. */
86 if (RTC->FREEZE & RTC_FREEZE_REGFREEZE)
87 return;
88
89 /* Wait for any pending previous write operation to have been completed */
90 /* in low frequency domain. This is only required for the Gecko Family */
91 while (RTC->SYNCBUSY & mask)
92 ;
93 }
94 #endif
95
96 /** @endcond */
97
98 /*******************************************************************************
99 ************************** GLOBAL FUNCTIONS *******************************
100 ******************************************************************************/
101
102 /***************************************************************************//**
103 * @brief
104 * Get RTC compare register value.
105 *
106 * @param[in] comp
107 * Compare register to get, either 0 or 1
108 *
109 * @return
110 * Compare register value, 0 if invalid register selected.
111 ******************************************************************************/
RTC_CompareGet(unsigned int comp)112 uint32_t RTC_CompareGet(unsigned int comp)
113 {
114 uint32_t ret;
115
116 EFM_ASSERT(RTC_COMP_REG_VALID(comp));
117
118 /* Initialize selected compare value */
119 switch (comp)
120 {
121 case 0:
122 ret = RTC->COMP0;
123 break;
124
125 case 1:
126 ret = RTC->COMP1;
127 break;
128
129 default:
130 /* Unknown compare register selected */
131 ret = 0;
132 break;
133 }
134
135 return ret;
136 }
137
138
139 /***************************************************************************//**
140 * @brief
141 * Set RTC compare register value.
142 *
143 * @note
144 * The setting of a compare register requires synchronization into the
145 * low frequency domain. If the same register is modified before a previous
146 * update has completed, this function will stall until the previous
147 * synchronization has completed. This only applies to the Gecko Family, see
148 * comment in the RTC_Sync() internal function call.
149 *
150 * @param[in] comp
151 * Compare register to set, either 0 or 1
152 *
153 * @param[in] value
154 * Initialization value (<= 0x00ffffff)
155 ******************************************************************************/
RTC_CompareSet(unsigned int comp,uint32_t value)156 void RTC_CompareSet(unsigned int comp, uint32_t value)
157 {
158 volatile uint32_t *compReg;
159 #if defined(_EFM32_GECKO_FAMILY)
160 uint32_t syncbusy;
161 #endif
162
163 EFM_ASSERT(RTC_COMP_REG_VALID(comp) &&
164 ((value & ~(_RTC_COMP0_COMP0_MASK >> _RTC_COMP0_COMP0_SHIFT)) == 0));
165
166 /* Initialize selected compare value */
167 switch (comp)
168 {
169 case 0:
170 compReg = &(RTC->COMP0);
171 #if defined(_EFM32_GECKO_FAMILY)
172 syncbusy = RTC_SYNCBUSY_COMP0;
173 #endif
174 break;
175
176 case 1:
177 compReg = &(RTC->COMP1);
178 #if defined(_EFM32_GECKO_FAMILY)
179 syncbusy = RTC_SYNCBUSY_COMP1;
180 #endif
181 break;
182
183 default:
184 /* Unknown compare register selected, abort */
185 return;
186 }
187 #if defined(_EFM32_GECKO_FAMILY)
188 /* LF register about to be modified require sync. busy check */
189 RTC_Sync(syncbusy);
190 #endif
191
192 *compReg = value;
193 }
194
195
196 /***************************************************************************//**
197 * @brief
198 * Enable/disable RTC.
199 *
200 * @note
201 * The enabling/disabling of the RTC modifies the RTC CTRL register which
202 * requires synchronization into the low frequency domain. If this register is
203 * modified before a previous update to the same register has completed, this
204 * function will stall until the previous synchronization has completed. This
205 * only applies to the Gecko Family, see comment in the RTC_Sync() internal
206 * function call.
207 *
208 * @param[in] enable
209 * true to enable counting, false to disable.
210 ******************************************************************************/
RTC_Enable(bool enable)211 void RTC_Enable(bool enable)
212 {
213 #if defined(_EFM32_GECKO_FAMILY)
214 /* LF register about to be modified require sync. busy check */
215 RTC_Sync(RTC_SYNCBUSY_CTRL);
216 #endif
217
218 BITBAND_Peripheral(&(RTC->CTRL), _RTC_CTRL_EN_SHIFT, (unsigned int) enable);
219 }
220
221
222 /***************************************************************************//**
223 * @brief
224 * RTC register synchronization freeze control.
225 *
226 * @details
227 * Some RTC registers require synchronization into the low frequency (LF)
228 * domain. The freeze feature allows for several such registers to be
229 * modified before passing them to the LF domain simultaneously (which
230 * takes place when the freeze mode is disabled).
231 *
232 * @note
233 * When enabling freeze mode, this function will wait for all current
234 * ongoing RTC synchronization to LF domain to complete (Normally
235 * synchronization will not be in progress.) However for this reason, when
236 * using freeze mode, modifications of registers requiring LF synchronization
237 * should be done within one freeze enable/disable block to avoid unecessary
238 * stalling. This only applies to the Gecko Family, see the reference manual
239 * chapter about Access to Low Energy Peripherals (Asynchronos Registers)
240 * for details.
241 *
242 * @param[in] enable
243 * @li true - enable freeze, modified registers are not propagated to the
244 * LF domain
245 * @li false - disables freeze, modified registers are propagated to LF
246 * domain
247 ******************************************************************************/
RTC_FreezeEnable(bool enable)248 void RTC_FreezeEnable(bool enable)
249 {
250 if (enable)
251 {
252 #if defined(_EFM32_GECKO_FAMILY)
253 /* Wait for any ongoing LF synchronization to complete. This is just to */
254 /* protect against the rare case when a user */
255 /* - modifies a register requiring LF sync */
256 /* - then enables freeze before LF sync completed */
257 /* - then modifies the same register again */
258 /* since modifying a register while it is in sync progress should be */
259 /* avoided. */
260 while (RTC->SYNCBUSY)
261 ;
262 #endif
263 RTC->FREEZE = RTC_FREEZE_REGFREEZE;
264 }
265 else
266 {
267 RTC->FREEZE = 0;
268 }
269 }
270
271
272 /***************************************************************************//**
273 * @brief
274 * Initialize RTC.
275 *
276 * @details
277 * Note that the compare values must be set separately with RTC_CompareSet().
278 * That should probably be done prior to the use of this function if
279 * configuring the RTC to start when initialization is completed.
280 *
281 * @note
282 * The initialization of the RTC modifies the RTC CTRL register which requires
283 * synchronization into the low frequency domain. If this register is
284 * modified before a previous update to the same register has completed, this
285 * function will stall until the previous synchronization has completed. This
286 * only applies to the Gecko Family, see comment in the RTC_Sync() internal
287 * function call.
288 *
289 * @param[in] init
290 * Pointer to RTC initialization structure.
291 ******************************************************************************/
RTC_Init(const RTC_Init_TypeDef * init)292 void RTC_Init(const RTC_Init_TypeDef *init)
293 {
294 uint32_t tmp;
295
296 if (init->enable)
297 {
298 tmp = RTC_CTRL_EN;
299 }
300 else
301 {
302 tmp = 0;
303 }
304
305 /* Configure DEBUGRUN flag, sets whether or not counter should be
306 * updated when debugger is active */
307 if (init->debugRun)
308 {
309 tmp |= RTC_CTRL_DEBUGRUN;
310 }
311
312 /* Configure COMP0TOP, this will use the COMP0 compare value as an
313 * overflow value, instead of default 24-bit 0x00ffffff */
314 if (init->comp0Top)
315 {
316 tmp |= RTC_CTRL_COMP0TOP;
317 }
318
319 #if defined(_EFM32_GECKO_FAMILY)
320 /* LF register about to be modified require sync. busy check */
321 RTC_Sync(RTC_SYNCBUSY_CTRL);
322 #endif
323
324 RTC->CTRL = tmp;
325 }
326
327
328
329 /***************************************************************************//**
330 * @brief
331 * Restore RTC to reset state
332 ******************************************************************************/
RTC_Reset(void)333 void RTC_Reset(void)
334 {
335 /* Restore all essential RTC register to default config */
336 RTC->FREEZE = _RTC_FREEZE_RESETVALUE;
337 RTC->CTRL = _RTC_CTRL_RESETVALUE;
338 RTC->COMP0 = _RTC_COMP0_RESETVALUE;
339 RTC->COMP1 = _RTC_COMP1_RESETVALUE;
340 RTC->IEN = _RTC_IEN_RESETVALUE;
341 RTC->IFC = _RTC_IFC_RESETVALUE;
342 }
343
344
345
346 /***************************************************************************//**
347 * @brief
348 * Restart RTC counter from zero
349 ******************************************************************************/
RTC_CounterReset(void)350 void RTC_CounterReset(void)
351 {
352 /* A disable/enable sequnce will start the counter at zero */
353 RTC_Enable(false);
354 RTC_Enable(true);
355 }
356
357
358 /** @} (end addtogroup RTC) */
359 /** @} (end addtogroup EM_Library) */
360