Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:00

0001 /*
0002  * Copyright (c) 2015, Freescale Semiconductor, Inc.
0003  * Copyright 2016-2022 NXP
0004  * All rights reserved.
0005  *
0006  * SPDX-License-Identifier: BSD-3-Clause
0007  */
0008 
0009 #include "fsl_pwm.h"
0010 
0011 /* Component ID definition, used by tools. */
0012 #ifndef FSL_COMPONENT_ID
0013 #define FSL_COMPONENT_ID "platform.drivers.pwm"
0014 #endif
0015 
0016 /*******************************************************************************
0017  * Prototypes
0018  ******************************************************************************/
0019 /*!
0020  * @brief Get the instance from the base address
0021  *
0022  * @param base PWM peripheral base address
0023  *
0024  * @return The PWM module instance
0025  */
0026 static uint32_t PWM_GetInstance(PWM_Type *base);
0027 
0028 /*******************************************************************************
0029  * Variables
0030  ******************************************************************************/
0031 /*! @brief Pointers to PWM bases for each instance. */
0032 static PWM_Type *const s_pwmBases[] = PWM_BASE_PTRS;
0033 
0034 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
0035 /*! @brief Pointers to PWM clocks for each PWM submodule. */
0036 static const clock_ip_name_t s_pwmClocks[][FSL_FEATURE_PWM_SUBMODULE_COUNT] = PWM_CLOCKS;
0037 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0038 
0039 /*! @brief Temporary PWM duty cycle. */
0040 static uint8_t s_pwmGetPwmDutyCycle[FSL_FEATURE_PWM_SUBMODULE_COUNT][PWM_SUBMODULE_CHANNEL] = {{0}};
0041 
0042 /*******************************************************************************
0043  * Code
0044  ******************************************************************************/
0045 
0046 /*!
0047  * brief Complement the variable of type uint16_t as needed
0048  *
0049  * This function can complement the variable of type uint16_t as needed.For example,
0050  * need to ask for the opposite of a positive integer.
0051  *
0052  * param value    Parameters of type uint16_t
0053  */
0054 static inline uint16_t PWM_GetComplementU16(uint16_t value)
0055 {
0056     return (~value + 1U);
0057 }
0058 
0059 static inline uint16_t dutyCycleToReloadValue(uint8_t dutyCyclePercent)
0060 {
0061     /* Rounding calculations to improve the accuracy of reloadValue */
0062     return ((65535U * dutyCyclePercent) + 50U) / 100U;
0063 }
0064 
0065 static uint32_t PWM_GetInstance(PWM_Type *base)
0066 {
0067     uint32_t instance;
0068 
0069     /* Find the instance index from base address mappings. */
0070     for (instance = 0; instance < ARRAY_SIZE(s_pwmBases); instance++)
0071     {
0072         if (s_pwmBases[instance] == base)
0073         {
0074             break;
0075         }
0076     }
0077 
0078     assert(instance < ARRAY_SIZE(s_pwmBases));
0079 
0080     return instance;
0081 }
0082 
0083 /*!
0084  * brief Ungates the PWM submodule clock and configures the peripheral for basic operation.
0085  *
0086  * note This API should be called at the beginning of the application using the PWM driver.
0087  *
0088  * param base      PWM peripheral base address
0089  * param subModule PWM submodule to configure
0090  * param config    Pointer to user's PWM config structure.
0091  *
0092  * return kStatus_Success means success; else failed.
0093  */
0094 status_t PWM_Init(PWM_Type *base, pwm_submodule_t subModule, const pwm_config_t *config)
0095 {
0096     assert(config);
0097 
0098     uint16_t reg;
0099 
0100     /* Source clock for submodule 0 cannot be itself */
0101     if ((config->clockSource == kPWM_Submodule0Clock) && (subModule == kPWM_Module_0))
0102     {
0103         return kStatus_Fail;
0104     }
0105 
0106     /* Reload source select clock for submodule 0 cannot be master reload */
0107     if ((config->reloadSelect == kPWM_MasterReload) && (subModule == kPWM_Module_0))
0108     {
0109         return kStatus_Fail;
0110     }
0111 
0112 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
0113     /* Ungate the PWM submodule clock*/
0114     CLOCK_EnableClock(s_pwmClocks[PWM_GetInstance(base)][subModule]);
0115 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0116 
0117     /* Clear the fault status flags */
0118     base->FSTS |= PWM_FSTS_FFLAG_MASK;
0119 
0120     reg = base->SM[subModule].CTRL2;
0121 
0122     /* Setup the submodule clock-source, control source of the INIT signal,
0123      * source of the force output signal, operation in debug & wait modes and reload source select
0124      */
0125     reg &=
0126         ~(uint16_t)(PWM_CTRL2_CLK_SEL_MASK | PWM_CTRL2_FORCE_SEL_MASK | PWM_CTRL2_INIT_SEL_MASK | PWM_CTRL2_INDEP_MASK |
0127 #if !defined(FSL_FEATURE_PWM_HAS_NO_WAITEN) || (!FSL_FEATURE_PWM_HAS_NO_WAITEN)
0128                     PWM_CTRL2_WAITEN_MASK |
0129 #endif /* FSL_FEATURE_PWM_HAS_NO_WAITEN */
0130                     PWM_CTRL2_DBGEN_MASK | PWM_CTRL2_RELOAD_SEL_MASK);
0131     reg |= (PWM_CTRL2_CLK_SEL(config->clockSource) | PWM_CTRL2_FORCE_SEL(config->forceTrigger) |
0132             PWM_CTRL2_INIT_SEL(config->initializationControl) | PWM_CTRL2_DBGEN(config->enableDebugMode) |
0133 #if !defined(FSL_FEATURE_PWM_HAS_NO_WAITEN) || (!FSL_FEATURE_PWM_HAS_NO_WAITEN)
0134             PWM_CTRL2_WAITEN(config->enableWait) |
0135 #endif /* FSL_FEATURE_PWM_HAS_NO_WAITEN */
0136             PWM_CTRL2_RELOAD_SEL(config->reloadSelect));
0137 
0138     /* Setup PWM A & B to be independent or a complementary-pair */
0139     switch (config->pairOperation)
0140     {
0141         case kPWM_Independent:
0142             reg |= PWM_CTRL2_INDEP_MASK;
0143             break;
0144         case kPWM_ComplementaryPwmA:
0145             base->MCTRL &= ~((uint16_t)1U << (PWM_MCTRL_IPOL_SHIFT + (uint16_t)subModule));
0146             break;
0147         case kPWM_ComplementaryPwmB:
0148             base->MCTRL |= ((uint16_t)1U << (PWM_MCTRL_IPOL_SHIFT + (uint16_t)subModule));
0149             break;
0150         default:
0151             assert(false);
0152             break;
0153     }
0154     base->SM[subModule].CTRL2 = reg;
0155 
0156     reg = base->SM[subModule].CTRL;
0157 
0158     /* Setup the clock prescale, load mode and frequency */
0159     reg &= ~(uint16_t)(PWM_CTRL_PRSC_MASK | PWM_CTRL_LDFQ_MASK | PWM_CTRL_LDMOD_MASK);
0160     reg |= (PWM_CTRL_PRSC(config->prescale) | PWM_CTRL_LDFQ(config->reloadFrequency));
0161 
0162     /* Setup register reload logic */
0163     switch (config->reloadLogic)
0164     {
0165         case kPWM_ReloadImmediate:
0166             reg |= PWM_CTRL_LDMOD_MASK;
0167             break;
0168         case kPWM_ReloadPwmHalfCycle:
0169             reg |= PWM_CTRL_HALF_MASK;
0170             reg &= (uint16_t)(~PWM_CTRL_FULL_MASK);
0171             break;
0172         case kPWM_ReloadPwmFullCycle:
0173             reg &= (uint16_t)(~PWM_CTRL_HALF_MASK);
0174             reg |= PWM_CTRL_FULL_MASK;
0175             break;
0176         case kPWM_ReloadPwmHalfAndFullCycle:
0177             reg |= PWM_CTRL_HALF_MASK;
0178             reg |= PWM_CTRL_FULL_MASK;
0179             break;
0180         default:
0181             assert(false);
0182             break;
0183     }
0184     base->SM[subModule].CTRL = reg;
0185 
0186     /* Set PWM output normal */
0187     base->MASK &= ~(uint16_t)(PWM_MASK_MASKX_MASK | PWM_MASK_MASKA_MASK | PWM_MASK_MASKB_MASK);
0188 
0189     base->DTSRCSEL = 0U;
0190 
0191     /* Issue a Force trigger event when configured to trigger locally */
0192     if (config->forceTrigger == kPWM_Force_Local)
0193     {
0194         base->SM[subModule].CTRL2 |= PWM_CTRL2_FORCE(1U);
0195     }
0196 
0197     return kStatus_Success;
0198 }
0199 
0200 /*!
0201  * brief Gate the PWM submodule clock
0202  *
0203  * param base      PWM peripheral base address
0204  * param subModule PWM submodule to deinitialize
0205  */
0206 void PWM_Deinit(PWM_Type *base, pwm_submodule_t subModule)
0207 {
0208     /* Stop the submodule */
0209     base->MCTRL &= ~((uint16_t)1U << (PWM_MCTRL_RUN_SHIFT + (uint16_t)subModule));
0210 
0211 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
0212     /* Gate the PWM submodule clock*/
0213     CLOCK_DisableClock(s_pwmClocks[PWM_GetInstance(base)][subModule]);
0214 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0215 }
0216 
0217 /*!
0218  * brief  Fill in the PWM config struct with the default settings
0219  *
0220  * The default values are:
0221  * code
0222  *   config->enableDebugMode = false;
0223  *   config->enableWait = false;
0224  *   config->reloadSelect = kPWM_LocalReload;
0225  *   config->clockSource = kPWM_BusClock;
0226  *   config->prescale = kPWM_Prescale_Divide_1;
0227  *   config->initializationControl = kPWM_Initialize_LocalSync;
0228  *   config->forceTrigger = kPWM_Force_Local;
0229  *   config->reloadFrequency = kPWM_LoadEveryOportunity;
0230  *   config->reloadLogic = kPWM_ReloadImmediate;
0231  *   config->pairOperation = kPWM_Independent;
0232  * endcode
0233  * param config Pointer to user's PWM config structure.
0234  */
0235 void PWM_GetDefaultConfig(pwm_config_t *config)
0236 {
0237     assert(config);
0238 
0239     /* Initializes the configure structure to zero. */
0240     (void)memset(config, 0, sizeof(*config));
0241 
0242     /* PWM is paused in debug mode */
0243     config->enableDebugMode = false;
0244     /* PWM is paused in wait mode */
0245 #if !defined(FSL_FEATURE_PWM_HAS_NO_WAITEN) || (!FSL_FEATURE_PWM_HAS_NO_WAITEN)
0246     config->enableWait = false;
0247 #endif /* FSL_FEATURE_PWM_HAS_NO_WAITEN */
0248     /* PWM module uses the local reload signal to reload registers */
0249     config->reloadSelect = kPWM_LocalReload;
0250     /* Use the IP Bus clock as source clock for the PWM submodule */
0251     config->clockSource = kPWM_BusClock;
0252     /* Clock source prescale is set to divide by 1*/
0253     config->prescale = kPWM_Prescale_Divide_1;
0254     /* Local sync causes initialization */
0255     config->initializationControl = kPWM_Initialize_LocalSync;
0256     /* The local force signal, CTRL2[FORCE], from the submodule is used to force updates */
0257     config->forceTrigger = kPWM_Force_Local;
0258     /* PWM reload frequency, reload opportunity is PWM half cycle or full cycle.
0259      * This field is not used in Immediate reload mode
0260      */
0261     config->reloadFrequency = kPWM_LoadEveryOportunity;
0262     /* Buffered-registers get loaded with new values as soon as LDOK bit is set */
0263     config->reloadLogic = kPWM_ReloadImmediate;
0264     /* PWM A & PWM B operate as 2 independent channels */
0265     config->pairOperation = kPWM_Independent;
0266 }
0267 
0268 /*!
0269  * brief Sets up the PWM signals for a PWM submodule.
0270  *
0271  * The function initializes the submodule according to the parameters passed in by the user. The function
0272  * also sets up the value compare registers to match the PWM signal requirements.
0273  * If the dead time insertion logic is enabled, the pulse period is reduced by the
0274  * dead time period specified by the user.
0275  *
0276  * param base        PWM peripheral base address
0277  * param subModule   PWM submodule to configure
0278  * param chnlParams  Array of PWM channel parameters to configure the channel(s), PWMX submodule is not supported.
0279  * param numOfChnls  Number of channels to configure, this should be the size of the array passed in.
0280  *                    Array size should not be more than 2 as each submodule has 2 pins to output PWM
0281  * param mode        PWM operation mode, options available in enumeration ::pwm_mode_t
0282  * param pwmFreq_Hz  PWM signal frequency in Hz
0283  * param srcClock_Hz PWM main counter clock in Hz.
0284  *
0285  * return Returns kStatusFail if there was error setting up the signal; kStatusSuccess otherwise
0286  */
0287 status_t PWM_SetupPwm(PWM_Type *base,
0288                       pwm_submodule_t subModule,
0289                       const pwm_signal_param_t *chnlParams,
0290                       uint8_t numOfChnls,
0291                       pwm_mode_t mode,
0292                       uint32_t pwmFreq_Hz,
0293                       uint32_t srcClock_Hz)
0294 {
0295     assert(chnlParams);
0296     assert(pwmFreq_Hz);
0297     assert(numOfChnls);
0298     assert(srcClock_Hz);
0299 
0300     uint32_t pwmClock;
0301     uint16_t pulseCnt = 0, pwmHighPulse = 0;
0302     uint16_t modulo = 0;
0303     uint8_t i, polarityShift = 0, outputEnableShift = 0;
0304 
0305     for (i = 0; i < numOfChnls; i++)
0306     {
0307         if (chnlParams[i].pwmChannel == kPWM_PwmX)
0308         {
0309             /* PWMX configuration is not supported yet */
0310             return kStatus_Fail;
0311         }
0312     }
0313 
0314     /* Divide the clock by the prescale value */
0315     pwmClock = (srcClock_Hz / (1UL << ((base->SM[subModule].CTRL & PWM_CTRL_PRSC_MASK) >> PWM_CTRL_PRSC_SHIFT)));
0316     pulseCnt = (uint16_t)(pwmClock / pwmFreq_Hz);
0317 
0318     /* Setup each PWM channel */
0319     for (i = 0; i < numOfChnls; i++)
0320     {
0321         /* Calculate pulse width */
0322         pwmHighPulse = (pulseCnt * chnlParams->dutyCyclePercent) / 100U;
0323 
0324         /* Setup the different match registers to generate the PWM signal */
0325         switch (mode)
0326         {
0327             case kPWM_SignedCenterAligned:
0328                 /* Setup the PWM period for a signed center aligned signal */
0329                 if (i == 0U)
0330                 {
0331                     modulo = (pulseCnt >> 1U);
0332                     /* Indicates the start of the PWM period */
0333                     base->SM[subModule].INIT = PWM_GetComplementU16(modulo);
0334                     /* Indicates the center value */
0335                     base->SM[subModule].VAL0 = 0;
0336                     /* Indicates the end of the PWM period */
0337                     /* The change during the end to start of the PWM period requires a count time */
0338                     base->SM[subModule].VAL1 = modulo - 1U;
0339                 }
0340 
0341                 /* Setup the PWM dutycycle */
0342                 if (chnlParams->pwmChannel == kPWM_PwmA)
0343                 {
0344                     base->SM[subModule].VAL2 = PWM_GetComplementU16(pwmHighPulse / 2U);
0345                     base->SM[subModule].VAL3 = (pwmHighPulse / 2U);
0346                 }
0347                 else
0348                 {
0349                     base->SM[subModule].VAL4 = PWM_GetComplementU16(pwmHighPulse / 2U);
0350                     base->SM[subModule].VAL5 = (pwmHighPulse / 2U);
0351                 }
0352                 break;
0353             case kPWM_CenterAligned:
0354                 /* Setup the PWM period for an unsigned center aligned signal */
0355                 /* Indicates the start of the PWM period */
0356                 if (i == 0U)
0357                 {
0358                     base->SM[subModule].INIT = 0;
0359                     /* Indicates the center value */
0360                     base->SM[subModule].VAL0 = (pulseCnt / 2U);
0361                     /* Indicates the end of the PWM period */
0362                     /* The change during the end to start of the PWM period requires a count time */
0363                     base->SM[subModule].VAL1 = pulseCnt - 1U;
0364                 }
0365 
0366                 /* Setup the PWM dutycycle */
0367                 if (chnlParams->pwmChannel == kPWM_PwmA)
0368                 {
0369                     base->SM[subModule].VAL2 = ((pulseCnt - pwmHighPulse) / 2U);
0370                     base->SM[subModule].VAL3 = ((pulseCnt + pwmHighPulse) / 2U);
0371                 }
0372                 else
0373                 {
0374                     base->SM[subModule].VAL4 = ((pulseCnt - pwmHighPulse) / 2U);
0375                     base->SM[subModule].VAL5 = ((pulseCnt + pwmHighPulse) / 2U);
0376                 }
0377                 break;
0378             case kPWM_SignedEdgeAligned:
0379                 /* Setup the PWM period for a signed edge aligned signal */
0380                 if (i == 0U)
0381                 {
0382                     modulo = (pulseCnt >> 1U);
0383                     /* Indicates the start of the PWM period */
0384                     base->SM[subModule].INIT = PWM_GetComplementU16(modulo);
0385                     /* Indicates the center value */
0386                     base->SM[subModule].VAL0 = 0;
0387                     /* Indicates the end of the PWM period */
0388                     /* The change during the end to start of the PWM period requires a count time */
0389                     base->SM[subModule].VAL1 = modulo - 1U;
0390                 }
0391 
0392                 /* Setup the PWM dutycycle */
0393                 if (chnlParams->pwmChannel == kPWM_PwmA)
0394                 {
0395                     base->SM[subModule].VAL2 = PWM_GetComplementU16(modulo);
0396                     base->SM[subModule].VAL3 = PWM_GetComplementU16(modulo) + pwmHighPulse;
0397                 }
0398                 else
0399                 {
0400                     base->SM[subModule].VAL4 = PWM_GetComplementU16(modulo);
0401                     base->SM[subModule].VAL5 = PWM_GetComplementU16(modulo) + pwmHighPulse;
0402                 }
0403                 break;
0404             case kPWM_EdgeAligned:
0405                 /* Setup the PWM period for a unsigned edge aligned signal */
0406                 /* Indicates the start of the PWM period */
0407                 if (i == 0U)
0408                 {
0409                     base->SM[subModule].INIT = 0;
0410                     /* Indicates the center value */
0411                     base->SM[subModule].VAL0 = (pulseCnt / 2U);
0412                     /* Indicates the end of the PWM period */
0413                     /* The change during the end to start of the PWM period requires a count time */
0414                     base->SM[subModule].VAL1 = pulseCnt - 1U;
0415                 }
0416 
0417                 /* Setup the PWM dutycycle */
0418                 if (chnlParams->pwmChannel == kPWM_PwmA)
0419                 {
0420                     base->SM[subModule].VAL2 = 0;
0421                     base->SM[subModule].VAL3 = pwmHighPulse;
0422                 }
0423                 else
0424                 {
0425                     base->SM[subModule].VAL4 = 0;
0426                     base->SM[subModule].VAL5 = pwmHighPulse;
0427                 }
0428                 break;
0429             default:
0430                 assert(false);
0431                 break;
0432         }
0433         /* Setup register shift values based on the channel being configured.
0434          * Also setup the deadtime value
0435          */
0436         if (chnlParams->pwmChannel == kPWM_PwmA)
0437         {
0438             polarityShift              = PWM_OCTRL_POLA_SHIFT;
0439             outputEnableShift          = PWM_OUTEN_PWMA_EN_SHIFT;
0440             base->SM[subModule].DTCNT0 = PWM_DTCNT0_DTCNT0(chnlParams->deadtimeValue);
0441         }
0442         else
0443         {
0444             polarityShift              = PWM_OCTRL_POLB_SHIFT;
0445             outputEnableShift          = PWM_OUTEN_PWMB_EN_SHIFT;
0446             base->SM[subModule].DTCNT1 = PWM_DTCNT1_DTCNT1(chnlParams->deadtimeValue);
0447         }
0448 
0449         /* Set PWM output fault status */
0450         switch (chnlParams->pwmChannel)
0451         {
0452             case kPWM_PwmA:
0453                 base->SM[subModule].OCTRL &= ~((uint16_t)PWM_OCTRL_PWMAFS_MASK);
0454                 base->SM[subModule].OCTRL |= (((uint16_t)(chnlParams->faultState) << (uint16_t)PWM_OCTRL_PWMAFS_SHIFT) &
0455                                               (uint16_t)PWM_OCTRL_PWMAFS_MASK);
0456                 break;
0457             case kPWM_PwmB:
0458                 base->SM[subModule].OCTRL &= ~((uint16_t)PWM_OCTRL_PWMBFS_MASK);
0459                 base->SM[subModule].OCTRL |= (((uint16_t)(chnlParams->faultState) << (uint16_t)PWM_OCTRL_PWMBFS_SHIFT) &
0460                                               (uint16_t)PWM_OCTRL_PWMBFS_MASK);
0461                 break;
0462             default:
0463                 assert(false);
0464                 break;
0465         }
0466 
0467         /* Setup signal active level */
0468         if ((bool)chnlParams->level == kPWM_HighTrue)
0469         {
0470             base->SM[subModule].OCTRL &= ~((uint16_t)1U << (uint16_t)polarityShift);
0471         }
0472         else
0473         {
0474             base->SM[subModule].OCTRL |= ((uint16_t)1U << (uint16_t)polarityShift);
0475         }
0476         if (chnlParams->pwmchannelenable)
0477         {
0478             /* Enable PWM output */
0479             base->OUTEN |= ((uint16_t)1U << ((uint16_t)outputEnableShift + (uint16_t)subModule));
0480         }
0481 
0482         /* Get the pwm duty cycle */
0483         s_pwmGetPwmDutyCycle[subModule][chnlParams->pwmChannel] = chnlParams->dutyCyclePercent;
0484 
0485         /* Get the next channel parameters */
0486         chnlParams++;
0487     }
0488 
0489     return kStatus_Success;
0490 }
0491 
0492 /*!
0493  * brief Set PWM phase shift for PWM channel running on channel PWM_A, PWM_B which with 50% duty cycle.
0494  *
0495  * param base        PWM peripheral base address
0496  * param subModule   PWM submodule to configure
0497  * param pwmChannel  PWM channel to configure
0498  * param pwmFreq_Hz  PWM signal frequency in Hz
0499  * param srcClock_Hz PWM main counter clock in Hz.
0500  * param shiftvalue  Phase shift value, range in 0 ~ 50
0501  * param doSync      true: Set LDOK bit for the submodule list;
0502  *                   false: LDOK bit don't set, need to call PWM_SetPwmLdok to sync update.
0503  *
0504  * return Returns kStatus_Fail if there was error setting up the signal; kStatus_Success otherwise
0505  */
0506 status_t PWM_SetupPwmPhaseShift(PWM_Type *base,
0507                                 pwm_submodule_t subModule,
0508                                 pwm_channels_t pwmChannel,
0509                                 uint32_t pwmFreq_Hz,
0510                                 uint32_t srcClock_Hz,
0511                                 uint8_t shiftvalue,
0512                                 bool doSync)
0513 {
0514     assert(pwmFreq_Hz != 0U);
0515     assert(srcClock_Hz != 0U);
0516     assert(shiftvalue <= 50U);
0517 
0518     uint32_t pwmClock;
0519     uint16_t pulseCnt = 0, pwmHighPulse = 0;
0520     uint16_t modulo = 0;
0521     uint16_t shift  = 0;
0522 
0523     if (pwmChannel != kPWM_PwmX)
0524     {
0525         /* Divide the clock by the prescale value */
0526         pwmClock = (srcClock_Hz / (1UL << ((base->SM[subModule].CTRL & PWM_CTRL_PRSC_MASK) >> PWM_CTRL_PRSC_SHIFT)));
0527         pulseCnt = (uint16_t)(pwmClock / pwmFreq_Hz);
0528 
0529         /* Clear LDOK bit if it is set */
0530         if (0U != (base->MCTRL & PWM_MCTRL_LDOK(1UL << (uint8_t)subModule)))
0531         {
0532             base->MCTRL |= PWM_MCTRL_CLDOK(1UL << (uint8_t)subModule);
0533         }
0534 
0535         modulo = (pulseCnt >> 1U);
0536         /* Indicates the start of the PWM period */
0537         base->SM[subModule].INIT = PWM_GetComplementU16(modulo);
0538         /* Indicates the center value */
0539         base->SM[subModule].VAL0 = 0;
0540         /* Indicates the end of the PWM period */
0541         /* The change during the end to start of the PWM period requires a count time */
0542         base->SM[subModule].VAL1 = modulo - 1U;
0543 
0544         /* Immediately upon when MCTRL[LDOK] being set */
0545         base->SM[subModule].CTRL |= PWM_CTRL_LDMOD_MASK;
0546 
0547         /* phase shift value */
0548         shift = (pulseCnt * shiftvalue) / 100U;
0549 
0550         /* duty cycle 50% */
0551         pwmHighPulse = pulseCnt / 2U;
0552 
0553         if (pwmChannel == kPWM_PwmA)
0554         {
0555             base->SM[subModule].VAL2 = PWM_GetComplementU16(modulo) + shift;
0556             base->SM[subModule].VAL3 = PWM_GetComplementU16(modulo) + pwmHighPulse + shift - 1U;
0557         }
0558         else if (pwmChannel == kPWM_PwmB)
0559         {
0560             base->SM[subModule].VAL4 = PWM_GetComplementU16(modulo) + shift;
0561             base->SM[subModule].VAL5 = PWM_GetComplementU16(modulo) + pwmHighPulse + shift - 1U;
0562         }
0563         else
0564         {
0565             return kStatus_Fail;
0566         }
0567 
0568         if (doSync)
0569         {
0570             /* Set LDOK bit to load VALx bit */
0571             base->MCTRL |= PWM_MCTRL_LDOK(1UL << (uint8_t)subModule);
0572         }
0573     }
0574     else
0575     {
0576         return kStatus_Fail;
0577     }
0578 
0579     return kStatus_Success;
0580 }
0581 
0582 /*!
0583  * brief Updates the PWM signal's dutycycle.
0584  *
0585  * The function updates the PWM dutycyle to the new value that is passed in.
0586  * If the dead time insertion logic is enabled then the pulse period is reduced by the
0587  * dead time period specified by the user.
0588  *
0589  * param base              PWM peripheral base address
0590  * param subModule         PWM submodule to configure
0591  * param pwmSignal         Signal (PWM A or PWM B) to update
0592  * param currPwmMode       The current PWM mode set during PWM setup
0593  * param dutyCyclePercent  New PWM pulse width, value should be between 0 to 100
0594  *                          0=inactive signal(0% duty cycle)...
0595  *                          100=active signal (100% duty cycle)
0596  */
0597 void PWM_UpdatePwmDutycycle(PWM_Type *base,
0598                             pwm_submodule_t subModule,
0599                             pwm_channels_t pwmSignal,
0600                             pwm_mode_t currPwmMode,
0601                             uint8_t dutyCyclePercent)
0602 {
0603     assert(dutyCyclePercent <= 100U);
0604     assert(pwmSignal != kPWM_PwmX);
0605     uint16_t reloadValue = dutyCycleToReloadValue(dutyCyclePercent);
0606 
0607     PWM_UpdatePwmDutycycleHighAccuracy(base, subModule, pwmSignal, currPwmMode, reloadValue);
0608 }
0609 
0610 /*!
0611  * brief Updates the PWM signal's dutycycle with 16-bit accuracy.
0612  *
0613  * The function updates the PWM dutycyle to the new value that is passed in.
0614  * If the dead time insertion logic is enabled then the pulse period is reduced by the
0615  * dead time period specified by the user.
0616  *
0617  * param base              PWM peripheral base address
0618  * param subModule         PWM submodule to configure
0619  * param pwmSignal         Signal (PWM A or PWM B) to update
0620  * param currPwmMode       The current PWM mode set during PWM setup
0621  * param dutyCycle         New PWM pulse width, value should be between 0 to 65535
0622  *                          0=inactive signal(0% duty cycle)...
0623  *                          65535=active signal (100% duty cycle)
0624  */
0625 void PWM_UpdatePwmDutycycleHighAccuracy(
0626     PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmSignal, pwm_mode_t currPwmMode, uint16_t dutyCycle)
0627 {
0628     assert(pwmSignal != kPWM_PwmX);
0629     uint16_t pulseCnt = 0, pwmHighPulse = 0;
0630     uint16_t modulo = 0;
0631 
0632     switch (currPwmMode)
0633     {
0634         case kPWM_SignedCenterAligned:
0635             modulo   = base->SM[subModule].VAL1 + 1U;
0636             pulseCnt = modulo * 2U;
0637             /* Calculate pulse width */
0638             pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
0639 
0640             /* Setup the PWM dutycycle */
0641             if (pwmSignal == kPWM_PwmA)
0642             {
0643                 base->SM[subModule].VAL2 = PWM_GetComplementU16(pwmHighPulse / 2U);
0644                 base->SM[subModule].VAL3 = (pwmHighPulse / 2U);
0645             }
0646             else if (pwmSignal == kPWM_PwmB)
0647             {
0648                 base->SM[subModule].VAL4 = PWM_GetComplementU16(pwmHighPulse / 2U);
0649                 base->SM[subModule].VAL5 = (pwmHighPulse / 2U);
0650             }
0651             else
0652             {
0653                 assert(false);
0654             }
0655             break;
0656         case kPWM_CenterAligned:
0657             pulseCnt = base->SM[subModule].VAL1 + 1U;
0658             /* Calculate pulse width */
0659             pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
0660 
0661             /* Setup the PWM dutycycle */
0662             if (pwmSignal == kPWM_PwmA)
0663             {
0664                 base->SM[subModule].VAL2 = ((pulseCnt - pwmHighPulse) / 2U);
0665                 base->SM[subModule].VAL3 = ((pulseCnt + pwmHighPulse) / 2U);
0666             }
0667             else if (pwmSignal == kPWM_PwmB)
0668             {
0669                 base->SM[subModule].VAL4 = ((pulseCnt - pwmHighPulse) / 2U);
0670                 base->SM[subModule].VAL5 = ((pulseCnt + pwmHighPulse) / 2U);
0671             }
0672             else
0673             {
0674                 assert(false);
0675             }
0676             break;
0677         case kPWM_SignedEdgeAligned:
0678             modulo   = base->SM[subModule].VAL1 + 1U;
0679             pulseCnt = modulo * 2U;
0680             /* Calculate pulse width */
0681             pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
0682 
0683             /* Setup the PWM dutycycle */
0684             if (pwmSignal == kPWM_PwmA)
0685             {
0686                 base->SM[subModule].VAL2 = PWM_GetComplementU16(modulo);
0687                 base->SM[subModule].VAL3 = PWM_GetComplementU16(modulo) + pwmHighPulse;
0688             }
0689             else if (pwmSignal == kPWM_PwmB)
0690             {
0691                 base->SM[subModule].VAL4 = PWM_GetComplementU16(modulo);
0692                 base->SM[subModule].VAL5 = PWM_GetComplementU16(modulo) + pwmHighPulse;
0693             }
0694             else
0695             {
0696                 assert(false);
0697             }
0698             break;
0699         case kPWM_EdgeAligned:
0700             pulseCnt = base->SM[subModule].VAL1 + 1U;
0701             /* Calculate pulse width */
0702             pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
0703 
0704             /* Setup the PWM dutycycle */
0705             if (pwmSignal == kPWM_PwmA)
0706             {
0707                 base->SM[subModule].VAL2 = 0;
0708                 base->SM[subModule].VAL3 = pwmHighPulse;
0709             }
0710             else if (pwmSignal == kPWM_PwmB)
0711             {
0712                 base->SM[subModule].VAL4 = 0;
0713                 base->SM[subModule].VAL5 = pwmHighPulse;
0714             }
0715             else
0716             {
0717                 assert(false);
0718             }
0719             break;
0720         default:
0721             assert(false);
0722             break;
0723     }
0724     if (kPWM_PwmX != pwmSignal)
0725     {
0726         /* Get the pwm duty cycle */
0727         s_pwmGetPwmDutyCycle[subModule][pwmSignal] = (uint8_t)(dutyCycle / 65535U);
0728     }
0729 }
0730 
0731 /*!
0732  * brief Sets up the PWM input capture
0733  *
0734  * Each PWM submodule has 3 pins that can be configured for use as input capture pins. This function
0735  * sets up the capture parameters for each pin and enables the pin for input capture operation.
0736  *
0737  * param base               PWM peripheral base address
0738  * param subModule          PWM submodule to configure
0739  * param pwmChannel         Channel in the submodule to setup
0740  * param inputCaptureParams Parameters passed in to set up the input pin
0741  */
0742 void PWM_SetupInputCapture(PWM_Type *base,
0743                            pwm_submodule_t subModule,
0744                            pwm_channels_t pwmChannel,
0745                            const pwm_input_capture_param_t *inputCaptureParams)
0746 {
0747     uint16_t reg = 0;
0748     switch (pwmChannel)
0749     {
0750         case kPWM_PwmA:
0751             /* Setup the capture paramters for PWM A pin */
0752             reg = (PWM_CAPTCTRLA_INP_SELA(inputCaptureParams->captureInputSel) |
0753                    PWM_CAPTCTRLA_EDGA0(inputCaptureParams->edge0) | PWM_CAPTCTRLA_EDGA1(inputCaptureParams->edge1) |
0754                    PWM_CAPTCTRLA_ONESHOTA(inputCaptureParams->enableOneShotCapture) |
0755                    PWM_CAPTCTRLA_CFAWM(inputCaptureParams->fifoWatermark));
0756             /* Enable the edge counter if using the output edge counter */
0757             if (inputCaptureParams->captureInputSel)
0758             {
0759                 reg |= PWM_CAPTCTRLA_EDGCNTA_EN_MASK;
0760             }
0761             /* Enable input capture operation */
0762             reg |= PWM_CAPTCTRLA_ARMA_MASK;
0763 
0764             base->SM[subModule].CAPTCTRLA = reg;
0765 
0766             /* Setup the compare value when using the edge counter as source */
0767             base->SM[subModule].CAPTCOMPA = PWM_CAPTCOMPA_EDGCMPA(inputCaptureParams->edgeCompareValue);
0768             /* Setup PWM A pin for input capture */
0769             base->OUTEN &= ~((uint16_t)1U << (PWM_OUTEN_PWMA_EN_SHIFT + (uint16_t)subModule));
0770             break;
0771         case kPWM_PwmB:
0772             /* Setup the capture paramters for PWM B pin */
0773             reg = (PWM_CAPTCTRLB_INP_SELB(inputCaptureParams->captureInputSel) |
0774                    PWM_CAPTCTRLB_EDGB0(inputCaptureParams->edge0) | PWM_CAPTCTRLB_EDGB1(inputCaptureParams->edge1) |
0775                    PWM_CAPTCTRLB_ONESHOTB(inputCaptureParams->enableOneShotCapture) |
0776                    PWM_CAPTCTRLB_CFBWM(inputCaptureParams->fifoWatermark));
0777             /* Enable the edge counter if using the output edge counter */
0778             if (inputCaptureParams->captureInputSel)
0779             {
0780                 reg |= PWM_CAPTCTRLB_EDGCNTB_EN_MASK;
0781             }
0782             /* Enable input capture operation */
0783             reg |= PWM_CAPTCTRLB_ARMB_MASK;
0784 
0785             base->SM[subModule].CAPTCTRLB = reg;
0786 
0787             /* Setup the compare value when using the edge counter as source */
0788             base->SM[subModule].CAPTCOMPB = PWM_CAPTCOMPB_EDGCMPB(inputCaptureParams->edgeCompareValue);
0789             /* Setup PWM B pin for input capture */
0790             base->OUTEN &= ~((uint16_t)1U << (PWM_OUTEN_PWMB_EN_SHIFT + (uint16_t)subModule));
0791             break;
0792         case kPWM_PwmX:
0793             reg = (PWM_CAPTCTRLX_INP_SELX(inputCaptureParams->captureInputSel) |
0794                    PWM_CAPTCTRLX_EDGX0(inputCaptureParams->edge0) | PWM_CAPTCTRLX_EDGX1(inputCaptureParams->edge1) |
0795                    PWM_CAPTCTRLX_ONESHOTX(inputCaptureParams->enableOneShotCapture) |
0796                    PWM_CAPTCTRLX_CFXWM(inputCaptureParams->fifoWatermark));
0797             /* Enable the edge counter if using the output edge counter */
0798             if (inputCaptureParams->captureInputSel)
0799             {
0800                 reg |= PWM_CAPTCTRLX_EDGCNTX_EN_MASK;
0801             }
0802             /* Enable input capture operation */
0803             reg |= PWM_CAPTCTRLX_ARMX_MASK;
0804 
0805             base->SM[subModule].CAPTCTRLX = reg;
0806 
0807             /* Setup the compare value when using the edge counter as source */
0808             base->SM[subModule].CAPTCOMPX = PWM_CAPTCOMPX_EDGCMPX(inputCaptureParams->edgeCompareValue);
0809             /* Setup PWM X pin for input capture */
0810             base->OUTEN &= ~((uint16_t)1U << (PWM_OUTEN_PWMX_EN_SHIFT + (uint16_t)subModule));
0811             break;
0812         default:
0813             assert(false);
0814             break;
0815     }
0816 }
0817 
0818 /*!
0819  * @brief Sets up the PWM fault input filter.
0820  *
0821  * @param base                   PWM peripheral base address
0822  * @param faultInputFilterParams Parameters passed in to set up the fault input filter.
0823  */
0824 void PWM_SetupFaultInputFilter(PWM_Type *base, const pwm_fault_input_filter_param_t *faultInputFilterParams)
0825 {
0826     assert(NULL != faultInputFilterParams);
0827 
0828     /* When changing values for fault period from a non-zero value, first write a value of 0 to clear the filter. */
0829     if (0U != (base->FFILT & PWM_FFILT_FILT_PER_MASK))
0830     {
0831         base->FFILT &= ~(uint16_t)(PWM_FFILT_FILT_PER_MASK);
0832     }
0833 
0834     base->FFILT = (uint16_t)(PWM_FFILT_FILT_PER(faultInputFilterParams->faultFilterPeriod) |
0835                              PWM_FFILT_FILT_CNT(faultInputFilterParams->faultFilterCount) |
0836                              PWM_FFILT_GSTR(faultInputFilterParams->faultGlitchStretch ? 1U : 0U));
0837 }
0838 
0839 /*!
0840  * brief Sets up the PWM fault protection.
0841  *
0842  * PWM has 4 fault inputs.
0843  *
0844  * param base        PWM peripheral base address
0845  * param faultNum    PWM fault to configure.
0846  * param faultParams Pointer to the PWM fault config structure
0847  */
0848 void PWM_SetupFaults(PWM_Type *base, pwm_fault_input_t faultNum, const pwm_fault_param_t *faultParams)
0849 {
0850     assert(faultParams);
0851     uint16_t reg;
0852 
0853     reg = base->FCTRL;
0854     /* Set the faults level-settting */
0855     if (faultParams->faultLevel)
0856     {
0857         reg |= ((uint16_t)1U << (PWM_FCTRL_FLVL_SHIFT + (uint16_t)faultNum));
0858     }
0859     else
0860     {
0861         reg &= ~((uint16_t)1U << (PWM_FCTRL_FLVL_SHIFT + (uint16_t)faultNum));
0862     }
0863     /* Set the fault clearing mode */
0864     if ((uint16_t)faultParams->faultClearingMode != 0U)
0865     {
0866         /* Use manual fault clearing */
0867         reg &= ~((uint16_t)1U << (PWM_FCTRL_FAUTO_SHIFT + (uint16_t)faultNum));
0868         if (faultParams->faultClearingMode == kPWM_ManualSafety)
0869         {
0870             /* Use manual fault clearing with safety mode enabled */
0871             reg |= ((uint16_t)1U << (PWM_FCTRL_FSAFE_SHIFT + (uint16_t)faultNum));
0872         }
0873         else
0874         {
0875             /* Use manual fault clearing with safety mode disabled */
0876             reg &= ~((uint16_t)1U << (PWM_FCTRL_FSAFE_SHIFT + (uint16_t)faultNum));
0877         }
0878     }
0879     else
0880     {
0881         /* Use automatic fault clearing */
0882         reg |= ((uint16_t)1U << (PWM_FCTRL_FAUTO_SHIFT + (uint16_t)faultNum));
0883     }
0884     base->FCTRL = reg;
0885 
0886     /* Set the combinational path option */
0887     if (faultParams->enableCombinationalPath)
0888     {
0889         /* Combinational path from the fault input to the PWM output is available */
0890         base->FCTRL2 &= ~((uint16_t)1U << (uint16_t)faultNum);
0891     }
0892     else
0893     {
0894         /* No combinational path available, only fault filter & latch signal can disable PWM output */
0895         base->FCTRL2 |= ((uint16_t)1U << (uint16_t)faultNum);
0896     }
0897 
0898     /* Initially clear both recovery modes */
0899     reg = base->FSTS;
0900     reg &= ~(((uint16_t)1U << (PWM_FSTS_FFULL_SHIFT + (uint16_t)faultNum)) |
0901              ((uint16_t)1U << (PWM_FSTS_FHALF_SHIFT + (uint16_t)faultNum)));
0902     /* Setup fault recovery */
0903     switch (faultParams->recoverMode)
0904     {
0905         case kPWM_NoRecovery:
0906             break;
0907         case kPWM_RecoverHalfCycle:
0908             reg |= ((uint16_t)1U << (PWM_FSTS_FHALF_SHIFT + (uint16_t)faultNum));
0909             break;
0910         case kPWM_RecoverFullCycle:
0911             reg |= ((uint16_t)1U << (PWM_FSTS_FFULL_SHIFT + (uint16_t)faultNum));
0912             break;
0913         case kPWM_RecoverHalfAndFullCycle:
0914             reg |= ((uint16_t)1U << (PWM_FSTS_FHALF_SHIFT + (uint16_t)faultNum));
0915             reg |= ((uint16_t)1U << (PWM_FSTS_FFULL_SHIFT + (uint16_t)faultNum));
0916             break;
0917         default:
0918             assert(false);
0919             break;
0920     }
0921     base->FSTS = reg;
0922 }
0923 
0924 /*!
0925  * brief  Fill in the PWM fault config struct with the default settings
0926  *
0927  * The default values are:
0928  * code
0929  *   config->faultClearingMode = kPWM_Automatic;
0930  *   config->faultLevel = false;
0931  *   config->enableCombinationalPath = true;
0932  *   config->recoverMode = kPWM_NoRecovery;
0933  * endcode
0934  * param config Pointer to user's PWM fault config structure.
0935  */
0936 void PWM_FaultDefaultConfig(pwm_fault_param_t *config)
0937 {
0938     assert(config);
0939 
0940     /* Initializes the configure structure to zero. */
0941     (void)memset(config, 0, sizeof(*config));
0942 
0943     /* PWM uses automatic fault clear mode */
0944     config->faultClearingMode = kPWM_Automatic;
0945     /* PWM fault level is set to logic 0 */
0946     config->faultLevel = false;
0947     /* Combinational Path from fault input is enabled */
0948     config->enableCombinationalPath = true;
0949     /* PWM output will stay inactive when recovering from a fault */
0950     config->recoverMode = kPWM_NoRecovery;
0951 }
0952 
0953 /*!
0954  * brief Selects the signal to output on a PWM pin when a FORCE_OUT signal is asserted.
0955  *
0956  * The user specifies which channel to configure by supplying the submodule number and whether
0957  * to modify PWM A or PWM B within that submodule.
0958  *
0959  * param base       PWM peripheral base address
0960  * param subModule  PWM submodule to configure
0961  * param pwmChannel Channel to configure
0962  * param mode       Signal to output when a FORCE_OUT is triggered
0963  */
0964 void PWM_SetupForceSignal(PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmChannel, pwm_force_signal_t mode)
0965 
0966 {
0967     uint16_t shift;
0968     uint16_t reg;
0969 
0970     /* DTSRCSEL register has 4 bits per submodule; 2 bits for PWM A and 2 bits for PWM B */
0971     shift = ((uint16_t)subModule * 4U) + ((uint16_t)pwmChannel * 2U);
0972 
0973     /* Setup the signal to be passed upon occurrence of a FORCE_OUT signal */
0974     reg = base->DTSRCSEL;
0975     reg &= ~((uint16_t)0x3U << shift);
0976     reg |= (uint16_t)((uint16_t)mode << shift);
0977     base->DTSRCSEL = reg;
0978 }
0979 
0980 /*!
0981  * brief Enables the selected PWM interrupts
0982  *
0983  * param base      PWM peripheral base address
0984  * param subModule PWM submodule to configure
0985  * param mask      The interrupts to enable. This is a logical OR of members of the
0986  *                  enumeration ::pwm_interrupt_enable_t
0987  */
0988 void PWM_EnableInterrupts(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask)
0989 {
0990     /* Upper 16 bits are for related to the submodule */
0991     base->SM[subModule].INTEN |= ((uint16_t)mask & 0xFFFFU);
0992     /* Fault related interrupts */
0993     base->FCTRL |= ((uint16_t)(mask >> 16U) & PWM_FCTRL_FIE_MASK);
0994 }
0995 
0996 /*!
0997  * brief Disables the selected PWM interrupts
0998  *
0999  * param base      PWM peripheral base address
1000  * param subModule PWM submodule to configure
1001  * param mask      The interrupts to enable. This is a logical OR of members of the
1002  *                  enumeration ::pwm_interrupt_enable_t
1003  */
1004 void PWM_DisableInterrupts(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask)
1005 {
1006     base->SM[subModule].INTEN &= ~((uint16_t)mask & 0xFFFFU);
1007     base->FCTRL &= ~((uint16_t)(mask >> 16U) & PWM_FCTRL_FIE_MASK);
1008 }
1009 
1010 /*!
1011  * brief Gets the enabled PWM interrupts
1012  *
1013  * param base      PWM peripheral base address
1014  * param subModule PWM submodule to configure
1015  *
1016  * return The enabled interrupts. This is the logical OR of members of the
1017  *         enumeration ::pwm_interrupt_enable_t
1018  */
1019 uint32_t PWM_GetEnabledInterrupts(PWM_Type *base, pwm_submodule_t subModule)
1020 {
1021     uint32_t enabledInterrupts;
1022 
1023     enabledInterrupts = base->SM[subModule].INTEN;
1024     enabledInterrupts |= (((uint32_t)base->FCTRL & PWM_FCTRL_FIE_MASK) << 16UL);
1025     return enabledInterrupts;
1026 }
1027 
1028 /*!
1029  * brief Gets the PWM status flags
1030  *
1031  * param base      PWM peripheral base address
1032  * param subModule PWM submodule to configure
1033  *
1034  * return The status flags. This is the logical OR of members of the
1035  *         enumeration ::pwm_status_flags_t
1036  */
1037 uint32_t PWM_GetStatusFlags(PWM_Type *base, pwm_submodule_t subModule)
1038 {
1039     uint32_t statusFlags;
1040 
1041     statusFlags = base->SM[subModule].STS;
1042     statusFlags |= (((uint32_t)base->FSTS & PWM_FSTS_FFLAG_MASK) << 16UL);
1043 
1044     return statusFlags;
1045 }
1046 
1047 /*!
1048  * brief Clears the PWM status flags
1049  *
1050  * param base      PWM peripheral base address
1051  * param subModule PWM submodule to configure
1052  * param mask      The status flags to clear. This is a logical OR of members of the
1053  *                  enumeration ::pwm_status_flags_t
1054  */
1055 void PWM_ClearStatusFlags(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask)
1056 {
1057     uint16_t reg;
1058 
1059     base->SM[subModule].STS = ((uint16_t)mask & 0xFFFFU);
1060     reg                     = base->FSTS;
1061     /* Clear the fault flags and set only the ones we wish to clear as the fault flags are cleared
1062      * by writing a login one
1063      */
1064     reg &= ~(uint16_t)(PWM_FSTS_FFLAG_MASK);
1065     reg |= (uint16_t)((mask >> 16U) & PWM_FSTS_FFLAG_MASK);
1066     base->FSTS = reg;
1067 }
1068 
1069 /*!
1070  * brief Set PWM output in idle status (high or low).
1071  *
1072  * note This API should call after PWM_SetupPwm() APIs, and PWMX submodule is not supported.
1073  *
1074  * param base               PWM peripheral base address
1075  * param pwmChannel         PWM channel to configure
1076  * param subModule          PWM submodule to configure
1077  * param idleStatus         True: PWM output is high in idle status; false: PWM output is low in idle status.
1078  *
1079  * return kStatus_Fail if there was error setting up the signal; kStatus_Success if set output idle success
1080  */
1081 status_t PWM_SetOutputToIdle(PWM_Type *base, pwm_channels_t pwmChannel, pwm_submodule_t subModule, bool idleStatus)
1082 {
1083     uint16_t valOn = 0, valOff = 0;
1084     uint16_t ldmod;
1085 
1086     /* Clear LDOK bit if it is set */
1087     if (0U != (base->MCTRL & PWM_MCTRL_LDOK(1UL << (uint8_t)subModule)))
1088     {
1089         base->MCTRL |= PWM_MCTRL_CLDOK(1UL << (uint8_t)subModule);
1090     }
1091 
1092     valOff = base->SM[subModule].INIT;
1093     valOn  = base->SM[subModule].VAL1 + 0x1U;
1094 
1095     if ((valOff + 1U) == valOn)
1096     {
1097         return kStatus_Fail;
1098     }
1099 
1100     /* Should not PWM_X channel */
1101     if (kPWM_PwmA == pwmChannel)
1102     {
1103         if (0U != (base->SM[subModule].OCTRL & PWM_OCTRL_POLA_MASK))
1104         {
1105             if (!idleStatus)
1106             {
1107                 valOn  = base->SM[subModule].INIT;
1108                 valOff = base->SM[subModule].VAL1 + 0x1U;
1109             }
1110         }
1111         else
1112         {
1113             if (idleStatus)
1114             {
1115                 valOn  = base->SM[subModule].INIT;
1116                 valOff = base->SM[subModule].VAL1 + 0x1U;
1117             }
1118         }
1119         base->SM[subModule].VAL2 = valOn;
1120         base->SM[subModule].VAL3 = valOff;
1121     }
1122     else if (kPWM_PwmB == pwmChannel)
1123     {
1124         if (0U != (base->SM[subModule].OCTRL & PWM_OCTRL_POLB_MASK))
1125         {
1126             if (!idleStatus)
1127             {
1128                 valOn  = base->SM[subModule].INIT;
1129                 valOff = base->SM[subModule].VAL1 + 0x1U;
1130             }
1131         }
1132         else
1133         {
1134             if (idleStatus)
1135             {
1136                 valOn  = base->SM[subModule].INIT;
1137                 valOff = base->SM[subModule].VAL1 + 0x1U;
1138             }
1139         }
1140         base->SM[subModule].VAL4 = valOn;
1141         base->SM[subModule].VAL5 = valOff;
1142     }
1143     else
1144     {
1145         return kStatus_Fail;
1146     }
1147 
1148     /* Record Load mode */
1149     ldmod = base->SM[subModule].CTRL;
1150     /* Set Load mode to make Buffered registers take effect immediately when LDOK bit set */
1151     base->SM[subModule].CTRL |= PWM_CTRL_LDMOD_MASK;
1152     /* Set LDOK bit to load buffer registers */
1153     base->MCTRL |= PWM_MCTRL_LDOK(1UL << (uint8_t)subModule);
1154     /* Restore Load mode */
1155     base->SM[subModule].CTRL = ldmod;
1156 
1157     /* Get pwm duty cycle */
1158     s_pwmGetPwmDutyCycle[subModule][pwmChannel] = 0x0U;
1159 
1160     return kStatus_Success;
1161 }
1162 
1163 /*!
1164  * brief Get the dutycycle value.
1165  *
1166  * param base        PWM peripheral base address
1167  * param subModule   PWM submodule to configure
1168  * param pwmChannel  PWM channel to configure
1169  *
1170  * return Current channel dutycycle value.
1171  */
1172 uint8_t PWM_GetPwmChannelState(PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmChannel)
1173 {
1174     return s_pwmGetPwmDutyCycle[subModule][pwmChannel];
1175 }
1176 
1177 /*!
1178  * brief Set the pwm submodule prescaler.
1179  *
1180  * param base               PWM peripheral base address
1181  * param subModule          PWM submodule to configure
1182  * param prescaler          Set prescaler value
1183  */
1184 void PWM_SetClockMode(PWM_Type *base, pwm_submodule_t subModule, pwm_clock_prescale_t prescaler)
1185 {
1186     uint16_t reg = base->SM[subModule].CTRL;
1187 
1188     /* Clear LDOK bit if it is set */
1189     if (0U != (base->MCTRL & PWM_MCTRL_LDOK(1UL << (uint8_t)subModule)))
1190     {
1191         base->MCTRL |= PWM_MCTRL_CLDOK(1UL << (uint8_t)subModule);
1192     }
1193     /* Set submodule prescaler. */
1194     reg &= ~(uint16_t)PWM_CTRL_PRSC_MASK;
1195     reg |= PWM_CTRL_PRSC(prescaler);
1196     base->SM[subModule].CTRL = reg;
1197     /* Set Load mode to make Buffered registers take effect immediately when LDOK bit set */
1198     base->SM[subModule].CTRL |= PWM_CTRL_LDMOD_MASK;
1199     /* Set LDOK bit to load buffer registers */
1200     base->MCTRL |= PWM_MCTRL_LDOK(1UL << (uint8_t)subModule);
1201     /* Restore Load mode */
1202     base->SM[subModule].CTRL = reg;
1203 }
1204 
1205 /*!
1206  * brief This function enables-disables the forcing of the output of a given eFlexPwm channel to logic 0.
1207  *
1208  * param base               PWM peripheral base address
1209  * param pwmChannel         PWM channel to configure
1210  * param subModule          PWM submodule to configure
1211  * param forcetozero        True: Enable the pwm force output to zero; False: Disable the pwm output resumes normal
1212  *                          function.
1213  */
1214 void PWM_SetPwmForceOutputToZero(PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmChannel, bool forcetozero)
1215 {
1216     uint16_t reg = base->SM[subModule].CTRL2;
1217     uint16_t mask;
1218 
1219     if (kPWM_PwmA == pwmChannel)
1220     {
1221         mask = PWM_MASK_MASKA(0x01UL << (uint8_t)subModule);
1222     }
1223     else if (kPWM_PwmB == pwmChannel)
1224     {
1225         mask = PWM_MASK_MASKB(0x01UL << (uint8_t)subModule);
1226     }
1227     else
1228     {
1229         mask = PWM_MASK_MASKX(0x01UL << (uint8_t)subModule);
1230     }
1231 
1232     if (forcetozero)
1233     {
1234         /* Disables the channel output, forcing output level to 0 */
1235         base->MASK |= mask;
1236     }
1237     else
1238     {
1239         /* Enables the channel output */
1240         base->MASK &= ~mask;
1241     }
1242 
1243     /* Select local force signal */
1244     base->SM[subModule].CTRL2 &= ~(uint16_t)PWM_CTRL2_FORCE_SEL_MASK;
1245     /* Issue a local Force trigger event */
1246     base->SM[subModule].CTRL2 |= PWM_CTRL2_FORCE_MASK;
1247     /* Restore the source of FORCE OUTPUT signal */
1248     base->SM[subModule].CTRL2 = reg;
1249 }
1250 
1251 /*!
1252  * brief This function set the output state of the PWM pin as requested for the current cycle.
1253  *
1254  * param base               PWM peripheral base address
1255  * param subModule          PWM submodule to configure
1256  * param pwmChannel         PWM channel to configure
1257  * param outputstate        Set pwm output state, see @ref pwm_output_state_t.
1258  */
1259 void PWM_SetChannelOutput(PWM_Type *base,
1260                           pwm_submodule_t subModule,
1261                           pwm_channels_t pwmChannel,
1262                           pwm_output_state_t outputstate)
1263 {
1264     uint16_t mask, swcout, sourceShift;
1265     uint16_t reg = base->SM[subModule].CTRL2;
1266 
1267     if (kPWM_PwmA == pwmChannel)
1268     {
1269         mask        = PWM_MASK_MASKA(0x01UL << (uint8_t)subModule);
1270         swcout      = (uint16_t)PWM_SWCOUT_SM0OUT23_MASK << ((uint8_t)subModule * 2U);
1271         sourceShift = PWM_DTSRCSEL_SM0SEL23_SHIFT + ((uint16_t)subModule * 4U);
1272     }
1273     else if (kPWM_PwmB == pwmChannel)
1274     {
1275         mask        = PWM_MASK_MASKB(0x01UL << (uint8_t)subModule);
1276         swcout      = (uint16_t)PWM_SWCOUT_SM0OUT45_MASK << ((uint8_t)subModule * 2U);
1277         sourceShift = PWM_DTSRCSEL_SM0SEL45_SHIFT + ((uint16_t)subModule * 4U);
1278     }
1279     else
1280     {
1281         mask        = PWM_MASK_MASKX(0x01UL << (uint8_t)subModule);
1282         swcout      = 0U;
1283         sourceShift = 0U;
1284     }
1285 
1286     if (kPWM_MaskState == outputstate)
1287     {
1288         /* Disables the channel output, forcing output level to 0 */
1289         base->MASK |= mask;
1290     }
1291     else
1292     {
1293         /* Enables the channel output first */
1294         base->MASK &= ~mask;
1295         /* PwmX only support MASK mode */
1296         if (kPWM_PwmX != pwmChannel)
1297         {
1298             if (kPWM_HighState == outputstate)
1299             {
1300                 base->SWCOUT |= swcout;
1301                 base->DTSRCSEL =
1302                     (base->DTSRCSEL & ~(uint16_t)(0x3UL << sourceShift)) | (uint16_t)(0x2UL << sourceShift);
1303             }
1304             else if (kPWM_LowState == outputstate)
1305             {
1306                 base->SWCOUT &= ~swcout;
1307                 base->DTSRCSEL =
1308                     (base->DTSRCSEL & ~(uint16_t)(0x3UL << sourceShift)) | (uint16_t)(0x2UL << sourceShift);
1309             }
1310             else if (kPWM_NormalState == outputstate)
1311             {
1312                 base->DTSRCSEL &= ~(uint16_t)(0x3UL << sourceShift);
1313             }
1314             else
1315             {
1316                 base->DTSRCSEL =
1317                     (base->DTSRCSEL & ~(uint16_t)(0x3UL << sourceShift)) | (uint16_t)(0x1UL << sourceShift);
1318             }
1319         }
1320     }
1321 
1322     /* Select local force signal */
1323     base->SM[subModule].CTRL2 &= ~(uint16_t)PWM_CTRL2_FORCE_SEL_MASK;
1324     /* Issue a local Force trigger event */
1325     base->SM[subModule].CTRL2 |= PWM_CTRL2_FORCE_MASK;
1326     /* Restore the source of FORCE OUTPUT signal */
1327     base->SM[subModule].CTRL2 = reg;
1328 }