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