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_pwm.h"
10 
11 /* Component ID definition, used by tools. */
12 #ifndef FSL_COMPONENT_ID
13 #define FSL_COMPONENT_ID "platform.drivers.pwm"
14 #endif
15 
16 /*******************************************************************************
17  * Prototypes
18  ******************************************************************************/
19 /*!
20  * @brief Get the instance from the base address
21  *
22  * @param base PWM peripheral base address
23  *
24  * @return The PWM module instance
25  */
26 static uint32_t PWM_GetInstance(PWM_Type *base);
27 
28 #if defined(PWM_RSTS)
29 #define PWM_RESETS_ARRAY PWM_RSTS
30 #elif defined(FLEXPWM_RSTS)
31 #define PWM_RESETS_ARRAY FLEXPWM_RSTS
32 #elif defined(FLEXPWM_RSTS_N)
33 #define PWM_RESETS_ARRAY FLEXPWM_RSTS_N
34 #endif
35 
36 /*******************************************************************************
37  * Variables
38  ******************************************************************************/
39 /*! @brief Pointers to PWM bases for each instance. */
40 static PWM_Type *const s_pwmBases[] = PWM_BASE_PTRS;
41 
42 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
43 /*! @brief Pointers to PWM clocks for each PWM submodule. */
44 static const clock_ip_name_t s_pwmClocks[][FSL_FEATURE_PWM_SUBMODULE_COUNT] = PWM_CLOCKS;
45 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
46 
47 #if defined(PWM_RESETS_ARRAY)
48 /* Reset array */
49 static const reset_ip_name_t s_pwmResets[] = PWM_RESETS_ARRAY;
50 #endif
51 
52 /*! @brief Temporary PWM duty cycle. */
53 static uint8_t s_pwmGetPwmDutyCycle[FSL_FEATURE_PWM_SUBMODULE_COUNT][PWM_SUBMODULE_CHANNEL] = {{0}};
54 
55 /*******************************************************************************
56  * Code
57  ******************************************************************************/
58 
59 /*!
60  * brief Complement the variable of type uint16_t as needed
61  *
62  * This function can complement the variable of type uint16_t as needed.For example,
63  * need to ask for the opposite of a positive integer.
64  *
65  * param value    Parameters of type uint16_t
66  */
PWM_GetComplementU16(uint16_t value)67 static inline uint16_t PWM_GetComplementU16(uint16_t value)
68 {
69     return (~value + 1U);
70 }
71 
dutyCycleToReloadValue(uint8_t dutyCyclePercent)72 static inline uint16_t dutyCycleToReloadValue(uint8_t dutyCyclePercent)
73 {
74     /* Rounding calculations to improve the accuracy of reloadValue */
75     return ((65535U * dutyCyclePercent) + 50U) / 100U;
76 }
77 
PWM_GetInstance(PWM_Type * base)78 static uint32_t PWM_GetInstance(PWM_Type *base)
79 {
80     uint32_t instance;
81 
82     /* Find the instance index from base address mappings. */
83     for (instance = 0; instance < ARRAY_SIZE(s_pwmBases); instance++)
84     {
85         if (s_pwmBases[instance] == base)
86         {
87             break;
88         }
89     }
90 
91     assert(instance < ARRAY_SIZE(s_pwmBases));
92 
93     return instance;
94 }
95 
96 /*!
97  * brief Set register about period on one PWM submodule.
98  *
99  * param base        PWM peripheral base address
100  * param subModule   PWM submodule to configure
101  * param mode        PWM operation mode, options available in enumeration ::pwm_mode_t
102  * param pulseCnt    PWM period, value should be between 0 to 65535
103  */
PWM_SetPeriodRegister(PWM_Type * base,pwm_submodule_t subModule,pwm_mode_t mode,uint16_t pulseCnt)104 static void PWM_SetPeriodRegister(PWM_Type *base, pwm_submodule_t subModule, pwm_mode_t mode, uint16_t pulseCnt)
105 {
106     uint16_t modulo = 0;
107 
108     switch (mode)
109     {
110         case kPWM_SignedCenterAligned:
111             /* Setup the PWM period for a signed center aligned signal */
112             modulo = (pulseCnt >> 1U);
113             /* Indicates the start of the PWM period */
114             base->SM[subModule].INIT = PWM_GetComplementU16(modulo);
115             /* Indicates the center value */
116             base->SM[subModule].VAL0 = 0;
117             /* Indicates the end of the PWM period */
118             /* The change during the end to start of the PWM period requires a count time */
119             base->SM[subModule].VAL1 = modulo - 1U;
120             break;
121         case kPWM_CenterAligned:
122             /* Setup the PWM period for an unsigned center aligned signal */
123             /* Indicates the start of the PWM period */
124             base->SM[subModule].INIT = 0;
125             /* Indicates the center value */
126             base->SM[subModule].VAL0 = (pulseCnt / 2U);
127             /* Indicates the end of the PWM period */
128             /* The change during the end to start of the PWM period requires a count time */
129             base->SM[subModule].VAL1 = pulseCnt - 1U;
130             break;
131         case kPWM_SignedEdgeAligned:
132             /* Setup the PWM period for a signed edge aligned signal */
133             modulo = (pulseCnt >> 1U);
134             /* Indicates the start of the PWM period */
135             base->SM[subModule].INIT = PWM_GetComplementU16(modulo);
136             /* Indicates the center value */
137             base->SM[subModule].VAL0 = 0;
138             /* Indicates the end of the PWM period */
139             /* The change during the end to start of the PWM period requires a count time */
140             base->SM[subModule].VAL1 = modulo - 1U;
141             break;
142         case kPWM_EdgeAligned:
143             /* Setup the PWM period for a unsigned edge aligned signal */
144             /* Indicates the start of the PWM period */
145             base->SM[subModule].INIT = 0;
146             /* Indicates the center value */
147             base->SM[subModule].VAL0 = (pulseCnt / 2U);
148             /* Indicates the end of the PWM period */
149             /* The change during the end to start of the PWM period requires a count time */
150             base->SM[subModule].VAL1 = pulseCnt - 1U;
151             break;
152         default:
153             assert(false);
154             break;
155     }
156 }
157 
158 /*!
159  * brief Set register about dutycycle on one PWM submodule.
160  *
161  * param base        PWM peripheral base address
162  * param subModule   PWM submodule to configure
163  * param pwmSignal   Signal (PWM A or PWM B) to update
164  * param mode        PWM operation mode, options available in enumeration ::pwm_mode_t
165  * param pulseCnt    PWM period, value should be between 0 to 65535
166  * param dutyCycle         New PWM pulse width, value should be between 0 to 65535
167  */
PWM_SetDutycycleRegister(PWM_Type * base,pwm_submodule_t subModule,pwm_channels_t pwmSignal,pwm_mode_t mode,uint16_t pulseCnt,uint16_t pwmHighPulse)168 static void PWM_SetDutycycleRegister(PWM_Type *base,
169                                      pwm_submodule_t subModule,
170                                      pwm_channels_t pwmSignal,
171                                      pwm_mode_t mode,
172                                      uint16_t pulseCnt,
173                                      uint16_t pwmHighPulse)
174 {
175     uint16_t modulo = 0;
176 
177     switch (mode)
178     {
179         case kPWM_SignedCenterAligned:
180             /* Setup the PWM dutycycle for a signed center aligned signal */
181             if (pwmSignal == kPWM_PwmA)
182             {
183                 base->SM[subModule].VAL2 = PWM_GetComplementU16(pwmHighPulse / 2U);
184                 base->SM[subModule].VAL3 = (pwmHighPulse / 2U);
185             }
186             else if (pwmSignal == kPWM_PwmB)
187             {
188                 base->SM[subModule].VAL4 = PWM_GetComplementU16(pwmHighPulse / 2U);
189                 base->SM[subModule].VAL5 = (pwmHighPulse / 2U);
190             }
191             else
192             {
193                 ; /* Intentional empty */
194             }
195             break;
196         case kPWM_CenterAligned:
197             /* Setup the PWM dutycycle for an unsigned center aligned signal */
198             if (pwmSignal == kPWM_PwmA)
199             {
200                 base->SM[subModule].VAL2 = ((pulseCnt - pwmHighPulse) / 2U);
201                 base->SM[subModule].VAL3 = ((pulseCnt + pwmHighPulse) / 2U);
202             }
203             else if (pwmSignal == kPWM_PwmB)
204             {
205                 base->SM[subModule].VAL4 = ((pulseCnt - pwmHighPulse) / 2U);
206                 base->SM[subModule].VAL5 = ((pulseCnt + pwmHighPulse) / 2U);
207             }
208             else
209             {
210                 ; /* Intentional empty */
211             }
212             break;
213         case kPWM_SignedEdgeAligned:
214             modulo = (pulseCnt >> 1U);
215 
216             /* Setup the PWM dutycycle for a signed edge aligned signal */
217             if (pwmSignal == kPWM_PwmA)
218             {
219                 base->SM[subModule].VAL2 = PWM_GetComplementU16(modulo);
220                 base->SM[subModule].VAL3 = PWM_GetComplementU16(modulo) + pwmHighPulse;
221             }
222             else if (pwmSignal == kPWM_PwmB)
223             {
224                 base->SM[subModule].VAL4 = PWM_GetComplementU16(modulo);
225                 base->SM[subModule].VAL5 = PWM_GetComplementU16(modulo) + pwmHighPulse;
226             }
227             else
228             {
229                 ; /* Intentional empty */
230             }
231             break;
232         case kPWM_EdgeAligned:
233             /* Setup the PWM dutycycle for a unsigned edge aligned signal */
234             if (pwmSignal == kPWM_PwmA)
235             {
236                 base->SM[subModule].VAL2 = 0;
237                 base->SM[subModule].VAL3 = pwmHighPulse;
238             }
239             else if (pwmSignal == kPWM_PwmB)
240             {
241                 base->SM[subModule].VAL4 = 0;
242                 base->SM[subModule].VAL5 = pwmHighPulse;
243             }
244             else
245             {
246                 ; /* Intentional empty */
247             }
248             break;
249         default:
250             assert(false);
251             break;
252     }
253 }
254 
255 /*!
256  * brief Ungates the PWM submodule clock and configures the peripheral for basic operation.
257  *
258  * note This API should be called at the beginning of the application using the PWM driver.
259  *
260  * param base      PWM peripheral base address
261  * param subModule PWM submodule to configure
262  * param config    Pointer to user's PWM config structure.
263  *
264  * return kStatus_Success means success; else failed.
265  */
PWM_Init(PWM_Type * base,pwm_submodule_t subModule,const pwm_config_t * config)266 status_t PWM_Init(PWM_Type *base, pwm_submodule_t subModule, const pwm_config_t *config)
267 {
268     assert(config);
269 
270     uint16_t reg;
271 
272     /* Source clock for submodule 0 cannot be itself */
273     if ((config->clockSource == kPWM_Submodule0Clock) && (subModule == kPWM_Module_0))
274     {
275         return kStatus_Fail;
276     }
277 
278     /* Reload source select clock for submodule 0 cannot be master reload */
279     if ((config->reloadSelect == kPWM_MasterReload) && (subModule == kPWM_Module_0))
280     {
281         return kStatus_Fail;
282     }
283 
284 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
285     /* Ungate the PWM submodule clock*/
286     CLOCK_EnableClock(s_pwmClocks[PWM_GetInstance(base)][subModule]);
287 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
288 
289 #if defined(PWM_RESETS_ARRAY)
290     RESET_ReleasePeripheralReset(s_pwmResets[PWM_GetInstance(base)]);
291 #endif
292 
293     /* Clear the fault status flags */
294     base->FSTS |= PWM_FSTS_FFLAG_MASK;
295 
296     reg = base->SM[subModule].CTRL2;
297 
298     /* Setup the submodule clock-source, control source of the INIT signal,
299      * source of the force output signal, operation in debug & wait modes and reload source select
300      */
301     reg &=
302         ~(uint16_t)(PWM_CTRL2_CLK_SEL_MASK | PWM_CTRL2_FORCE_SEL_MASK | PWM_CTRL2_INIT_SEL_MASK | PWM_CTRL2_INDEP_MASK |
303 #if !defined(FSL_FEATURE_PWM_HAS_NO_WAITEN) || (!FSL_FEATURE_PWM_HAS_NO_WAITEN)
304                     PWM_CTRL2_WAITEN_MASK |
305 #endif /* FSL_FEATURE_PWM_HAS_NO_WAITEN */
306                     PWM_CTRL2_DBGEN_MASK | PWM_CTRL2_RELOAD_SEL_MASK);
307     reg |= (PWM_CTRL2_CLK_SEL(config->clockSource) | PWM_CTRL2_FORCE_SEL(config->forceTrigger) |
308             PWM_CTRL2_INIT_SEL(config->initializationControl) | PWM_CTRL2_DBGEN(config->enableDebugMode) |
309 #if !defined(FSL_FEATURE_PWM_HAS_NO_WAITEN) || (!FSL_FEATURE_PWM_HAS_NO_WAITEN)
310             PWM_CTRL2_WAITEN(config->enableWait) |
311 #endif /* FSL_FEATURE_PWM_HAS_NO_WAITEN */
312             PWM_CTRL2_RELOAD_SEL(config->reloadSelect));
313 
314     /* Setup PWM A & B to be independent or a complementary-pair */
315     switch (config->pairOperation)
316     {
317         case kPWM_Independent:
318             reg |= PWM_CTRL2_INDEP_MASK;
319             break;
320         case kPWM_ComplementaryPwmA:
321             base->MCTRL &= ~((uint16_t)1U << (PWM_MCTRL_IPOL_SHIFT + (uint16_t)subModule));
322             break;
323         case kPWM_ComplementaryPwmB:
324             base->MCTRL |= ((uint16_t)1U << (PWM_MCTRL_IPOL_SHIFT + (uint16_t)subModule));
325             break;
326         default:
327             assert(false);
328             break;
329     }
330     base->SM[subModule].CTRL2 = reg;
331 
332     reg = base->SM[subModule].CTRL;
333 
334     /* Setup the clock prescale, load mode and frequency */
335     reg &= ~(uint16_t)(PWM_CTRL_PRSC_MASK | PWM_CTRL_LDFQ_MASK | PWM_CTRL_LDMOD_MASK);
336     reg |= (PWM_CTRL_PRSC(config->prescale) | PWM_CTRL_LDFQ(config->reloadFrequency));
337 
338     /* Setup register reload logic */
339     switch (config->reloadLogic)
340     {
341         case kPWM_ReloadImmediate:
342             reg |= PWM_CTRL_LDMOD_MASK;
343             break;
344         case kPWM_ReloadPwmHalfCycle:
345             reg |= PWM_CTRL_HALF_MASK;
346             reg &= (uint16_t)(~PWM_CTRL_FULL_MASK);
347             break;
348         case kPWM_ReloadPwmFullCycle:
349             reg &= (uint16_t)(~PWM_CTRL_HALF_MASK);
350             reg |= PWM_CTRL_FULL_MASK;
351             break;
352         case kPWM_ReloadPwmHalfAndFullCycle:
353             reg |= PWM_CTRL_HALF_MASK;
354             reg |= PWM_CTRL_FULL_MASK;
355             break;
356         default:
357             assert(false);
358             break;
359     }
360     base->SM[subModule].CTRL = reg;
361 
362     /* Set PWM output normal */
363 #if defined(PWM_MASK_UPDATE_MASK)
364     base->MASK &= (uint16_t)(~(uint16_t)(PWM_MASK_MASKX_MASK | PWM_MASK_MASKA_MASK | PWM_MASK_MASKB_MASK |
365                                          PWM_MASK_UPDATE_MASK_MASK));
366 #else
367     base->MASK &= ~(uint16_t)(PWM_MASK_MASKX_MASK | PWM_MASK_MASKA_MASK | PWM_MASK_MASKB_MASK);
368 #endif
369 
370     base->DTSRCSEL = 0U;
371 
372     /* Issue a Force trigger event when configured to trigger locally */
373     if (config->forceTrigger == kPWM_Force_Local)
374     {
375         base->SM[subModule].CTRL2 |= PWM_CTRL2_FORCE(1U);
376     }
377 
378     return kStatus_Success;
379 }
380 
381 /*!
382  * brief Gate the PWM submodule clock
383  *
384  * param base      PWM peripheral base address
385  * param subModule PWM submodule to deinitialize
386  */
PWM_Deinit(PWM_Type * base,pwm_submodule_t subModule)387 void PWM_Deinit(PWM_Type *base, pwm_submodule_t subModule)
388 {
389     /* Stop the submodule */
390     base->MCTRL &= ~((uint16_t)1U << (PWM_MCTRL_RUN_SHIFT + (uint16_t)subModule));
391 
392 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
393     /* Gate the PWM submodule clock*/
394     CLOCK_DisableClock(s_pwmClocks[PWM_GetInstance(base)][subModule]);
395 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
396 }
397 
398 /*!
399  * brief  Fill in the PWM config struct with the default settings
400  *
401  * The default values are:
402  * code
403  *   config->enableDebugMode = false;
404  *   config->enableWait = false;
405  *   config->reloadSelect = kPWM_LocalReload;
406  *   config->clockSource = kPWM_BusClock;
407  *   config->prescale = kPWM_Prescale_Divide_1;
408  *   config->initializationControl = kPWM_Initialize_LocalSync;
409  *   config->forceTrigger = kPWM_Force_Local;
410  *   config->reloadFrequency = kPWM_LoadEveryOportunity;
411  *   config->reloadLogic = kPWM_ReloadImmediate;
412  *   config->pairOperation = kPWM_Independent;
413  * endcode
414  * param config Pointer to user's PWM config structure.
415  */
PWM_GetDefaultConfig(pwm_config_t * config)416 void PWM_GetDefaultConfig(pwm_config_t *config)
417 {
418     assert(config);
419 
420     /* Initializes the configure structure to zero. */
421     (void)memset(config, 0, sizeof(*config));
422 
423     /* PWM is paused in debug mode */
424     config->enableDebugMode = false;
425     /* PWM is paused in wait mode */
426 #if !defined(FSL_FEATURE_PWM_HAS_NO_WAITEN) || (!FSL_FEATURE_PWM_HAS_NO_WAITEN)
427     config->enableWait = false;
428 #endif /* FSL_FEATURE_PWM_HAS_NO_WAITEN */
429     /* PWM module uses the local reload signal to reload registers */
430     config->reloadSelect = kPWM_LocalReload;
431     /* Use the IP Bus clock as source clock for the PWM submodule */
432     config->clockSource = kPWM_BusClock;
433     /* Clock source prescale is set to divide by 1*/
434     config->prescale = kPWM_Prescale_Divide_1;
435     /* Local sync causes initialization */
436     config->initializationControl = kPWM_Initialize_LocalSync;
437     /* The local force signal, CTRL2[FORCE], from the submodule is used to force updates */
438     config->forceTrigger = kPWM_Force_Local;
439     /* PWM reload frequency, reload opportunity is PWM half cycle or full cycle.
440      * This field is not used in Immediate reload mode
441      */
442     config->reloadFrequency = kPWM_LoadEveryOportunity;
443     /* Buffered-registers get loaded with new values as soon as LDOK bit is set */
444     config->reloadLogic = kPWM_ReloadImmediate;
445     /* PWM A & PWM B operate as 2 independent channels */
446     config->pairOperation = kPWM_Independent;
447 }
448 
449 /*!
450  * brief Sets up the PWM signals for a PWM submodule.
451  *
452  * The function initializes the submodule according to the parameters passed in by the user. The function
453  * also sets up the value compare registers to match the PWM signal requirements.
454  * If the dead time insertion logic is enabled, the pulse period is reduced by the
455  * dead time period specified by the user.
456  *
457  * param base        PWM peripheral base address
458  * param subModule   PWM submodule to configure
459  * param chnlParams  Array of PWM channel parameters to configure the channel(s), PWMX submodule is not supported.
460  * param numOfChnls  Number of channels to configure, this should be the size of the array passed in.
461  *                    Array size should not be more than 2 as each submodule has 2 pins to output PWM
462  * param mode        PWM operation mode, options available in enumeration ::pwm_mode_t
463  * param pwmFreq_Hz  PWM signal frequency in Hz
464  * param srcClock_Hz PWM source clock of correspond submodule in Hz. If source clock of submodule1,2,3 is from
465  *                   submodule0 AUX_CLK, its source clock is submodule0 source clock divided with submodule0
466  *                   prescaler value instead of submodule0 source clock.
467  *
468  * return Returns kStatusFail if there was error setting up the signal; kStatusSuccess otherwise
469  */
PWM_SetupPwm(PWM_Type * base,pwm_submodule_t subModule,const pwm_signal_param_t * chnlParams,uint8_t numOfChnls,pwm_mode_t mode,uint32_t pwmFreq_Hz,uint32_t srcClock_Hz)470 status_t PWM_SetupPwm(PWM_Type *base,
471                       pwm_submodule_t subModule,
472                       const pwm_signal_param_t *chnlParams,
473                       uint8_t numOfChnls,
474                       pwm_mode_t mode,
475                       uint32_t pwmFreq_Hz,
476                       uint32_t srcClock_Hz)
477 {
478     assert(chnlParams);
479     assert(pwmFreq_Hz);
480     assert(numOfChnls);
481     assert(srcClock_Hz);
482 
483     uint32_t pwmClock;
484     uint16_t pulseCnt = 0, pwmHighPulse = 0;
485     uint8_t i, polarityShift = 0, outputEnableShift = 0;
486 
487     for (i = 0; i < numOfChnls; i++)
488     {
489         if (chnlParams[i].pwmChannel == kPWM_PwmX)
490         {
491             /* PWMX configuration is not supported yet */
492             return kStatus_Fail;
493         }
494     }
495 
496     /* Divide the clock by the prescale value */
497     pwmClock = (srcClock_Hz / (1UL << ((base->SM[subModule].CTRL & PWM_CTRL_PRSC_MASK) >> PWM_CTRL_PRSC_SHIFT)));
498     pulseCnt = (uint16_t)(pwmClock / pwmFreq_Hz);
499 
500     /* Setup each PWM channel */
501     for (i = 0; i < numOfChnls; i++)
502     {
503         /* Calculate pulse width */
504         pwmHighPulse = (pulseCnt * chnlParams->dutyCyclePercent) / 100U;
505 
506         /* Setup the different match registers to generate the PWM signal */
507         if (i == 0U)
508         {
509             /* Update register about period */
510             PWM_SetPeriodRegister(base, subModule, mode, pulseCnt);
511         }
512 
513         /* Update register about dutycycle */
514         PWM_SetDutycycleRegister(base, subModule, chnlParams->pwmChannel, mode, pulseCnt, pwmHighPulse);
515 
516         /* Setup register shift values based on the channel being configured.
517          * Also setup the deadtime value
518          */
519         if (chnlParams->pwmChannel == kPWM_PwmA)
520         {
521             polarityShift              = PWM_OCTRL_POLA_SHIFT;
522             outputEnableShift          = PWM_OUTEN_PWMA_EN_SHIFT;
523             base->SM[subModule].DTCNT0 = PWM_DTCNT0_DTCNT0(chnlParams->deadtimeValue);
524         }
525         else
526         {
527             polarityShift              = PWM_OCTRL_POLB_SHIFT;
528             outputEnableShift          = PWM_OUTEN_PWMB_EN_SHIFT;
529             base->SM[subModule].DTCNT1 = PWM_DTCNT1_DTCNT1(chnlParams->deadtimeValue);
530         }
531 
532         /* Set PWM output fault status */
533         switch (chnlParams->pwmChannel)
534         {
535             case kPWM_PwmA:
536                 base->SM[subModule].OCTRL &= ~((uint16_t)PWM_OCTRL_PWMAFS_MASK);
537                 base->SM[subModule].OCTRL |= (((uint16_t)(chnlParams->faultState) << (uint16_t)PWM_OCTRL_PWMAFS_SHIFT) &
538                                               (uint16_t)PWM_OCTRL_PWMAFS_MASK);
539                 break;
540             case kPWM_PwmB:
541                 base->SM[subModule].OCTRL &= ~((uint16_t)PWM_OCTRL_PWMBFS_MASK);
542                 base->SM[subModule].OCTRL |= (((uint16_t)(chnlParams->faultState) << (uint16_t)PWM_OCTRL_PWMBFS_SHIFT) &
543                                               (uint16_t)PWM_OCTRL_PWMBFS_MASK);
544                 break;
545             default:
546                 assert(false);
547                 break;
548         }
549 
550         /* Setup signal active level */
551         if ((bool)chnlParams->level == kPWM_HighTrue)
552         {
553             base->SM[subModule].OCTRL &= ~((uint16_t)1U << (uint16_t)polarityShift);
554         }
555         else
556         {
557             base->SM[subModule].OCTRL |= ((uint16_t)1U << (uint16_t)polarityShift);
558         }
559         if (chnlParams->pwmchannelenable)
560         {
561             /* Enable PWM output */
562             base->OUTEN |= ((uint16_t)1U << ((uint16_t)outputEnableShift + (uint16_t)subModule));
563         }
564 
565         /* Get the pwm duty cycle */
566         s_pwmGetPwmDutyCycle[subModule][chnlParams->pwmChannel] = chnlParams->dutyCyclePercent;
567 
568         /* Get the next channel parameters */
569         chnlParams++;
570     }
571 
572     return kStatus_Success;
573 }
574 
575 /*!
576  * brief Set PWM phase shift for PWM channel running on channel PWM_A, PWM_B which with 50% duty cycle.
577  *
578  * param base        PWM peripheral base address
579  * param subModule   PWM submodule to configure
580  * param pwmChannel  PWM channel to configure
581  * param pwmFreq_Hz  PWM signal frequency in Hz
582  * param srcClock_Hz PWM main counter clock in Hz.
583  * param shiftvalue  Phase shift value, range in 0 ~ 50
584  * param doSync      true: Set LDOK bit for the submodule list;
585  *                   false: LDOK bit don't set, need to call PWM_SetPwmLdok to sync update.
586  *
587  * return Returns kStatus_Fail if there was error setting up the signal; kStatus_Success otherwise
588  */
PWM_SetupPwmPhaseShift(PWM_Type * base,pwm_submodule_t subModule,pwm_channels_t pwmChannel,uint32_t pwmFreq_Hz,uint32_t srcClock_Hz,uint8_t shiftvalue,bool doSync)589 status_t PWM_SetupPwmPhaseShift(PWM_Type *base,
590                                 pwm_submodule_t subModule,
591                                 pwm_channels_t pwmChannel,
592                                 uint32_t pwmFreq_Hz,
593                                 uint32_t srcClock_Hz,
594                                 uint8_t shiftvalue,
595                                 bool doSync)
596 {
597     assert(pwmFreq_Hz != 0U);
598     assert(srcClock_Hz != 0U);
599     assert(shiftvalue <= 50U);
600 
601     uint32_t pwmClock;
602     uint16_t pulseCnt = 0, pwmHighPulse = 0;
603     uint16_t modulo = 0;
604     uint16_t shift  = 0;
605 
606     if (pwmChannel != kPWM_PwmX)
607     {
608         /* Divide the clock by the prescale value */
609         pwmClock = (srcClock_Hz / (1UL << ((base->SM[subModule].CTRL & PWM_CTRL_PRSC_MASK) >> PWM_CTRL_PRSC_SHIFT)));
610         pulseCnt = (uint16_t)(pwmClock / pwmFreq_Hz);
611 
612         /* Clear LDOK bit if it is set */
613         if (0U != (base->MCTRL & PWM_MCTRL_LDOK(1UL << (uint8_t)subModule)))
614         {
615             base->MCTRL |= PWM_MCTRL_CLDOK(1UL << (uint8_t)subModule);
616         }
617 
618         modulo = (pulseCnt >> 1U);
619         /* Indicates the start of the PWM period */
620         base->SM[subModule].INIT = PWM_GetComplementU16(modulo);
621         /* Indicates the center value */
622         base->SM[subModule].VAL0 = 0;
623         /* Indicates the end of the PWM period */
624         /* The change during the end to start of the PWM period requires a count time */
625         base->SM[subModule].VAL1 = modulo - 1U;
626 
627         /* Immediately upon when MCTRL[LDOK] being set */
628         base->SM[subModule].CTRL |= PWM_CTRL_LDMOD_MASK;
629 
630         /* phase shift value */
631         shift = (pulseCnt * shiftvalue) / 100U;
632 
633         /* duty cycle 50% */
634         pwmHighPulse = pulseCnt / 2U;
635 
636         if (pwmChannel == kPWM_PwmA)
637         {
638             base->SM[subModule].VAL2 = PWM_GetComplementU16(modulo) + shift;
639             base->SM[subModule].VAL3 = PWM_GetComplementU16(modulo) + pwmHighPulse + shift - 1U;
640         }
641         else if (pwmChannel == kPWM_PwmB)
642         {
643             base->SM[subModule].VAL4 = PWM_GetComplementU16(modulo) + shift;
644             base->SM[subModule].VAL5 = PWM_GetComplementU16(modulo) + pwmHighPulse + shift - 1U;
645         }
646         else
647         {
648             return kStatus_Fail;
649         }
650 
651         if (doSync)
652         {
653             /* Set LDOK bit to load VALx bit */
654             base->MCTRL |= PWM_MCTRL_LDOK(1UL << (uint8_t)subModule);
655         }
656     }
657     else
658     {
659         return kStatus_Fail;
660     }
661 
662     return kStatus_Success;
663 }
664 
665 /*!
666  * brief Updates the PWM signal's dutycycle.
667  *
668  * The function updates the PWM dutycyle to the new value that is passed in.
669  * If the dead time insertion logic is enabled then the pulse period is reduced by the
670  * dead time period specified by the user.
671  *
672  * param base              PWM peripheral base address
673  * param subModule         PWM submodule to configure
674  * param pwmSignal         Signal (PWM A or PWM B) to update
675  * param currPwmMode       The current PWM mode set during PWM setup
676  * param dutyCyclePercent  New PWM pulse width, value should be between 0 to 100
677  *                          0=inactive signal(0% duty cycle)...
678  *                          100=active signal (100% duty cycle)
679  */
PWM_UpdatePwmDutycycle(PWM_Type * base,pwm_submodule_t subModule,pwm_channels_t pwmSignal,pwm_mode_t currPwmMode,uint8_t dutyCyclePercent)680 void PWM_UpdatePwmDutycycle(PWM_Type *base,
681                             pwm_submodule_t subModule,
682                             pwm_channels_t pwmSignal,
683                             pwm_mode_t currPwmMode,
684                             uint8_t dutyCyclePercent)
685 {
686     assert(dutyCyclePercent <= 100U);
687     assert(pwmSignal != kPWM_PwmX);
688     uint16_t reloadValue = dutyCycleToReloadValue(dutyCyclePercent);
689 
690     PWM_UpdatePwmDutycycleHighAccuracy(base, subModule, pwmSignal, currPwmMode, reloadValue);
691 }
692 
693 /*!
694  * brief Updates the PWM signal's dutycycle with 16-bit accuracy.
695  *
696  * The function updates the PWM dutycyle to the new value that is passed in.
697  * If the dead time insertion logic is enabled then the pulse period is reduced by the
698  * dead time period specified by the user.
699  *
700  * param base              PWM peripheral base address
701  * param subModule         PWM submodule to configure
702  * param pwmSignal         Signal (PWM A or PWM B) to update
703  * param currPwmMode       The current PWM mode set during PWM setup
704  * param dutyCycle         New PWM pulse width, value should be between 0 to 65535
705  *                          0=inactive signal(0% duty cycle)...
706  *                          65535=active signal (100% duty cycle)
707  */
PWM_UpdatePwmDutycycleHighAccuracy(PWM_Type * base,pwm_submodule_t subModule,pwm_channels_t pwmSignal,pwm_mode_t currPwmMode,uint16_t dutyCycle)708 void PWM_UpdatePwmDutycycleHighAccuracy(
709     PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmSignal, pwm_mode_t currPwmMode, uint16_t dutyCycle)
710 {
711     assert(pwmSignal != kPWM_PwmX);
712     uint16_t pulseCnt = 0, pwmHighPulse = 0;
713     uint16_t modulo = 0;
714 
715     switch (currPwmMode)
716     {
717         case kPWM_SignedCenterAligned:
718             modulo   = base->SM[subModule].VAL1 + 1U;
719             pulseCnt = modulo * 2U;
720             /* Calculate pulse width */
721             pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
722             break;
723         case kPWM_CenterAligned:
724             pulseCnt = base->SM[subModule].VAL1 + 1U;
725             /* Calculate pulse width */
726             pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
727             break;
728         case kPWM_SignedEdgeAligned:
729             modulo   = base->SM[subModule].VAL1 + 1U;
730             pulseCnt = modulo * 2U;
731             /* Calculate pulse width */
732             pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
733             break;
734         case kPWM_EdgeAligned:
735             pulseCnt = base->SM[subModule].VAL1 + 1U;
736             /* Calculate pulse width */
737             pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
738             break;
739         default:
740             assert(false);
741             break;
742     }
743 
744     /* Update register about dutycycle */
745     if (kPWM_PwmA == pwmSignal)
746     {
747         PWM_SetDutycycleRegister(base, subModule, kPWM_PwmA, currPwmMode, pulseCnt, pwmHighPulse);
748     }
749     else if (kPWM_PwmB == pwmSignal)
750     {
751         PWM_SetDutycycleRegister(base, subModule, kPWM_PwmB, currPwmMode, pulseCnt, pwmHighPulse);
752     }
753     else
754     {
755         ; /* Intentional empty */
756     }
757 
758     if (kPWM_PwmX != pwmSignal)
759     {
760         /* Get the pwm duty cycle */
761         s_pwmGetPwmDutyCycle[subModule][pwmSignal] = (uint8_t)(dutyCycle * 100U / 65535U);
762     }
763 }
764 
765 /*!
766  * brief Update the PWM signal's period and dutycycle for a PWM submodule.
767  *
768  * The function updates PWM signal period generated by a specific submodule according to the parameters
769  * passed in by the user. This function can also set dutycycle weather you want to keep original dutycycle
770  * or update new dutycycle. Call this function in local sync control mode because PWM period is depended by
771  * INIT and VAL1 register of each submodule. In master sync initialization control mode, call this function
772  * to update INIT and VAL1 register of all submodule because PWM period is depended by INIT and VAL1 register
773  * in submodule0. If the dead time insertion logic is enabled, the pulse period is reduced by the dead time
774  * period specified by the user. PWM signal will not be generated if its period is less than dead time duration.
775  *
776  * param base        PWM peripheral base address
777  * param subModule   PWM submodule to configure
778  * param pwmSignal   Signal (PWM A or PWM B) to update
779  * param currPwmMode The current PWM mode set during PWM setup, options available in enumeration ::pwm_mode_t
780  * param pulseCnt    New PWM period, value should be between 0 to 65535
781  *                    0=minimum PWM period...
782  *                    65535=maximum PWM period
783  * param dutyCycle   New PWM pulse width of channel, value should be between 0 to 65535
784  *                    0=inactive signal(0% duty cycle)...
785  *                    65535=active signal (100% duty cycle)
786  *                    You can keep original dutycycle or update new dutycycle
787  */
PWM_UpdatePwmPeriodAndDutycycle(PWM_Type * base,pwm_submodule_t subModule,pwm_channels_t pwmSignal,pwm_mode_t currPwmMode,uint16_t pulseCnt,uint16_t dutyCycle)788 void PWM_UpdatePwmPeriodAndDutycycle(PWM_Type *base,
789                                      pwm_submodule_t subModule,
790                                      pwm_channels_t pwmSignal,
791                                      pwm_mode_t currPwmMode,
792                                      uint16_t pulseCnt,
793                                      uint16_t dutyCycle)
794 {
795     uint16_t pwmHighPulse = 0;
796 
797     assert(pwmSignal != kPWM_PwmX);
798 
799     /* Calculate pulse width */
800     pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
801 
802     /* Update register about period */
803     PWM_SetPeriodRegister(base, subModule, currPwmMode, pulseCnt);
804 
805     /* Update register about dutycycle */
806     PWM_SetDutycycleRegister(base, subModule, pwmSignal, currPwmMode, pulseCnt, pwmHighPulse);
807 
808     /* Get the pwm duty cycle */
809     s_pwmGetPwmDutyCycle[subModule][pwmSignal] = (uint8_t)((dutyCycle * 100U) / 65535U);
810 }
811 
812 /*!
813  * brief Sets up the PWM input capture
814  *
815  * Each PWM submodule has 3 pins that can be configured for use as input capture pins. This function
816  * sets up the capture parameters for each pin and enables the pin for input capture operation.
817  *
818  * param base               PWM peripheral base address
819  * param subModule          PWM submodule to configure
820  * param pwmChannel         Channel in the submodule to setup
821  * param inputCaptureParams Parameters passed in to set up the input pin
822  */
PWM_SetupInputCapture(PWM_Type * base,pwm_submodule_t subModule,pwm_channels_t pwmChannel,const pwm_input_capture_param_t * inputCaptureParams)823 void PWM_SetupInputCapture(PWM_Type *base,
824                            pwm_submodule_t subModule,
825                            pwm_channels_t pwmChannel,
826                            const pwm_input_capture_param_t *inputCaptureParams)
827 {
828     uint16_t reg = 0;
829     switch (pwmChannel)
830     {
831 #if defined(FSL_FEATURE_PWM_HAS_CAPTURE_ON_CHANNELA) && FSL_FEATURE_PWM_HAS_CAPTURE_ON_CHANNELA
832         case kPWM_PwmA:
833             /* Setup the capture paramters for PWM A pin */
834             reg = (PWM_CAPTCTRLA_INP_SELA(inputCaptureParams->captureInputSel) |
835                    PWM_CAPTCTRLA_EDGA0(inputCaptureParams->edge0) | PWM_CAPTCTRLA_EDGA1(inputCaptureParams->edge1) |
836                    PWM_CAPTCTRLA_ONESHOTA(inputCaptureParams->enableOneShotCapture) |
837                    PWM_CAPTCTRLA_CFAWM(inputCaptureParams->fifoWatermark));
838             /* Enable the edge counter if using the output edge counter */
839             if (inputCaptureParams->captureInputSel)
840             {
841                 reg |= PWM_CAPTCTRLA_EDGCNTA_EN_MASK;
842             }
843             /* Enable input capture operation */
844             reg |= PWM_CAPTCTRLA_ARMA_MASK;
845 
846             base->SM[subModule].CAPTCTRLA = reg;
847 
848             /* Setup the compare value when using the edge counter as source */
849             base->SM[subModule].CAPTCOMPA = PWM_CAPTCOMPA_EDGCMPA(inputCaptureParams->edgeCompareValue);
850             /* Setup PWM A pin for input capture */
851             base->OUTEN &= ~((uint16_t)1U << (PWM_OUTEN_PWMA_EN_SHIFT + (uint16_t)subModule));
852             break;
853 #endif /* FSL_FEATURE_PWM_HAS_CAPTURE_ON_CHANNELA */
854 #if defined(FSL_FEATURE_PWM_HAS_CAPTURE_ON_CHANNELB) && FSL_FEATURE_PWM_HAS_CAPTURE_ON_CHANNELB
855         case kPWM_PwmB:
856             /* Setup the capture paramters for PWM B pin */
857             reg = (PWM_CAPTCTRLB_INP_SELB(inputCaptureParams->captureInputSel) |
858                    PWM_CAPTCTRLB_EDGB0(inputCaptureParams->edge0) | PWM_CAPTCTRLB_EDGB1(inputCaptureParams->edge1) |
859                    PWM_CAPTCTRLB_ONESHOTB(inputCaptureParams->enableOneShotCapture) |
860                    PWM_CAPTCTRLB_CFBWM(inputCaptureParams->fifoWatermark));
861             /* Enable the edge counter if using the output edge counter */
862             if (inputCaptureParams->captureInputSel)
863             {
864                 reg |= PWM_CAPTCTRLB_EDGCNTB_EN_MASK;
865             }
866             /* Enable input capture operation */
867             reg |= PWM_CAPTCTRLB_ARMB_MASK;
868 
869             base->SM[subModule].CAPTCTRLB = reg;
870 
871             /* Setup the compare value when using the edge counter as source */
872             base->SM[subModule].CAPTCOMPB = PWM_CAPTCOMPB_EDGCMPB(inputCaptureParams->edgeCompareValue);
873             /* Setup PWM B pin for input capture */
874             base->OUTEN &= ~((uint16_t)1U << (PWM_OUTEN_PWMB_EN_SHIFT + (uint16_t)subModule));
875             break;
876 #endif /* FSL_FEATURE_PWM_HAS_CAPTURE_ON_CHANNELB */
877 #if defined(FSL_FEATURE_PWM_HAS_CAPTURE_ON_CHANNELX) && FSL_FEATURE_PWM_HAS_CAPTURE_ON_CHANNELX
878         case kPWM_PwmX:
879             reg = (PWM_CAPTCTRLX_INP_SELX(inputCaptureParams->captureInputSel) |
880                    PWM_CAPTCTRLX_EDGX0(inputCaptureParams->edge0) | PWM_CAPTCTRLX_EDGX1(inputCaptureParams->edge1) |
881                    PWM_CAPTCTRLX_ONESHOTX(inputCaptureParams->enableOneShotCapture) |
882                    PWM_CAPTCTRLX_CFXWM(inputCaptureParams->fifoWatermark));
883             /* Enable the edge counter if using the output edge counter */
884             if (inputCaptureParams->captureInputSel)
885             {
886                 reg |= PWM_CAPTCTRLX_EDGCNTX_EN_MASK;
887             }
888             /* Enable input capture operation */
889             reg |= PWM_CAPTCTRLX_ARMX_MASK;
890 
891             base->SM[subModule].CAPTCTRLX = reg;
892 
893             /* Setup the compare value when using the edge counter as source */
894             base->SM[subModule].CAPTCOMPX = PWM_CAPTCOMPX_EDGCMPX(inputCaptureParams->edgeCompareValue);
895             /* Setup PWM X pin for input capture */
896             base->OUTEN &= ~((uint16_t)1U << (PWM_OUTEN_PWMX_EN_SHIFT + (uint16_t)subModule));
897             break;
898 #endif /* FSL_FEATURE_PWM_HAS_CAPTURE_ON_CHANNELX */
899         default:
900             assert(false);
901             break;
902     }
903 }
904 
905 /*!
906  * @brief Sets up the PWM fault input filter.
907  *
908  * @param base                   PWM peripheral base address
909  * @param faultInputFilterParams Parameters passed in to set up the fault input filter.
910  */
PWM_SetupFaultInputFilter(PWM_Type * base,const pwm_fault_input_filter_param_t * faultInputFilterParams)911 void PWM_SetupFaultInputFilter(PWM_Type *base, const pwm_fault_input_filter_param_t *faultInputFilterParams)
912 {
913     assert(NULL != faultInputFilterParams);
914 
915     /* When changing values for fault period from a non-zero value, first write a value of 0 to clear the filter. */
916     if (0U != (base->FFILT & PWM_FFILT_FILT_PER_MASK))
917     {
918         base->FFILT &= ~(uint16_t)(PWM_FFILT_FILT_PER_MASK);
919     }
920 
921     base->FFILT = (uint16_t)(PWM_FFILT_FILT_PER(faultInputFilterParams->faultFilterPeriod) |
922                              PWM_FFILT_FILT_CNT(faultInputFilterParams->faultFilterCount) |
923                              PWM_FFILT_GSTR(faultInputFilterParams->faultGlitchStretch ? 1U : 0U));
924 }
925 
926 /*!
927  * brief Sets up the PWM fault protection.
928  *
929  * PWM has 4 fault inputs.
930  *
931  * param base        PWM peripheral base address
932  * param faultNum    PWM fault to configure.
933  * param faultParams Pointer to the PWM fault config structure
934  */
PWM_SetupFaults(PWM_Type * base,pwm_fault_input_t faultNum,const pwm_fault_param_t * faultParams)935 void PWM_SetupFaults(PWM_Type *base, pwm_fault_input_t faultNum, const pwm_fault_param_t *faultParams)
936 {
937     assert(faultParams);
938     uint16_t reg;
939 
940     reg = base->FCTRL;
941     /* Set the faults level-settting */
942     if (faultParams->faultLevel)
943     {
944         reg |= ((uint16_t)1U << (PWM_FCTRL_FLVL_SHIFT + (uint16_t)faultNum));
945     }
946     else
947     {
948         reg &= ~((uint16_t)1U << (PWM_FCTRL_FLVL_SHIFT + (uint16_t)faultNum));
949     }
950     /* Set the fault clearing mode */
951     if ((uint16_t)faultParams->faultClearingMode != 0U)
952     {
953         /* Use manual fault clearing */
954         reg &= ~((uint16_t)1U << (PWM_FCTRL_FAUTO_SHIFT + (uint16_t)faultNum));
955         if (faultParams->faultClearingMode == kPWM_ManualSafety)
956         {
957             /* Use manual fault clearing with safety mode enabled */
958             reg |= ((uint16_t)1U << (PWM_FCTRL_FSAFE_SHIFT + (uint16_t)faultNum));
959         }
960         else
961         {
962             /* Use manual fault clearing with safety mode disabled */
963             reg &= ~((uint16_t)1U << (PWM_FCTRL_FSAFE_SHIFT + (uint16_t)faultNum));
964         }
965     }
966     else
967     {
968         /* Use automatic fault clearing */
969         reg |= ((uint16_t)1U << (PWM_FCTRL_FAUTO_SHIFT + (uint16_t)faultNum));
970     }
971     base->FCTRL = reg;
972 
973     /* Set the combinational path option */
974     if (faultParams->enableCombinationalPath)
975     {
976         /* Combinational path from the fault input to the PWM output is available */
977         base->FCTRL2 &= ~((uint16_t)1U << (uint16_t)faultNum);
978     }
979     else
980     {
981         /* No combinational path available, only fault filter & latch signal can disable PWM output */
982         base->FCTRL2 |= ((uint16_t)1U << (uint16_t)faultNum);
983     }
984 
985     /* Initially clear both recovery modes */
986     reg = base->FSTS;
987     reg &= ~(((uint16_t)1U << (PWM_FSTS_FFULL_SHIFT + (uint16_t)faultNum)) |
988              ((uint16_t)1U << (PWM_FSTS_FHALF_SHIFT + (uint16_t)faultNum)));
989     /* Setup fault recovery */
990     switch (faultParams->recoverMode)
991     {
992         case kPWM_NoRecovery:
993             break;
994         case kPWM_RecoverHalfCycle:
995             reg |= ((uint16_t)1U << (PWM_FSTS_FHALF_SHIFT + (uint16_t)faultNum));
996             break;
997         case kPWM_RecoverFullCycle:
998             reg |= ((uint16_t)1U << (PWM_FSTS_FFULL_SHIFT + (uint16_t)faultNum));
999             break;
1000         case kPWM_RecoverHalfAndFullCycle:
1001             reg |= ((uint16_t)1U << (PWM_FSTS_FHALF_SHIFT + (uint16_t)faultNum));
1002             reg |= ((uint16_t)1U << (PWM_FSTS_FFULL_SHIFT + (uint16_t)faultNum));
1003             break;
1004         default:
1005             assert(false);
1006             break;
1007     }
1008     base->FSTS = reg;
1009 }
1010 
1011 /*!
1012  * brief  Fill in the PWM fault config struct with the default settings
1013  *
1014  * The default values are:
1015  * code
1016  *   config->faultClearingMode = kPWM_Automatic;
1017  *   config->faultLevel = false;
1018  *   config->enableCombinationalPath = true;
1019  *   config->recoverMode = kPWM_NoRecovery;
1020  * endcode
1021  * param config Pointer to user's PWM fault config structure.
1022  */
PWM_FaultDefaultConfig(pwm_fault_param_t * config)1023 void PWM_FaultDefaultConfig(pwm_fault_param_t *config)
1024 {
1025     assert(config);
1026 
1027     /* Initializes the configure structure to zero. */
1028     (void)memset(config, 0, sizeof(*config));
1029 
1030     /* PWM uses automatic fault clear mode */
1031     config->faultClearingMode = kPWM_Automatic;
1032     /* PWM fault level is set to logic 0 */
1033     config->faultLevel = false;
1034     /* Combinational Path from fault input is enabled */
1035     config->enableCombinationalPath = true;
1036     /* PWM output will stay inactive when recovering from a fault */
1037     config->recoverMode = kPWM_NoRecovery;
1038 }
1039 
1040 /*!
1041  * brief Selects the signal to output on a PWM pin when a FORCE_OUT signal is asserted.
1042  *
1043  * The user specifies which channel to configure by supplying the submodule number and whether
1044  * to modify PWM A or PWM B within that submodule.
1045  *
1046  * param base       PWM peripheral base address
1047  * param subModule  PWM submodule to configure
1048  * param pwmChannel Channel to configure
1049  * param mode       Signal to output when a FORCE_OUT is triggered
1050  */
PWM_SetupForceSignal(PWM_Type * base,pwm_submodule_t subModule,pwm_channels_t pwmChannel,pwm_force_signal_t mode)1051 void PWM_SetupForceSignal(PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmChannel, pwm_force_signal_t mode)
1052 
1053 {
1054     uint16_t shift;
1055     uint16_t reg;
1056 
1057     /* DTSRCSEL register has 4 bits per submodule; 2 bits for PWM A and 2 bits for PWM B */
1058     shift = ((uint16_t)subModule * 4U) + ((uint16_t)pwmChannel * 2U);
1059 
1060     /* Setup the signal to be passed upon occurrence of a FORCE_OUT signal */
1061     reg = base->DTSRCSEL;
1062     reg &= ~((uint16_t)0x3U << shift);
1063     reg |= (uint16_t)((uint16_t)mode << shift);
1064     base->DTSRCSEL = reg;
1065 }
1066 
1067 /*!
1068  * brief Enables the selected PWM interrupts
1069  *
1070  * param base      PWM peripheral base address
1071  * param subModule PWM submodule to configure
1072  * param mask      The interrupts to enable. This is a logical OR of members of the
1073  *                  enumeration ::pwm_interrupt_enable_t
1074  */
PWM_EnableInterrupts(PWM_Type * base,pwm_submodule_t subModule,uint32_t mask)1075 void PWM_EnableInterrupts(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask)
1076 {
1077     /* Upper 16 bits are for related to the submodule */
1078     base->SM[subModule].INTEN |= ((uint16_t)mask & 0xFFFFU);
1079     /* Fault related interrupts */
1080     base->FCTRL |= ((uint16_t)(mask >> 16U) & PWM_FCTRL_FIE_MASK);
1081 }
1082 
1083 /*!
1084  * brief Disables the selected PWM interrupts
1085  *
1086  * param base      PWM peripheral base address
1087  * param subModule PWM submodule to configure
1088  * param mask      The interrupts to enable. This is a logical OR of members of the
1089  *                  enumeration ::pwm_interrupt_enable_t
1090  */
PWM_DisableInterrupts(PWM_Type * base,pwm_submodule_t subModule,uint32_t mask)1091 void PWM_DisableInterrupts(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask)
1092 {
1093     base->SM[subModule].INTEN &= ~((uint16_t)mask & 0xFFFFU);
1094     base->FCTRL &= ~((uint16_t)(mask >> 16U) & PWM_FCTRL_FIE_MASK);
1095 }
1096 
1097 /*!
1098  * brief Gets the enabled PWM interrupts
1099  *
1100  * param base      PWM peripheral base address
1101  * param subModule PWM submodule to configure
1102  *
1103  * return The enabled interrupts. This is the logical OR of members of the
1104  *         enumeration ::pwm_interrupt_enable_t
1105  */
PWM_GetEnabledInterrupts(PWM_Type * base,pwm_submodule_t subModule)1106 uint32_t PWM_GetEnabledInterrupts(PWM_Type *base, pwm_submodule_t subModule)
1107 {
1108     uint32_t enabledInterrupts;
1109 
1110     enabledInterrupts = base->SM[subModule].INTEN;
1111     enabledInterrupts |= (((uint32_t)base->FCTRL & PWM_FCTRL_FIE_MASK) << 16UL);
1112     return enabledInterrupts;
1113 }
1114 
1115 /*!
1116  * brief Gets the PWM status flags
1117  *
1118  * param base      PWM peripheral base address
1119  * param subModule PWM submodule to configure
1120  *
1121  * return The status flags. This is the logical OR of members of the
1122  *         enumeration ::pwm_status_flags_t
1123  */
PWM_GetStatusFlags(PWM_Type * base,pwm_submodule_t subModule)1124 uint32_t PWM_GetStatusFlags(PWM_Type *base, pwm_submodule_t subModule)
1125 {
1126     uint32_t statusFlags;
1127 
1128     statusFlags = base->SM[subModule].STS;
1129     statusFlags |= (((uint32_t)base->FSTS & PWM_FSTS_FFLAG_MASK) << 16UL);
1130 
1131     return statusFlags;
1132 }
1133 
1134 /*!
1135  * brief Clears the PWM status flags
1136  *
1137  * param base      PWM peripheral base address
1138  * param subModule PWM submodule to configure
1139  * param mask      The status flags to clear. This is a logical OR of members of the
1140  *                  enumeration ::pwm_status_flags_t
1141  */
PWM_ClearStatusFlags(PWM_Type * base,pwm_submodule_t subModule,uint32_t mask)1142 void PWM_ClearStatusFlags(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask)
1143 {
1144     uint16_t reg;
1145 
1146     base->SM[subModule].STS = ((uint16_t)mask & 0xFFFFU);
1147     reg                     = base->FSTS;
1148     /* Clear the fault flags and set only the ones we wish to clear as the fault flags are cleared
1149      * by writing a login one
1150      */
1151     reg &= ~(uint16_t)(PWM_FSTS_FFLAG_MASK);
1152     reg |= (uint16_t)((mask >> 16U) & PWM_FSTS_FFLAG_MASK);
1153     base->FSTS = reg;
1154 }
1155 
1156 /*!
1157  * brief Set PWM output in idle status (high or low).
1158  *
1159  * note This API should call after PWM_SetupPwm() APIs, and PWMX submodule is not supported.
1160  *
1161  * param base               PWM peripheral base address
1162  * param pwmChannel         PWM channel to configure
1163  * param subModule          PWM submodule to configure
1164  * param idleStatus         True: PWM output is high in idle status; false: PWM output is low in idle status.
1165  *
1166  * return kStatus_Fail if there was error setting up the signal; kStatus_Success if set output idle success
1167  */
PWM_SetOutputToIdle(PWM_Type * base,pwm_channels_t pwmChannel,pwm_submodule_t subModule,bool idleStatus)1168 status_t PWM_SetOutputToIdle(PWM_Type *base, pwm_channels_t pwmChannel, pwm_submodule_t subModule, bool idleStatus)
1169 {
1170     uint16_t valOn = 0, valOff = 0;
1171     uint16_t ldmod;
1172 
1173     /* Clear LDOK bit if it is set */
1174     if (0U != (base->MCTRL & PWM_MCTRL_LDOK(1UL << (uint8_t)subModule)))
1175     {
1176         base->MCTRL |= PWM_MCTRL_CLDOK(1UL << (uint8_t)subModule);
1177     }
1178 
1179     valOff = base->SM[subModule].INIT;
1180     valOn  = base->SM[subModule].VAL1 + 0x1U;
1181 
1182     if ((valOff + 1U) == valOn)
1183     {
1184         return kStatus_Fail;
1185     }
1186 
1187     /* Should not PWM_X channel */
1188     if (kPWM_PwmA == pwmChannel)
1189     {
1190         if (0U != (base->SM[subModule].OCTRL & PWM_OCTRL_POLA_MASK))
1191         {
1192             if (!idleStatus)
1193             {
1194                 valOn  = base->SM[subModule].INIT;
1195                 valOff = base->SM[subModule].VAL1 + 0x1U;
1196             }
1197         }
1198         else
1199         {
1200             if (idleStatus)
1201             {
1202                 valOn  = base->SM[subModule].INIT;
1203                 valOff = base->SM[subModule].VAL1 + 0x1U;
1204             }
1205         }
1206         base->SM[subModule].VAL2 = valOn;
1207         base->SM[subModule].VAL3 = valOff;
1208     }
1209     else if (kPWM_PwmB == pwmChannel)
1210     {
1211         if (0U != (base->SM[subModule].OCTRL & PWM_OCTRL_POLB_MASK))
1212         {
1213             if (!idleStatus)
1214             {
1215                 valOn  = base->SM[subModule].INIT;
1216                 valOff = base->SM[subModule].VAL1 + 0x1U;
1217             }
1218         }
1219         else
1220         {
1221             if (idleStatus)
1222             {
1223                 valOn  = base->SM[subModule].INIT;
1224                 valOff = base->SM[subModule].VAL1 + 0x1U;
1225             }
1226         }
1227         base->SM[subModule].VAL4 = valOn;
1228         base->SM[subModule].VAL5 = valOff;
1229     }
1230     else
1231     {
1232         return kStatus_Fail;
1233     }
1234 
1235     /* Record Load mode */
1236     ldmod = base->SM[subModule].CTRL;
1237     /* Set Load mode to make Buffered registers take effect immediately when LDOK bit set */
1238     base->SM[subModule].CTRL |= PWM_CTRL_LDMOD_MASK;
1239     /* Set LDOK bit to load buffer registers */
1240     base->MCTRL |= PWM_MCTRL_LDOK(1UL << (uint8_t)subModule);
1241     /* Restore Load mode */
1242     base->SM[subModule].CTRL = ldmod;
1243 
1244     /* Get pwm duty cycle */
1245     s_pwmGetPwmDutyCycle[subModule][pwmChannel] = 0x0U;
1246 
1247     return kStatus_Success;
1248 }
1249 
1250 /*!
1251  * brief Get the dutycycle value.
1252  *
1253  * param base        PWM peripheral base address
1254  * param subModule   PWM submodule to configure
1255  * param pwmChannel  PWM channel to configure
1256  *
1257  * return Current channel dutycycle value.
1258  */
PWM_GetPwmChannelState(PWM_Type * base,pwm_submodule_t subModule,pwm_channels_t pwmChannel)1259 uint8_t PWM_GetPwmChannelState(PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmChannel)
1260 {
1261     return s_pwmGetPwmDutyCycle[subModule][pwmChannel];
1262 }
1263 
1264 /*!
1265  * brief Set the pwm submodule prescaler.
1266  *
1267  * param base               PWM peripheral base address
1268  * param subModule          PWM submodule to configure
1269  * param prescaler          Set prescaler value
1270  */
PWM_SetClockMode(PWM_Type * base,pwm_submodule_t subModule,pwm_clock_prescale_t prescaler)1271 void PWM_SetClockMode(PWM_Type *base, pwm_submodule_t subModule, pwm_clock_prescale_t prescaler)
1272 {
1273     uint16_t reg = base->SM[subModule].CTRL;
1274 
1275     /* Clear LDOK bit if it is set */
1276     if (0U != (base->MCTRL & PWM_MCTRL_LDOK(1UL << (uint8_t)subModule)))
1277     {
1278         base->MCTRL |= PWM_MCTRL_CLDOK(1UL << (uint8_t)subModule);
1279     }
1280     /* Set submodule prescaler. */
1281     reg &= ~(uint16_t)PWM_CTRL_PRSC_MASK;
1282     reg |= PWM_CTRL_PRSC(prescaler);
1283     base->SM[subModule].CTRL = reg;
1284     /* Set Load mode to make Buffered registers take effect immediately when LDOK bit set */
1285     base->SM[subModule].CTRL |= PWM_CTRL_LDMOD_MASK;
1286     /* Set LDOK bit to load buffer registers */
1287     base->MCTRL |= PWM_MCTRL_LDOK(1UL << (uint8_t)subModule);
1288     /* Restore Load mode */
1289     base->SM[subModule].CTRL = reg;
1290 }
1291 
1292 /*!
1293  * brief This function enables-disables the forcing of the output of a given eFlexPwm channel to logic 0.
1294  *
1295  * param base               PWM peripheral base address
1296  * param pwmChannel         PWM channel to configure
1297  * param subModule          PWM submodule to configure
1298  * param forcetozero        True: Enable the pwm force output to zero; False: Disable the pwm output resumes normal
1299  *                          function.
1300  */
PWM_SetPwmForceOutputToZero(PWM_Type * base,pwm_submodule_t subModule,pwm_channels_t pwmChannel,bool forcetozero)1301 void PWM_SetPwmForceOutputToZero(PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmChannel, bool forcetozero)
1302 {
1303 #if !defined(PWM_MASK_UPDATE_MASK)
1304     uint16_t reg = base->SM[subModule].CTRL2;
1305 #endif
1306     uint16_t mask;
1307 
1308     if (kPWM_PwmA == pwmChannel)
1309     {
1310         mask = PWM_MASK_MASKA(0x01UL << (uint8_t)subModule);
1311     }
1312     else if (kPWM_PwmB == pwmChannel)
1313     {
1314         mask = PWM_MASK_MASKB(0x01UL << (uint8_t)subModule);
1315     }
1316     else
1317     {
1318         mask = PWM_MASK_MASKX(0x01UL << (uint8_t)subModule);
1319     }
1320 
1321     if (forcetozero)
1322     {
1323         /* Disables the channel output, forcing output level to 0 */
1324         base->MASK |= mask;
1325     }
1326     else
1327     {
1328         /* Enables the channel output */
1329         base->MASK &= ~mask;
1330     }
1331 
1332 #if defined(PWM_MASK_UPDATE_MASK)
1333     /* Update output mask bits immediately with UPDATE_MASK bit */
1334     base->MASK |= PWM_MASK_UPDATE_MASK(0x01UL << (uint8_t)subModule);
1335 #else
1336     /* Select local force signal */
1337     base->SM[subModule].CTRL2 &= ~(uint16_t)PWM_CTRL2_FORCE_SEL_MASK;
1338     /* Issue a local Force trigger event */
1339     base->SM[subModule].CTRL2 |= PWM_CTRL2_FORCE_MASK;
1340     /* Restore the source of FORCE OUTPUT signal */
1341     base->SM[subModule].CTRL2 = reg;
1342 #endif
1343 }
1344 
1345 /*!
1346  * brief This function set the output state of the PWM pin as requested for the current cycle.
1347  *
1348  * param base               PWM peripheral base address
1349  * param subModule          PWM submodule to configure
1350  * param pwmChannel         PWM channel to configure
1351  * param outputstate        Set pwm output state, see @ref pwm_output_state_t.
1352  */
PWM_SetChannelOutput(PWM_Type * base,pwm_submodule_t subModule,pwm_channels_t pwmChannel,pwm_output_state_t outputstate)1353 void PWM_SetChannelOutput(PWM_Type *base,
1354                           pwm_submodule_t subModule,
1355                           pwm_channels_t pwmChannel,
1356                           pwm_output_state_t outputstate)
1357 {
1358     uint16_t mask, swcout, sourceShift;
1359     uint16_t reg = base->SM[subModule].CTRL2;
1360 
1361     if (kPWM_PwmA == pwmChannel)
1362     {
1363         mask        = PWM_MASK_MASKA(0x01UL << (uint8_t)subModule);
1364         swcout      = (uint16_t)PWM_SWCOUT_SM0OUT23_MASK << ((uint8_t)subModule * 2U);
1365         sourceShift = PWM_DTSRCSEL_SM0SEL23_SHIFT + ((uint16_t)subModule * 4U);
1366     }
1367     else if (kPWM_PwmB == pwmChannel)
1368     {
1369         mask        = PWM_MASK_MASKB(0x01UL << (uint8_t)subModule);
1370         swcout      = (uint16_t)PWM_SWCOUT_SM0OUT45_MASK << ((uint8_t)subModule * 2U);
1371         sourceShift = PWM_DTSRCSEL_SM0SEL45_SHIFT + ((uint16_t)subModule * 4U);
1372     }
1373     else
1374     {
1375         mask        = PWM_MASK_MASKX(0x01UL << (uint8_t)subModule);
1376         swcout      = 0U;
1377         sourceShift = 0U;
1378     }
1379 
1380     if (kPWM_MaskState == outputstate)
1381     {
1382         /* Disables the channel output, forcing output level to 0 */
1383         base->MASK |= mask;
1384     }
1385     else
1386     {
1387         /* Enables the channel output first */
1388         base->MASK &= ~mask;
1389         /* PwmX only support MASK mode */
1390         if (kPWM_PwmX != pwmChannel)
1391         {
1392             if (kPWM_HighState == outputstate)
1393             {
1394                 base->SWCOUT |= swcout;
1395                 base->DTSRCSEL =
1396                     (base->DTSRCSEL & ~(uint16_t)(0x3UL << sourceShift)) | (uint16_t)(0x2UL << sourceShift);
1397             }
1398             else if (kPWM_LowState == outputstate)
1399             {
1400                 base->SWCOUT &= ~swcout;
1401                 base->DTSRCSEL =
1402                     (base->DTSRCSEL & ~(uint16_t)(0x3UL << sourceShift)) | (uint16_t)(0x2UL << sourceShift);
1403             }
1404             else if (kPWM_NormalState == outputstate)
1405             {
1406                 base->DTSRCSEL &= ~(uint16_t)(0x3UL << sourceShift);
1407             }
1408             else
1409             {
1410                 base->DTSRCSEL =
1411                     (base->DTSRCSEL & ~(uint16_t)(0x3UL << sourceShift)) | (uint16_t)(0x1UL << sourceShift);
1412             }
1413         }
1414     }
1415 
1416     /* Select local force signal */
1417     base->SM[subModule].CTRL2 &= ~(uint16_t)PWM_CTRL2_FORCE_SEL_MASK;
1418     /* Issue a local Force trigger event */
1419     base->SM[subModule].CTRL2 |= PWM_CTRL2_FORCE_MASK;
1420     /* Restore the source of FORCE OUTPUT signal */
1421     base->SM[subModule].CTRL2 = reg;
1422 }
1423 
1424 #if defined(FSL_FEATURE_PWM_HAS_PHASE_DELAY) && FSL_FEATURE_PWM_HAS_PHASE_DELAY
1425 /*!
1426  * brief This function set the phase delay from the master sync signal of submodule 0.
1427  *
1428  * param base               PWM peripheral base address
1429  * param subModule          PWM submodule to configure
1430  * param pwmChannel         PWM channel to configure
1431  * param delayCycles        Number of cycles delayed from submodule 0.
1432  *
1433  * return kStatus_Fail if the number of delay cycles is set larger than the period defined in submodule 0;
1434  *        kStatus_Success if set phase delay success
1435  */
PWM_SetPhaseDelay(PWM_Type * base,pwm_channels_t pwmChannel,pwm_submodule_t subModule,uint16_t delayCycles)1436 status_t PWM_SetPhaseDelay(PWM_Type *base, pwm_channels_t pwmChannel, pwm_submodule_t subModule, uint16_t delayCycles)
1437 {
1438     assert(subModule != kPWM_Module_0);
1439     uint16_t reg = base->SM[subModule].CTRL2;
1440 
1441     /* Clear LDOK bit if it is set */
1442     if (0U != (base->MCTRL & PWM_MCTRL_LDOK(1UL << (uint8_t)subModule)))
1443     {
1444         base->MCTRL |= PWM_MCTRL_CLDOK(1UL << (uint8_t)subModule);
1445     }
1446 
1447     if (base->SM[kPWM_Module_0].VAL1 < delayCycles)
1448     {
1449         return kStatus_Fail;
1450     }
1451     else
1452     {
1453         /*
1454          * ERR051989: When the value of the phase delay register SMxPHASEDLY is reduced from a
1455          * non-zero value to 0 and submodule x reload source is from submodule0, the submodule
1456          * x may output an unexpected wide PWM pulse. The workaround is set SMxPHASEDLY=1,
1457          * SMxINIT=SM0INIT-1, SMxVALy=SM0VALy-1 (x=1,2,3, y=0,1,2,3,4,5).
1458          */
1459 #if defined(FSL_FEATURE_PWM_HAS_ERRATA_51989) && FSL_FEATURE_PWM_HAS_ERRATA_51989
1460         if (delayCycles == 0 &&
1461             ((base->SM[subModule].CTRL2 & PWM_CTRL2_RELOAD_SEL_MASK) >> PWM_CTRL2_RELOAD_SEL_SHIFT) == 1U)
1462         {
1463             base->SM[subModule].PHASEDLY = 1U;
1464             base->SM[subModule].INIT     = base->SM[0].INIT - 1U;
1465             base->SM[subModule].VAL0     = base->SM[0].VAL0 - 1U;
1466             base->SM[subModule].VAL1     = base->SM[0].VAL1 - 1U;
1467             base->SM[subModule].VAL2     = base->SM[0].VAL2 - 1U;
1468             base->SM[subModule].VAL3     = base->SM[0].VAL3 - 1U;
1469             base->SM[subModule].VAL4     = base->SM[0].VAL4 - 1U;
1470             base->SM[subModule].VAL5     = base->SM[0].VAL5 - 1U;
1471         }
1472         else
1473         {
1474             base->SM[subModule].PHASEDLY = delayCycles;
1475         }
1476 #else
1477         base->SM[subModule].PHASEDLY = delayCycles;
1478 #endif
1479     }
1480 
1481     /* Select the master sync signal as the source for initialization */
1482     reg = (reg & ~(uint16_t)PWM_CTRL2_INIT_SEL_MASK) | PWM_CTRL2_INIT_SEL(2);
1483     /* Set Load mode to make Buffered registers take effect immediately when LDOK bit set */
1484     base->SM[subModule].CTRL |= PWM_CTRL_LDMOD_MASK;
1485     /* Set LDOK bit to load buffer registers */
1486     base->MCTRL |= PWM_MCTRL_LDOK(1UL << (uint8_t)subModule);
1487     /* Restore the source of phase delay register intialization */
1488     base->SM[subModule].CTRL2 = reg;
1489     return kStatus_Success;
1490 }
1491 #endif /* FSL_FEATURE_PWM_HAS_PHASE_DELAY */