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 */