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