1 /***************************************************************************//**
2  * @file
3  * @brief Low Energy Timer (LETIMER) 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_LETIMER_H
32 #define EM_LETIMER_H
33 
34 #include <stdbool.h>
35 #include "em_device.h"
36 #if defined(LETIMER_COUNT) && (LETIMER_COUNT > 0)
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 
42 /***************************************************************************//**
43  * @addtogroup letimer
44  * @{
45  ******************************************************************************/
46 
47 /*******************************************************************************
48  ********************************   ENUMS   ************************************
49  ******************************************************************************/
50 
51 /** Repeat mode. */
52 typedef enum {
53   /** Count until stopped by SW. */
54   letimerRepeatFree     = _LETIMER_CTRL_REPMODE_FREE,
55   /** Count REP0 times. */
56   letimerRepeatOneshot  = _LETIMER_CTRL_REPMODE_ONESHOT,
57   /**
58    * Count REP0 times, if REP1 has been written to, it is loaded into
59    * REP0 when REP0 is about to be decremented to 0.
60    */
61   letimerRepeatBuffered = _LETIMER_CTRL_REPMODE_BUFFERED,
62   /**
63    * Run as long as both REP0 and REP1 are not 0. Both REP0 and REP1
64    * are decremented when counter underflows.
65    */
66   letimerRepeatDouble   = _LETIMER_CTRL_REPMODE_DOUBLE
67 } LETIMER_RepeatMode_TypeDef;
68 
69 /** Underflow action on output. */
70 typedef enum {
71   /** No output action. */
72   letimerUFOANone   = _LETIMER_CTRL_UFOA0_NONE,
73   /** Toggle output when counter underflows. */
74   letimerUFOAToggle = _LETIMER_CTRL_UFOA0_TOGGLE,
75   /** Hold output one LETIMER clock cycle when counter underflows. */
76   letimerUFOAPulse  = _LETIMER_CTRL_UFOA0_PULSE,
77   /** Set output idle when counter underflows, and active when matching COMP1. */
78   letimerUFOAPwm    = _LETIMER_CTRL_UFOA0_PWM
79 } LETIMER_UFOA_TypeDef;
80 
81 /*******************************************************************************
82  *******************************   STRUCTS   ***********************************
83  ******************************************************************************/
84 
85 /** LETIMER initialization structure. */
86 typedef struct {
87   bool                       enable;         /**< Start counting when initialization completes. */
88   bool                       debugRun;       /**< Counter shall keep running during debug halt. */
89 #if defined(LETIMER_CTRL_RTCC0TEN)
90   bool                       rtcComp0Enable; /**< Start counting on RTC COMP0 match. */
91   bool                       rtcComp1Enable; /**< Start counting on RTC COMP1 match. */
92 #endif
93   bool                       comp0Top;       /**< Load COMP0 register into CNT when counter underflows. */
94   bool                       bufTop;         /**< Load COMP1 into COMP0 when REP0 reaches 0. */
95   uint8_t                    out0Pol;        /**< Idle value for output 0. */
96   uint8_t                    out1Pol;        /**< Idle value for output 1. */
97   LETIMER_UFOA_TypeDef       ufoa0;          /**< Underflow output 0 action. */
98   LETIMER_UFOA_TypeDef       ufoa1;          /**< Underflow output 1 action. */
99   LETIMER_RepeatMode_TypeDef repMode;        /**< Repeat mode. */
100   uint32_t                   topValue;       /**< Top value. Counter wraps when top value matches counter value is reached. */
101 } LETIMER_Init_TypeDef;
102 
103 /** Default configuration for LETIMER initialization structure. */
104 #if defined(LETIMER_CTRL_RTCC0TEN)
105 #define LETIMER_INIT_DEFAULT                                                   \
106   {                                                                            \
107     true,              /* Enable timer when initialization completes. */       \
108     false,             /* Stop counter during debug halt. */                   \
109     false,             /* Do not start counting on RTC COMP0 match. */         \
110     false,             /* Do not start counting on RTC COMP1 match. */         \
111     false,             /* Do not load COMP0 into CNT on underflow. */          \
112     false,             /* Do not load COMP1 into COMP0 when REP0 reaches 0. */ \
113     0,                 /* Idle value 0 for output 0. */                        \
114     0,                 /* Idle value 0 for output 1. */                        \
115     letimerUFOANone,   /* No action on underflow on output 0. */               \
116     letimerUFOANone,   /* No action on underflow on output 1. */               \
117     letimerRepeatFree, /* Count until stopped by SW. */                        \
118     0                  /* Use default top Value. */                            \
119   }
120 #else
121 #define LETIMER_INIT_DEFAULT                                                   \
122   {                                                                            \
123     true,              /* Enable timer when initialization completes. */       \
124     false,             /* Stop counter during debug halt. */                   \
125     false,             /* Do not load COMP0 into CNT on underflow. */          \
126     false,             /* Do not load COMP1 into COMP0 when REP0 reaches 0. */ \
127     0,                 /* Idle value 0 for output 0. */                        \
128     0,                 /* Idle value 0 for output 1. */                        \
129     letimerUFOANone,   /* No action on underflow on output 0. */               \
130     letimerUFOANone,   /* No action on underflow on output 1. */               \
131     letimerRepeatFree, /* Count until stopped by SW. */                        \
132     0                  /* Use default top Value. */                            \
133   }
134 #endif
135 
136 /*******************************************************************************
137  *****************************   PROTOTYPES   **********************************
138  ******************************************************************************/
139 
140 uint32_t LETIMER_CompareGet(LETIMER_TypeDef *letimer, unsigned int comp);
141 void LETIMER_CompareSet(LETIMER_TypeDef *letimer,
142                         unsigned int comp,
143                         uint32_t value);
144 uint32_t LETIMER_CounterGet(LETIMER_TypeDef *letimer);
145 #if !defined(_EFM32_GECKO_FAMILY)
146 void LETIMER_CounterSet(LETIMER_TypeDef *letimer, uint32_t value);
147 #endif
148 
149 void LETIMER_Enable(LETIMER_TypeDef *letimer, bool enable);
150 #if defined(_LETIMER_FREEZE_MASK)
151 void LETIMER_FreezeEnable(LETIMER_TypeDef *letimer, bool enable);
152 #endif
153 void LETIMER_Init(LETIMER_TypeDef *letimer, const LETIMER_Init_TypeDef *init);
154 
155 /***************************************************************************//**
156  * @brief
157  *   Clear one or more pending LETIMER interrupts.
158  *
159  * @param[in] letimer
160  *   Pointer to LETIMER peripheral register block.
161  *
162  * @param[in] flags
163  *   Pending LETIMER interrupt source to clear. Use a bitwise logic OR
164  *    combination of valid interrupt flags for the LETIMER module
165  *    (LETIMER_IF_nnn).
166  ******************************************************************************/
LETIMER_IntClear(LETIMER_TypeDef * letimer,uint32_t flags)167 __STATIC_INLINE void LETIMER_IntClear(LETIMER_TypeDef *letimer, uint32_t flags)
168 {
169 #if defined (LETIMER_HAS_SET_CLEAR)
170   letimer->IF_CLR = flags;
171 #else
172   letimer->IFC = flags;
173 #endif
174 }
175 
176 /***************************************************************************//**
177  * @brief
178  *   Disable one or more LETIMER interrupts.
179  *
180  * @param[in] letimer
181  *   Pointer to LETIMER peripheral register block.
182  *
183  * @param[in] flags
184  *   LETIMER interrupt sources to disable. Use a bitwise logic OR combination of
185  *   valid interrupt flags for the LETIMER module (LETIMER_IF_nnn).
186  ******************************************************************************/
LETIMER_IntDisable(LETIMER_TypeDef * letimer,uint32_t flags)187 __STATIC_INLINE void LETIMER_IntDisable(LETIMER_TypeDef *letimer, uint32_t flags)
188 {
189   letimer->IEN &= ~flags;
190 }
191 
192 /***************************************************************************//**
193  * @brief
194  *   Enable one or more LETIMER interrupts.
195  *
196  * @note
197  *   Depending on the use, a pending interrupt may already be set prior to
198  *   enabling the interrupt. To ignore a pending interrupt, consider using
199  *   LETIMER_IntClear() prior to enabling the interrupt.
200  *
201  * @param[in] letimer
202  *   Pointer to the LETIMER peripheral register block.
203  *
204  * @param[in] flags
205  *   LETIMER interrupt sources to enable. Use a bitwise logic OR combination of
206  *   valid interrupt flags for the LETIMER module (LETIMER_IF_nnn).
207  ******************************************************************************/
LETIMER_IntEnable(LETIMER_TypeDef * letimer,uint32_t flags)208 __STATIC_INLINE void LETIMER_IntEnable(LETIMER_TypeDef *letimer, uint32_t flags)
209 {
210   letimer->IEN |= flags;
211 }
212 
213 /***************************************************************************//**
214  * @brief
215  *   Get pending LETIMER interrupt flags.
216  *
217  * @note
218  *   Event bits are not cleared by the use of this function.
219  *
220  * @param[in] letimer
221  *   Pointer to LETIMER peripheral register block.
222  *
223  * @return
224  *   LETIMER interrupt sources pending. A bitwise logic OR combination of
225  *   valid interrupt flags for the LETIMER module (LETIMER_IF_nnn).
226  ******************************************************************************/
LETIMER_IntGet(LETIMER_TypeDef * letimer)227 __STATIC_INLINE uint32_t LETIMER_IntGet(LETIMER_TypeDef *letimer)
228 {
229   return letimer->IF;
230 }
231 
232 /***************************************************************************//**
233  * @brief
234  *   Get enabled and pending LETIMER interrupt flags.
235  *
236  * @details
237  *   Useful for handling more interrupt sources in the same interrupt handler.
238  *
239  * @note
240  *   Event bits are not cleared by the use of this function.
241  *
242  * @param[in] letimer
243  *   Pointer to LETIMER peripheral register block.
244  *
245  * @return
246  *   Pending and enabled LETIMER interrupt sources.
247  *   Return value is the bitwise AND combination of
248  *   - the OR combination of enabled interrupt sources in LETIMER_IEN_nnn
249  *   register (LETIMER_IEN_nnn) and
250  *   - the OR combination of valid interrupt flags of the LETIMER module
251  *   (LETIMER_IF_nnn).
252  ******************************************************************************/
LETIMER_IntGetEnabled(LETIMER_TypeDef * letimer)253 __STATIC_INLINE uint32_t LETIMER_IntGetEnabled(LETIMER_TypeDef *letimer)
254 {
255   uint32_t ien;
256 
257   /* Store flags in temporary variable in order to define explicit order
258    * of volatile accesses. */
259   ien = letimer->IEN;
260 
261   /* Bitwise AND of pending and enabled interrupts */
262   return letimer->IF & ien;
263 }
264 
265 /***************************************************************************//**
266  * @brief
267  *   Set one or more pending LETIMER interrupts from SW.
268  *
269  * @param[in] letimer
270  *   Pointer to LETIMER peripheral register block.
271  *
272  * @param[in] flags
273  *   LETIMER interrupt sources to set to pending. Use a bitwise logic OR
274  *   combination of valid interrupt flags for the LETIMER module (LETIMER_IF_nnn).
275  ******************************************************************************/
LETIMER_IntSet(LETIMER_TypeDef * letimer,uint32_t flags)276 __STATIC_INLINE void LETIMER_IntSet(LETIMER_TypeDef *letimer, uint32_t flags)
277 {
278 #if defined (LETIMER_HAS_SET_CLEAR)
279   letimer->IF_SET = flags;
280 #else
281   letimer->IFS = flags;
282 #endif
283 }
284 
285 #if defined(_LETIMER_LOCK_MASK)
286 /***************************************************************************//**
287  * @brief
288  *   Locks LETIMER registers.
289  *
290  * @param[in] letimer
291  *   Pointer to LETIMER peripheral register block.
292  *
293  * @note When LETIMER registers are locked LETIMER_EN, LETIMER_SWRST,
294  *            LETIMER_CTRL, LETIMER_CMD, LETIMER_CNT, LETIMER_COMPx,
295  *            LETIMER_TOP, LETIMER_TOPBUFF, LETIMER_REPx, and PRSMODE registers
296  *            cannot be written to.
297  ******************************************************************************/
LETIMER_Lock(LETIMER_TypeDef * letimer)298 __STATIC_INLINE void LETIMER_Lock(LETIMER_TypeDef *letimer)
299 {
300   letimer->LOCK = ~LETIMER_LOCK_LETIMERLOCKKEY_UNLOCK;
301 }
302 #endif
303 
304 #if defined(_LETIMER_LOCK_MASK)
305 /***************************************************************************//**
306  * @brief
307  *   Unlocks LETIMER registers.
308  *
309  * @param[in] letimer
310  *   Pointer to LETIMER peripheral register block.
311  ******************************************************************************/
LETIMER_Unlock(LETIMER_TypeDef * letimer)312 __STATIC_INLINE void LETIMER_Unlock(LETIMER_TypeDef *letimer)
313 {
314   letimer->LOCK = LETIMER_LOCK_LETIMERLOCKKEY_UNLOCK;
315 }
316 #endif
317 
318 uint32_t LETIMER_RepeatGet(LETIMER_TypeDef *letimer, unsigned int rep);
319 void LETIMER_RepeatSet(LETIMER_TypeDef *letimer,
320                        unsigned int rep,
321                        uint32_t value);
322 void LETIMER_Reset(LETIMER_TypeDef *letimer);
323 void LETIMER_SyncWait(LETIMER_TypeDef *letimer);
324 void LETIMER_TopSet(LETIMER_TypeDef *letimer, uint32_t value);
325 uint32_t LETIMER_TopGet(LETIMER_TypeDef *letimer);
326 
327 /** @} (end addtogroup letimer) */
328 
329 #ifdef __cplusplus
330 }
331 #endif
332 
333 #endif /* defined(LETIMER_COUNT) && (LETIMER_COUNT > 0) */
334 #endif /* EM_LETIMER_H */
335