1 /***************************************************************************//**
2  * @file
3  * @brief Ultra Low Energy Timer/Counter (CRYOTIMER) peripheral API
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 
31 #ifndef EM_CRYOTIMER_H
32 #define EM_CRYOTIMER_H
33 
34 #include <stdbool.h>
35 #include "em_device.h"
36 #include "em_bus.h"
37 
38 #if defined(CRYOTIMER_PRESENT) && (CRYOTIMER_COUNT == 1)
39 
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43 
44 /***************************************************************************//**
45  * @addtogroup cryotimer CRYOTIMER - Ultra Low Energy Timer
46  * @brief Ultra Low Energy Timer/Counter (CRYOTIMER) Peripheral API
47  *
48  * @details
49  *   The CRYOTIMER is a 32 bit counter, which operates on a low-frequency
50  *   oscillator and is capable of running in all Energy Modes. It can provide
51  *   periodic wakeup events and PRS signals, which can be used to wake up
52  *   peripherals from any energy mode. The CRYOTIMER provides a wide range
53  *   of periods for the interrupts facilitating flexible ultra-low energy
54  *   operation. Because of its simplicity, the CRYOTIMER is a lower energy
55  *   solution for periodically waking up the MCU compared to the RTCC.
56  *
57  *   To configure the CRYOTIMER, call the @ref CRYOTIMER_Init function.
58  *   This function will configure the CRYOTIMER peripheral according to the
59  *   user configuration.
60  *
61  * @details
62  *   When using the CRYOTIMER, choose which oscillator to use
63  *   as the CRYOTIMER clock. The CRYOTIMER supports 3 low-frequency clocks
64  *   LFXO, LFRCO, and ULFRCO. The oscillator that is chosen must be
65  *   enabled and ready before calling this @ref CRYOTIMER_Init function.
66  *   See @ref CMU_OscillatorEnable for details of how to enable and wait for an
67  *   oscillator to become ready. Note that ULFRCO is always ready while LFRCO
68  *   @ref cmuOsc_LFRCO and LFXO @ref cmuOsc_LFXO must be enabled by the user.
69  *
70  * @details
71  *   Note that the only oscillator which is running in EM3 is ULFRCO. Keep this
72  *   in mind when choosing which oscillator to use for the CRYOTIMER.
73  *
74  *   This example shows how to use the CRYOTIMER to generate an interrupt
75  *   at a configurable period.
76  *
77  * @include em_cryotimer_period.c
78  *
79  * @details
80  *   To use the CRYOTIMER in EM4, enable EM4 wakeup in the
81  *   CRYOTIMER. This can be done either in the @ref CRYOTIMER_Init_TypeDef
82  *   structure when initializing the CRYOTIMER or at a later time by using
83  *   @ref CRYOTIMER_EM4WakeupEnable.
84  *
85  *   Note that when using the CRYOTIMER to wake up from EM4, the application has
86  *   the responsibility to clear the wakeup event by calling
87  *   @ref CRYOTIMER_IntClear. If the you do not clear the wakeup event,
88  *   the wakeup event will stay pending and will cause an immediate wakeup the
89  *   next time the application attempts to enter EM4.
90  *
91  *   This example shows how to use the CRYOTIMER to wake up from EM4 after
92  *   a configurable amount of time.
93  *
94  * @include em_cryotimer_em4.c
95  *
96  * @details
97  *   All the low frequency oscillators can be used in EM4, however, the
98  *   oscillator that is used must be be configured to be retained when going
99  *   into EM4 by using functions in the @ref emu module.
100  *   See @ref EMU_EM4Init and @ref EMU_EM4Init_TypeDef. If an oscillator is
101  *   retained in EM4, users are also responsible for unlatching the retained
102  *   configuration on a wakeup from EM4.
103  *
104  * @{
105  ******************************************************************************/
106 
107 /*******************************************************************************
108  *********************************   ENUM   ************************************
109  ******************************************************************************/
110 
111 /** Prescaler selection. */
112 typedef enum {
113   cryotimerPresc_1     = _CRYOTIMER_CTRL_PRESC_DIV1,      /**< Divide clock by 1. */
114   cryotimerPresc_2     = _CRYOTIMER_CTRL_PRESC_DIV2,      /**< Divide clock by 2. */
115   cryotimerPresc_4     = _CRYOTIMER_CTRL_PRESC_DIV4,      /**< Divide clock by 4. */
116   cryotimerPresc_8     = _CRYOTIMER_CTRL_PRESC_DIV8,      /**< Divide clock by 8. */
117   cryotimerPresc_16    = _CRYOTIMER_CTRL_PRESC_DIV16,     /**< Divide clock by 16. */
118   cryotimerPresc_32    = _CRYOTIMER_CTRL_PRESC_DIV32,     /**< Divide clock by 32. */
119   cryotimerPresc_64    = _CRYOTIMER_CTRL_PRESC_DIV64,     /**< Divide clock by 64. */
120   cryotimerPresc_128   = _CRYOTIMER_CTRL_PRESC_DIV128,    /**< Divide clock by 128. */
121 } CRYOTIMER_Presc_TypeDef;
122 
123 /** Low frequency oscillator selection. */
124 typedef enum {
125   cryotimerOscLFRCO   = _CRYOTIMER_CTRL_OSCSEL_LFRCO,  /**< Select Low-frequency RC Oscillator. */
126   cryotimerOscLFXO    = _CRYOTIMER_CTRL_OSCSEL_LFXO,   /**< Select Low-frequency Crystal Oscillator. */
127   cryotimerOscULFRCO  = _CRYOTIMER_CTRL_OSCSEL_ULFRCO, /**< Select Ultra Low Frequency RC Oscillator. */
128 } CRYOTIMER_Osc_TypeDef;
129 
130 /** Period selection value */
131 typedef enum {
132   cryotimerPeriod_1     = 0,    /**< Wakeup event after every Pre-scaled clock cycle. */
133   cryotimerPeriod_2     = 1,    /**< Wakeup event after 2 Pre-scaled clock cycles. */
134   cryotimerPeriod_4     = 2,    /**< Wakeup event after 4 Pre-scaled clock cycles. */
135   cryotimerPeriod_8     = 3,    /**< Wakeup event after 8 Pre-scaled clock cycles. */
136   cryotimerPeriod_16    = 4,    /**< Wakeup event after 16 Pre-scaled clock cycles. */
137   cryotimerPeriod_32    = 5,    /**< Wakeup event after 32 Pre-scaled clock cycles. */
138   cryotimerPeriod_64    = 6,    /**< Wakeup event after 64 Pre-scaled clock cycles. */
139   cryotimerPeriod_128   = 7,    /**< Wakeup event after 128 Pre-scaled clock cycles. */
140   cryotimerPeriod_256   = 8,    /**< Wakeup event after 256 Pre-scaled clock cycles. */
141   cryotimerPeriod_512   = 9,    /**< Wakeup event after 512 Pre-scaled clock cycles. */
142   cryotimerPeriod_1k    = 10,   /**< Wakeup event after 1k Pre-scaled clock cycles. */
143   cryotimerPeriod_2k    = 11,   /**< Wakeup event after 2k Pre-scaled clock cycles. */
144   cryotimerPeriod_4k    = 12,   /**< Wakeup event after 4k Pre-scaled clock cycles. */
145   cryotimerPeriod_8k    = 13,   /**< Wakeup event after 8k Pre-scaled clock cycles. */
146   cryotimerPeriod_16k   = 14,   /**< Wakeup event after 16k Pre-scaled clock cycles. */
147   cryotimerPeriod_32k   = 15,   /**< Wakeup event after 32k Pre-scaled clock cycles. */
148   cryotimerPeriod_64k   = 16,   /**< Wakeup event after 64k Pre-scaled clock cycles. */
149   cryotimerPeriod_128k  = 17,   /**< Wakeup event after 128k Pre-scaled clock cycles. */
150   cryotimerPeriod_256k  = 18,   /**< Wakeup event after 256k Pre-scaled clock cycles. */
151   cryotimerPeriod_512k  = 19,   /**< Wakeup event after 512k Pre-scaled clock cycles. */
152   cryotimerPeriod_1m    = 20,   /**< Wakeup event after 1m Pre-scaled clock cycles. */
153   cryotimerPeriod_2m    = 21,   /**< Wakeup event after 2m Pre-scaled clock cycles. */
154   cryotimerPeriod_4m    = 22,   /**< Wakeup event after 4m Pre-scaled clock cycles. */
155   cryotimerPeriod_8m    = 23,   /**< Wakeup event after 8m Pre-scaled clock cycles. */
156   cryotimerPeriod_16m   = 24,   /**< Wakeup event after 16m Pre-scaled clock cycles. */
157   cryotimerPeriod_32m   = 25,   /**< Wakeup event after 32m Pre-scaled clock cycles. */
158   cryotimerPeriod_64m   = 26,   /**< Wakeup event after 64m Pre-scaled clock cycles. */
159   cryotimerPeriod_128m  = 27,   /**< Wakeup event after 128m Pre-scaled clock cycles. */
160   cryotimerPeriod_256m  = 28,   /**< Wakeup event after 256m Pre-scaled clock cycles. */
161   cryotimerPeriod_512m  = 29,   /**< Wakeup event after 512m Pre-scaled clock cycles. */
162   cryotimerPeriod_1024m = 30,   /**< Wakeup event after 1024m Pre-scaled clock cycles. */
163   cryotimerPeriod_2048m = 31,   /**< Wakeup event after 2048m Pre-scaled clock cycles. */
164   cryotimerPeriod_4096m = 32,   /**< Wakeup event after 4096m Pre-scaled clock cycles. */
165 } CRYOTIMER_Period_TypeDef;
166 
167 /*******************************************************************************
168  *******************************   STRUCTURES   ***********************************
169  ******************************************************************************/
170 
171 /** CRYOTIMER initialization structure. */
172 typedef struct {
173   /** Enable/disable counting when initialization is complete. */
174   bool                      enable;
175 
176   /** Enable/disable timer counting during debug halt. */
177   bool                      debugRun;
178 
179   /** Enable/disable EM4 Wakeup. */
180   bool                      em4Wakeup;
181 
182   /** Select the oscillator for the CRYOTIMER. */
183   CRYOTIMER_Osc_TypeDef     osc;
184 
185   /** Prescaler. */
186   CRYOTIMER_Presc_TypeDef   presc;
187 
188   /** A period between a wakeup event/interrupt. */
189   CRYOTIMER_Period_TypeDef  period;
190 } CRYOTIMER_Init_TypeDef;
191 
192 /*******************************************************************************
193  *******************************   DEFINES   ***********************************
194  ******************************************************************************/
195 
196 /** Default CRYOTIMER init structure. */
197 #define CRYOTIMER_INIT_DEFAULT                                                                      \
198   {                                                                                                 \
199     true,                  /* Start counting when the initialization is done.                    */ \
200     false,                 /* Disable CRYOTIMER during debug halt.              */                  \
201     false,                 /* Disable EM4 wakeup.                               */                  \
202     cryotimerOscLFRCO,     /* Select Low Frequency RC Oscillator.               */                  \
203     cryotimerPresc_1,      /* LF Oscillator frequency undivided.                */                  \
204     cryotimerPeriod_4096m, /* Wakeup event after 4096 M pre-scaled clock cycles. */                 \
205   }
206 
207 /*******************************************************************************
208  *****************************   PROTOTYPES   **********************************
209  ******************************************************************************/
210 
211 /***************************************************************************//**
212  * @brief
213  *   Clear the CRYOTIMER period interrupt.
214  *
215  * @param[in] flags
216  *   CRYOTIMER interrupt sources to clear. Use CRYOTIMER_IFC_PERIOD.
217  ******************************************************************************/
CRYOTIMER_IntClear(uint32_t flags)218 __STATIC_INLINE void CRYOTIMER_IntClear(uint32_t flags)
219 {
220   CRYOTIMER->IFC = flags & _CRYOTIMER_IFC_MASK;
221 }
222 
223 /***************************************************************************//**
224  * @brief
225  *   Get the CRYOTIMER interrupt flag.
226  *
227  * @note
228  *   This function does not clear event bits.
229  *
230  * @return
231  *   Pending CRYOTIMER interrupt sources. The only interrupt source available
232  *   for the CRYOTIMER is CRYOTIMER_IF_PERIOD.
233  ******************************************************************************/
CRYOTIMER_IntGet(void)234 __STATIC_INLINE uint32_t CRYOTIMER_IntGet(void)
235 {
236   return CRYOTIMER->IF;
237 }
238 
239 /***************************************************************************//**
240  * @brief
241  *   Get enabled and pending CRYOTIMER interrupt flags.
242  *   Useful for handling more interrupt sources in the same interrupt handler.
243  *
244  * @note
245  *    This function does not clear interrupt flags.
246  *
247  * @return
248  *   Pending and enabled CRYOTIMER interrupt sources.
249  *   The return value is the bitwise AND of
250  *   - the enabled interrupt sources in CRYOTIMER_IEN and
251  *   - the pending interrupt flags CRYOTIMER_IF
252  ******************************************************************************/
CRYOTIMER_IntGetEnabled(void)253 __STATIC_INLINE uint32_t CRYOTIMER_IntGetEnabled(void)
254 {
255   uint32_t ien;
256 
257   ien = CRYOTIMER->IEN & _CRYOTIMER_IEN_MASK;
258   return CRYOTIMER->IF & ien;
259 }
260 
261 /***************************************************************************//**
262  * @brief
263  *   Enable one or more CRYOTIMER interrupts.
264  *
265  * @param[in] flags
266  *   CRYOTIMER interrupt sources to enable. Use CRYOTIMER_IEN_PERIOD.
267  ******************************************************************************/
CRYOTIMER_IntEnable(uint32_t flags)268 __STATIC_INLINE void CRYOTIMER_IntEnable(uint32_t flags)
269 {
270   CRYOTIMER->IEN |= (flags & _CRYOTIMER_IEN_MASK);
271 }
272 
273 /***************************************************************************//**
274  * @brief
275  *   Disable one or more CRYOTIMER interrupts.
276  *
277  * @param[in] flags
278  *   CRYOTIMER interrupt sources to disable. Use CRYOTIMER_IEN_PERIOD.
279  ******************************************************************************/
CRYOTIMER_IntDisable(uint32_t flags)280 __STATIC_INLINE void CRYOTIMER_IntDisable(uint32_t flags)
281 {
282   CRYOTIMER->IEN &= ~(flags & _CRYOTIMER_IEN_MASK);
283 }
284 
285 /***************************************************************************//**
286  * @brief
287  *   Set the CRYOTIMER period interrupt flag.
288  *
289  * @note
290  *   Writes 1 to the interrupt flag set register.
291  *
292  * @param[in] flags
293  *   CRYOTIMER interrupt sources to set to pending. Use
294  *   CRYOTIMER_IFS_PERIOD.
295  ******************************************************************************/
CRYOTIMER_IntSet(uint32_t flags)296 __STATIC_INLINE void CRYOTIMER_IntSet(uint32_t flags)
297 {
298   CRYOTIMER->IFS = flags & _CRYOTIMER_IFS_MASK;
299 }
300 
301 /***************************************************************************//**
302  * @brief
303  *   Set the CRYOTIMER period select.
304  *
305  * @note
306  *   Sets the duration between the interrupts/wakeup events based on
307  *   the pre-scaled clock.
308  *
309  * @param[in] period
310  *   2^period is the number of clock cycles before a wakeup event or
311  *   interrupt is triggered. The CRYOTIMER_Periodsel_TypeDef enumeration can
312  *   be used a convenience type when calling this function.
313  ******************************************************************************/
CRYOTIMER_PeriodSet(uint32_t period)314 __STATIC_INLINE void CRYOTIMER_PeriodSet(uint32_t period)
315 {
316   CRYOTIMER->PERIODSEL = period & _CRYOTIMER_PERIODSEL_MASK;
317 }
318 
319 /***************************************************************************//**
320  * @brief
321  *   Get the CRYOTIMER period select value.
322  *
323  * @note
324  *   Gets the duration between the interrupts/wakeup events in the
325  *   CRYOTIMER.
326  *
327  * @return
328  *   Duration between the interrupts/wakeup events. Returns the value
329  *   of the PERIODSEL register. The number of clock cycles can be calculated
330  *   as the 2^n where n is the return value of this function.
331  ******************************************************************************/
CRYOTIMER_PeriodGet(void)332 __STATIC_INLINE uint32_t CRYOTIMER_PeriodGet(void)
333 {
334   return CRYOTIMER->PERIODSEL;
335 }
336 
337 /***************************************************************************//**
338  * @brief
339  *   Get the CRYOTIMER counter value.
340  *
341  * @return
342  *   Returns the current CRYOTIMER counter value.
343  ******************************************************************************/
CRYOTIMER_CounterGet(void)344 __STATIC_INLINE uint32_t CRYOTIMER_CounterGet(void)
345 {
346   return CRYOTIMER->CNT;
347 }
348 
349 /***************************************************************************//**
350  * @brief
351  *   Enable/disable EM4 wakeup capability.
352  *
353  * @param[in] enable
354  *   True to enable EM4 wakeup, false to disable.
355  ******************************************************************************/
CRYOTIMER_EM4WakeupEnable(bool enable)356 __STATIC_INLINE void CRYOTIMER_EM4WakeupEnable(bool enable)
357 {
358   BUS_RegBitWrite((&CRYOTIMER->EM4WUEN),
359                   _CRYOTIMER_EM4WUEN_EM4WU_SHIFT,
360                   (uint32_t)enable);
361 }
362 
363 /***************************************************************************//**
364  * @brief
365  *   Enable/disable the CRYOTIMER.
366  *
367  * @param[in] enable
368  *   True to enable the CRYOTIMER, false to disable.
369  ******************************************************************************/
CRYOTIMER_Enable(bool enable)370 __STATIC_INLINE void CRYOTIMER_Enable(bool enable)
371 {
372   BUS_RegBitWrite((&CRYOTIMER->CTRL),
373                   _CRYOTIMER_CTRL_EN_SHIFT,
374                   (uint32_t)enable);
375 }
376 
377 /***************************************************************************//**
378  * @brief
379  *   Initialize the CRYOTIMER.
380  *
381  * @details
382  *   Use this function to initialize the CRYOTIMER.
383  *   Select a prescaler setting and select a low-frequency oscillator.
384  *   See the configuration structure @ref CRYOTIMER_Init_TypeDef for more
385  *   details.
386  *
387  * @param[in] init
388  *   A pointer to the initialization structure.
389  ******************************************************************************/
390 void CRYOTIMER_Init(const CRYOTIMER_Init_TypeDef *init);
391 
392 #ifdef __cplusplus
393 }
394 #endif
395 
396 /** @} (end addtogroup cryotimer) */
397 
398 #endif /* defined(CRYOTIMER_PRESENT) && (CRYOTIMER_COUNT == 1) */
399 #endif /* EM_CRYOTIMER_H */
400