1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2022 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_ftm.h"
10
11 /* Component ID definition, used by tools. */
12 #ifndef FSL_COMPONENT_ID
13 #define FSL_COMPONENT_ID "platform.drivers.ftm"
14 #endif
15
16 /*******************************************************************************
17 * Prototypes
18 ******************************************************************************/
19 /*!
20 * @brief Sets the FTM register PWM synchronization method
21 *
22 * This function will set the necessary bits for the PWM synchronization mode that
23 * user wishes to use.
24 *
25 * @param base FTM peripheral base address
26 * @param syncMethod Synchronization methods to use to update buffered registers. This is a logical
27 * OR of members of the enumeration ::ftm_pwm_sync_method_t
28 * @param swRstCnt true:Enable FTM counter synchronization activated by software trigger, avtive when (syncMethod &
29 * FTM_SYNC_SWSYNC_MASK) != 0U;
30 * false:The software trigger does not activate the FTM counter synchronization.
31 * @param hwRstCnt true:Enable FTM counter synchronization activated by hardware trigger, avtive when (syncMethod &
32 * (FTM_SYNC_TRIG0_MASK | FTM_SYNC_TRIG1_MASK | FTM_SYNC_TRIG2_MASK)) != 0U;
33 * false:Hardware trigger does not activate FTM counter synchronization
34 */
35 static void FTM_SetPwmSync(FTM_Type *base, uint32_t syncMethod, bool swRstCnt, bool hwRstCnt);
36
37 /*!
38 * @brief Sets the reload points used as loading points for register update
39 *
40 * This function will set the necessary bits based on what the user wishes to use as loading
41 * points for FTM register update. When using this it is not required to use PWM synchnronization.
42 *
43 * @param base FTM peripheral base address
44 * @param reloadPoints FTM reload points. This is a logical OR of members of the
45 * enumeration ::ftm_reload_point_t
46 */
47 static void FTM_SetReloadPoints(FTM_Type *base, uint32_t reloadPoints);
48
49 /*******************************************************************************
50 * Variables
51 ******************************************************************************/
52 /*! @brief Pointers to FTM bases for each instance. */
53 static FTM_Type *const s_ftmBases[] = FTM_BASE_PTRS;
54
55 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
56 /*! @brief Pointers to FTM clocks for each instance. */
57 static const clock_ip_name_t s_ftmClocks[] = FTM_CLOCKS;
58 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
59
60 /*******************************************************************************
61 * Code
62 ******************************************************************************/
FTM_GetInstance(FTM_Type * base)63 uint32_t FTM_GetInstance(FTM_Type *base)
64 {
65 uint32_t instance;
66 uint32_t ftmArrayCount = (sizeof(s_ftmBases) / sizeof(s_ftmBases[0]));
67
68 /* Find the instance index from base address mappings. */
69 for (instance = 0; instance < ftmArrayCount; instance++)
70 {
71 if (s_ftmBases[instance] == base)
72 {
73 break;
74 }
75 }
76
77 assert(instance < ftmArrayCount);
78
79 return instance;
80 }
81
FTM_SetPwmSync(FTM_Type * base,uint32_t syncMethod,bool swRstCnt,bool hwRstCnt)82 static void FTM_SetPwmSync(FTM_Type *base, uint32_t syncMethod, bool swRstCnt, bool hwRstCnt)
83 {
84 uint8_t chnlNumber = 0;
85 uint32_t reg = 0, syncReg = 0;
86
87 /* The CHANNEL_COUNT macro returns -1 if it cannot match the FTM instance */
88 assert(-1 != FSL_FEATURE_FTM_CHANNEL_COUNTn(base));
89
90 syncReg = base->SYNC;
91 /* Enable PWM synchronization of output mask register */
92 syncReg |= FTM_SYNC_SYNCHOM_MASK;
93
94 reg = base->COMBINE;
95 for (chnlNumber = 0; chnlNumber < ((uint8_t)FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2U); chnlNumber++)
96 {
97 /* Enable PWM synchronization of registers C(n)V and C(n+1)V */
98 reg |= (1UL << (FTM_COMBINE_SYNCEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlNumber)));
99 }
100 base->COMBINE = reg;
101
102 reg = base->SYNCONF;
103
104 /* Use enhanced PWM synchronization method. Use PWM sync to update register values */
105 reg |= (FTM_SYNCONF_SYNCMODE_MASK | FTM_SYNCONF_CNTINC_MASK | FTM_SYNCONF_INVC_MASK | FTM_SYNCONF_SWOC_MASK);
106
107 if ((syncMethod & FTM_SYNC_SWSYNC_MASK) != 0U)
108 {
109 /* Enable needed bits for software trigger to update registers with its buffer value */
110 reg |= (FTM_SYNCONF_SWWRBUF_MASK | FTM_SYNCONF_SWINVC_MASK | FTM_SYNCONF_SWSOC_MASK | FTM_SYNCONF_SWOM_MASK);
111 /* Enable software trigger synchronization count. */
112 if (swRstCnt)
113 {
114 reg |= FTM_SYNCONF_SWRSTCNT_MASK;
115 }
116 }
117
118 if ((syncMethod & (FTM_SYNC_TRIG0_MASK | FTM_SYNC_TRIG1_MASK | FTM_SYNC_TRIG2_MASK)) != 0U)
119 {
120 /* Enable needed bits for hardware trigger to update registers with its buffer value */
121 reg |= (FTM_SYNCONF_HWWRBUF_MASK | FTM_SYNCONF_HWINVC_MASK | FTM_SYNCONF_HWSOC_MASK | FTM_SYNCONF_HWOM_MASK);
122 /* Enable hardware trigger synchronization count */
123 if (hwRstCnt)
124 {
125 reg |= FTM_SYNCONF_HWRSTCNT_MASK;
126 }
127
128 /* Enable the appropriate hardware trigger that is used for PWM sync */
129 if ((syncMethod & FTM_SYNC_TRIG0_MASK) != 0U)
130 {
131 syncReg |= FTM_SYNC_TRIG0_MASK;
132 }
133 if ((syncMethod & FTM_SYNC_TRIG1_MASK) != 0U)
134 {
135 syncReg |= FTM_SYNC_TRIG1_MASK;
136 }
137 if ((syncMethod & FTM_SYNC_TRIG2_MASK) != 0U)
138 {
139 syncReg |= FTM_SYNC_TRIG2_MASK;
140 }
141 }
142
143 /* Write back values to the SYNC register */
144 base->SYNC = syncReg;
145
146 /* Write the PWM synch values to the SYNCONF register */
147 base->SYNCONF = reg;
148 }
149
FTM_SetReloadPoints(FTM_Type * base,uint32_t reloadPoints)150 static void FTM_SetReloadPoints(FTM_Type *base, uint32_t reloadPoints)
151 {
152 uint32_t chnlNumber = 0;
153 uint32_t reg = 0;
154 int8_t chnlCount = FSL_FEATURE_FTM_CHANNEL_COUNTn(base);
155
156 /* The CHANNEL_COUNT macro returns -1 if it cannot match the FTM instance */
157 assert(-1 != chnlCount);
158
159 /* Need CNTINC bit to be 1 for CNTIN register to update with its buffer value on reload */
160 base->SYNCONF |= FTM_SYNCONF_CNTINC_MASK;
161
162 reg = base->COMBINE;
163 for (chnlNumber = 0; chnlNumber < ((uint32_t)chnlCount / 2U); chnlNumber++)
164 {
165 /* Need SYNCEN bit to be 1 for CnV reg to update with its buffer value on reload */
166 reg |= (1UL << (FTM_COMBINE_SYNCEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlNumber)));
167 }
168 base->COMBINE = reg;
169
170 /* Set the reload points */
171 reg = base->PWMLOAD;
172
173 /* Enable the selected channel match reload points */
174 reg &= ~((1UL << (uint32_t)chnlCount) - 1U);
175 reg |= (reloadPoints & ((1UL << (uint32_t)chnlCount) - 1U));
176
177 #if defined(FSL_FEATURE_FTM_HAS_HALFCYCLE_RELOAD) && (FSL_FEATURE_FTM_HAS_HALFCYCLE_RELOAD)
178 /* Enable half cycle match as a reload point */
179 if ((reloadPoints & (uint32_t)kFTM_HalfCycMatch) != 0U)
180 {
181 reg |= FTM_PWMLOAD_HCSEL_MASK;
182 }
183 else
184 {
185 reg &= ~FTM_PWMLOAD_HCSEL_MASK;
186 }
187 #endif /* FSL_FEATURE_FTM_HAS_HALFCYCLE_RELOAD */
188
189 base->PWMLOAD = reg;
190
191 /* These reload points are used when counter is in up-down counting mode */
192 reg = base->SYNC;
193 if ((reloadPoints & (uint32_t)kFTM_CntMax) != 0U)
194 {
195 /* Reload when counter turns from up to down */
196 reg |= FTM_SYNC_CNTMAX_MASK;
197 }
198 else
199 {
200 reg &= ~FTM_SYNC_CNTMAX_MASK;
201 }
202
203 if ((reloadPoints & (uint32_t)kFTM_CntMin) != 0U)
204 {
205 /* Reload when counter turns from down to up */
206 reg |= FTM_SYNC_CNTMIN_MASK;
207 }
208 else
209 {
210 reg &= ~FTM_SYNC_CNTMIN_MASK;
211 }
212 base->SYNC = reg;
213 }
214
215 /*!
216 * brief Ungates the FTM clock and configures the peripheral for basic operation.
217 *
218 * note This API should be called at the beginning of the application which is using the FTM driver.
219 * If the FTM instance has only TPM features, please use the TPM driver.
220 *
221 * param base FTM peripheral base address
222 * param config Pointer to the user configuration structure.
223 *
224 * return kStatus_Success indicates success; Else indicates failure.
225 */
FTM_Init(FTM_Type * base,const ftm_config_t * config)226 status_t FTM_Init(FTM_Type *base, const ftm_config_t *config)
227 {
228 assert(config);
229 #if defined(FSL_FEATURE_FTM_IS_TPM_ONLY_INSTANCE)
230 /* This function does not support the current instance, please use the TPM driver. */
231 assert((FSL_FEATURE_FTM_IS_TPM_ONLY_INSTANCE(base) == 0U));
232 #endif /* FSL_FEATURE_FTM_IS_TPM_ONLY_INSTANCE */
233
234 uint32_t reg;
235
236 if ((config->pwmSyncMode & (uint32_t)((uint32_t)FTM_SYNC_TRIG0_MASK | (uint32_t)FTM_SYNC_TRIG1_MASK |
237 (uint32_t)FTM_SYNC_TRIG2_MASK | (uint32_t)FTM_SYNC_SWSYNC_MASK)) == 0U)
238 {
239 /* Invalid PWM sync mode */
240 return kStatus_Fail;
241 }
242
243 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
244 /* Ungate the FTM clock*/
245 (void)CLOCK_EnableClock(s_ftmClocks[FTM_GetInstance(base)]);
246 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
247
248 #if (defined(FSL_FEATURE_FTM_HAS_BASIC_FEATURE_ONLY_INSTANCE) && FSL_FEATURE_FTM_HAS_BASIC_FEATURE_ONLY_INSTANCE)
249 if (0 != FSL_FEATURE_FTM_IS_BASIC_FEATURE_ONLY_INSTANCEn(base))
250 {
251 /* Enable FTM mode and disable write protection */
252 base->MODE = FTM_MODE_FTMEN_MASK | FTM_MODE_WPDIS_MASK;
253 }
254 else
255 {
256 /* Configure the fault mode, enable FTM mode and disable write protection */
257 base->MODE = FTM_MODE_FAULTM(config->faultMode) | FTM_MODE_FTMEN_MASK | FTM_MODE_WPDIS_MASK;
258 }
259 #else
260 /* Configure the fault mode, enable FTM mode and disable write protection */
261 base->MODE = FTM_MODE_FAULTM(config->faultMode) | FTM_MODE_FTMEN_MASK | FTM_MODE_WPDIS_MASK;
262 #endif
263
264 /* Configure the update mechanism for buffered registers */
265 FTM_SetPwmSync(base, config->pwmSyncMode, config->swTriggerResetCount, config->hwTriggerResetCount);
266
267 /* Setup intermediate register reload points */
268 FTM_SetReloadPoints(base, config->reloadPoints);
269
270 /* Set the clock prescale factor */
271 base->SC = FTM_SC_PS(config->prescale);
272
273 /* Setup the counter operation */
274 base->CONF = (FTM_CONF_BDMMODE(config->bdmMode) | FTM_CONF_GTBEEN(config->useGlobalTimeBase));
275
276 /* Initial state of channel output */
277 base->OUTINIT = config->chnlInitState;
278
279 /* Channel polarity */
280 base->POL = config->chnlPolarity;
281
282 /* Set the external trigger sources */
283 base->EXTTRIG = config->extTriggers;
284 #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INITIALIZATION_TRIGGER) && (FSL_FEATURE_FTM_HAS_RELOAD_INITIALIZATION_TRIGGER)
285 if ((config->extTriggers & (uint32_t)kFTM_ReloadInitTrigger) != 0U)
286 {
287 base->CONF |= FTM_CONF_ITRIGR_MASK;
288 }
289 else
290 {
291 base->CONF &= ~FTM_CONF_ITRIGR_MASK;
292 }
293 #endif /* FSL_FEATURE_FTM_HAS_RELOAD_INITIALIZATION_TRIGGER */
294
295 /* FTM deadtime insertion control */
296 base->DEADTIME = (0u |
297 #if defined(FSL_FEATURE_FTM_HAS_EXTENDED_DEADTIME_VALUE) && (FSL_FEATURE_FTM_HAS_EXTENDED_DEADTIME_VALUE)
298 /* Has extended deadtime value register) */
299 FTM_DEADTIME_DTVALEX(config->deadTimeValue >> 6) |
300 #endif /* FSL_FEATURE_FTM_HAS_EXTENDED_DEADTIME_VALUE */
301 FTM_DEADTIME_DTPS(config->deadTimePrescale) | FTM_DEADTIME_DTVAL(config->deadTimeValue));
302
303 #if (defined(FSL_FEATURE_FTM_HAS_BASIC_FEATURE_ONLY_INSTANCE) && FSL_FEATURE_FTM_HAS_BASIC_FEATURE_ONLY_INSTANCE)
304 if (0 == FSL_FEATURE_FTM_IS_BASIC_FEATURE_ONLY_INSTANCEn(base))
305 {
306 /* FTM fault filter value */
307 reg = base->FLTCTRL;
308 reg &= ~FTM_FLTCTRL_FFVAL_MASK;
309 reg |= FTM_FLTCTRL_FFVAL(config->faultFilterValue);
310 base->FLTCTRL = reg;
311 }
312 #else
313 /* FTM fault filter value */
314 reg = base->FLTCTRL;
315 reg &= ~FTM_FLTCTRL_FFVAL_MASK;
316 reg |= FTM_FLTCTRL_FFVAL(config->faultFilterValue);
317 base->FLTCTRL = reg;
318 #endif
319
320 return kStatus_Success;
321 }
322
323 /*!
324 * brief Gates the FTM clock.
325 *
326 * param base FTM peripheral base address
327 */
FTM_Deinit(FTM_Type * base)328 void FTM_Deinit(FTM_Type *base)
329 {
330 /* Set clock source to none to disable counter */
331 base->SC &= ~(FTM_SC_CLKS_MASK);
332
333 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
334 /* Gate the FTM clock */
335 (void)CLOCK_DisableClock(s_ftmClocks[FTM_GetInstance(base)]);
336 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
337 }
338
339 /*!
340 * brief Fills in the FTM configuration structure with the default settings.
341 *
342 * The default values are:
343 * code
344 * config->prescale = kFTM_Prescale_Divide_1;
345 * config->bdmMode = kFTM_BdmMode_0;
346 * config->pwmSyncMode = kFTM_SoftwareTrigger;
347 * config->reloadPoints = 0;
348 * config->faultMode = kFTM_Fault_Disable;
349 * config->faultFilterValue = 0;
350 * config->deadTimePrescale = kFTM_Deadtime_Prescale_1;
351 * config->deadTimeValue = 0;
352 * config->extTriggers = 0;
353 * config->chnlInitState = 0;
354 * config->chnlPolarity = 0;
355 * config->useGlobalTimeBase = false;
356 * config->hwTriggerResetCount = false;
357 * config->swTriggerResetCount = true;
358 * endcode
359 * param config Pointer to the user configuration structure.
360 */
FTM_GetDefaultConfig(ftm_config_t * config)361 void FTM_GetDefaultConfig(ftm_config_t *config)
362 {
363 assert(config != NULL);
364
365 /* Initializes the configure structure to zero. */
366 (void)memset(config, 0, sizeof(*config));
367
368 /* Divide FTM clock by 1 */
369 config->prescale = kFTM_Prescale_Divide_1;
370 /* FTM behavior in BDM mode */
371 config->bdmMode = kFTM_BdmMode_0;
372 /* Software trigger will be used to update registers */
373 config->pwmSyncMode = (uint32_t)kFTM_SoftwareTrigger;
374 /* No intermediate register load */
375 config->reloadPoints = 0;
376 /* Fault control disabled for all channels */
377 config->faultMode = kFTM_Fault_Disable;
378 /* Disable the fault filter */
379 config->faultFilterValue = 0;
380 /* Divide the system clock by 1 */
381 config->deadTimePrescale = kFTM_Deadtime_Prescale_1;
382 /* No counts are inserted */
383 config->deadTimeValue = 0;
384 /* No external trigger */
385 config->extTriggers = 0;
386 /* Initialization value is 0 for all channels */
387 config->chnlInitState = 0;
388 /* Active high polarity for all channels */
389 config->chnlPolarity = 0;
390 /* Use internal FTM counter as timebase */
391 config->useGlobalTimeBase = false;
392 /* Set hardware trigger activation counter sync to false */
393 config->hwTriggerResetCount = false;
394 /* Set software trigger activation counter sync to true */
395 config->swTriggerResetCount = true;
396 }
397
398 /*!
399 * brief Configures the PWM signal parameters.
400 *
401 * Call this function to configure the PWM signal period, mode, duty cycle, and edge. Use this
402 * function to configure all FTM channels that are used to output a PWM signal.
403 *
404 * param base FTM peripheral base address
405 * param chnlParams Array of PWM channel parameters to configure the channel(s)
406 * param numOfChnls Number of channels to configure; This should be the size of the array passed in
407 * param mode PWM operation mode, options available in enumeration ::ftm_pwm_mode_t
408 * param pwmFreq_Hz PWM signal frequency in Hz
409 * param srcClock_Hz FTM counter clock in Hz
410 *
411 * return kStatus_Success if the PWM setup was successful
412 * kStatus_Error on failure
413 */
FTM_SetupPwm(FTM_Type * base,const ftm_chnl_pwm_signal_param_t * chnlParams,uint8_t numOfChnls,ftm_pwm_mode_t mode,uint32_t pwmFreq_Hz,uint32_t srcClock_Hz)414 status_t FTM_SetupPwm(FTM_Type *base,
415 const ftm_chnl_pwm_signal_param_t *chnlParams,
416 uint8_t numOfChnls,
417 ftm_pwm_mode_t mode,
418 uint32_t pwmFreq_Hz,
419 uint32_t srcClock_Hz)
420 {
421 assert(NULL != chnlParams);
422
423 uint32_t mod, reg;
424 uint32_t ftmClock = (srcClock_Hz / (1UL << (base->SC & FTM_SC_PS_MASK)));
425 uint32_t cnv, cnvFirstEdge;
426 uint8_t i;
427
428 if ((0U == pwmFreq_Hz) || (0U == srcClock_Hz) || (0U == numOfChnls))
429 {
430 return kStatus_InvalidArgument;
431 }
432
433 if (mode == kFTM_CenterAlignedPwm)
434 {
435 base->SC |= FTM_SC_CPWMS_MASK;
436 mod = ftmClock / (pwmFreq_Hz * 2U);
437 }
438 else
439 {
440 base->SC &= ~FTM_SC_CPWMS_MASK;
441 mod = (ftmClock / pwmFreq_Hz) - 1U;
442 }
443
444 /* Return an error in case we overflow the registers, probably would require changing
445 * clock source to get the desired frequency */
446 if (mod > 65535U)
447 {
448 return kStatus_OutOfRange;
449 }
450 /* Set the PWM period */
451 base->CNTIN = 0U;
452 base->MOD = mod;
453
454 /* Setup each FTM channel */
455 for (i = 0; i < numOfChnls; i++)
456 {
457 /* Return error if requested chnlNumber is greater than the max allowed */
458 if (((uint8_t)chnlParams->chnlNumber >= (uint8_t)FSL_FEATURE_FTM_CHANNEL_COUNTn(base)) ||
459 (-1 == (int8_t)FSL_FEATURE_FTM_CHANNEL_COUNTn(base)))
460 {
461 return kStatus_InvalidArgument;
462 }
463 /* Return error if requested dutycycle is greater than the max allowed */
464 if (chnlParams->dutyCyclePercent > 100U)
465 {
466 return kStatus_OutOfRange;
467 }
468
469 if (chnlParams->dutyCyclePercent == 100U)
470 {
471 /* For 100% duty cycle */
472 cnv = mod + 1U;
473 }
474 else
475 {
476 cnv = (mod * chnlParams->dutyCyclePercent) / 100U;
477 }
478
479 if ((mode == kFTM_EdgeAlignedPwm) || (mode == kFTM_CenterAlignedPwm))
480 {
481 /* Clear the current mode and edge level bits */
482 reg = base->CONTROLS[chnlParams->chnlNumber].CnSC;
483 reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
484
485 /* Setup the active level */
486 reg |= (uint32_t)chnlParams->level << FTM_CnSC_ELSA_SHIFT;
487
488 /* Edge-aligned mode needs MSB to be 1, don't care for Center-aligned mode */
489 reg |= FTM_CnSC_MSB(1U);
490
491 /* Update the mode and edge level */
492 base->CONTROLS[chnlParams->chnlNumber].CnSC = reg;
493
494 base->CONTROLS[chnlParams->chnlNumber].CnV = cnv;
495 #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
496 /* Set to output mode */
497 FTM_SetPwmOutputEnable(base, chnlParams->chnlNumber, true);
498 #endif
499 }
500 else
501 {
502 /* This check is added for combined mode as the channel number should be the pair number */
503 if (((uint32_t)chnlParams->chnlNumber) >= ((uint32_t)FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2U))
504 {
505 return kStatus_InvalidArgument;
506 }
507
508 if (mode == kFTM_EdgeAlignedCombinedPwm)
509 {
510 cnvFirstEdge = 0;
511 }
512 else if (mode == kFTM_CenterAlignedCombinedPwm)
513 {
514 cnvFirstEdge = (mod > cnv) ? ((mod - cnv) / 2U) : 0U;
515 }
516 else
517 {
518 /* Return error if requested value is greater than the max allowed */
519 if ((chnlParams->firstEdgeDelayPercent + chnlParams->dutyCyclePercent) > 100U)
520 {
521 return kStatus_OutOfRange;
522 }
523 /* Configure delay of the first edge */
524 cnvFirstEdge = (mod * chnlParams->firstEdgeDelayPercent) / 100U;
525 }
526
527 /* Clear the current mode and edge level bits for channel n */
528 reg = base->CONTROLS[((uint32_t)chnlParams->chnlNumber) * 2U].CnSC;
529 reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
530
531 /* Setup the active level for channel n */
532 reg |= (uint32_t)chnlParams->level << FTM_CnSC_ELSA_SHIFT;
533
534 /* Update the mode and edge level for channel n */
535 base->CONTROLS[((uint32_t)chnlParams->chnlNumber) * 2U].CnSC = reg;
536
537 /* Clear the current mode and edge level bits for channel n + 1 */
538 reg = base->CONTROLS[(((uint32_t)chnlParams->chnlNumber) * 2U) + 1U].CnSC;
539 reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
540
541 /* Setup the active level for channel n + 1 */
542 reg |= (uint32_t)chnlParams->level << FTM_CnSC_ELSA_SHIFT;
543
544 /* Update the mode and edge level for channel n + 1*/
545 base->CONTROLS[(((uint32_t)chnlParams->chnlNumber) * 2U) + 1U].CnSC = reg;
546
547 /* Set the combine bit for the channel pair */
548 base->COMBINE |=
549 (1UL << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (uint32_t)chnlParams->chnlNumber)));
550
551 /* Set the channel pair values */
552 base->CONTROLS[((uint32_t)chnlParams->chnlNumber) * 2U].CnV = cnvFirstEdge;
553 base->CONTROLS[(((uint32_t)chnlParams->chnlNumber) * 2U) + 1U].CnV = cnvFirstEdge + cnv;
554
555 #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
556 /* Set to output mode */
557 FTM_SetPwmOutputEnable(base, (ftm_chnl_t)(uint8_t)((uint8_t)chnlParams->chnlNumber * 2U), true);
558 FTM_SetPwmOutputEnable(base, (ftm_chnl_t)(uint8_t)((uint8_t)chnlParams->chnlNumber * 2U + 1U), true);
559 #endif /* FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT */
560
561 /* Enable/Disable complementary output on the channel pair */
562 FTM_SetComplementaryEnable(base, chnlParams->chnlNumber, chnlParams->enableComplementary);
563 /* Enable/Disable Deadtime insertion on the channel pair */
564 FTM_SetDeadTimeEnable(base, chnlParams->chnlNumber, chnlParams->enableDeadtime);
565 }
566 chnlParams++;
567 }
568
569 return kStatus_Success;
570 }
571
572 /*!
573 * brief Updates the duty cycle of an active PWM signal.
574 *
575 * param base FTM peripheral base address
576 * param chnlNumber The channel/channel pair number. In combined mode, this represents
577 * the channel pair number
578 * param currentPwmMode The current PWM mode set during PWM setup
579 * param dutyCyclePercent New PWM pulse width; The value should be between 0 to 100
580 * 0=inactive signal(0% duty cycle)...
581 * 100=active signal (100% duty cycle)
582 * return kStatus_Success if the PWM update was successful
583 * kStatus_Error on failure
584 */
FTM_UpdatePwmDutycycle(FTM_Type * base,ftm_chnl_t chnlNumber,ftm_pwm_mode_t currentPwmMode,uint8_t dutyCyclePercent)585 status_t FTM_UpdatePwmDutycycle(FTM_Type *base,
586 ftm_chnl_t chnlNumber,
587 ftm_pwm_mode_t currentPwmMode,
588 uint8_t dutyCyclePercent)
589 {
590 uint32_t cnv, cnvFirstEdge = 0, mod;
591
592 /* Return error if requested chnlNumber is greater than the max allowed */
593 if (((uint8_t)chnlNumber >= (uint8_t)FSL_FEATURE_FTM_CHANNEL_COUNTn(base)) ||
594 (-1 == (int8_t)FSL_FEATURE_FTM_CHANNEL_COUNTn(base)))
595 {
596 return kStatus_InvalidArgument;
597 }
598
599 mod = base->MOD;
600
601 if (dutyCyclePercent > 100U)
602 {
603 return kStatus_OutOfRange;
604 }
605 if (dutyCyclePercent == 100U)
606 {
607 /* For 100% duty cycle */
608 cnv = mod + 1U;
609 }
610 else
611 {
612 cnv = (mod * dutyCyclePercent) / 100U;
613 }
614
615 if ((currentPwmMode == kFTM_EdgeAlignedPwm) || (currentPwmMode == kFTM_CenterAlignedPwm))
616 {
617 base->CONTROLS[chnlNumber].CnV = cnv;
618 }
619 else
620 {
621 /* This check is added for combined mode as the channel number should be the pair number */
622 if ((uint32_t)chnlNumber >= ((uint32_t)FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2U))
623 {
624 return kStatus_InvalidArgument;
625 }
626
627 if (currentPwmMode == kFTM_CenterAlignedCombinedPwm)
628 {
629 cnvFirstEdge = (mod > cnv) ? ((mod - cnv) / 2U) : 0U;
630 }
631 else
632 {
633 cnvFirstEdge = base->CONTROLS[((uint32_t)chnlNumber) * 2U].CnV;
634 if (((cnvFirstEdge != 0U) && (cnv == (mod + 1U))) || (((cnvFirstEdge + cnv) > mod) && (cnv < mod)))
635 {
636 /* Return error if firstEdgeDelayPercent + dutyCyclePercent > 100 */
637 return kStatus_OutOfRange;
638 }
639 }
640 base->CONTROLS[((uint32_t)chnlNumber * 2U)].CnV = cnvFirstEdge;
641 base->CONTROLS[((uint32_t)chnlNumber * 2U) + 1U].CnV = cnvFirstEdge + cnv;
642 }
643 return kStatus_Success;
644 }
645
646 /*!
647 * brief Updates the edge level selection for a channel.
648 *
649 * param base FTM peripheral base address
650 * param chnlNumber The channel number
651 * param level The level to be set to the ELSnB:ELSnA field; Valid values are 00, 01, 10, 11.
652 * See the Kinetis SoC reference manual for details about this field.
653 */
FTM_UpdateChnlEdgeLevelSelect(FTM_Type * base,ftm_chnl_t chnlNumber,uint8_t level)654 void FTM_UpdateChnlEdgeLevelSelect(FTM_Type *base, ftm_chnl_t chnlNumber, uint8_t level)
655 {
656 uint32_t reg = base->CONTROLS[chnlNumber].CnSC;
657
658 /* Clear the field and write the new level value */
659 reg &= ~(FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
660 reg |= ((uint32_t)level << FTM_CnSC_ELSA_SHIFT) & (FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
661
662 base->CONTROLS[chnlNumber].CnSC = reg;
663 }
664
665 /*!
666 * brief Configures the PWM mode parameters.
667 *
668 * Call this function to configure the PWM signal mode, duty cycle in ticks, and edge. Use this
669 * function to configure all FTM channels that are used to output a PWM signal.
670 * Please note that: This API is similar with FTM_SetupPwm() API, but will not set the timer period,
671 * and this API will set channel match value in timer ticks, not period percent.
672 *
673 * param base FTM peripheral base address
674 * param chnlParams Array of PWM channel parameters to configure the channel(s)
675 * param numOfChnls Number of channels to configure; This should be the size of the array passed in
676 * param mode PWM operation mode, options available in enumeration ::ftm_pwm_mode_t
677 *
678 * return kStatus_Success if the PWM setup was successful
679 * kStatus_Error on failure
680 */
FTM_SetupPwmMode(FTM_Type * base,const ftm_chnl_pwm_config_param_t * chnlParams,uint8_t numOfChnls,ftm_pwm_mode_t mode)681 status_t FTM_SetupPwmMode(FTM_Type *base,
682 const ftm_chnl_pwm_config_param_t *chnlParams,
683 uint8_t numOfChnls,
684 ftm_pwm_mode_t mode)
685 {
686 assert(chnlParams != NULL);
687 assert(numOfChnls != 0U);
688 /* The CHANNEL_COUNT macro returns -1 if it cannot match the FTM instance */
689 assert(-1 != FSL_FEATURE_FTM_CHANNEL_COUNTn(base));
690
691 uint32_t reg;
692 uint32_t mod, cnvFirstEdge;
693 uint8_t i;
694
695 switch (mode)
696 {
697 case kFTM_EdgeAlignedPwm:
698 case kFTM_EdgeAlignedCombinedPwm:
699 case kFTM_CenterAlignedCombinedPwm:
700 case kFTM_AsymmetricalCombinedPwm:
701 base->SC &= ~FTM_SC_CPWMS_MASK;
702 break;
703 case kFTM_CenterAlignedPwm:
704 base->SC |= FTM_SC_CPWMS_MASK;
705 break;
706 default:
707 assert(false);
708 break;
709 }
710
711 /* Get percent PWM period */
712 mod = base->MOD;
713 /* Setup each FTM channel */
714 for (i = 0; i < numOfChnls; i++)
715 {
716 if ((mode == kFTM_EdgeAlignedPwm) || (mode == kFTM_CenterAlignedPwm))
717 {
718 /* Clear the current mode and edge level bits */
719 reg = base->CONTROLS[chnlParams->chnlNumber].CnSC;
720 reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
721
722 /* Setup the active level */
723 reg |= (uint32_t)chnlParams->level << FTM_CnSC_ELSA_SHIFT;
724
725 /* Edge-aligned mode needs MSB to be 1, don't care for Center-aligned mode */
726 reg |= FTM_CnSC_MSB(1U);
727
728 /* Update the mode and edge level */
729 base->CONTROLS[chnlParams->chnlNumber].CnSC = reg;
730
731 base->CONTROLS[chnlParams->chnlNumber].CnV = chnlParams->dutyValue;
732 #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
733 /* Set to output mode */
734 FTM_SetPwmOutputEnable(base, chnlParams->chnlNumber, true);
735 #endif
736 }
737 else
738 {
739 /* This check is added for combined mode as the channel number should be the pair number */
740 if (((uint32_t)chnlParams->chnlNumber) >= (((uint32_t)FSL_FEATURE_FTM_CHANNEL_COUNTn(base)) / 2U))
741 {
742 return kStatus_Fail;
743 }
744
745 if (mode == kFTM_EdgeAlignedCombinedPwm)
746 {
747 cnvFirstEdge = 0;
748 }
749 else if (mode == kFTM_CenterAlignedCombinedPwm)
750 {
751 cnvFirstEdge = (mod - chnlParams->dutyValue) / 2U;
752 }
753 else
754 {
755 /* Return error if requested value is greater than the mod */
756 if (chnlParams->firstEdgeValue > mod)
757 {
758 return kStatus_Fail;
759 }
760 cnvFirstEdge = chnlParams->firstEdgeValue;
761 }
762
763 /* Re-configure first edge when 0% duty cycle */
764 if (chnlParams->dutyValue == 0U)
765 {
766 /* Signal stays low */
767 cnvFirstEdge = 0;
768 }
769
770 /* Clear the current mode and edge level bits for channel n */
771 reg = base->CONTROLS[((uint32_t)chnlParams->chnlNumber) * 2U].CnSC;
772 reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
773
774 /* Setup the active level for channel n */
775 reg |= (uint32_t)chnlParams->level << FTM_CnSC_ELSA_SHIFT;
776
777 /* Update the mode and edge level for channel n */
778 base->CONTROLS[((uint32_t)chnlParams->chnlNumber) * 2U].CnSC = reg;
779
780 /* Clear the current mode and edge level bits for channel n + 1 */
781 reg = base->CONTROLS[(((uint32_t)chnlParams->chnlNumber) * 2U) + 1U].CnSC;
782 reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
783
784 /* Setup the active level for channel n + 1 */
785 reg |= (uint32_t)chnlParams->level << FTM_CnSC_ELSA_SHIFT;
786
787 /* Update the mode and edge level for channel n + 1*/
788 base->CONTROLS[(((uint32_t)chnlParams->chnlNumber) * 2U) + 1U].CnSC = reg;
789
790 /* Set the combine bit for the channel pair */
791 base->COMBINE |=
792 (1UL << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (uint32_t)chnlParams->chnlNumber)));
793
794 /* Set the channel pair values */
795 base->CONTROLS[((uint32_t)chnlParams->chnlNumber) * 2U].CnV = cnvFirstEdge;
796 base->CONTROLS[(((uint32_t)chnlParams->chnlNumber) * 2U) + 1U].CnV = cnvFirstEdge + chnlParams->dutyValue;
797
798 #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
799 /* Set to output mode */
800 FTM_SetPwmOutputEnable(base, (ftm_chnl_t)(uint8_t)((uint8_t)chnlParams->chnlNumber * 2U), true);
801 FTM_SetPwmOutputEnable(base, (ftm_chnl_t)(uint8_t)((uint8_t)chnlParams->chnlNumber * 2U + 1U), true);
802 #endif /* FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT */
803
804 /* Enable/Disable complementary output on the channel pair */
805 FTM_SetComplementaryEnable(base, chnlParams->chnlNumber, chnlParams->enableComplementary);
806 /* Enable/Disable Deadtime insertion on the channel pair */
807 FTM_SetDeadTimeEnable(base, chnlParams->chnlNumber, chnlParams->enableDeadtime);
808 }
809 chnlParams++;
810 }
811
812 return kStatus_Success;
813 }
814
815 /*!
816 * brief Enables capturing an input signal on the channel using the function parameters.
817 *
818 * When the edge specified in the captureMode argument occurs on the channel, the FTM counter is
819 * captured into the CnV register. The user has to read the CnV register separately to get this
820 * value. The filter function is disabled if the filterVal argument passed in is 0. The filter
821 * function is available only for channels 0, 1, 2, 3.
822 *
823 * param base FTM peripheral base address
824 * param chnlNumber The channel number
825 * param captureMode Specifies which edge to capture
826 * param filterValue Filter value, specify 0 to disable filter. Available only for channels 0-3.
827 */
FTM_SetupInputCapture(FTM_Type * base,ftm_chnl_t chnlNumber,ftm_input_capture_edge_t captureMode,uint32_t filterValue)828 void FTM_SetupInputCapture(FTM_Type *base,
829 ftm_chnl_t chnlNumber,
830 ftm_input_capture_edge_t captureMode,
831 uint32_t filterValue)
832 {
833 uint32_t reg;
834
835 /* Clear the combine bit for the channel pair */
836 base->COMBINE &=
837 ~(1UL << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * ((uint32_t)chnlNumber >> 1))));
838 /* Clear the dual edge capture mode because it's it's higher priority */
839 base->COMBINE &=
840 ~(1UL << (FTM_COMBINE_DECAPEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * ((uint32_t)chnlNumber >> 1))));
841 #if !(defined(FSL_FEATURE_FTM_HAS_NO_QDCTRL) && FSL_FEATURE_FTM_HAS_NO_QDCTRL)
842 /* Clear the quadrature decoder mode beacause it's higher priority */
843 base->QDCTRL &= ~FTM_QDCTRL_QUADEN_MASK;
844 #endif
845
846 reg = base->CONTROLS[chnlNumber].CnSC;
847 reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
848 reg |= (uint32_t)captureMode;
849
850 /* Set the requested input capture mode */
851 base->CONTROLS[chnlNumber].CnSC = reg;
852 /* Input filter available only for channels 0, 1, 2, 3 */
853 if (chnlNumber < kFTM_Chnl_4)
854 {
855 reg = base->FILTER;
856 reg &= ~((uint32_t)FTM_FILTER_CH0FVAL_MASK << (FTM_FILTER_CH1FVAL_SHIFT * (uint32_t)chnlNumber));
857 reg |= (filterValue << (FTM_FILTER_CH1FVAL_SHIFT * (uint32_t)chnlNumber));
858 base->FILTER = reg;
859 }
860 #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
861 /* Set to input mode */
862 FTM_SetPwmOutputEnable(base, chnlNumber, false);
863 #endif
864 }
865
866 /*!
867 * brief Configures the FTM to generate timed pulses.
868 *
869 * When the FTM counter matches the value of compareVal argument (this is written into CnV reg),
870 * the channel output is changed based on what is specified in the compareMode argument.
871 *
872 * param base FTM peripheral base address
873 * param chnlNumber The channel number
874 * param compareMode Action to take on the channel output when the compare condition is met
875 * param compareValue Value to be programmed in the CnV register.
876 */
FTM_SetupOutputCompare(FTM_Type * base,ftm_chnl_t chnlNumber,ftm_output_compare_mode_t compareMode,uint32_t compareValue)877 void FTM_SetupOutputCompare(FTM_Type *base,
878 ftm_chnl_t chnlNumber,
879 ftm_output_compare_mode_t compareMode,
880 uint32_t compareValue)
881 {
882 uint32_t reg;
883
884 /* Clear the combine bit for the channel pair */
885 base->COMBINE &=
886 ~(1UL << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * ((uint32_t)chnlNumber >> 1))));
887 /* Clear the dual edge capture mode because it's it's higher priority */
888 base->COMBINE &=
889 ~(1UL << (FTM_COMBINE_DECAPEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * ((uint32_t)chnlNumber >> 1))));
890 #if !(defined(FSL_FEATURE_FTM_HAS_NO_QDCTRL) && FSL_FEATURE_FTM_HAS_NO_QDCTRL)
891 /* Clear the quadrature decoder mode beacause it's higher priority */
892 base->QDCTRL &= ~FTM_QDCTRL_QUADEN_MASK;
893 #endif
894
895 reg = base->CONTROLS[chnlNumber].CnSC;
896 reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
897 reg |= (uint32_t)compareMode;
898 /* Setup the channel output behaviour when a match occurs with the compare value */
899 base->CONTROLS[chnlNumber].CnSC = reg;
900
901 /* Set output on match to the requested level */
902 base->CONTROLS[chnlNumber].CnV = compareValue;
903
904 #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
905 /* Set to output mode */
906 FTM_SetPwmOutputEnable(base, chnlNumber, true);
907 #endif
908 }
909
910 /*!
911 * brief Configures the dual edge capture mode of the FTM.
912 *
913 * This function sets up the dual edge capture mode on a channel pair. The capture edge for the
914 * channel pair and the capture mode (one-shot or continuous) is specified in the parameter
915 * argument. The filter function is disabled if the filterVal argument passed is zero. The filter
916 * function is available only on channels 0 and 2. The user has to read the channel CnV registers
917 * separately to get the capture values.
918 *
919 * param base FTM peripheral base address
920 * param chnlPairNumber The FTM channel pair number; options are 0, 1, 2, 3
921 * param edgeParam Sets up the dual edge capture function
922 * param filterValue Filter value, specify 0 to disable filter. Available only for channel pair 0 and 1.
923 */
FTM_SetupDualEdgeCapture(FTM_Type * base,ftm_chnl_t chnlPairNumber,const ftm_dual_edge_capture_param_t * edgeParam,uint32_t filterValue)924 void FTM_SetupDualEdgeCapture(FTM_Type *base,
925 ftm_chnl_t chnlPairNumber,
926 const ftm_dual_edge_capture_param_t *edgeParam,
927 uint32_t filterValue)
928 {
929 assert(edgeParam);
930
931 uint32_t reg;
932
933 reg = base->COMBINE;
934 /* Clear the combine bit for the channel pair */
935 reg &= ~(1UL << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (uint32_t)chnlPairNumber)));
936 /* Enable the DECAPEN bit */
937 reg |= (1UL << (FTM_COMBINE_DECAPEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (uint32_t)chnlPairNumber)));
938 reg |= (1UL << (FTM_COMBINE_DECAP0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (uint32_t)chnlPairNumber)));
939 base->COMBINE = reg;
940
941 /* Setup the edge detection from channel n and n + 1 */
942 reg = base->CONTROLS[((uint32_t)chnlPairNumber) * 2U].CnSC;
943 reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
944 reg |= ((uint32_t)edgeParam->mode | (uint32_t)edgeParam->currChanEdgeMode);
945 base->CONTROLS[((uint32_t)chnlPairNumber) * 2U].CnSC = reg;
946
947 reg = base->CONTROLS[(((uint32_t)chnlPairNumber) * 2U) + 1U].CnSC;
948 reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
949 reg |= ((uint32_t)edgeParam->mode | (uint32_t)edgeParam->nextChanEdgeMode);
950 base->CONTROLS[(((uint32_t)chnlPairNumber) * 2U) + 1U].CnSC = reg;
951
952 /* Input filter available only for channels 0, 1, 2, 3 */
953 if (chnlPairNumber < kFTM_Chnl_4)
954 {
955 reg = base->FILTER;
956 reg &= ~((uint32_t)FTM_FILTER_CH0FVAL_MASK << (FTM_FILTER_CH1FVAL_SHIFT * (uint32_t)chnlPairNumber));
957 reg |= (filterValue << (FTM_FILTER_CH1FVAL_SHIFT * (uint32_t)chnlPairNumber));
958 base->FILTER = reg;
959 }
960
961 #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
962 /* Set to input mode */
963 FTM_SetPwmOutputEnable(base, chnlPairNumber, false);
964 #endif
965 }
966
967 /*!
968 * brief Configures the parameters and activates the quadrature decoder mode.
969 *
970 * param base FTM peripheral base address
971 * param phaseAParams Phase A configuration parameters
972 * param phaseBParams Phase B configuration parameters
973 * param quadMode Selects encoding mode used in quadrature decoder mode
974 */
FTM_SetupQuadDecode(FTM_Type * base,const ftm_phase_params_t * phaseAParams,const ftm_phase_params_t * phaseBParams,ftm_quad_decode_mode_t quadMode)975 void FTM_SetupQuadDecode(FTM_Type *base,
976 const ftm_phase_params_t *phaseAParams,
977 const ftm_phase_params_t *phaseBParams,
978 ftm_quad_decode_mode_t quadMode)
979 {
980 assert(phaseAParams != NULL);
981 assert(phaseBParams != NULL);
982
983 uint32_t reg;
984
985 /* Set Phase A filter value if phase filter is enabled */
986 if (phaseAParams->enablePhaseFilter)
987 {
988 reg = base->FILTER;
989 reg &= ~(FTM_FILTER_CH0FVAL_MASK);
990 reg |= FTM_FILTER_CH0FVAL(phaseAParams->phaseFilterVal);
991 base->FILTER = reg;
992 }
993
994 /* Set Phase B filter value if phase filter is enabled */
995 if (phaseBParams->enablePhaseFilter)
996 {
997 reg = base->FILTER;
998 reg &= ~(FTM_FILTER_CH1FVAL_MASK);
999 reg |= FTM_FILTER_CH1FVAL(phaseBParams->phaseFilterVal);
1000 base->FILTER = reg;
1001 }
1002 #if !(defined(FSL_FEATURE_FTM_HAS_NO_QDCTRL) && FSL_FEATURE_FTM_HAS_NO_QDCTRL)
1003 /* Set Quadrature decode properties */
1004 reg = base->QDCTRL;
1005 reg &= ~(FTM_QDCTRL_QUADMODE_MASK | FTM_QDCTRL_PHAFLTREN_MASK | FTM_QDCTRL_PHBFLTREN_MASK | FTM_QDCTRL_PHAPOL_MASK |
1006 FTM_QDCTRL_PHBPOL_MASK);
1007 reg |= (FTM_QDCTRL_QUADMODE(quadMode) | FTM_QDCTRL_PHAFLTREN(phaseAParams->enablePhaseFilter) |
1008 FTM_QDCTRL_PHBFLTREN(phaseBParams->enablePhaseFilter) | FTM_QDCTRL_PHAPOL(phaseAParams->phasePolarity) |
1009 FTM_QDCTRL_PHBPOL(phaseBParams->phasePolarity));
1010 base->QDCTRL = reg;
1011 /* Enable Quad decode */
1012 base->QDCTRL |= FTM_QDCTRL_QUADEN_MASK;
1013 #endif
1014 }
1015
1016 /*!
1017 * brief Sets up the working of the FTM fault inputs protection.
1018 *
1019 * FTM can have up to 4 fault inputs. This function sets up fault parameters, fault level, and input filter.
1020 *
1021 * param base FTM peripheral base address
1022 * param faultNumber FTM fault to configure.
1023 * param faultParams Parameters passed in to set up the fault input
1024 */
FTM_SetupFaultInput(FTM_Type * base,ftm_fault_input_t faultNumber,const ftm_fault_param_t * faultParams)1025 void FTM_SetupFaultInput(FTM_Type *base, ftm_fault_input_t faultNumber, const ftm_fault_param_t *faultParams)
1026 {
1027 assert(faultParams != NULL);
1028 /* Fault input is not supported if the instance has only basic feature.*/
1029 #if (defined(FSL_FEATURE_FTM_HAS_BASIC_FEATURE_ONLY_INSTANCE) && FSL_FEATURE_FTM_HAS_BASIC_FEATURE_ONLY_INSTANCE)
1030 assert(0 == FSL_FEATURE_FTM_IS_BASIC_FEATURE_ONLY_INSTANCEn(base));
1031 #endif
1032
1033 if (faultParams->useFaultFilter)
1034 {
1035 /* Enable the fault filter */
1036 base->FLTCTRL |= ((uint32_t)FTM_FLTCTRL_FFLTR0EN_MASK << (FTM_FLTCTRL_FFLTR0EN_SHIFT + (uint32_t)faultNumber));
1037 }
1038 else
1039 {
1040 /* Disable the fault filter */
1041 base->FLTCTRL &= ~((uint32_t)FTM_FLTCTRL_FFLTR0EN_MASK << (FTM_FLTCTRL_FFLTR0EN_SHIFT + (uint32_t)faultNumber));
1042 }
1043
1044 if (faultParams->faultLevel)
1045 {
1046 /* Active low polarity for the fault input pin */
1047 base->FLTPOL |= (1UL << (uint32_t)faultNumber);
1048 }
1049 else
1050 {
1051 /* Active high polarity for the fault input pin */
1052 base->FLTPOL &= ~(1UL << (uint32_t)faultNumber);
1053 }
1054
1055 if (faultParams->enableFaultInput)
1056 {
1057 /* Enable the fault input */
1058 base->FLTCTRL |= ((uint32_t)FTM_FLTCTRL_FAULT0EN_MASK << (uint32_t)faultNumber);
1059 }
1060 else
1061 {
1062 /* Disable the fault input */
1063 base->FLTCTRL &= ~((uint32_t)FTM_FLTCTRL_FAULT0EN_MASK << (uint32_t)faultNumber);
1064 }
1065 }
1066
1067 /*!
1068 * brief Enables the selected FTM interrupts.
1069 *
1070 * param base FTM peripheral base address
1071 * param mask The interrupts to enable. This is a logical OR of members of the
1072 * enumeration ::ftm_interrupt_enable_t
1073 */
FTM_EnableInterrupts(FTM_Type * base,uint32_t mask)1074 void FTM_EnableInterrupts(FTM_Type *base, uint32_t mask)
1075 {
1076 uint32_t chnlInts = (mask & 0xFFU);
1077 uint8_t chnlNumber = 0;
1078
1079 /* Enable the timer overflow interrupt */
1080 if ((mask & (uint32_t)kFTM_TimeOverflowInterruptEnable) != 0U)
1081 {
1082 base->SC |= FTM_SC_TOIE_MASK;
1083 }
1084
1085 /* Fault input is not supported if the instance has only basic feature.*/
1086 #if (defined(FSL_FEATURE_FTM_HAS_BASIC_FEATURE_ONLY_INSTANCE) && FSL_FEATURE_FTM_HAS_BASIC_FEATURE_ONLY_INSTANCE)
1087 if (0 == FSL_FEATURE_FTM_IS_BASIC_FEATURE_ONLY_INSTANCEn(base))
1088 {
1089 /* Enable the fault interrupt */
1090 if ((mask & (uint32_t)kFTM_FaultInterruptEnable) != 0U)
1091 {
1092 base->MODE |= FTM_MODE_FAULTIE_MASK;
1093 }
1094 }
1095 #else
1096 /* Enable the fault interrupt */
1097 if ((mask & (uint32_t)kFTM_FaultInterruptEnable) != 0U)
1098 {
1099 base->MODE |= FTM_MODE_FAULTIE_MASK;
1100 }
1101 #endif
1102
1103 #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
1104 /* Enable the reload interrupt available only on certain SoC's */
1105 if ((mask & (uint32_t)kFTM_ReloadInterruptEnable) != 0U)
1106 {
1107 base->SC |= FTM_SC_RIE_MASK;
1108 }
1109 #endif
1110
1111 /* Enable the channel interrupts */
1112 while (chnlInts != 0U)
1113 {
1114 if ((chnlInts & 0x1U) != 0U)
1115 {
1116 base->CONTROLS[chnlNumber].CnSC |= FTM_CnSC_CHIE_MASK;
1117 }
1118 chnlNumber++;
1119 chnlInts = chnlInts >> 1U;
1120 }
1121 }
1122
1123 /*!
1124 * brief Disables the selected FTM interrupts.
1125 *
1126 * param base FTM peripheral base address
1127 * param mask The interrupts to enable. This is a logical OR of members of the
1128 * enumeration ::ftm_interrupt_enable_t
1129 */
FTM_DisableInterrupts(FTM_Type * base,uint32_t mask)1130 void FTM_DisableInterrupts(FTM_Type *base, uint32_t mask)
1131 {
1132 uint32_t chnlInts = (mask & 0xFFU);
1133 uint8_t chnlNumber = 0;
1134
1135 /* Disable the timer overflow interrupt */
1136 if ((mask & (uint32_t)kFTM_TimeOverflowInterruptEnable) != 0U)
1137 {
1138 base->SC &= ~FTM_SC_TOIE_MASK;
1139 }
1140 /* Fault input is not supported if the instance has only basic feature.*/
1141 #if (defined(FSL_FEATURE_FTM_HAS_BASIC_FEATURE_ONLY_INSTANCE) && FSL_FEATURE_FTM_HAS_BASIC_FEATURE_ONLY_INSTANCE)
1142 if (0 == FSL_FEATURE_FTM_IS_BASIC_FEATURE_ONLY_INSTANCEn(base))
1143 {
1144 /* Disable the fault interrupt */
1145 if ((mask & (uint32_t)kFTM_FaultInterruptEnable) != 0U)
1146 {
1147 base->MODE &= ~FTM_MODE_FAULTIE_MASK;
1148 }
1149 }
1150 #else
1151 /* Disable the fault interrupt */
1152 if ((mask & (uint32_t)kFTM_FaultInterruptEnable) != 0U)
1153 {
1154 base->MODE &= ~FTM_MODE_FAULTIE_MASK;
1155 }
1156 #endif
1157
1158 #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
1159 /* Disable the reload interrupt available only on certain SoC's */
1160 if ((mask & (uint32_t)kFTM_ReloadInterruptEnable) != 0U)
1161 {
1162 base->SC &= ~FTM_SC_RIE_MASK;
1163 }
1164 #endif
1165
1166 /* Disable the channel interrupts */
1167 while (chnlInts != 0U)
1168 {
1169 if ((chnlInts & 0x01U) != 0U)
1170 {
1171 base->CONTROLS[chnlNumber].CnSC &= ~FTM_CnSC_CHIE_MASK;
1172 }
1173 chnlNumber++;
1174 chnlInts = chnlInts >> 1U;
1175 }
1176 }
1177
1178 /*!
1179 * brief Gets the enabled FTM interrupts.
1180 *
1181 * param base FTM peripheral base address
1182 *
1183 * return The enabled interrupts. This is the logical OR of members of the
1184 * enumeration ::ftm_interrupt_enable_t
1185 */
FTM_GetEnabledInterrupts(FTM_Type * base)1186 uint32_t FTM_GetEnabledInterrupts(FTM_Type *base)
1187 {
1188 uint32_t enabledInterrupts = 0;
1189 int8_t chnlCount = FSL_FEATURE_FTM_CHANNEL_COUNTn(base);
1190
1191 /* The CHANNEL_COUNT macro returns -1 if it cannot match the FTM instance */
1192 assert(chnlCount != -1);
1193
1194 /* Check if timer overflow interrupt is enabled */
1195 if ((base->SC & FTM_SC_TOIE_MASK) != 0U)
1196 {
1197 enabledInterrupts |= (uint32_t)kFTM_TimeOverflowInterruptEnable;
1198 }
1199 /* Fault input is not supported if the instance has only basic feature.*/
1200 #if (defined(FSL_FEATURE_FTM_HAS_BASIC_FEATURE_ONLY_INSTANCE) && FSL_FEATURE_FTM_HAS_BASIC_FEATURE_ONLY_INSTANCE)
1201 if (0 == FSL_FEATURE_FTM_IS_BASIC_FEATURE_ONLY_INSTANCEn(base))
1202 {
1203 /* Check if fault interrupt is enabled */
1204 if ((base->MODE & FTM_MODE_FAULTIE_MASK) != 0U)
1205 {
1206 enabledInterrupts |= (uint32_t)kFTM_FaultInterruptEnable;
1207 }
1208 }
1209 #else
1210 /* Check if fault interrupt is enabled */
1211 if ((base->MODE & FTM_MODE_FAULTIE_MASK) != 0U)
1212 {
1213 enabledInterrupts |= (uint32_t)kFTM_FaultInterruptEnable;
1214 }
1215 #endif
1216
1217 #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
1218 /* Check if the reload interrupt is enabled */
1219 if ((base->SC & FTM_SC_RIE_MASK) != 0U)
1220 {
1221 enabledInterrupts |= (uint32_t)kFTM_ReloadInterruptEnable;
1222 }
1223 #endif
1224
1225 /* Check if the channel interrupts are enabled */
1226 while (chnlCount > 0)
1227 {
1228 chnlCount--;
1229 if ((base->CONTROLS[chnlCount].CnSC & FTM_CnSC_CHIE_MASK) != 0x00U)
1230 {
1231 enabledInterrupts |= (1UL << (uint32_t)chnlCount);
1232 }
1233 }
1234
1235 return enabledInterrupts;
1236 }
1237
1238 /*!
1239 * brief Gets the FTM status flags.
1240 *
1241 * param base FTM peripheral base address
1242 *
1243 * return The status flags. This is the logical OR of members of the
1244 * enumeration ::ftm_status_flags_t
1245 */
FTM_GetStatusFlags(FTM_Type * base)1246 uint32_t FTM_GetStatusFlags(FTM_Type *base)
1247 {
1248 uint32_t statusFlags = 0;
1249
1250 /* Check the timer flag */
1251 if ((base->SC & FTM_SC_TOF_MASK) != 0U)
1252 {
1253 statusFlags |= (uint32_t)kFTM_TimeOverflowFlag;
1254 }
1255 /* Fault input is not supported if the instance has only basic feature.*/
1256 #if (defined(FSL_FEATURE_FTM_HAS_BASIC_FEATURE_ONLY_INSTANCE) && FSL_FEATURE_FTM_HAS_BASIC_FEATURE_ONLY_INSTANCE)
1257 if (0 == FSL_FEATURE_FTM_IS_BASIC_FEATURE_ONLY_INSTANCEn(base))
1258 {
1259 /* Check fault flag */
1260 if ((base->FMS & FTM_FMS_FAULTF_MASK) != 0U)
1261 {
1262 statusFlags |= (uint32_t)kFTM_FaultFlag;
1263 }
1264 }
1265 #else
1266 /* Check fault flag */
1267 if ((base->FMS & FTM_FMS_FAULTF_MASK) != 0U)
1268 {
1269 statusFlags |= (uint32_t)kFTM_FaultFlag;
1270 }
1271 #endif
1272 /* Check channel trigger flag */
1273 if ((base->EXTTRIG & FTM_EXTTRIG_TRIGF_MASK) != 0U)
1274 {
1275 statusFlags |= (uint32_t)kFTM_ChnlTriggerFlag;
1276 }
1277 #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
1278 /* Check reload flag */
1279 if ((base->SC & FTM_SC_RF_MASK) != 0U)
1280 {
1281 statusFlags |= (uint32_t)kFTM_ReloadFlag;
1282 }
1283 #endif
1284
1285 /* Lower 8 bits contain the channel status flags */
1286 statusFlags |= (base->STATUS & 0xFFU);
1287
1288 return statusFlags;
1289 }
1290
1291 /*!
1292 * brief Clears the FTM status flags.
1293 *
1294 * param base FTM peripheral base address
1295 * param mask The status flags to clear. This is a logical OR of members of the
1296 * enumeration ::ftm_status_flags_t
1297 */
FTM_ClearStatusFlags(FTM_Type * base,uint32_t mask)1298 void FTM_ClearStatusFlags(FTM_Type *base, uint32_t mask)
1299 {
1300 /* Clear the timer overflow flag by writing a 0 to the bit while it is set */
1301 if ((mask & (uint32_t)kFTM_TimeOverflowFlag) != 0U)
1302 {
1303 base->SC &= ~FTM_SC_TOF_MASK;
1304 }
1305 /* Fault input is not supported if the instance has only basic feature.*/
1306 #if (defined(FSL_FEATURE_FTM_HAS_BASIC_FEATURE_ONLY_INSTANCE) && FSL_FEATURE_FTM_HAS_BASIC_FEATURE_ONLY_INSTANCE)
1307 if (0 == FSL_FEATURE_FTM_IS_BASIC_FEATURE_ONLY_INSTANCEn(base))
1308 {
1309 /* Clear fault flag by writing a 0 to the bit while it is set */
1310 if ((mask & (uint32_t)kFTM_FaultFlag) != 0U)
1311 {
1312 base->FMS &= ~FTM_FMS_FAULTF_MASK;
1313 }
1314 }
1315 #else
1316 /* Clear fault flag by writing a 0 to the bit while it is set */
1317 if ((mask & (uint32_t)kFTM_FaultFlag) != 0U)
1318 {
1319 base->FMS &= ~FTM_FMS_FAULTF_MASK;
1320 }
1321 #endif
1322 /* Clear channel trigger flag */
1323 if ((mask & (uint32_t)kFTM_ChnlTriggerFlag) != 0U)
1324 {
1325 base->EXTTRIG &= ~FTM_EXTTRIG_TRIGF_MASK;
1326 }
1327
1328 #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
1329 /* Check reload flag by writing a 0 to the bit while it is set */
1330 if ((mask & (uint32_t)kFTM_ReloadFlag) != 0U)
1331 {
1332 base->SC &= ~FTM_SC_RF_MASK;
1333 }
1334 #endif
1335 /* Clear the channel status flags by writing a 0 to the bit */
1336 base->STATUS &= ~(mask & 0xFFU);
1337 }
1338