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