1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2020 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_qtmr.h"
10 /* Component ID definition, used by tools. */
11 #ifndef FSL_COMPONENT_ID
12 #define FSL_COMPONENT_ID "platform.drivers.qtmr_2"
13 #endif
14
15 /*******************************************************************************
16 * Prototypes
17 ******************************************************************************/
18 /*!
19 * @brief Gets the instance from the base address to be used to gate or ungate the module clock
20 *
21 * @param base Quad Timer peripheral base address
22 *
23 * @return The Quad Timer instance
24 */
25 static uint32_t QTMR_GetInstance(TMR_Type *base);
26
27 /*******************************************************************************
28 * Variables
29 ******************************************************************************/
30 /*! @brief Pointers to Quad Timer bases for each instance. */
31 static TMR_Type *const s_qtmrBases[] = TMR_BASE_PTRS;
32
33 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
34 /*! @brief Pointers to Quad Timer clocks for each instance. */
35 static const clock_ip_name_t s_qtmrClocks[] = TMR_CLOCKS;
36 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
37
38 /*******************************************************************************
39 * Code
40 ******************************************************************************/
QTMR_GetInstance(TMR_Type * base)41 static uint32_t QTMR_GetInstance(TMR_Type *base)
42 {
43 uint32_t instance;
44
45 /* Find the instance index from base address mappings. */
46 for (instance = 0; instance < ARRAY_SIZE(s_qtmrBases); instance++)
47 {
48 if (s_qtmrBases[instance] == base)
49 {
50 break;
51 }
52 }
53
54 assert(instance < ARRAY_SIZE(s_qtmrBases));
55
56 return instance;
57 }
58
59 /*!
60 * brief Ungates the Quad Timer clock and configures the peripheral for basic operation.
61 *
62 * note This API should be called at the beginning of the application using the Quad Timer driver.
63 *
64 * param base Quad Timer peripheral base address
65 * param config Pointer to user's Quad Timer config structure
66 */
QTMR_Init(TMR_Type * base,const qtmr_config_t * config)67 void QTMR_Init(TMR_Type *base, const qtmr_config_t *config)
68 {
69 assert(NULL != config);
70
71 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
72 /* Enable the module clock */
73 CLOCK_EnableClock(s_qtmrClocks[QTMR_GetInstance(base)]);
74 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
75
76 /* Setup the counter sources */
77 base->CTRL = (TMR_CTRL_PCS(config->primarySource) | TMR_CTRL_SCS(config->secondarySource));
78
79 /* Setup the master mode operation */
80 base->SCTRL = (TMR_SCTRL_EEOF(config->enableExternalForce) | TMR_SCTRL_MSTR(config->enableMasterMode));
81
82 /* Setup debug mode */
83 base->CSCTRL = TMR_CSCTRL_DBG_EN(config->debugMode);
84
85 /* Setup input filter */
86 base->FILT = (TMR_FILT_FILT_CNT(config->faultFilterCount) | TMR_FILT_FILT_PER(config->faultFilterPeriod));
87 }
88
89 /*!
90 * brief Stops the counter and gates the Quad Timer clock
91 *
92 * param base Quad Timer peripheral base address
93 */
QTMR_Deinit(TMR_Type * base)94 void QTMR_Deinit(TMR_Type *base)
95 {
96 /* Stop the counter */
97 base->CTRL &= ~(uint16_t)TMR_CTRL_CM_MASK;
98
99 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
100 /* Disable the module clock */
101 CLOCK_DisableClock(s_qtmrClocks[QTMR_GetInstance(base)]);
102 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
103 }
104
105 /*!
106 * brief Fill in the Quad Timer config struct with the default settings
107 *
108 * The default values are:
109 * code
110 * config->debugMode = kQTMR_RunNormalInDebug;
111 * config->enableExternalForce = false;
112 * config->enableMasterMode = false;
113 * config->faultFilterCount = 0;
114 * config->faultFilterPeriod = 0;
115 * config->primarySource = kQTMR_ClockDivide_2;
116 * config->secondarySource = kQTMR_Counter0InputPin;
117 * endcode
118 * param config Pointer to user's Quad Timer config structure.
119 */
QTMR_GetDefaultConfig(qtmr_config_t * config)120 void QTMR_GetDefaultConfig(qtmr_config_t *config)
121 {
122 assert(NULL != config);
123
124 /* Initializes the configure structure to zero. */
125 (void)memset(config, 0, sizeof(*config));
126
127 /* Halt counter during debug mode */
128 config->debugMode = kQTMR_RunNormalInDebug;
129 /* Another counter cannot force state of OFLAG signal */
130 config->enableExternalForce = false;
131 /* Compare function's output from this counter is not broadcast to other counters */
132 config->enableMasterMode = false;
133 /* Fault filter count is set to 0 */
134 config->faultFilterCount = 0;
135 /* Fault filter period is set to 0 which disables the fault filter */
136 config->faultFilterPeriod = 0;
137 /* Primary count source is IP bus clock divide by 2 */
138 config->primarySource = kQTMR_ClockDivide_2;
139 /* Secondary count source is counter 0 input pin */
140 config->secondarySource = kQTMR_Counter0InputPin;
141 }
142
143 /*!
144 * brief Sets up Quad timer module for PWM signal output.
145 *
146 * The function initializes the timer module according to the parameters passed in by the user. The
147 * function also sets up the value compare registers to match the PWM signal requirements.
148 *
149 * param base Quad Timer peripheral base address
150 * param pwmFreqHz PWM signal frequency in Hz
151 * param dutyCyclePercent PWM pulse width, value should be between 0 to 100
152 * 0=inactive signal(0% duty cycle)...
153 * 100=active signal (100% duty cycle)
154 * param outputPolarity true: invert polarity of the output signal, false: no inversion
155 * param srcClock_Hz Main counter clock in Hz.
156 *
157 * return Returns an error if there was error setting up the signal.
158 */
QTMR_SetupPwm(TMR_Type * base,uint32_t pwmFreqHz,uint8_t dutyCyclePercent,bool outputPolarity,uint32_t srcClock_Hz)159 status_t QTMR_SetupPwm(
160 TMR_Type *base, uint32_t pwmFreqHz, uint8_t dutyCyclePercent, bool outputPolarity, uint32_t srcClock_Hz)
161 {
162 uint32_t periodCount, highCount, lowCount;
163 uint16_t reg;
164 status_t status = kStatus_Success;
165
166 if (dutyCyclePercent <= 100U)
167 {
168 /* Set OFLAG pin for output mode and force out a low on the pin */
169 base->SCTRL |= (TMR_SCTRL_FORCE_MASK | TMR_SCTRL_OEN_MASK);
170
171 /* Counter values to generate a PWM signal */
172 periodCount = (srcClock_Hz / pwmFreqHz);
173 highCount = (periodCount * dutyCyclePercent) / 100U;
174 lowCount = periodCount - highCount;
175
176 /* Setup the compare registers for PWM output */
177 base->COMP1 = (uint16_t)lowCount;
178 base->COMP2 = (uint16_t)highCount;
179
180 /* Setup the pre-load registers for PWM output */
181 base->CMPLD1 = (uint16_t)lowCount;
182 base->CMPLD2 = (uint16_t)highCount;
183
184 reg = base->CSCTRL;
185 /* Setup the compare load control for COMP1 and COMP2.
186 * Load COMP1 when CSCTRL[TCF2] is asserted, load COMP2 when CSCTRL[TCF1] is asserted
187 */
188 reg &= ~((uint16_t)TMR_CSCTRL_CL1_MASK | (uint16_t)TMR_CSCTRL_CL2_MASK);
189 reg |= (TMR_CSCTRL_CL1(kQTMR_LoadOnComp2) | TMR_CSCTRL_CL2(kQTMR_LoadOnComp1));
190 base->CSCTRL = reg;
191
192 if (outputPolarity)
193 {
194 /* Invert the polarity */
195 base->SCTRL |= TMR_SCTRL_OPS_MASK;
196 }
197 else
198 {
199 /* True polarity, no inversion */
200 base->SCTRL &= ~(uint16_t)TMR_SCTRL_OPS_MASK;
201 }
202
203 reg = base->CTRL;
204 reg &= ~(uint16_t)TMR_CTRL_OUTMODE_MASK;
205 /* Count until compare value is reached and re-initialize the counter, toggle OFLAG output
206 * using alternating compare register
207 */
208 reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_ToggleOnAltCompareReg));
209 base->CTRL = reg;
210 }
211 else
212 {
213 /* Invalid dutycycle */
214 status = kStatus_Fail;
215 }
216
217 return status;
218 }
219
220 /*!
221 * brief Allows the user to count the source clock cycles until a capture event arrives.
222 *
223 * The count is stored in the capture register.
224 *
225 * param base Quad Timer peripheral base address
226 * param capturePin Pin through which we receive the input signal to trigger the capture
227 * param inputPolarity true: invert polarity of the input signal, false: no inversion
228 * param reloadOnCapture true: reload the counter when an input capture occurs, false: no reload
229 * param captureMode Specifies which edge of the input signal triggers a capture
230 */
QTMR_SetupInputCapture(TMR_Type * base,qtmr_input_source_t capturePin,bool inputPolarity,bool reloadOnCapture,qtmr_input_capture_edge_t captureMode)231 void QTMR_SetupInputCapture(TMR_Type *base,
232 qtmr_input_source_t capturePin,
233 bool inputPolarity,
234 bool reloadOnCapture,
235 qtmr_input_capture_edge_t captureMode)
236 {
237 uint16_t reg;
238
239 /* Clear the prior value for the input source for capture */
240 reg = base->CTRL & (~(uint16_t)TMR_CTRL_SCS_MASK);
241
242 /* Set the new input source */
243 reg |= TMR_CTRL_SCS(capturePin);
244 base->CTRL = reg;
245
246 /* Clear the prior values for input polarity, capture mode. Set the external pin as input */
247 reg = base->SCTRL &
248 (~((uint16_t)TMR_SCTRL_IPS_MASK | (uint16_t)TMR_SCTRL_CAPTURE_MODE_MASK | (uint16_t)TMR_SCTRL_OEN_MASK));
249 /* Set the new values */
250 reg |= (TMR_SCTRL_IPS(inputPolarity) | TMR_SCTRL_CAPTURE_MODE(captureMode));
251 base->SCTRL = reg;
252
253 /* Setup if counter should reload when a capture occurs */
254 if (reloadOnCapture)
255 {
256 base->CSCTRL |= TMR_CSCTRL_ROC_MASK;
257 }
258 else
259 {
260 base->CSCTRL &= ~(uint16_t)TMR_CSCTRL_ROC_MASK;
261 }
262 }
263
264 /*!
265 * brief Enables the selected Quad Timer interrupts
266 *
267 * param base Quad Timer peripheral base address
268 * param mask The interrupts to enable. This is a logical OR of members of the
269 * enumeration ::qtmr_interrupt_enable_t
270 */
QTMR_EnableInterrupts(TMR_Type * base,uint32_t mask)271 void QTMR_EnableInterrupts(TMR_Type *base, uint32_t mask)
272 {
273 uint16_t reg;
274
275 reg = base->SCTRL;
276 /* Compare interrupt */
277 if (0U != (mask & (uint32_t)kQTMR_CompareInterruptEnable))
278 {
279 reg |= TMR_SCTRL_TCFIE_MASK;
280 }
281 /* Overflow interrupt */
282 if (0U != (mask & (uint32_t)kQTMR_OverflowInterruptEnable))
283 {
284 reg |= TMR_SCTRL_TOFIE_MASK;
285 }
286 /* Input edge interrupt */
287 if (0U != (mask & (uint32_t)kQTMR_EdgeInterruptEnable))
288 {
289 reg |= TMR_SCTRL_IEFIE_MASK;
290 }
291 base->SCTRL = reg;
292
293 reg = base->CSCTRL;
294 /* Compare 1 interrupt */
295 if (0U != (mask & (uint32_t)kQTMR_Compare1InterruptEnable))
296 {
297 reg |= TMR_CSCTRL_TCF1EN_MASK;
298 }
299 /* Compare 2 interrupt */
300 if (0U != (mask & (uint32_t)kQTMR_Compare2InterruptEnable))
301 {
302 reg |= TMR_CSCTRL_TCF2EN_MASK;
303 }
304 base->CSCTRL = reg;
305 }
306
307 /*!
308 * brief Disables the selected Quad Timer interrupts
309 *
310 * param base Quad Timer peripheral base address
311 * param mask The interrupts to enable. This is a logical OR of members of the
312 * enumeration ::qtmr_interrupt_enable_t
313 */
QTMR_DisableInterrupts(TMR_Type * base,uint32_t mask)314 void QTMR_DisableInterrupts(TMR_Type *base, uint32_t mask)
315 {
316 uint16_t reg;
317
318 reg = base->SCTRL;
319 /* Compare interrupt */
320 if (0U != (mask & (uint32_t)kQTMR_CompareInterruptEnable))
321 {
322 reg &= ~(uint16_t)TMR_SCTRL_TCFIE_MASK;
323 }
324 /* Overflow interrupt */
325 if (0U != (mask & (uint32_t)kQTMR_OverflowInterruptEnable))
326 {
327 reg &= ~(uint16_t)TMR_SCTRL_TOFIE_MASK;
328 }
329 /* Input edge interrupt */
330 if (0U != (mask & (uint32_t)kQTMR_EdgeInterruptEnable))
331 {
332 reg &= ~(uint16_t)TMR_SCTRL_IEFIE_MASK;
333 }
334 base->SCTRL = reg;
335
336 reg = base->CSCTRL;
337 /* Compare 1 interrupt */
338 if (0U != (mask & (uint32_t)kQTMR_Compare1InterruptEnable))
339 {
340 reg &= ~(uint16_t)TMR_CSCTRL_TCF1EN_MASK;
341 }
342 /* Compare 2 interrupt */
343 if (0U != (mask & (uint32_t)kQTMR_Compare2InterruptEnable))
344 {
345 reg &= ~(uint16_t)TMR_CSCTRL_TCF2EN_MASK;
346 }
347 base->CSCTRL = reg;
348 }
349
350 /*!
351 * brief Gets the enabled Quad Timer interrupts
352 *
353 * param base Quad Timer peripheral base address
354 *
355 * return The enabled interrupts. This is the logical OR of members of the
356 * enumeration ::qtmr_interrupt_enable_t
357 */
QTMR_GetEnabledInterrupts(TMR_Type * base)358 uint32_t QTMR_GetEnabledInterrupts(TMR_Type *base)
359 {
360 uint32_t enabledInterrupts = 0;
361 uint16_t reg;
362
363 reg = base->SCTRL;
364 /* Compare interrupt */
365 if (0U != (reg & TMR_SCTRL_TCFIE_MASK))
366 {
367 enabledInterrupts |= (uint32_t)kQTMR_CompareFlag;
368 }
369 /* Overflow interrupt */
370 if (0U != (reg & TMR_SCTRL_TOFIE_MASK))
371 {
372 enabledInterrupts |= (uint32_t)kQTMR_OverflowInterruptEnable;
373 }
374 /* Input edge interrupt */
375 if (0U != (reg & TMR_SCTRL_IEFIE_MASK))
376 {
377 enabledInterrupts |= (uint32_t)kQTMR_EdgeInterruptEnable;
378 }
379
380 reg = base->CSCTRL;
381 /* Compare 1 interrupt */
382 if (0U != (reg & TMR_CSCTRL_TCF1EN_MASK))
383 {
384 enabledInterrupts |= (uint32_t)kQTMR_Compare1InterruptEnable;
385 }
386 /* Compare 2 interrupt */
387 if (0U != (reg & TMR_CSCTRL_TCF2EN_MASK))
388 {
389 enabledInterrupts |= (uint32_t)kQTMR_Compare2InterruptEnable;
390 }
391
392 return enabledInterrupts;
393 }
394
395 /*!
396 * brief Gets the Quad Timer status flags
397 *
398 * param base Quad Timer peripheral base address
399 *
400 * return The status flags. This is the logical OR of members of the
401 * enumeration ::qtmr_status_flags_t
402 */
QTMR_GetStatus(TMR_Type * base)403 uint32_t QTMR_GetStatus(TMR_Type *base)
404 {
405 uint32_t statusFlags = 0;
406 uint16_t reg;
407
408 reg = base->SCTRL;
409 /* Timer compare flag */
410 if (0U != (reg & TMR_SCTRL_TCF_MASK))
411 {
412 statusFlags |= (uint32_t)kQTMR_CompareFlag;
413 }
414 /* Timer overflow flag */
415 if (0U != (reg & TMR_SCTRL_TOF_MASK))
416 {
417 statusFlags |= (uint32_t)kQTMR_OverflowFlag;
418 }
419 /* Input edge flag */
420 if (0U != (reg & TMR_SCTRL_IEF_MASK))
421 {
422 statusFlags |= (uint32_t)kQTMR_EdgeFlag;
423 }
424
425 reg = base->CSCTRL;
426 /* Compare 1 flag */
427 if (0U != (reg & TMR_CSCTRL_TCF1_MASK))
428 {
429 statusFlags |= (uint32_t)kQTMR_Compare1Flag;
430 }
431 /* Compare 2 flag */
432 if (0U != (reg & TMR_CSCTRL_TCF2_MASK))
433 {
434 statusFlags |= (uint32_t)kQTMR_Compare2Flag;
435 }
436
437 return statusFlags;
438 }
439
440 /*!
441 * brief Clears the Quad Timer status flags.
442 *
443 * param base Quad Timer peripheral base address
444 * param mask The status flags to clear. This is a logical OR of members of the
445 * enumeration ::qtmr_status_flags_t
446 */
QTMR_ClearStatusFlags(TMR_Type * base,uint32_t mask)447 void QTMR_ClearStatusFlags(TMR_Type *base, uint32_t mask)
448 {
449 uint16_t reg;
450
451 reg = base->SCTRL;
452 /* Timer compare flag */
453 if (0U != (mask & (uint32_t)kQTMR_CompareFlag))
454 {
455 reg &= ~(uint16_t)TMR_SCTRL_TCF_MASK;
456 }
457 /* Timer overflow flag */
458 if (0U != (mask & (uint32_t)kQTMR_OverflowFlag))
459 {
460 reg &= ~(uint16_t)TMR_SCTRL_TOF_MASK;
461 }
462 /* Input edge flag */
463 if (0U != (mask & (uint32_t)kQTMR_EdgeFlag))
464 {
465 reg &= ~(uint16_t)TMR_SCTRL_IEF_MASK;
466 }
467 base->SCTRL = reg;
468
469 reg = base->CSCTRL;
470 /* Compare 1 flag */
471 if (0U != (mask & (uint32_t)kQTMR_Compare1Flag))
472 {
473 reg &= ~(uint16_t)TMR_CSCTRL_TCF1_MASK;
474 }
475 /* Compare 2 flag */
476 if (0U != (mask & (uint32_t)kQTMR_Compare2Flag))
477 {
478 reg &= ~(uint16_t)TMR_CSCTRL_TCF2_MASK;
479 }
480 base->CSCTRL = reg;
481 }
482
483 /*!
484 * brief Sets the timer period in ticks.
485 *
486 * Timers counts from initial value till it equals the count value set here. The counter
487 * will then reinitialize to the value specified in the Load register.
488 *
489 * note
490 * 1. This function will write the time period in ticks to COMP1 or COMP2 register
491 * depending on the count direction
492 * 2. User can call the utility macros provided in fsl_common.h to convert to ticks
493 * 3. This function supports cases, providing only primary source clock without secondary source clock.
494 *
495 * param base Quad Timer peripheral base address
496 * param ticks Timer period in units of ticks
497 */
QTMR_SetTimerPeriod(TMR_Type * base,uint16_t ticks)498 void QTMR_SetTimerPeriod(TMR_Type *base, uint16_t ticks)
499 {
500 /* Set the length bit to reinitialize the counters on a match */
501 base->CTRL |= TMR_CTRL_LENGTH_MASK;
502
503 if (0U != (base->CTRL & TMR_CTRL_DIR_MASK))
504 {
505 /* Counting down */
506 base->COMP2 = ticks;
507 }
508 else
509 {
510 /* Counting up */
511 base->COMP1 = ticks;
512 }
513 }
514