1 /***************************************************************************//**
2 * @file
3 * @brief Timer/counter (TIMER) 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_timer.h"
34 #include "em_cmu.h"
35 #include "em_assert.h"
36
37 /***************************************************************************//**
38 * @addtogroup EM_Library
39 * @{
40 ******************************************************************************/
41
42 /***************************************************************************//**
43 * @addtogroup TIMER
44 * @brief Timer/Counter (TIMER) Peripheral API
45 * @details
46 * The timer module consists of three main parts:
47 * @li General timer config and enable control.
48 * @li Compare/capture control.
49 * @li Dead time insertion control (may not be available for all timers).
50 * @{
51 ******************************************************************************/
52
53 /*******************************************************************************
54 ******************************* DEFINES ***********************************
55 ******************************************************************************/
56
57 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
58
59
60 /** Validation of TIMER register block pointer reference for assert statements. */
61 #if (TIMER_COUNT == 1)
62 #define TIMER_REF_VALID(ref) ((ref) == TIMER0)
63 #elif (TIMER_COUNT == 2)
64 #define TIMER_REF_VALID(ref) (((ref) == TIMER0) || ((ref) == TIMER1))
65 #elif (TIMER_COUNT == 3)
66 #define TIMER_REF_VALID(ref) (((ref) == TIMER0) || \
67 ((ref) == TIMER1) || \
68 ((ref) == TIMER2))
69 #elif (TIMER_COUNT == 4)
70 #define TIMER_REF_VALID(ref) (((ref) == TIMER0) || \
71 ((ref) == TIMER1) || \
72 ((ref) == TIMER2) || \
73 ((ref) == TIMER3))
74 #else
75 #error Undefined number of timers.
76 #endif
77
78 /** Validation of TIMER compare/capture channel number */
79 #define TIMER_CH_VALID(ch) ((ch) < 3)
80
81 /** @endcond */
82
83
84 /*******************************************************************************
85 ************************** GLOBAL FUNCTIONS *******************************
86 ******************************************************************************/
87
88 /***************************************************************************//**
89 * @brief
90 * Start/stop TIMER.
91 *
92 * @param[in] timer
93 * Pointer to TIMER peripheral register block.
94 *
95 * @param[in] enable
96 * true to enable counting, false to disable.
97 ******************************************************************************/
TIMER_Enable(TIMER_TypeDef * timer,bool enable)98 void TIMER_Enable(TIMER_TypeDef *timer, bool enable)
99 {
100 EFM_ASSERT(TIMER_REF_VALID(timer));
101
102 if (enable)
103 {
104 timer->CMD = TIMER_CMD_START;
105 }
106 else
107 {
108 timer->CMD = TIMER_CMD_STOP;
109 }
110 }
111
112
113 /***************************************************************************//**
114 * @brief
115 * Initialize TIMER.
116 *
117 * @details
118 * Notice that counter top must be configured separately with for instance
119 * TIMER_TopSet(). In addition, compare/capture and dead-time insertion
120 * init must be initialized separately if used. That should probably
121 * be done prior to the use of this function if configuring the TIMER to
122 * start when initialization is completed.
123 *
124 * @param[in] timer
125 * Pointer to TIMER peripheral register block.
126 *
127 * @param[in] init
128 * Pointer to TIMER initialization structure.
129 ******************************************************************************/
TIMER_Init(TIMER_TypeDef * timer,const TIMER_Init_TypeDef * init)130 void TIMER_Init(TIMER_TypeDef *timer, const TIMER_Init_TypeDef *init)
131 {
132 EFM_ASSERT(TIMER_REF_VALID(timer));
133
134 /* Stop timer if specified to be disabled (dosn't hurt if already stopped) */
135 if (!(init->enable))
136 {
137 timer->CMD = TIMER_CMD_STOP;
138 }
139
140 /* Reset counter */
141 timer->CNT = _TIMER_CNT_RESETVALUE;
142
143 timer->CTRL =
144 ((uint32_t)(init->prescale) << _TIMER_CTRL_PRESC_SHIFT) |
145 ((uint32_t)(init->clkSel) << _TIMER_CTRL_CLKSEL_SHIFT) |
146 ((uint32_t)(init->fallAction) << _TIMER_CTRL_FALLA_SHIFT) |
147 ((uint32_t)(init->riseAction) << _TIMER_CTRL_RISEA_SHIFT) |
148 ((uint32_t)(init->mode) << _TIMER_CTRL_MODE_SHIFT) |
149 (init->debugRun ? TIMER_CTRL_DEBUGRUN : 0) |
150 (init->dmaClrAct ? TIMER_CTRL_DMACLRACT : 0) |
151 (init->quadModeX4 ? TIMER_CTRL_QDM_X4 : 0) |
152 (init->oneShot ? TIMER_CTRL_OSMEN : 0) |
153
154 #if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_TINY_FAMILY)
155 (init->count2x ? TIMER_CTRL_X2CNT : 0) |
156 (init->ati ? TIMER_CTRL_ATI : 0) |
157 #endif
158 (init->sync ? TIMER_CTRL_SYNC : 0);
159
160 /* Start timer if specified to be enabled (dosn't hurt if already started) */
161 if (init->enable)
162 {
163 timer->CMD = TIMER_CMD_START;
164 }
165 }
166
167
168 /***************************************************************************//**
169 * @brief
170 * Initialize TIMER compare/capture channel.
171 *
172 * @details
173 * Notice that if operating channel in compare mode, the CCV and CCVB register
174 * must be set separately as required.
175 *
176 * @param[in] timer
177 * Pointer to TIMER peripheral register block.
178 *
179 * @param[in] ch
180 * Compare/capture channel to init for.
181 *
182 * @param[in] init
183 * Pointer to TIMER initialization structure.
184 ******************************************************************************/
TIMER_InitCC(TIMER_TypeDef * timer,unsigned int ch,const TIMER_InitCC_TypeDef * init)185 void TIMER_InitCC(TIMER_TypeDef *timer,
186 unsigned int ch,
187 const TIMER_InitCC_TypeDef *init)
188 {
189 EFM_ASSERT(TIMER_REF_VALID(timer));
190 EFM_ASSERT(TIMER_CH_VALID(ch));
191
192 timer->CC[ch].CTRL =
193 ((uint32_t)(init->eventCtrl) << _TIMER_CC_CTRL_ICEVCTRL_SHIFT) |
194 ((uint32_t)(init->edge) << _TIMER_CC_CTRL_ICEDGE_SHIFT) |
195 ((uint32_t)(init->prsSel) << _TIMER_CC_CTRL_PRSSEL_SHIFT) |
196 ((uint32_t)(init->cufoa) << _TIMER_CC_CTRL_CUFOA_SHIFT) |
197 ((uint32_t)(init->cofoa) << _TIMER_CC_CTRL_COFOA_SHIFT) |
198 ((uint32_t)(init->cmoa) << _TIMER_CC_CTRL_CMOA_SHIFT) |
199 ((uint32_t)(init->mode) << _TIMER_CC_CTRL_MODE_SHIFT) |
200 (init->filter ? TIMER_CC_CTRL_FILT_ENABLE : 0) |
201 (init->prsInput ? TIMER_CC_CTRL_INSEL_PRS : 0) |
202 (init->coist ? TIMER_CC_CTRL_COIST : 0) |
203 (init->outInvert ? TIMER_CC_CTRL_OUTINV : 0);
204 }
205
206 #ifdef TIMER_DTLOCK_LOCKKEY_LOCK
207 /***************************************************************************//**
208 * @brief
209 * Lock the TIMER in order to protect some of its registers against unintended
210 * modification.
211 *
212 * @details
213 * Please refer to the reference manual for TIMER registers that will be
214 * locked.
215 *
216 * @note
217 * If locking the TIMER registers, they must be unlocked prior to using any
218 * TIMER API functions modifying TIMER registers protected by the lock.
219 *
220 * @param[in] timer
221 * Pointer to TIMER peripheral register block.
222 ******************************************************************************/
TIMER_Lock(TIMER_TypeDef * timer)223 void TIMER_Lock(TIMER_TypeDef *timer)
224 {
225 EFM_ASSERT(TIMER_REF_VALID(timer));
226
227 timer->DTLOCK = TIMER_DTLOCK_LOCKKEY_LOCK;
228 }
229 #endif
230
231 /***************************************************************************//**
232 * @brief
233 * Reset TIMER to same state as after a HW reset.
234 *
235 * @note
236 * The ROUTE register is NOT reset by this function, in order to allow for
237 * centralized setup of this feature.
238 *
239 * @param[in] timer
240 * Pointer to TIMER peripheral register block.
241 ******************************************************************************/
TIMER_Reset(TIMER_TypeDef * timer)242 void TIMER_Reset(TIMER_TypeDef *timer)
243 {
244 int i;
245
246 EFM_ASSERT(TIMER_REF_VALID(timer));
247
248 /* Make sure disabled first, before resetting other registers */
249 timer->CMD = TIMER_CMD_STOP;
250
251 timer->CTRL = _TIMER_CTRL_RESETVALUE;
252 timer->IEN = _TIMER_IEN_RESETVALUE;
253 timer->IFC = _TIMER_IFC_MASK;
254 timer->TOP = _TIMER_TOP_RESETVALUE;
255 timer->TOPB = _TIMER_TOPB_RESETVALUE;
256 timer->CNT = _TIMER_CNT_RESETVALUE;
257 /* Do not reset route register, setting should be done independently */
258 /* (Note: ROUTE register may be locked by DTLOCK register.) */
259
260 for (i = 0; TIMER_CH_VALID(i); i++)
261 {
262 timer->CC[i].CTRL = _TIMER_CC_CTRL_RESETVALUE;
263 timer->CC[i].CCV = _TIMER_CC_CCV_RESETVALUE;
264 timer->CC[i].CCVB = _TIMER_CC_CCVB_RESETVALUE;
265 }
266
267 /* Reset dead time insertion module, no effect on timers without DTI */
268
269 #ifdef TIMER_DTLOCK_LOCKKEY_UNLOCK
270 /* Unlock DTI registers first in case locked */
271 timer->DTLOCK = TIMER_DTLOCK_LOCKKEY_UNLOCK;
272
273 timer->DTCTRL = _TIMER_DTCTRL_RESETVALUE;
274 timer->DTTIME = _TIMER_DTTIME_RESETVALUE;
275 timer->DTFC = _TIMER_DTFC_RESETVALUE;
276 timer->DTOGEN = _TIMER_DTOGEN_RESETVALUE;
277 timer->DTFAULTC = _TIMER_DTFAULTC_MASK;
278 #endif
279 }
280
281
282 #ifdef TIMER_DTLOCK_LOCKKEY_UNLOCK
283 /***************************************************************************//**
284 * @brief
285 * Unlock the TIMER so that writing to locked registers again is possible.
286 *
287 * @param[in] timer
288 * Pointer to TIMER peripheral register block.
289 ******************************************************************************/
TIMER_Unlock(TIMER_TypeDef * timer)290 void TIMER_Unlock(TIMER_TypeDef *timer)
291 {
292 EFM_ASSERT(TIMER_REF_VALID(timer));
293
294 timer->DTLOCK = TIMER_DTLOCK_LOCKKEY_UNLOCK;
295 }
296 #endif
297
298
299 /** @} (end addtogroup TIMER) */
300 /** @} (end addtogroup EM_Library) */
301