1 /**************************************************************************//**
2 * @file lptmr.c
3 * @brief LPTMR Controller (Low Power Timer) driver source file
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 * @copyright (C) 2023 Nuvoton Technology Corp. All rights reserved.
7 *****************************************************************************/
8 #include "NuMicro.h"
9
10
11 /** @addtogroup Standard_Driver Standard Driver
12 @{
13 */
14
15 /** @addtogroup LPTMR_Driver LPTMR Driver
16 @{
17 */
18
19 /** @addtogroup LPTMR_EXPORTED_FUNCTIONS LPTMR Exported Functions
20 @{
21 */
22
23 /**
24 * @brief Open LPTMR with Operate Mode and Frequency
25 *
26 * @param[in] lptmr The pointer of the specified LPTMR module. It could be LPTMR0, LPTMR1.
27 * @param[in] u32Mode Operation mode. Possible options are
28 * - \ref LPTMR_ONESHOT_MODE
29 * - \ref LPTMR_PERIODIC_MODE
30 * - \ref LPTMR_TOGGLE_MODE
31 * - \ref LPTMR_CONTINUOUS_MODE
32 * @param[in] u32Freq Target working frequency
33 *
34 * @return Real lptmr working frequency
35 *
36 * @details This API is used to configure lptmr to operate in specified mode and frequency.
37 * If lptmr cannot work in target frequency, a closest frequency will be chose and returned.
38 * @note After calling this API, LPTMR is \b NOT running yet. But could start lptmr running be calling
39 * \ref LPTMR_Start macro or program registers directly.
40 */
LPTMR_Open(LPTMR_T * lptmr,uint32_t u32Mode,uint32_t u32Freq)41 uint32_t LPTMR_Open(LPTMR_T *lptmr, uint32_t u32Mode, uint32_t u32Freq)
42 {
43 uint32_t u32Clk = LPTMR_GetModuleClock(lptmr);
44 uint32_t u32Cmpr = 0UL, u32Prescale = 0UL;
45
46 if (u32Freq == 0)
47 return 0;
48
49 /* Fastest possible lptmr working freq is (u32Clk / 2). While cmpr = 2, prescaler = 0. */
50 if(u32Freq > (u32Clk / 2UL))
51 {
52 u32Cmpr = 2UL;
53 }
54 else
55 {
56 u32Cmpr = u32Clk / u32Freq;
57 u32Prescale = (u32Cmpr >> 24); /* for 24 bits CMPDAT */
58 if (u32Prescale > 0UL)
59 u32Cmpr = u32Cmpr / (u32Prescale + 1UL);
60 }
61
62 lptmr->CTL = (u32Mode | u32Prescale);
63 lptmr->CMP = u32Cmpr;
64
65 return(u32Clk / (u32Cmpr * (u32Prescale + 1UL)));
66 }
67
68
69 /**
70 * @brief Stop LPTMR Counting
71 *
72 * @param[in] lptmr The pointer of the specified LPTMR module. It could be LPTMR0, LPTMR1.
73 *
74 * @return None
75 *
76 * @details This API stops lptmr counting and disable all lptmr interrupt function.
77 */
LPTMR_Close(LPTMR_T * lptmr)78 void LPTMR_Close(LPTMR_T *lptmr)
79 {
80 lptmr->CTL = 0UL;
81 lptmr->EXTCTL = 0UL;
82 }
83
84
85 /**
86 * @brief Create a specify Delay Time
87 *
88 * @param[in] lptmr The pointer of the specified LPTMR module. It could be LPTMR0, LPTMR1.
89 * @param[in] u32Usec Delay period in micro seconds. Valid values are between 100~1000000 (100 micro second ~ 1 second).
90 *
91 * @retval 0 Delay success, target delay time reached
92 * @retval LPTMR_TIMEOUT_ERR Delay function execute failed due to timer stop working
93 *
94 * @details This API is used to create a delay loop for u32usec micro seconds by using lptmr one-shot mode.
95 * @note This API overwrites the register setting of the lptmr used to count the delay time.
96 * @note This API use polling mode. So there is no need to enable interrupt for the lptmr module used to generate delay.
97 */
LPTMR_Delay(LPTMR_T * lptmr,uint32_t u32Usec)98 int32_t LPTMR_Delay(LPTMR_T *lptmr, uint32_t u32Usec)
99 {
100 uint32_t u32Clk = LPTMR_GetModuleClock(lptmr);
101 uint32_t u32Prescale = 0UL, u32Delay;
102 uint32_t u32Cmpr, u32Cntr, u32NsecPerTick, i = 0UL;
103
104 /* Clear current lptmr configuration */
105 lptmr->CTL = 0UL;
106 lptmr->EXTCTL = 0UL;
107
108 if(u32Clk <= 1000000UL) /* min delay is 1000 us if lptmr clock source is <= 1 MHz */
109 {
110 if(u32Usec < 1000UL)
111 {
112 u32Usec = 1000UL;
113 }
114 if(u32Usec > 1000000UL)
115 {
116 u32Usec = 1000000UL;
117 }
118 }
119 else
120 {
121 if(u32Usec < 100UL)
122 {
123 u32Usec = 100UL;
124 }
125 if(u32Usec > 1000000UL)
126 {
127 u32Usec = 1000000UL;
128 }
129 }
130
131 if(u32Clk <= 1000000UL)
132 {
133 u32Prescale = 0UL;
134 u32NsecPerTick = 1000000000UL / u32Clk;
135 u32Cmpr = (u32Usec * 1000UL) / u32NsecPerTick;
136 }
137 else
138 {
139 u32Cmpr = u32Usec * (u32Clk / 1000000UL);
140 u32Prescale = (u32Cmpr >> 24); /* for 24 bits CMPDAT */
141 if (u32Prescale > 0UL)
142 u32Cmpr = u32Cmpr / (u32Prescale + 1UL);
143 }
144
145 lptmr->CMP = u32Cmpr;
146 lptmr->CTL = LPTMR_CTL_CNTEN_Msk | LPTMR_ONESHOT_MODE | u32Prescale;
147
148 /* When system clock is faster than LPTMR clock, it is possible LPTMR active bit cannot set
149 in time while we check it. And the while loop below return immediately, so put a tiny
150 delay larger than 1 ECLK here allowing LPTMR start counting and raise active flag. */
151 for(u32Delay = (SystemCoreClock / u32Clk) + 1UL; u32Delay > 0UL; u32Delay--)
152 {
153 __NOP();
154 }
155
156 /* Add a bail out counter here in case timer clock source is disabled accidentally.
157 Prescale counter reset every ECLK * (prescale value + 1).
158 The u32Delay here is to make sure timer counter value changed when prescale counter reset */
159 u32Delay = (SystemCoreClock / LPTMR_GetModuleClock(lptmr)) * (u32Prescale + 1);
160 u32Cntr = lptmr->CNT;
161 i = 0;
162 while(lptmr->CTL & LPTMR_CTL_ACTSTS_Msk)
163 {
164 /* Bailed out if LPTMR stop counting e.g. Some interrupt handler close LPTMR clock source. */
165 if(u32Cntr == lptmr->CNT)
166 {
167 if(i++ > u32Delay)
168 {
169 return LPTMR_TIMEOUT_ERR;
170 }
171 }
172 else
173 {
174 i = 0;
175 u32Cntr = lptmr->CNT;
176 }
177 }
178 return 0;
179 }
180
181
182 /**
183 * @brief Enable LPTMR Capture Function
184 *
185 * @param[in] lptmr The pointer of the specified LPTMR module. It could be LPTMR0, LPTMR1.
186 * @param[in] u32CapMode LPTMR capture mode. Could be
187 * - \ref LPTMR_CAPTURE_FREE_COUNTING_MODE
188 * - \ref LPTMR_CAPTURE_COUNTER_RESET_MODE
189 * @param[in] u32Edge LPTMR capture trigger edge. Possible values are
190 * - \ref LPTMR_CAPTURE_EVENT_FALLING
191 * - \ref LPTMR_CAPTURE_EVENT_RISING
192 * - \ref LPTMR_CAPTURE_EVENT_FALLING_RISING
193 * - \ref LPTMR_CAPTURE_EVENT_RISING_FALLING
194 * - \ref LPTMR_CAPTURE_EVENT_GET_LOW_PERIOD
195 * - \ref LPTMR_CAPTURE_EVENT_GET_HIGH_PERIOD
196 *
197 * @return None
198 *
199 * @details This API is used to enable lptmr capture function with specify capture trigger edge \n
200 * to get current counter value or reset counter value to 0.
201 * @note LPTMR frequency should be configured separately by using \ref LPTMR_Open API, or program registers directly.
202 */
LPTMR_EnableCapture(LPTMR_T * lptmr,uint32_t u32CapMode,uint32_t u32Edge)203 void LPTMR_EnableCapture(LPTMR_T *lptmr, uint32_t u32CapMode, uint32_t u32Edge)
204 {
205 lptmr->EXTCTL = (lptmr->EXTCTL & ~(LPTMR_EXTCTL_CAPFUNCS_Msk | LPTMR_EXTCTL_CAPEDGE_Msk)) |
206 u32CapMode | u32Edge | LPTMR_EXTCTL_CAPEN_Msk;
207 }
208
209
210 /**
211 * @brief Disable LPTMR Capture Function
212 *
213 * @param[in] lptmr The pointer of the specified LPTMR module. It could be LPTMR0, LPTMR1.
214 *
215 * @return None
216 *
217 * @details This API is used to disable the lptmr capture function.
218 */
LPTMR_DisableCapture(LPTMR_T * lptmr)219 void LPTMR_DisableCapture(LPTMR_T *lptmr)
220 {
221 lptmr->EXTCTL &= ~LPTMR_EXTCTL_CAPEN_Msk;
222 }
223
224
225 /**
226 * @brief Enable LPTMR Counter Function
227 *
228 * @param[in] lptmr The pointer of the specified LPTMR module. It could be LPTMR0, LPTMR1.
229 * @param[in] u32Edge Detection edge of counter pin. Could be ether
230 * - \ref LPTMR_COUNTER_EVENT_FALLING
231 * - \ref LPTMR_COUNTER_EVENT_RISING
232 *
233 * @return None
234 *
235 * @details This function is used to enable the lptmr counter function with specify detection edge.
236 * @note LPTMR compare value should be configured separately by using \ref LPTMR_SET_CMP_VALUE macro or program registers directly.
237 * @note While using event counter function, \ref LPTMR_TOGGLE_MODE cannot set as lptmr operation mode.
238 */
LPTMR_EnableEventCounter(LPTMR_T * lptmr,uint32_t u32Edge)239 void LPTMR_EnableEventCounter(LPTMR_T *lptmr, uint32_t u32Edge)
240 {
241 lptmr->EXTCTL = (lptmr->EXTCTL & ~LPTMR_EXTCTL_CNTPHASE_Msk) | u32Edge;
242 lptmr->CTL |= LPTMR_CTL_EXTCNTEN_Msk;
243 }
244
245
246 /**
247 * @brief Disable LPTMR Counter Function
248 *
249 * @param[in] lptmr The pointer of the specified LPTMR module. It could be LPTMR0, LPTMR1.
250 *
251 * @return None
252 *
253 * @details This API is used to disable the lptmr event counter function.
254 */
LPTMR_DisableEventCounter(LPTMR_T * lptmr)255 void LPTMR_DisableEventCounter(LPTMR_T *lptmr)
256 {
257 lptmr->CTL &= ~LPTMR_CTL_EXTCNTEN_Msk;
258 }
259
260
261 /**
262 * @brief Get LPTMR Clock Frequency
263 *
264 * @param[in] lptmr The pointer of the specified LPTMR module. It could be LPTMR0, LPTMR1.
265 *
266 * @return LPTMR clock frequency
267 *
268 * @details This API is used to get the lptmr clock frequency.
269 * @note This API cannot return correct clock rate if lptmr source is from external clock input.
270 */
LPTMR_GetModuleClock(LPTMR_T * lptmr)271 uint32_t LPTMR_GetModuleClock(LPTMR_T *lptmr)
272 {
273 uint32_t u32Src, u32Clk;
274 const uint32_t au32Clk[] = {__HIRC, __MIRC, __LXT, __LIRC, 0UL, 0UL, 0UL, 0UL};
275
276 if(lptmr == LPTMR0)
277 {
278 u32Src = (LPSCC->CLKSEL0 & LPSCC_CLKSEL0_LPTMR0SEL_Msk) >> LPSCC_CLKSEL0_LPTMR0SEL_Pos;
279 }
280 else if(lptmr == LPTMR1)
281 {
282 u32Src = (LPSCC->CLKSEL0 & LPSCC_CLKSEL0_LPTMR1SEL_Msk) >> LPSCC_CLKSEL0_LPTMR1SEL_Pos;
283 }
284
285 u32Clk = au32Clk[u32Src];
286
287 return u32Clk;
288 }
289
290
291 /**
292 * @brief This function is used to select the interrupt source used to trigger other modules.
293 * @param[in] lptmr The base address of LPTMR module
294 * @param[in] u32Src Selects the interrupt source to trigger other modules. Could be:
295 * - \ref LPTMR_TRGSRC_TIMEOUT_EVENT
296 * - \ref LPTMR_TRGSRC_CAPTURE_EVENT
297 * @return None
298 */
LPTMR_SetTriggerSource(LPTMR_T * lptmr,uint32_t u32Src)299 void LPTMR_SetTriggerSource(LPTMR_T *lptmr, uint32_t u32Src)
300 {
301 lptmr->TRGCTL = (lptmr->TRGCTL & ~LPTMR_TRGCTL_TRGSSEL_Msk) | u32Src;
302 }
303
304
305 /**
306 * @brief This function is used to set modules trigger by lptmr interrupt
307 * @param[in] lptmr The base address of LPTMR module
308 * @param[in] u32Mask The mask of modules (Low power IPs and LPPDMA) trigger by lptmr. Is the combination of
309 * - \ref LPTMR_TRGEN
310 * - \ref LPTMR_TRG_TO_LPPDMA
311 * @return None
312 */
LPTMR_SetTriggerTarget(LPTMR_T * lptmr,uint32_t u32Mask)313 void LPTMR_SetTriggerTarget(LPTMR_T *lptmr, uint32_t u32Mask)
314 {
315 lptmr->TRGCTL = (lptmr->TRGCTL & ~(LPTMR_TRGCTL_TRGEN_Msk | LPTMR_TRGCTL_TRGLPPDMA_Msk)) | u32Mask;
316 }
317
318
319 /**
320 * @brief Select LPTMR Capture Source
321 *
322 * @param[in] lptmr The pointer of the specified LPTMR module.
323 * @param[in] u32Src LPTMR capture source. Possible values are
324 * - \ref LPTMR_CAPTURE_FROM_EXTERNAL
325 * - \ref LPTMR_CAPTURE_FROM_ACMP0
326 * - \ref LPTMR_CAPTURE_FROM_ACMP1
327 * - \ref LPTMR_CAPTURE_FROM_ACMP2
328 *
329 * @return None
330 *
331 * @details This API is used to select LPTMR capture source from Tx_EXT or internal signal.
332 */
LPTMR_CaptureSelect(LPTMR_T * lptmr,uint32_t u32Src)333 void LPTMR_CaptureSelect(LPTMR_T *lptmr, uint32_t u32Src)
334 {
335 if (u32Src == LPTMR_CAPTURE_FROM_EXTERNAL)
336 {
337 lptmr->CTL = (lptmr->CTL & ~(LPTMR_CTL_CAPSRC_Msk)) |
338 (LPTMR_CAPSRC_TMX_EXT);
339 }
340 else
341 {
342 lptmr->CTL = (lptmr->CTL & ~(LPTMR_CTL_CAPSRC_Msk)) |
343 (LPTMR_CAPSRC_INTERNAL);
344 lptmr->EXTCTL = (lptmr->EXTCTL & ~(LPTMR_EXTCTL_INTERCAPSEL_Msk)) |
345 (u32Src);
346 }
347 }
348
349
350 /**
351 * @brief Reset LPTMR Counter
352 *
353 * @param[in] lptmr The base address of Timer module
354 *
355 * @return Reset success or not
356 * @retval 0 Timer reset success
357 * @retval LPTMR_TIMEOUT_ERR Timer reset failed
358 *
359 * @details This function is used to reset current counter value and internal prescale counter value.
360 */
LPTMR_ResetCounter(LPTMR_T * lptmr)361 int32_t LPTMR_ResetCounter(LPTMR_T *lptmr)
362 {
363 uint32_t u32Delay;
364
365 lptmr->CNT |= LPTMR_CNT_RSTACT_Msk;
366 /* Takes 2~3 ECLKs to reset timer counter */
367 u32Delay = (SystemCoreClock / LPTMR_GetModuleClock(lptmr)) * 3;
368 while(((lptmr->CNT & LPTMR_CNT_RSTACT_Msk) == LPTMR_CNT_RSTACT_Msk) && (--u32Delay))
369 {
370 __NOP();
371 }
372 return ((u32Delay > 0) ? 0 : LPTMR_TIMEOUT_ERR);
373 }
374
375 /**
376 * @brief Enable Capture Input Noise Filter Function
377 *
378 * @param[in] lptmr The pointer of the specified LPTMR module. It could be LPTMR0, LPTMR1.
379 *
380 * @param[in] u32FilterCount Noise filter counter. Valid values are between 0~7.
381 *
382 * @param[in] u32ClkSrcSel Noise filter counter clock source, could be one of following source
383 * - \ref LPTMR_CAPTURE_NOISE_FILTER_PCLK_DIV_1
384 * - \ref LPTMR_CAPTURE_NOISE_FILTER_PCLK_DIV_2
385 * - \ref LPTMR_CAPTURE_NOISE_FILTER_PCLK_DIV_4
386 * - \ref LPTMR_CAPTURE_NOISE_FILTER_PCLK_DIV_8
387 * - \ref LPTMR_CAPTURE_NOISE_FILTER_PCLK_DIV_16
388 * - \ref LPTMR_CAPTURE_NOISE_FILTER_PCLK_DIV_32
389 * - \ref LPTMR_CAPTURE_NOISE_FILTER_PCLK_DIV_64
390 * - \ref LPTMR_CAPTURE_NOISE_FILTER_PCLK_DIV_128
391 *
392 * @return None
393 *
394 * @details This function is used to enable capture input noise filter function.
395 */
LPTMR_EnableCaptureInputNoiseFilter(LPTMR_T * lptmr,uint32_t u32FilterCount,uint32_t u32ClkSrcSel)396 void LPTMR_EnableCaptureInputNoiseFilter(LPTMR_T *lptmr, uint32_t u32FilterCount, uint32_t u32ClkSrcSel)
397 {
398 lptmr->CAPNF = ( ((lptmr)->CAPNF & ~(LPTMR_CAPNF_CAPNFEN_Msk | LPTMR_CAPNF_CAPNFCNT_Msk | LPTMR_CAPNF_CAPNFSEL_Msk))
399 | (LPTMR_CAPNF_CAPNFEN_Msk | (u32FilterCount << LPTMR_CAPNF_CAPNFCNT_Pos) | (u32ClkSrcSel << LPTMR_CAPNF_CAPNFSEL_Pos)) );
400 }
401
402 /**
403 * @brief Disable Capture Input Noise Filter Function
404 *
405 * @param[in] lptmr The pointer of the specified LPTMR module. It could be LPTMR0, LPTMR1.
406 *
407 * @return None
408 *
409 * @details This function is used to disable capture input noise filter function.
410 */
LPTMR_DisableCaptureInputNoiseFilter(LPTMR_T * lptmr)411 void LPTMR_DisableCaptureInputNoiseFilter(LPTMR_T *lptmr)
412 {
413 lptmr->CAPNF &= ~LPTMR_CAPNF_CAPNFEN_Msk;
414 }
415
416 /*@}*/ /* end of group LPTMR_EXPORTED_FUNCTIONS */
417
418 /*@}*/ /* end of group LPTMR_Driver */
419
420 /*@}*/ /* end of group Standard_Driver */
421