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