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