1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016-2017 NXP
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * o Redistributions of source code must retain the above copyright notice, this list
9  *   of conditions and the following disclaimer.
10  *
11  * o Redistributions in binary form must reproduce the above copyright notice, this
12  *   list of conditions and the following disclaimer in the documentation and/or
13  *   other materials provided with the distribution.
14  *
15  * o Neither the name of the copyright holder nor the names of its
16  *   contributors may be used to endorse or promote products derived from this
17  *   software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "fsl_ftm.h"
32 
33 /*******************************************************************************
34  * Prototypes
35  ******************************************************************************/
36 /*!
37  * @brief Gets the instance from the base address
38  *
39  * @param base FTM peripheral base address
40  *
41  * @return The FTM instance
42  */
43 static uint32_t FTM_GetInstance(FTM_Type *base);
44 
45 /*!
46  * @brief Sets the FTM register PWM synchronization method
47  *
48  * This function will set the necessary bits for the PWM synchronization mode that
49  * user wishes to use.
50  *
51  * @param base       FTM peripheral base address
52  * @param syncMethod Syncronization methods to use to update buffered registers. This is a logical
53  *                   OR of members of the enumeration ::ftm_pwm_sync_method_t
54  */
55 static void FTM_SetPwmSync(FTM_Type *base, uint32_t syncMethod);
56 
57 /*!
58  * @brief Sets the reload points used as loading points for register update
59  *
60  * This function will set the necessary bits based on what the user wishes to use as loading
61  * points for FTM register update. When using this it is not required to use PWM synchnronization.
62  *
63  * @param base         FTM peripheral base address
64  * @param reloadPoints FTM reload points. This is a logical OR of members of the
65  *                     enumeration ::ftm_reload_point_t
66  */
67 static void FTM_SetReloadPoints(FTM_Type *base, uint32_t reloadPoints);
68 
69 /*******************************************************************************
70  * Variables
71  ******************************************************************************/
72 /*! @brief Pointers to FTM bases for each instance. */
73 static FTM_Type *const s_ftmBases[] = FTM_BASE_PTRS;
74 
75 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
76 /*! @brief Pointers to FTM clocks for each instance. */
77 static const clock_ip_name_t s_ftmClocks[] = FTM_CLOCKS;
78 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
79 
80 /*******************************************************************************
81  * Code
82  ******************************************************************************/
FTM_GetInstance(FTM_Type * base)83 static uint32_t FTM_GetInstance(FTM_Type *base)
84 {
85     uint32_t instance;
86     uint32_t ftmArrayCount = (sizeof(s_ftmBases) / sizeof(s_ftmBases[0]));
87 
88     /* Find the instance index from base address mappings. */
89     for (instance = 0; instance < ftmArrayCount; instance++)
90     {
91         if (s_ftmBases[instance] == base)
92         {
93             break;
94         }
95     }
96 
97     assert(instance < ftmArrayCount);
98 
99     return instance;
100 }
101 
FTM_SetPwmSync(FTM_Type * base,uint32_t syncMethod)102 static void FTM_SetPwmSync(FTM_Type *base, uint32_t syncMethod)
103 {
104     uint8_t chnlNumber = 0;
105     uint32_t reg = 0, syncReg = 0;
106 
107     syncReg = base->SYNC;
108     /* Enable PWM synchronization of output mask register */
109     syncReg |= FTM_SYNC_SYNCHOM_MASK;
110 
111     reg = base->COMBINE;
112     for (chnlNumber = 0; chnlNumber < (FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2); chnlNumber++)
113     {
114         /* Enable PWM synchronization of registers C(n)V and C(n+1)V */
115         reg |= (1U << (FTM_COMBINE_SYNCEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlNumber)));
116     }
117     base->COMBINE = reg;
118 
119     reg = base->SYNCONF;
120 
121     /* Use enhanced PWM synchronization method. Use PWM sync to update register values */
122     reg |= (FTM_SYNCONF_SYNCMODE_MASK | FTM_SYNCONF_CNTINC_MASK | FTM_SYNCONF_INVC_MASK | FTM_SYNCONF_SWOC_MASK);
123 
124     if (syncMethod & FTM_SYNC_SWSYNC_MASK)
125     {
126         /* Enable needed bits for software trigger to update registers with its buffer value */
127         reg |= (FTM_SYNCONF_SWRSTCNT_MASK | FTM_SYNCONF_SWWRBUF_MASK | FTM_SYNCONF_SWINVC_MASK |
128                 FTM_SYNCONF_SWSOC_MASK | FTM_SYNCONF_SWOM_MASK);
129     }
130 
131     if (syncMethod & (FTM_SYNC_TRIG0_MASK | FTM_SYNC_TRIG1_MASK | FTM_SYNC_TRIG2_MASK))
132     {
133         /* Enable needed bits for hardware trigger to update registers with its buffer value */
134         reg |= (FTM_SYNCONF_HWRSTCNT_MASK | FTM_SYNCONF_HWWRBUF_MASK | FTM_SYNCONF_HWINVC_MASK |
135                 FTM_SYNCONF_HWSOC_MASK | FTM_SYNCONF_HWOM_MASK);
136 
137         /* Enable the appropriate hardware trigger that is used for PWM sync */
138         if (syncMethod & FTM_SYNC_TRIG0_MASK)
139         {
140             syncReg |= FTM_SYNC_TRIG0_MASK;
141         }
142         if (syncMethod & FTM_SYNC_TRIG1_MASK)
143         {
144             syncReg |= FTM_SYNC_TRIG1_MASK;
145         }
146         if (syncMethod & FTM_SYNC_TRIG2_MASK)
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 
164     /* Need CNTINC bit to be 1 for CNTIN register to update with its buffer value on reload  */
165     base->SYNCONF |= FTM_SYNCONF_CNTINC_MASK;
166 
167     reg = base->COMBINE;
168     for (chnlNumber = 0; chnlNumber < (FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2); chnlNumber++)
169     {
170         /* Need SYNCEN bit to be 1 for CnV reg to update with its buffer value on reload  */
171         reg |= (1U << (FTM_COMBINE_SYNCEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlNumber)));
172     }
173     base->COMBINE = reg;
174 
175     /* Set the reload points */
176     reg = base->PWMLOAD;
177 
178     /* Enable the selected channel match reload points */
179     reg &= ~((1U << FSL_FEATURE_FTM_CHANNEL_COUNTn(base)) - 1);
180     reg |= (reloadPoints & ((1U << FSL_FEATURE_FTM_CHANNEL_COUNTn(base)) - 1));
181 
182 #if defined(FSL_FEATURE_FTM_HAS_HALFCYCLE_RELOAD) && (FSL_FEATURE_FTM_HAS_HALFCYCLE_RELOAD)
183     /* Enable half cycle match as a reload point */
184     if (reloadPoints & kFTM_HalfCycMatch)
185     {
186         reg |= FTM_PWMLOAD_HCSEL_MASK;
187     }
188     else
189     {
190         reg &= ~FTM_PWMLOAD_HCSEL_MASK;
191     }
192 #endif /* FSL_FEATURE_FTM_HAS_HALFCYCLE_RELOAD */
193 
194     base->PWMLOAD = reg;
195 
196     /* These reload points are used when counter is in up-down counting mode */
197     reg = base->SYNC;
198     if (reloadPoints & kFTM_CntMax)
199     {
200         /* Reload when counter turns from up to down */
201         reg |= FTM_SYNC_CNTMAX_MASK;
202     }
203     else
204     {
205         reg &= ~FTM_SYNC_CNTMAX_MASK;
206     }
207 
208     if (reloadPoints & kFTM_CntMin)
209     {
210         /* Reload when counter turns from down to up */
211         reg |= FTM_SYNC_CNTMIN_MASK;
212     }
213     else
214     {
215         reg &= ~FTM_SYNC_CNTMIN_MASK;
216     }
217     base->SYNC = reg;
218 }
219 
FTM_Init(FTM_Type * base,const ftm_config_t * config)220 status_t FTM_Init(FTM_Type *base, const ftm_config_t *config)
221 {
222     assert(config);
223 
224     uint32_t reg;
225 
226     if (!(config->pwmSyncMode &
227           (FTM_SYNC_TRIG0_MASK | FTM_SYNC_TRIG1_MASK | FTM_SYNC_TRIG2_MASK | FTM_SYNC_SWSYNC_MASK)))
228     {
229         /* Invalid PWM sync mode */
230         return kStatus_Fail;
231     }
232 
233 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
234     /* Ungate the FTM clock*/
235     CLOCK_EnableClock(s_ftmClocks[FTM_GetInstance(base)]);
236 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
237 
238     /* Configure the fault mode, enable FTM mode and disable write protection */
239     base->MODE = FTM_MODE_FAULTM(config->faultMode) | FTM_MODE_FTMEN_MASK | FTM_MODE_WPDIS_MASK;
240 
241     /* Configure the update mechanism for buffered registers */
242     FTM_SetPwmSync(base, config->pwmSyncMode);
243 
244     /* Setup intermediate register reload points */
245     FTM_SetReloadPoints(base, config->reloadPoints);
246 
247     /* Set the clock prescale factor */
248     base->SC = FTM_SC_PS(config->prescale);
249 
250     /* Setup the counter operation */
251     base->CONF = (FTM_CONF_BDMMODE(config->bdmMode) | FTM_CONF_GTBEEN(config->useGlobalTimeBase));
252 
253     /* Initial state of channel output */
254     base->OUTINIT = config->chnlInitState;
255 
256     /* Channel polarity */
257     base->POL = config->chnlPolarity;
258 
259     /* Set the external trigger sources */
260     base->EXTTRIG = config->extTriggers;
261 #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INITIALIZATION_TRIGGER) && (FSL_FEATURE_FTM_HAS_RELOAD_INITIALIZATION_TRIGGER)
262     if (config->extTriggers & kFTM_ReloadInitTrigger)
263     {
264         base->CONF |= FTM_CONF_ITRIGR_MASK;
265     }
266     else
267     {
268         base->CONF &= ~FTM_CONF_ITRIGR_MASK;
269     }
270 #endif /* FSL_FEATURE_FTM_HAS_RELOAD_INITIALIZATION_TRIGGER */
271 
272     /* FTM deadtime insertion control */
273     base->DEADTIME = (0u |
274 #if defined(FSL_FEATURE_FTM_HAS_EXTENDED_DEADTIME_VALUE) && (FSL_FEATURE_FTM_HAS_EXTENDED_DEADTIME_VALUE)
275                         /* Has extended deadtime value register) */
276                         FTM_DEADTIME_DTVALEX(config->deadTimeValue >> 6) |
277 #endif /* FSL_FEATURE_FTM_HAS_EXTENDED_DEADTIME_VALUE */
278                         FTM_DEADTIME_DTPS(config->deadTimePrescale) |
279                         FTM_DEADTIME_DTVAL(config->deadTimeValue));
280 
281     /* FTM fault filter value */
282     reg = base->FLTCTRL;
283     reg &= ~FTM_FLTCTRL_FFVAL_MASK;
284     reg |= FTM_FLTCTRL_FFVAL(config->faultFilterValue);
285     base->FLTCTRL = reg;
286 
287     return kStatus_Success;
288 }
289 
FTM_Deinit(FTM_Type * base)290 void FTM_Deinit(FTM_Type *base)
291 {
292     /* Set clock source to none to disable counter */
293     base->SC &= ~(FTM_SC_CLKS_MASK);
294 
295 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
296     /* Gate the FTM clock */
297     CLOCK_DisableClock(s_ftmClocks[FTM_GetInstance(base)]);
298 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
299 }
300 
FTM_GetDefaultConfig(ftm_config_t * config)301 void FTM_GetDefaultConfig(ftm_config_t *config)
302 {
303     assert(config);
304 
305     /* Divide FTM clock by 1 */
306     config->prescale = kFTM_Prescale_Divide_1;
307     /* FTM behavior in BDM mode */
308     config->bdmMode = kFTM_BdmMode_0;
309     /* Software trigger will be used to update registers */
310     config->pwmSyncMode = kFTM_SoftwareTrigger;
311     /* No intermediate register load */
312     config->reloadPoints = 0;
313     /* Fault control disabled for all channels */
314     config->faultMode = kFTM_Fault_Disable;
315     /* Disable the fault filter */
316     config->faultFilterValue = 0;
317     /* Divide the system clock by 1 */
318     config->deadTimePrescale = kFTM_Deadtime_Prescale_1;
319     /* No counts are inserted */
320     config->deadTimeValue = 0;
321     /* No external trigger */
322     config->extTriggers = 0;
323     /* Initialization value is 0 for all channels */
324     config->chnlInitState = 0;
325     /* Active high polarity for all channels */
326     config->chnlPolarity = 0;
327     /* Use internal FTM counter as timebase */
328     config->useGlobalTimeBase = false;
329 }
330 
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)331 status_t FTM_SetupPwm(FTM_Type *base,
332                       const ftm_chnl_pwm_signal_param_t *chnlParams,
333                       uint8_t numOfChnls,
334                       ftm_pwm_mode_t mode,
335                       uint32_t pwmFreq_Hz,
336                       uint32_t srcClock_Hz)
337 {
338     assert(chnlParams);
339     assert(srcClock_Hz);
340     assert(pwmFreq_Hz);
341     assert(numOfChnls);
342 
343     uint32_t mod, reg;
344     uint32_t ftmClock = (srcClock_Hz / (1U << (base->SC & FTM_SC_PS_MASK)));
345     uint16_t cnv, cnvFirstEdge;
346     uint8_t i;
347 
348     switch (mode)
349     {
350         case kFTM_EdgeAlignedPwm:
351         case kFTM_CombinedPwm:
352             base->SC &= ~FTM_SC_CPWMS_MASK;
353             mod = (ftmClock / pwmFreq_Hz) - 1;
354             break;
355         case kFTM_CenterAlignedPwm:
356             base->SC |= FTM_SC_CPWMS_MASK;
357             mod = ftmClock / (pwmFreq_Hz * 2);
358             break;
359         default:
360             return kStatus_Fail;
361     }
362 
363     /* Return an error in case we overflow the registers, probably would require changing
364      * clock source to get the desired frequency */
365     if (mod > 65535U)
366     {
367         return kStatus_Fail;
368     }
369     /* Set the PWM period */
370     base->MOD = mod;
371 
372     /* Setup each FTM channel */
373     for (i = 0; i < numOfChnls; i++)
374     {
375         /* Return error if requested dutycycle is greater than the max allowed */
376         if (chnlParams->dutyCyclePercent > 100)
377         {
378             return kStatus_Fail;
379         }
380 
381         if ((mode == kFTM_EdgeAlignedPwm) || (mode == kFTM_CenterAlignedPwm))
382         {
383             /* Clear the current mode and edge level bits */
384             reg = base->CONTROLS[chnlParams->chnlNumber].CnSC;
385             reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
386 
387             /* Setup the active level */
388             reg |= (uint32_t)(chnlParams->level << FTM_CnSC_ELSA_SHIFT);
389 
390             /* Edge-aligned mode needs MSB to be 1, don't care for Center-aligned mode */
391             reg |= FTM_CnSC_MSB(1U);
392 
393             /* Update the mode and edge level */
394             base->CONTROLS[chnlParams->chnlNumber].CnSC = reg;
395 
396             if (chnlParams->dutyCyclePercent == 0)
397             {
398                 /* Signal stays low */
399                 cnv = 0;
400             }
401             else
402             {
403                 cnv = (mod * chnlParams->dutyCyclePercent) / 100;
404                 /* For 100% duty cycle */
405                 if (cnv >= mod)
406                 {
407                     cnv = mod + 1;
408                 }
409             }
410 
411             base->CONTROLS[chnlParams->chnlNumber].CnV = cnv;
412 #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
413             /* Set to output mode */
414             FTM_SetPwmOutputEnable(base, chnlParams->chnlNumber, true);
415 #endif
416         }
417         else
418         {
419             /* This check is added for combined mode as the channel number should be the pair number */
420             if (chnlParams->chnlNumber >= (FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2))
421             {
422                 return kStatus_Fail;
423             }
424 
425             /* Return error if requested value is greater than the max allowed */
426             if (chnlParams->firstEdgeDelayPercent > 100)
427             {
428                 return kStatus_Fail;
429             }
430 
431             /* Configure delay of the first edge */
432             if (chnlParams->firstEdgeDelayPercent == 0)
433             {
434                 /* No delay for the first edge */
435                 cnvFirstEdge = 0;
436             }
437             else
438             {
439                 cnvFirstEdge = (mod * chnlParams->firstEdgeDelayPercent) / 100;
440             }
441 
442             /* Configure dutycycle */
443             if (chnlParams->dutyCyclePercent == 0)
444             {
445                 /* Signal stays low */
446                 cnv = 0;
447                 cnvFirstEdge = 0;
448             }
449             else
450             {
451                 cnv = (mod * chnlParams->dutyCyclePercent) / 100;
452                 /* For 100% duty cycle */
453                 if (cnv >= mod)
454                 {
455                     cnv = mod + 1;
456                 }
457             }
458 
459             /* Clear the current mode and edge level bits for channel n */
460             reg = base->CONTROLS[chnlParams->chnlNumber * 2].CnSC;
461             reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
462 
463             /* Setup the active level for channel n */
464             reg |= (uint32_t)(chnlParams->level << FTM_CnSC_ELSA_SHIFT);
465 
466             /* Update the mode and edge level for channel n */
467             base->CONTROLS[chnlParams->chnlNumber * 2].CnSC = reg;
468 
469             /* Clear the current mode and edge level bits for channel n + 1 */
470             reg = base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC;
471             reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
472 
473             /* Setup the active level for channel n + 1 */
474             reg |= (uint32_t)(chnlParams->level << FTM_CnSC_ELSA_SHIFT);
475 
476             /* Update the mode and edge level for channel n + 1*/
477             base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC = reg;
478 
479             /* Set the combine bit for the channel pair */
480             base->COMBINE |=
481                 (1U << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlParams->chnlNumber)));
482 
483             /* Set the channel pair values */
484             base->CONTROLS[chnlParams->chnlNumber * 2].CnV = cnvFirstEdge;
485             base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnV = cnvFirstEdge + cnv;
486 
487 #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
488             /* Set to output mode */
489             FTM_SetPwmOutputEnable(base, (ftm_chnl_t)((uint8_t)chnlParams->chnlNumber * 2), true);
490             FTM_SetPwmOutputEnable(base, (ftm_chnl_t)((uint8_t)chnlParams->chnlNumber * 2 + 1), true);
491 #endif
492         }
493         chnlParams++;
494     }
495 
496     return kStatus_Success;
497 }
498 
FTM_UpdatePwmDutycycle(FTM_Type * base,ftm_chnl_t chnlNumber,ftm_pwm_mode_t currentPwmMode,uint8_t dutyCyclePercent)499 void FTM_UpdatePwmDutycycle(FTM_Type *base,
500                             ftm_chnl_t chnlNumber,
501                             ftm_pwm_mode_t currentPwmMode,
502                             uint8_t dutyCyclePercent)
503 {
504     uint16_t cnv, cnvFirstEdge = 0, mod;
505 
506     mod = base->MOD;
507     if ((currentPwmMode == kFTM_EdgeAlignedPwm) || (currentPwmMode == kFTM_CenterAlignedPwm))
508     {
509         cnv = (mod * dutyCyclePercent) / 100;
510         /* For 100% duty cycle */
511         if (cnv >= mod)
512         {
513             cnv = mod + 1;
514         }
515         base->CONTROLS[chnlNumber].CnV = cnv;
516     }
517     else
518     {
519         /* This check is added for combined mode as the channel number should be the pair number */
520         if (chnlNumber >= (FSL_FEATURE_FTM_CHANNEL_COUNTn(base) / 2))
521         {
522             return;
523         }
524 
525         cnv = (mod * dutyCyclePercent) / 100;
526         cnvFirstEdge = base->CONTROLS[chnlNumber * 2].CnV;
527         /* For 100% duty cycle */
528         if (cnv >= mod)
529         {
530             cnv = mod + 1;
531         }
532         base->CONTROLS[(chnlNumber * 2) + 1].CnV = cnvFirstEdge + cnv;
533     }
534 }
535 
FTM_UpdateChnlEdgeLevelSelect(FTM_Type * base,ftm_chnl_t chnlNumber,uint8_t level)536 void FTM_UpdateChnlEdgeLevelSelect(FTM_Type *base, ftm_chnl_t chnlNumber, uint8_t level)
537 {
538     uint32_t reg = base->CONTROLS[chnlNumber].CnSC;
539 
540     /* Clear the field and write the new level value */
541     reg &= ~(FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
542     reg |= ((uint32_t)level << FTM_CnSC_ELSA_SHIFT) & (FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
543 
544     base->CONTROLS[chnlNumber].CnSC = reg;
545 }
546 
FTM_SetupInputCapture(FTM_Type * base,ftm_chnl_t chnlNumber,ftm_input_capture_edge_t captureMode,uint32_t filterValue)547 void FTM_SetupInputCapture(FTM_Type *base,
548                            ftm_chnl_t chnlNumber,
549                            ftm_input_capture_edge_t captureMode,
550                            uint32_t filterValue)
551 {
552     uint32_t reg;
553 
554     /* Clear the combine bit for the channel pair */
555     base->COMBINE &= ~(1U << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (chnlNumber >> 1))));
556     /* Clear the dual edge capture mode because it's it's higher priority */
557     base->COMBINE &= ~(1U << (FTM_COMBINE_DECAPEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (chnlNumber >> 1))));
558     /* Clear the quadrature decoder mode beacause it's higher priority */
559     base->QDCTRL &= ~FTM_QDCTRL_QUADEN_MASK;
560 
561     reg = base->CONTROLS[chnlNumber].CnSC;
562     reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
563     reg |= captureMode;
564 
565     /* Set the requested input capture mode */
566     base->CONTROLS[chnlNumber].CnSC = reg;
567     /* Input filter available only for channels 0, 1, 2, 3 */
568     if (chnlNumber < kFTM_Chnl_4)
569     {
570         reg = base->FILTER;
571         reg &= ~(FTM_FILTER_CH0FVAL_MASK << (FTM_FILTER_CH1FVAL_SHIFT * chnlNumber));
572         reg |= (filterValue << (FTM_FILTER_CH1FVAL_SHIFT * chnlNumber));
573         base->FILTER = reg;
574     }
575 #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
576     /* Set to input mode */
577     FTM_SetPwmOutputEnable(base, chnlNumber, false);
578 #endif
579 }
580 
FTM_SetupOutputCompare(FTM_Type * base,ftm_chnl_t chnlNumber,ftm_output_compare_mode_t compareMode,uint32_t compareValue)581 void FTM_SetupOutputCompare(FTM_Type *base,
582                             ftm_chnl_t chnlNumber,
583                             ftm_output_compare_mode_t compareMode,
584                             uint32_t compareValue)
585 {
586     uint32_t reg;
587 
588     /* Clear the combine bit for the channel pair */
589     base->COMBINE &= ~(1U << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (chnlNumber >> 1))));
590     /* Clear the dual edge capture mode because it's it's higher priority */
591     base->COMBINE &= ~(1U << (FTM_COMBINE_DECAPEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * (chnlNumber >> 1))));
592     /* Clear the quadrature decoder mode beacause it's higher priority */
593     base->QDCTRL &= ~FTM_QDCTRL_QUADEN_MASK;
594 
595     reg = base->CONTROLS[chnlNumber].CnSC;
596     reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
597     reg |= compareMode;
598     /* Setup the channel output behaviour when a match occurs with the compare value */
599     base->CONTROLS[chnlNumber].CnSC = reg;
600 
601     /* Set output on match to the requested level */
602     base->CONTROLS[chnlNumber].CnV = compareValue;
603 
604 #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
605     /* Set to output mode */
606     FTM_SetPwmOutputEnable(base, chnlNumber, true);
607 #endif
608 }
609 
FTM_SetupDualEdgeCapture(FTM_Type * base,ftm_chnl_t chnlPairNumber,const ftm_dual_edge_capture_param_t * edgeParam,uint32_t filterValue)610 void FTM_SetupDualEdgeCapture(FTM_Type *base,
611                               ftm_chnl_t chnlPairNumber,
612                               const ftm_dual_edge_capture_param_t *edgeParam,
613                               uint32_t filterValue)
614 {
615     assert(edgeParam);
616 
617     uint32_t reg;
618 
619     reg = base->COMBINE;
620     /* Clear the combine bit for the channel pair */
621     reg &= ~(1U << (FTM_COMBINE_COMBINE0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlPairNumber)));
622     /* Enable the DECAPEN bit */
623     reg |= (1U << (FTM_COMBINE_DECAPEN0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlPairNumber)));
624     reg |= (1U << (FTM_COMBINE_DECAP0_SHIFT + (FTM_COMBINE_COMBINE1_SHIFT * chnlPairNumber)));
625     base->COMBINE = reg;
626 
627     /* Setup the edge detection from channel n and n + 1 */
628     reg = base->CONTROLS[chnlPairNumber * 2].CnSC;
629     reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
630     reg |= ((uint32_t)edgeParam->mode | (uint32_t)edgeParam->currChanEdgeMode);
631     base->CONTROLS[chnlPairNumber * 2].CnSC = reg;
632 
633     reg = base->CONTROLS[(chnlPairNumber * 2) + 1].CnSC;
634     reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
635     reg |= ((uint32_t)edgeParam->mode | (uint32_t)edgeParam->nextChanEdgeMode);
636     base->CONTROLS[(chnlPairNumber * 2) + 1].CnSC = reg;
637 
638     /* Input filter available only for channels 0, 1, 2, 3 */
639     if (chnlPairNumber < kFTM_Chnl_4)
640     {
641         reg = base->FILTER;
642         reg &= ~(FTM_FILTER_CH0FVAL_MASK << (FTM_FILTER_CH1FVAL_SHIFT * chnlPairNumber));
643         reg |= (filterValue << (FTM_FILTER_CH1FVAL_SHIFT * chnlPairNumber));
644         base->FILTER = reg;
645     }
646 
647 #if defined(FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT) && (FSL_FEATURE_FTM_HAS_ENABLE_PWM_OUTPUT)
648     /* Set to input mode */
649     FTM_SetPwmOutputEnable(base, chnlPairNumber, false);
650 #endif
651 }
652 
FTM_SetupQuadDecode(FTM_Type * base,const ftm_phase_params_t * phaseAParams,const ftm_phase_params_t * phaseBParams,ftm_quad_decode_mode_t quadMode)653 void FTM_SetupQuadDecode(FTM_Type *base,
654                          const ftm_phase_params_t *phaseAParams,
655                          const ftm_phase_params_t *phaseBParams,
656                          ftm_quad_decode_mode_t quadMode)
657 {
658     assert(phaseAParams);
659     assert(phaseBParams);
660 
661     uint32_t reg;
662 
663     /* Set Phase A filter value if phase filter is enabled */
664     if (phaseAParams->enablePhaseFilter)
665     {
666         reg = base->FILTER;
667         reg &= ~(FTM_FILTER_CH0FVAL_MASK);
668         reg |= FTM_FILTER_CH0FVAL(phaseAParams->phaseFilterVal);
669         base->FILTER = reg;
670     }
671 
672     /* Set Phase B filter value if phase filter is enabled */
673     if (phaseBParams->enablePhaseFilter)
674     {
675         reg = base->FILTER;
676         reg &= ~(FTM_FILTER_CH1FVAL_MASK);
677         reg |= FTM_FILTER_CH1FVAL(phaseBParams->phaseFilterVal);
678         base->FILTER = reg;
679     }
680 
681     /* Set Quadrature decode properties */
682     reg = base->QDCTRL;
683     reg &= ~(FTM_QDCTRL_QUADMODE_MASK | FTM_QDCTRL_PHAFLTREN_MASK | FTM_QDCTRL_PHBFLTREN_MASK | FTM_QDCTRL_PHAPOL_MASK |
684              FTM_QDCTRL_PHBPOL_MASK);
685     reg |= (FTM_QDCTRL_QUADMODE(quadMode) | FTM_QDCTRL_PHAFLTREN(phaseAParams->enablePhaseFilter) |
686             FTM_QDCTRL_PHBFLTREN(phaseBParams->enablePhaseFilter) | FTM_QDCTRL_PHAPOL(phaseAParams->phasePolarity) |
687             FTM_QDCTRL_PHBPOL(phaseBParams->phasePolarity));
688     base->QDCTRL = reg;
689     /* Enable Quad decode */
690     base->QDCTRL |= FTM_QDCTRL_QUADEN_MASK;
691 }
692 
FTM_SetupFault(FTM_Type * base,ftm_fault_input_t faultNumber,const ftm_fault_param_t * faultParams)693 void FTM_SetupFault(FTM_Type *base, ftm_fault_input_t faultNumber, const ftm_fault_param_t *faultParams)
694 {
695     assert(faultParams);
696 
697     uint32_t reg;
698 
699     reg = base->FLTCTRL;
700     if (faultParams->enableFaultInput)
701     {
702         /* Enable the fault input */
703         reg |= (FTM_FLTCTRL_FAULT0EN_MASK << faultNumber);
704     }
705     else
706     {
707         /* Disable the fault input */
708         reg &= ~(FTM_FLTCTRL_FAULT0EN_MASK << faultNumber);
709     }
710 
711     if (faultParams->useFaultFilter)
712     {
713         /* Enable the fault filter */
714         reg |= (FTM_FLTCTRL_FFLTR0EN_MASK << (FTM_FLTCTRL_FFLTR0EN_SHIFT + faultNumber));
715     }
716     else
717     {
718         /* Disable the fault filter */
719         reg &= ~(FTM_FLTCTRL_FFLTR0EN_MASK << (FTM_FLTCTRL_FFLTR0EN_SHIFT + faultNumber));
720     }
721     base->FLTCTRL = reg;
722 
723     if (faultParams->faultLevel)
724     {
725         /* Active low polarity for the fault input pin */
726         base->FLTPOL |= (1U << faultNumber);
727     }
728     else
729     {
730         /* Active high polarity for the fault input pin */
731         base->FLTPOL &= ~(1U << faultNumber);
732     }
733 }
734 
FTM_EnableInterrupts(FTM_Type * base,uint32_t mask)735 void FTM_EnableInterrupts(FTM_Type *base, uint32_t mask)
736 {
737     uint32_t chnlInts = (mask & 0xFFU);
738     uint8_t chnlNumber = 0;
739 
740     /* Enable the timer overflow interrupt */
741     if (mask & kFTM_TimeOverflowInterruptEnable)
742     {
743         base->SC |= FTM_SC_TOIE_MASK;
744     }
745 
746     /* Enable the fault interrupt */
747     if (mask & kFTM_FaultInterruptEnable)
748     {
749         base->MODE |= FTM_MODE_FAULTIE_MASK;
750     }
751 
752 #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
753     /* Enable the reload interrupt available only on certain SoC's */
754     if (mask & kFTM_ReloadInterruptEnable)
755     {
756         base->SC |= FTM_SC_RIE_MASK;
757     }
758 #endif
759 
760     /* Enable the channel interrupts */
761     while (chnlInts)
762     {
763         if (chnlInts & 0x1)
764         {
765             base->CONTROLS[chnlNumber].CnSC |= FTM_CnSC_CHIE_MASK;
766         }
767         chnlNumber++;
768         chnlInts = chnlInts >> 1U;
769     }
770 }
771 
FTM_DisableInterrupts(FTM_Type * base,uint32_t mask)772 void FTM_DisableInterrupts(FTM_Type *base, uint32_t mask)
773 {
774     uint32_t chnlInts = (mask & 0xFF);
775     uint8_t chnlNumber = 0;
776 
777     /* Disable the timer overflow interrupt */
778     if (mask & kFTM_TimeOverflowInterruptEnable)
779     {
780         base->SC &= ~FTM_SC_TOIE_MASK;
781     }
782     /* Disable the fault interrupt */
783     if (mask & kFTM_FaultInterruptEnable)
784     {
785         base->MODE &= ~FTM_MODE_FAULTIE_MASK;
786     }
787 
788 #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
789     /* Disable the reload interrupt available only on certain SoC's */
790     if (mask & kFTM_ReloadInterruptEnable)
791     {
792         base->SC &= ~FTM_SC_RIE_MASK;
793     }
794 #endif
795 
796     /* Disable the channel interrupts */
797     while (chnlInts)
798     {
799         if (chnlInts & 0x1)
800         {
801             base->CONTROLS[chnlNumber].CnSC &= ~FTM_CnSC_CHIE_MASK;
802         }
803         chnlNumber++;
804         chnlInts = chnlInts >> 1U;
805     }
806 }
807 
FTM_GetEnabledInterrupts(FTM_Type * base)808 uint32_t FTM_GetEnabledInterrupts(FTM_Type *base)
809 {
810     uint32_t enabledInterrupts = 0;
811     int8_t chnlCount = FSL_FEATURE_FTM_CHANNEL_COUNTn(base);
812 
813     /* The CHANNEL_COUNT macro returns -1 if it cannot match the FTM instance */
814     assert(chnlCount != -1);
815 
816     /* Check if timer overflow interrupt is enabled */
817     if (base->SC & FTM_SC_TOIE_MASK)
818     {
819         enabledInterrupts |= kFTM_TimeOverflowInterruptEnable;
820     }
821     /* Check if fault interrupt is enabled */
822     if (base->MODE & FTM_MODE_FAULTIE_MASK)
823     {
824         enabledInterrupts |= kFTM_FaultInterruptEnable;
825     }
826 
827 #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
828     /* Check if the reload interrupt is enabled */
829     if (base->SC & FTM_SC_RIE_MASK)
830     {
831         enabledInterrupts |= kFTM_ReloadInterruptEnable;
832     }
833 #endif
834 
835     /* Check if the channel interrupts are enabled */
836     while (chnlCount > 0)
837     {
838         chnlCount--;
839         if (base->CONTROLS[chnlCount].CnSC & FTM_CnSC_CHIE_MASK)
840         {
841             enabledInterrupts |= (1U << chnlCount);
842         }
843     }
844 
845     return enabledInterrupts;
846 }
847 
FTM_GetStatusFlags(FTM_Type * base)848 uint32_t FTM_GetStatusFlags(FTM_Type *base)
849 {
850     uint32_t statusFlags = 0;
851 
852     /* Check the timer flag */
853     if (base->SC & FTM_SC_TOF_MASK)
854     {
855         statusFlags |= kFTM_TimeOverflowFlag;
856     }
857     /* Check fault flag */
858     if (base->FMS & FTM_FMS_FAULTF_MASK)
859     {
860         statusFlags |= kFTM_FaultFlag;
861     }
862     /* Check channel trigger flag */
863     if (base->EXTTRIG & FTM_EXTTRIG_TRIGF_MASK)
864     {
865         statusFlags |= kFTM_ChnlTriggerFlag;
866     }
867 #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
868     /* Check reload flag */
869     if (base->SC & FTM_SC_RF_MASK)
870     {
871         statusFlags |= kFTM_ReloadFlag;
872     }
873 #endif
874 
875     /* Lower 8 bits contain the channel status flags */
876     statusFlags |= (base->STATUS & 0xFFU);
877 
878     return statusFlags;
879 }
880 
FTM_ClearStatusFlags(FTM_Type * base,uint32_t mask)881 void FTM_ClearStatusFlags(FTM_Type *base, uint32_t mask)
882 {
883     /* Clear the timer overflow flag by writing a 0 to the bit while it is set */
884     if (mask & kFTM_TimeOverflowFlag)
885     {
886         base->SC &= ~FTM_SC_TOF_MASK;
887     }
888     /* Clear fault flag by writing a 0 to the bit while it is set */
889     if (mask & kFTM_FaultFlag)
890     {
891         base->FMS &= ~FTM_FMS_FAULTF_MASK;
892     }
893     /* Clear channel trigger flag */
894     if (mask & kFTM_ChnlTriggerFlag)
895     {
896         base->EXTTRIG &= ~FTM_EXTTRIG_TRIGF_MASK;
897     }
898 
899 #if defined(FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT) && (FSL_FEATURE_FTM_HAS_RELOAD_INTERRUPT)
900     /* Check reload flag by writing a 0 to the bit while it is set */
901     if (mask & kFTM_ReloadFlag)
902     {
903         base->SC &= ~FTM_SC_RF_MASK;
904     }
905 #endif
906     /* Clear the channel status flags by writing a 0 to the bit */
907     base->STATUS &= ~(mask & 0xFFU);
908 }
909