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