/*==================================================================================================
*   Project              : RTD AUTOSAR 4.4
*   Platform             : CORTEXM
*   Peripheral           : Emios Flexio
*   Dependencies         : none
*
*   Autosar Version      : 4.4.0
*   Autosar Revision     : ASR_REL_4_4_REV_0000
*   Autosar Conf.Variant :
*   SW Version           : 0.9.0
*   Build Version        : S32K3_RTD_0_9_0__ASR_REL_4_4_REV_0000_20210326
*
*   (c) Copyright 2020 - 2021 NXP Semiconductors
*   All Rights Reserved.
*
*   NXP Confidential. This software is owned or controlled by NXP and may only be
*   used strictly in accordance with the applicable license terms. By expressly
*   accepting such terms or by downloading, installing, activating and/or otherwise
*   using the software, you are agreeing that you have read, and that you agree to
*   comply with and are bound by, such license terms. If you do not agree to be
*   bound by the applicable license terms, then you may not retain, install,
*   activate or otherwise use the software.
==================================================================================================*/

/**
*   @file       Emios_Pwm_Ip.c
*
*   @addtogroup emios_pwm_ip Emios Pwm IPL
*   @{
*/

#ifdef __cplusplus
extern "C"{
#endif


/*==================================================================================================
*                                          INCLUDE FILES
* 1) system and project includes
* 2) needed interfaces from external units
* 3) internal and external interfaces from this unit
==================================================================================================*/
#include "Emios_Pwm_Ip.h"
#include "Emios_Pwm_Ip_HwAccess.h"
#include "Emios_Mcl_Ip.h"
#include "SchM_Pwm.h"

/*==================================================================================================
*                                 SOURCE FILE VERSION INFORMATION
==================================================================================================*/
#define EMIOS_PWM_IP_VENDOR_ID_C                      43
#define EMIOS_PWM_IP_AR_RELEASE_MAJOR_VERSION_C       4
#define EMIOS_PWM_IP_AR_RELEASE_MINOR_VERSION_C       4
#define EMIOS_PWM_IP_AR_RELEASE_REVISION_VERSION_C    0
#define EMIOS_PWM_IP_SW_MAJOR_VERSION_C               0
#define EMIOS_PWM_IP_SW_MINOR_VERSION_C               9
#define EMIOS_PWM_IP_SW_PATCH_VERSION_C               0

/*==================================================================================================
*                                       FILE VERSION CHECKS
==================================================================================================*/
#ifndef DISABLE_MCAL_INTERMODULE_ASR_CHECK
    /* Check if header file and Emios_Mcl_Ip.h are of the same AUTOSAR version */
    #if ((EMIOS_PWM_IP_AR_RELEASE_MAJOR_VERSION_C != EMIOS_MCL_IP_AR_RELEASE_MAJOR_VERSION_H) || \
         (EMIOS_PWM_IP_AR_RELEASE_MINOR_VERSION_C != EMIOS_MCL_IP_AR_RELEASE_MINOR_VERSION_H))
        #error "AUTOSAR Version Numbers of Emios_Pwm_Ip.c and Emios_Mcl_Ip.h are different"
    #endif

    /* Check if this source file and SchM_Pwm.h file are of the same Autosar version */
    #if ((EMIOS_PWM_IP_AR_RELEASE_MAJOR_VERSION_C != SCHM_PWM_AR_RELEASE_MAJOR_VERSION) || \
        (EMIOS_PWM_IP_AR_RELEASE_MINOR_VERSION_C != SCHM_PWM_AR_RELEASE_MINOR_VERSION))
        #error "AutoSar Version Numbers of Emios_Pwm_Ip.c and SchM_Pwm.h are different"
    #endif
#endif

/* Check if source file and Emios_Pwm_Ip.h file are of the same vendor */
#if (EMIOS_PWM_IP_VENDOR_ID_C != EMIOS_PWM_IP_VENDOR_ID)
    #error "Vendor IDs of Emios_Pwm_Ip.c and Emios_Pwm_Ip.h are different."
#endif

/* Check if source file and Emios_Pwm_Ip.h file are of the same AUTOSAR version */
#if ((EMIOS_PWM_IP_AR_RELEASE_MAJOR_VERSION_C    != EMIOS_PWM_IP_AR_RELEASE_MAJOR_VERSION) || \
     (EMIOS_PWM_IP_AR_RELEASE_MINOR_VERSION_C    != EMIOS_PWM_IP_AR_RELEASE_MINOR_VERSION) || \
     (EMIOS_PWM_IP_AR_RELEASE_REVISION_VERSION_C != EMIOS_PWM_IP_AR_RELEASE_REVISION_VERSION))
    #error "AUTOSAR version numbers of Emios_Pwm_Ip.c and Emios_Pwm_Ip.h are different."
#endif

/* Check if source file and Emios_Pwm_Ip.h file are of the same Software version */
#if ((EMIOS_PWM_IP_SW_MAJOR_VERSION_C != EMIOS_PWM_IP_SW_MAJOR_VERSION)  || \
     (EMIOS_PWM_IP_SW_MINOR_VERSION_C != EMIOS_PWM_IP_SW_MINOR_VERSION)  || \
     (EMIOS_PWM_IP_SW_PATCH_VERSION_C != EMIOS_PWM_IP_SW_PATCH_VERSION))
    #error "Software version numbers of Emios_Pwm_Ip.c and Emios_Pwm_Ip.h are different."
#endif

/* Check if source file and Emios_Pwm_Ip_HwAccess.h file are of the same vendor */
#if (EMIOS_PWM_IP_VENDOR_ID_C != EMIOS_PWM_IP_HWACCESS_VENDOR_ID)
    #error "Vendor IDs of Emios_Pwm_Ip.c and Emios_Pwm_Ip_HwAccess.h are different."
#endif

/* Check if source file and Emios_Pwm_Ip_HwAccess.h file are of the same AUTOSAR version */
#if ((EMIOS_PWM_IP_AR_RELEASE_MAJOR_VERSION_C    != EMIOS_PWM_IP_HWACCESS_AR_RELEASE_MAJOR_VERSION) || \
     (EMIOS_PWM_IP_AR_RELEASE_MINOR_VERSION_C    != EMIOS_PWM_IP_HWACCESS_AR_RELEASE_MINOR_VERSION) || \
     (EMIOS_PWM_IP_AR_RELEASE_REVISION_VERSION_C != EMIOS_PWM_IP_HWACCESS_AR_RELEASE_REVISION_VERSION))
    #error "AUTOSAR version numbers of Emios_Pwm_Ip.c and Emios_Pwm_Ip_HwAccess.h are different."
#endif

/* Check if source file and Emios_Pwm_Ip_HwAccess.h file are of the same Software version */
#if ((EMIOS_PWM_IP_SW_MAJOR_VERSION_C != EMIOS_PWM_IP_HWACCESS_SW_MAJOR_VERSION)  || \
     (EMIOS_PWM_IP_SW_MINOR_VERSION_C != EMIOS_PWM_IP_HWACCESS_SW_MINOR_VERSION)  || \
     (EMIOS_PWM_IP_SW_PATCH_VERSION_C != EMIOS_PWM_IP_HWACCESS_SW_PATCH_VERSION))
    #error "Software version numbers of Emios_Pwm_Ip.c and Emios_Pwm_Ip_HwAccess.h are different."
#endif

/*==================================================================================================
*                           LOCAL TYPEDEFS (STRUCTURES, UNIONS, ENUMS)
==================================================================================================*/

/*==================================================================================================
*                                          LOCAL MACROS
==================================================================================================*/

/*==================================================================================================
*                                         LOCAL CONSTANTS
==================================================================================================*/

/*==================================================================================================
*                                         LOCAL VARIABLES
==================================================================================================*/

/*==================================================================================================
*                                        GLOBAL CONSTANTS
==================================================================================================*/

/*==================================================================================================
*                                        GLOBAL VARIABLES
==================================================================================================*/
#define PWM_START_SEC_CONST_UNSPECIFIED
#include "Pwm_MemMap.h"

/** @brief Array with base addresses for Emios instances available on platform */
Emios_Pwm_Ip_HwAddrType *const Emios_Pwm_Ip_aBasePtr[EMIOS_PWM_INSTANCE_COUNT] = eMIOS_BASE_PTRS;

#define PWM_STOP_SEC_CONST_UNSPECIFIED
#include "Pwm_MemMap.h"

#define PWM_START_SEC_VAR_INIT_UNSPECIFIED
#include "Pwm_MemMap.h"
/** @brief Array with notification handlers for all configurable channels */
Emios_Pwm_Ip_NotificationType const *Emios_Pwm_Ip_aNotificationPtr[EMIOS_PWM_INSTANCE_COUNT][EMIOS_PWM_CHANNEL_COUNT] = EMIOS_PWM_NOTIFICATION_HANDLERS;

#define PWM_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Pwm_MemMap.h"

#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
#define PWM_START_SEC_VAR_INIT_32
#include "Pwm_MemMap.h"

/* Array with available pwm modes for each Emios channel */
static uint32 Emios_Pwm_Ip_ChannelModes[EMIOS_PWM_INSTANCE_COUNT][EMIOS_PWM_MODES] = EMIOS_PWM_CHANNEL_MODES;

#define PWM_STOP_SEC_VAR_INIT_32
#include "Pwm_MemMap.h"
#endif

#define PWM_START_SEC_VAR_INIT_16
#include "Pwm_MemMap.h"
/** @brief Array with period for OPWFMB channels */
uint16 Emios_Pwm_Ip_aPeriod[EMIOS_PWM_INSTANCE_COUNT][EMIOS_PWM_CHANNEL_COUNT] = EMIOS_PWM_INIT_VALUE_UINT16;
uint16 Emios_Pwm_Ip_aRegA[EMIOS_PWM_INSTANCE_COUNT][EMIOS_PWM_CHANNEL_COUNT] = EMIOS_PWM_INIT_VALUE_UINT16;
uint16 Emios_Pwm_Ip_aDaocDuty[EMIOS_PWM_INSTANCE_COUNT][EMIOS_PWM_CHANNEL_COUNT] = EMIOS_PWM_INIT_VALUE_UINT16;

#define PWM_STOP_SEC_VAR_INIT_16
#include "Pwm_MemMap.h"

#define PWM_START_SEC_VAR_INIT_8
#include "Pwm_MemMap.h"

uint8 Emios_Pwm_Ip_aNotif[EMIOS_PWM_INSTANCE_COUNT][EMIOS_PWM_CHANNEL_COUNT] = EMIOS_PWM_INIT_VALUE_UINT8;
uint8 Emios_Pwm_Ip_aCheckEnableNotif[EMIOS_PWM_INSTANCE_COUNT][EMIOS_PWM_CHANNEL_COUNT] = EMIOS_PWM_INIT_VALUE_UINT8;
uint8 Emios_Pwm_Ip_aPolarity[EMIOS_PWM_INSTANCE_COUNT][EMIOS_PWM_CHANNEL_COUNT] = EMIOS_PWM_INIT_VALUE_UINT8;
uint8 Emios_Pwm_Ip_aCheckState[EMIOS_PWM_INSTANCE_COUNT][EMIOS_PWM_CHANNEL_COUNT] = EMIOS_PWM_INIT_VALUE_UINT8;

#define PWM_STOP_SEC_VAR_INIT_8
#include "Pwm_MemMap.h"

/*==================================================================================================
*                                    LOCAL FUNCTION PROTOTYPES
==================================================================================================*/

/*==================================================================================================
*                                         LOCAL FUNCTIONS
==================================================================================================*/
#define PWM_START_SEC_CODE
#include "Pwm_MemMap.h"

#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
/*---------------------Validation API------------------------*/

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_ValidateMode
 * Description   : Validate a eMIOS mode can run on the channel or not.
 *END**************************************************************************/
static inline boolean Emios_Pwm_Ip_ValidateMode(uint8  instance,
                                                uint8  channel,
                                                Emios_Pwm_Ip_PwmType mode)
{
    return ((((Emios_Pwm_Ip_ChannelModes[instance][(uint8)mode] >> channel) & 0x01UL) == 1UL) ? TRUE : FALSE);
}

#endif

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_GetCounterBusPeriod
 * Description   : Return the period for channel using an external counter bus.
 * Only used for channels in OPWMB/OPWMCB/OPWMT modes
 *
 *END**************************************************************************/
static uint16 Emios_Pwm_Ip_GetCounterBusPeriod(uint8 instance,
                                               uint8 channel,
                                               Emios_Pwm_Ip_CounterBusSourceType counterBus)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif

    const Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    uint16 chPeriod = 0U;

    if (EMIOS_PWM_BUS_A == counterBus)
    {
        chPeriod = Emios_Pwm_Ip_GetUCRegA(base, EMIOS_PWM_COUNTER_BUS_A);
    }
    else if (EMIOS_PWM_BUS_F == counterBus)
    {
        chPeriod = Emios_Pwm_Ip_GetUCRegA(base, EMIOS_PWM_COUNTER_BUS_F);
    }
    else if (EMIOS_PWM_BUS_BCDE == counterBus)
    {
        chPeriod = Emios_Pwm_Ip_GetUCRegA(base, (channel & (uint8)EMIOS_PWM_COUNTER_BUS_BCDE));
    }
    else
    {
        /* Nothing to do. Internal Counter Cannot be selected for these modes. */
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
        DevAssert(FALSE);
#endif
    }

    return chPeriod;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_GetCounterBusMode
 * Description   : Return the counter bus mode for channel using an external counter bus.
 * Only used for channels in OPWMB/OPWMCB/OPWMT modes
 *
 *END**************************************************************************/
static Emios_Pwm_Ip_MasterBusModeType Emios_Pwm_Ip_GetCounterBusMode(uint8 instance,
                                                                 uint8 channel,
                                                                 Emios_Pwm_Ip_CounterBusSourceType counterBus)
{

    const Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    Emios_Pwm_Ip_MasterBusModeType counterBusMode = EMIOS_PWM_IP_MC_UP_COUNTER_START;
    switch (counterBus)
    {
        case EMIOS_PWM_BUS_A:
            counterBusMode = (Emios_Pwm_Ip_MasterBusModeType)Emios_Pwm_Ip_GetChannelPwmMode(base, EMIOS_PWM_COUNTER_BUS_A);
            break;
        case EMIOS_PWM_BUS_BCDE:
            counterBusMode = (Emios_Pwm_Ip_MasterBusModeType)Emios_Pwm_Ip_GetChannelPwmMode(base, (channel & (uint8)EMIOS_PWM_COUNTER_BUS_BCDE));
            break;
        case EMIOS_PWM_BUS_F:
            counterBusMode = (Emios_Pwm_Ip_MasterBusModeType)Emios_Pwm_Ip_GetChannelPwmMode(base, EMIOS_PWM_COUNTER_BUS_F);
            break;
        default:
            /* internal counter bus */
            counterBusMode = EMIOS_PWM_IP_NODEFINE_COUNTER;
            break;
    }

    return counterBusMode;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_InitPeriodDutyCycleMode
 * Description   : Initial Output Pulse Width and Frequency Modulation Buffered (OPWFMB) Mode.
 * This mode provides waveforms with variable duty cycle and frequency. The internal channel counter
 * is automatically selected as the time base when this mode is selected.
 *END**************************************************************************/
static void Emios_Pwm_Ip_InitPeriodDutyCycleMode(uint8 instance,
                                                 Emios_Pwm_Ip_ChannelConfigType const *userChCfg)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(NULL_PTR != userChCfg);
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > userChCfg->channelId);
    /* Check Selected channel is set for OPWFMB */
    DevAssert((userChCfg->mode == EMIOS_PWM_MODE_OPWFMB_FLAG) ||
              (userChCfg->mode == EMIOS_PWM_MODE_OPWFMB_FLAG_BOTH));
    /* Check that channel has internal counter for this mode */
    DevAssert(TRUE == Emios_Pwm_Ip_ValidateMode(instance, userChCfg->channelId, EMIOS_PWM_HW_MODE_OPWFMB));
    /* Validate opwfmb parametter */
    DevAssert(EMIOS_PWM_MIN_CNT_VAL < userChCfg->periodCount);
    DevAssert(userChCfg->dutyCycle <= userChCfg->periodCount);
#endif

    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];

    /* Configure OPWFMB special parameters */
    /* Configure Counter Bus used by this channel */
    Emios_Pwm_Ip_SetCounterBus(base, userChCfg->channelId, userChCfg->timebase);
    /* Configure DutyCycle in reg A */
    Emios_Pwm_Ip_SetUCRegA(base, userChCfg->channelId, userChCfg->dutyCycle);
    /* Configure Period in reg B */
    Emios_Pwm_Ip_SetUCRegB(base, userChCfg->channelId, userChCfg->periodCount);
    /* Transition from GPIO mode to OPWFMB mode */
    Emios_Pwm_Ip_SetPwmMode(base, userChCfg->channelId, userChCfg->mode);
    /* Configure output pin polarity */
    Emios_Pwm_Ip_SetEdgePolarity(base, userChCfg->channelId,(userChCfg->outputPolarity == EMIOS_PWM_ACTIVE_HIGH) ? EMIOS_PWM_ACTIVE_LOW : EMIOS_PWM_ACTIVE_HIGH );

    Emios_Pwm_Ip_aPeriod[instance][userChCfg->channelId] = userChCfg->periodCount;

    if (userChCfg->periodCount == userChCfg->dutyCycle)
    {   /* 100% dutyCycle is desired. */
        Emios_Pwm_Ip_aNotif[instance][userChCfg->channelId] = (uint8)1U;
    }
    else if(0U == userChCfg->dutyCycle)
    {
        /* 0% dutyCycle is desired. */
        Emios_Pwm_Ip_aNotif[instance][userChCfg->channelId] = (uint8)1U;
    }
    else
    {
        Emios_Pwm_Ip_aNotif[instance][userChCfg->channelId] = (uint8)0U;
    }
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_SetDutyCycleOpwfmb
 * Description   : Set new duty cycle for the channel in OPWFMB mode
 * This function will check the specific duty cycle and set new duty cycle for
 * this channel
 *
 *END**************************************************************************/
static Emios_Pwm_Ip_StatusType Emios_Pwm_Ip_SetDutyCycleOpwfmb(uint8  instance,
                                                               uint8  channel,
                                                               uint16 newDutyCycle)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    Emios_Pwm_Ip_StatusType ret = EMIOS_PWM_STATUS_SUCCESS;

    /* OPWFMB mode */
    if ((newDutyCycle > Emios_Pwm_Ip_aPeriod[instance][channel]) && ((uint16)0U != Emios_Pwm_Ip_aPeriod[instance][channel]))
    {   /* Duty cycle value should not be greater than the channel Period. */
        ret = EMIOS_PWM_STATUS_ERROR;
    }
    else if ((uint16)0U == Emios_Pwm_Ip_aPeriod[instance][channel])
    {
        /* Disable and clear interrupt flag */
        Emios_Pwm_Ip_SetInterruptRequest(base, channel, FALSE);
        Emios_Pwm_Ip_ClearFlagEvent(base, channel);
        /* If new period is 0, set duty cycle to 0 */
        Emios_Pwm_Ip_SetUCRegA(base, channel, (uint16)0U);
        Emios_Pwm_Ip_aNotif[instance][channel] = (uint8)1U;
    }
    else
    {
        if(newDutyCycle == 0U)
        {
            /* Disable and clear interrupt flag */
            Emios_Pwm_Ip_SetInterruptRequest(base, channel, FALSE);
            Emios_Pwm_Ip_ClearFlagEvent(base, channel);
            Emios_Pwm_Ip_aNotif[instance][channel] = (uint8)1U;
        }
        else if (newDutyCycle == Emios_Pwm_Ip_aPeriod[instance][channel])
        {
            /* Disable and clear interrupt flag */
            Emios_Pwm_Ip_SetInterruptRequest(base, channel, FALSE);
            Emios_Pwm_Ip_ClearFlagEvent(base, channel);
            Emios_Pwm_Ip_aNotif[instance][channel] = (uint8)1U;
        }
        else
        {
            Emios_Pwm_Ip_aNotif[instance][channel] = (uint8)0U;
            Emios_Pwm_Ip_SetInterruptRequest(base, channel, (Emios_Pwm_Ip_aCheckEnableNotif[instance][channel] == 0U)? FALSE : TRUE);
        }

        Emios_Pwm_Ip_SetUCRegA(base, channel, newDutyCycle);
    }

    return ret;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_InitDeadTimeMode
 * Description   : Initial Center Aligned Output Pulse Width Modulation with Dead Time Insertion Buffered (OPWMCB) Mode.
 * This operation mode generates a center aligned PWM with dead time insertion to the leading or trailing edge.
 * Allow smooth output signal generation when changing duty cycle and deadtime values.
 *
 * The time base selected for a channel configured to OPWMCB mode should be a channel configured to MCB Up/Down mode.
 * It is recommended to start the MCB channel time base after the OPWMCB mode is entered
 * in order to avoid missing A matches at the very first duty cycle.
 *
 * The internal counter runs in the internal prescaler ratio, while the selected time base
 * may be running in a different prescaler ratio.
 *
 *END**************************************************************************/
static void Emios_Pwm_Ip_InitDeadTimeMode(uint8 instance,
                                          Emios_Pwm_Ip_ChannelConfigType const *userChCfg)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(NULL_PTR != userChCfg);
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > userChCfg->channelId);
    /* Check Selected channel is set for OPWMCB */
    DevAssert((userChCfg->mode == EMIOS_PWM_MODE_OPWMCB_TRAIL_EDGE_FLAG) ||
              (userChCfg->mode == EMIOS_PWM_MODE_OPWMCB_TRAIL_EDGE_FLAG_BOTH) ||
              (userChCfg->mode == EMIOS_PWM_MODE_OPWMCB_LEAD_EDGE_FLAG) ||
              (userChCfg->mode == EMIOS_PWM_MODE_OPWMCB_LEAD_EDGE_FLAG_BOTH));
    /* Check selected channel supports OPWMCB mode */
    DevAssert(TRUE == Emios_Pwm_Ip_ValidateMode(instance, userChCfg->channelId, EMIOS_PWM_HW_MODE_OPWMCB));
    /* Check selected counter bus is configured in MCB Up-Down Mode */
    DevAssert(EMIOS_PWM_IP_MCB_UP_DOWN_COUNTER == Emios_Pwm_Ip_GetCounterBusMode(instance, userChCfg->channelId, userChCfg->timebase));
    /* Validate OPWMCB parametter */
    DevAssert(((2U * Emios_Pwm_Ip_GetCounterBusPeriod(instance, userChCfg->channelId, userChCfg->timebase)) - 2U) >= userChCfg->dutyCycle);
#endif

    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    uint16 dutyCycle = 0U;

    if (userChCfg->periodCount == userChCfg->dutyCycle)
    {   /* 100% dutyCycle is desired. */
        dutyCycle = 1U;
        Emios_Pwm_Ip_aNotif[instance][userChCfg->channelId] = (uint8)1U;
    }
    else if((0U == userChCfg->dutyCycle) || (1U == userChCfg->dutyCycle))
    {
        /* 0% dutyCycle is desired. */
        dutyCycle = Emios_Pwm_Ip_GetCounterBusPeriod(instance, userChCfg->channelId, userChCfg->timebase) + (uint8)1U;
        Emios_Pwm_Ip_aNotif[instance][userChCfg->channelId] = (uint8)1U;
    }
    else
    {
        dutyCycle = (userChCfg->dutyCycle) >> (uint8)1U;
        dutyCycle = Emios_Pwm_Ip_GetCounterBusPeriod(instance, userChCfg->channelId, userChCfg->timebase) - dutyCycle;
        Emios_Pwm_Ip_aNotif[instance][userChCfg->channelId] = (uint8)0U;
    }

    /* Configure OPWMCB special parameters */
    /* Configure Counter Bus used by this channel */
    Emios_Pwm_Ip_SetCounterBus(base, userChCfg->channelId, userChCfg->timebase);
    /* Configure DutyCycle in reg A */
    Emios_Pwm_Ip_SetUCRegA(base, userChCfg->channelId, dutyCycle);
    /* Configure DeadTime in reg B */
    Emios_Pwm_Ip_SetUCRegB(base, userChCfg->channelId, userChCfg->deadTime);
    /* To avoid spike pulse
    If duty cycle = 100%, when enter mode, EDPOL bit get complement of polarity
    after that, EDPOL bit is restored valid value */
    if (userChCfg->periodCount == userChCfg->dutyCycle)
    {
        Emios_Pwm_Ip_SetEdgePolarity(base, userChCfg->channelId,(userChCfg->outputPolarity == EMIOS_PWM_ACTIVE_HIGH) ? EMIOS_PWM_ACTIVE_LOW : EMIOS_PWM_ACTIVE_HIGH );
    }
    else
    {
        Emios_Pwm_Ip_SetEdgePolarity(base, userChCfg->channelId, userChCfg->outputPolarity);
    }
    /* Transition from GPIO mode to OPWMCB mode */
    Emios_Pwm_Ip_SetPwmMode(base, userChCfg->channelId, userChCfg->mode);
    /* Configure output pin polarity */
    Emios_Pwm_Ip_SetEdgePolarity(base, userChCfg->channelId, userChCfg->outputPolarity);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_SetDutyCycleOpwmcb
 * Description   : Set new duty cycle for the channel in OPWMCB mode
 * This function will check the specific duty cycle and set new duty cycle for
 * this channel
 *
 *END**************************************************************************/
static Emios_Pwm_Ip_StatusType Emios_Pwm_Ip_SetDutyCycleOpwmcb(uint8  instance,
                                                               uint8  channel,
                                                               uint16 newDutyCycle)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    Emios_Pwm_Ip_StatusType ret = EMIOS_PWM_STATUS_SUCCESS;
    Emios_Pwm_Ip_PwmModeType chMode = Emios_Pwm_Ip_GetPwmMode(base, channel);
    uint16 chPeriod = Emios_Pwm_Ip_GetCounterBusPeriod(instance, channel, Emios_Pwm_Ip_GetCounterBus(base, channel));

    /* OPWMCB mode */
    if(newDutyCycle > ((chPeriod * 2U) - 2U))
    { /* Duty cycle value should not be greater than the channel Period. */
        ret = EMIOS_PWM_STATUS_ERROR;
    }
    else if(0U == newDutyCycle)
    {
        /* Disable and clear interrupt flag */
        Emios_Pwm_Ip_SetInterruptRequest(base, channel, FALSE);
        Emios_Pwm_Ip_ClearFlagEvent(base, channel);

        Emios_Pwm_Ip_SetUCRegA(base, channel, chPeriod + 1U);
        Emios_Pwm_Ip_aNotif[instance][channel] = (uint8)1U;
        /* This statement is required to avoid limitation of 0% duty cycle (if call 100% to 0%) */
        if(1U == Emios_Pwm_Ip_GetUCRegA(base, channel))
        {
            if((chMode == EMIOS_PWM_MODE_OPWMCB_TRAIL_EDGE_FLAG) ||
               (chMode == EMIOS_PWM_MODE_OPWMCB_TRAIL_EDGE_FLAG_BOTH))
            {
                Emios_Pwm_Ip_SetForceMatchB(base, channel, TRUE);
            }
            else
            {
                Emios_Pwm_Ip_SetForceMatchA(base, channel, TRUE);
            }
        }
    }
    else if(newDutyCycle == ((chPeriod * 2U) - 2U))
    {
        /* Disable and clear interrupt flag */
        Emios_Pwm_Ip_SetInterruptRequest(base, channel, FALSE);
        Emios_Pwm_Ip_ClearFlagEvent(base, channel);

        Emios_Pwm_Ip_SetUCRegA(base, channel, 1U);
        Emios_Pwm_Ip_aNotif[instance][channel] = (uint8)1U;
    }
    else
    {
        Emios_Pwm_Ip_SetUCRegA(base, channel, (uint16)(chPeriod - (newDutyCycle >> 1U)));
        Emios_Pwm_Ip_aNotif[instance][channel] = (uint8)0U;
        Emios_Pwm_Ip_SetInterruptRequest(base, channel, (Emios_Pwm_Ip_aCheckEnableNotif[instance][channel] == 0U)? FALSE : TRUE);
    }

    return ret;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_InitEdgePlacementMode
 * Description   : Initial Output Pulse Width Modulation Buffered (OPWMB) Mode.
 * OPWMB mode is used to generate pulses with programmable leading and trailing edge placement.
 * An external counter driven in MCB Up mode must be selected from one of the counter buses.
 * userChCfg defines the first edge and the second edge. The output signal polarity is defined
 * by outputPolarity in userChCfg.
 *
 *END**************************************************************************/
static void Emios_Pwm_Ip_InitEdgePlacementMode(uint8 instance,
                                               Emios_Pwm_Ip_ChannelConfigType const *userChCfg)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(NULL_PTR != userChCfg);
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > userChCfg->channelId);
    /* Check Selected channel is set for OPWMB */
    DevAssert((userChCfg->mode == EMIOS_PWM_MODE_OPWMB_FLAG) ||
              (userChCfg->mode == EMIOS_PWM_MODE_OPWMB_FLAG_BOTH));
    /* Check selected channel supports OPWMB mode */
    DevAssert(TRUE == Emios_Pwm_Ip_ValidateMode(instance, userChCfg->channelId, EMIOS_PWM_HW_MODE_OPWMB));
    /* Check selected counter bus is configured in MCB Up-Down Mode */
    DevAssert(EMIOS_PWM_IP_MCB_UP_COUNTER == Emios_Pwm_Ip_GetCounterBusMode(instance, userChCfg->channelId, userChCfg->timebase));
    /* Validate OPWMB parametter */
    /* Phase Shift and DutyCycle cannot be bigger than the counter bus period */
    DevAssert((Emios_Pwm_Ip_GetCounterBusPeriod(instance, userChCfg->channelId, userChCfg->timebase)) >= (userChCfg->phaseShift + userChCfg->dutyCycle));
    DevAssert(EMIOS_PWM_MAX_CNT_VAL >= (uint32)((uint32)userChCfg->phaseShift + (uint32)userChCfg->dutyCycle));
#endif

    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];

    Emios_Pwm_Ip_aRegA[instance][userChCfg->channelId] = userChCfg->phaseShift;

    /* Configure Counter Bus used by this channel */
    Emios_Pwm_Ip_SetCounterBus(base, userChCfg->channelId, userChCfg->timebase);
    /* Configure Phase Shift in reg A */
    Emios_Pwm_Ip_SetUCRegA(base, userChCfg->channelId, userChCfg->phaseShift);
    /* Configure Trailing edge in reg B */
    Emios_Pwm_Ip_SetUCRegB(base, userChCfg->channelId, userChCfg->phaseShift + userChCfg->dutyCycle);
    /* Transition from GPIO mode to OPWMB mode */
    Emios_Pwm_Ip_SetPwmMode(base, userChCfg->channelId, userChCfg->mode);
    /* Configure output pin polarity */
    Emios_Pwm_Ip_SetEdgePolarity(base, userChCfg->channelId, userChCfg->outputPolarity);

    if (userChCfg->periodCount == userChCfg->dutyCycle)
    {   /* 100% dutyCycle is desired. */
        Emios_Pwm_Ip_aNotif[instance][userChCfg->channelId] = (uint8)1U;
    }
    else if((0U == userChCfg->dutyCycle) || (1U == userChCfg->dutyCycle))
    {
        /* 0% dutyCycle is desired. */
        Emios_Pwm_Ip_aNotif[instance][userChCfg->channelId] = (uint8)1U;
    }
    else
    {
        Emios_Pwm_Ip_aNotif[instance][userChCfg->channelId] = (uint8)0U;
    }
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_SetDutyCycleOpwmb
 * Description   : Set new duty cycle for the channel in OPWMB mode
 * This function will check the specific duty cycle and set new duty cycle for
 * this channel
 *
 *END**************************************************************************/
static Emios_Pwm_Ip_StatusType Emios_Pwm_Ip_SetDutyCycleOpwmb(uint8  instance,
                                                              uint8  channel,
                                                              uint16 newDutyCycle)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    Emios_Pwm_Ip_StatusType ret = EMIOS_PWM_STATUS_SUCCESS;
    uint16 chPeriod = Emios_Pwm_Ip_GetCounterBusPeriod(instance, channel, Emios_Pwm_Ip_GetCounterBus(base, channel));

    /* OPWMB mode */
    if ((newDutyCycle + Emios_Pwm_Ip_aRegA[instance][channel]) > chPeriod)
    { /* New duty cycle puts trailing edge outside of counter bus period. */
        ret = EMIOS_PWM_STATUS_ERROR;
    }
    else
    {
        if(newDutyCycle == 0U)
        {
            /* Disable and clear interrupt flag */
            Emios_Pwm_Ip_SetInterruptRequest(base, channel, FALSE);
            Emios_Pwm_Ip_ClearFlagEvent(base, channel);
            Emios_Pwm_Ip_aNotif[instance][channel] = (uint8)1U;
        }
        else if (newDutyCycle == chPeriod)
        {
            /* Disable and clear interrupt flag */
            Emios_Pwm_Ip_SetInterruptRequest(base, channel, FALSE);
            Emios_Pwm_Ip_ClearFlagEvent(base, channel);
            Emios_Pwm_Ip_aNotif[instance][channel] = (uint8)1U;
        }
        else
        {
            Emios_Pwm_Ip_aNotif[instance][channel] = (uint8)0U;
            Emios_Pwm_Ip_SetInterruptRequest(base, channel, (Emios_Pwm_Ip_aCheckEnableNotif[instance][channel] == 0U)? FALSE : TRUE);
        }
        Emios_Pwm_Ip_SetUCRegB(base, channel, (newDutyCycle + Emios_Pwm_Ip_aRegA[instance][channel]));
    }

    return ret;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_InitTriggerMode
 * Description   : Initial Output Pulse Width Modulation with Trigger (OPWMT) Mode
 * OPWMT mode is intended to support the generation of Pulse Width Modulation signals where
 * the period is not modified while the signal is being output, but where the duty cycle will
 * be varied and must not create glitches. The mode is intended to be used in conjunction with
 * other channels executing in the same mode and sharing a common timebase. It will support each
 * channel with a fixed PWM leading edge position with respect to the other channels and the
 * ability to generate a trigger signal at any point in the period that can be output from
 * the module to initiate activity in other parts of the SoC such as starting ADC conversions.
 *
 * An external counter driven in either MC Up or MCB Up mode must be selected from one of the counter buses.
 *
 * The leading edge can be configured with any value within the range of the selected time base. Note that registers
 * loaded with 0x0 will not produce matches if the timebase is driven by a channel in MCB mode.
 *
 *END**************************************************************************/
static void Emios_Pwm_Ip_InitTriggerMode(uint8 instance,
                                         Emios_Pwm_Ip_ChannelConfigType const *userChCfg)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(NULL_PTR != userChCfg);
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > userChCfg->channelId);
    /* Check Selected channel is set for OPWMT */
    DevAssert(userChCfg->mode == EMIOS_PWM_MODE_OPWMT);
    /* Check selected channel supports OPWMT mode */
    DevAssert(TRUE == Emios_Pwm_Ip_ValidateMode(instance, userChCfg->channelId, EMIOS_PWM_HW_MODE_OPWMT));
    /* Check selected counter bus is configured in MCB Up Mode or MC Up mode */
    DevAssert((EMIOS_PWM_IP_MCB_UP_COUNTER == Emios_Pwm_Ip_GetCounterBusMode(instance, userChCfg->channelId, userChCfg->timebase)) ||
              (EMIOS_PWM_IP_MC_UP_COUNTER_START == Emios_Pwm_Ip_GetCounterBusMode(instance, userChCfg->channelId, userChCfg->timebase)) ||
              (EMIOS_PWM_IP_MC_UP_COUNTER_END == Emios_Pwm_Ip_GetCounterBusMode(instance, userChCfg->channelId, userChCfg->timebase)));
#endif

    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    uint16 counterBusPeriod = Emios_Pwm_Ip_GetCounterBusPeriod(instance, userChCfg->channelId, userChCfg->timebase);
    uint16 trailingEdge = 0x0000U;
    uint8 counterStart = 0U;

#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    /* Validate OPWMT parameters */
    /* Phase Shift must be in the counter bus period range. */
    DevAssert(counterBusPeriod >= userChCfg->phaseShift);
    /* If 100% duty cycle must be implemented the maximum counter value for the time base is 0xFFFE */
    DevAssert(EMIOS_PWM_MAX_CNT_VAL > counterBusPeriod);
    /* Duty cycle must not exceed the counter bus period. If 100% duty is desired dutycycle must be counterbus period +1U */
    DevAssert((counterBusPeriod + 1U) >= userChCfg->dutyCycle);
    /* Trigger point must be inside the counter bus period */
    DevAssert(counterBusPeriod >= userChCfg->triggerPosition);
#endif

    if (EMIOS_PWM_IP_MCB_UP_COUNTER == Emios_Pwm_Ip_GetCounterBusMode(instance, userChCfg->channelId, userChCfg->timebase))
    {
        counterStart = 1U;
    }
    else
    {
        counterStart = 0U;
    }

    if (counterBusPeriod == userChCfg->dutyCycle)
    {   /* 100% dutyCycle is desired. Trailing edge must be placed outside counter bus period. */
        trailingEdge = userChCfg->dutyCycle + 1U;
        Emios_Pwm_Ip_aNotif[instance][userChCfg->channelId] = (uint8)1U;
    }
    else if (0U == userChCfg->dutyCycle)
    {
        trailingEdge = userChCfg->phaseShift;
        Emios_Pwm_Ip_aNotif[instance][userChCfg->channelId] = (uint8)1U;
    }
    else
    { /* Calculate trailing edge postion. Wrap-around if dutyCycle extends the signal past the counterbus period. */
        trailingEdge = (userChCfg->phaseShift + userChCfg->dutyCycle) % counterBusPeriod;
        Emios_Pwm_Ip_aNotif[instance][userChCfg->channelId] = (uint8)0U;
    }

    Emios_Pwm_Ip_aRegA[instance][userChCfg->channelId] = userChCfg->phaseShift + counterStart;

    /* Configure Counter Bus used by this channel */
    Emios_Pwm_Ip_SetCounterBus(base, userChCfg->channelId, userChCfg->timebase);
    /* Configure Leading Edge in reg A */
    Emios_Pwm_Ip_SetUCRegA(base, userChCfg->channelId, (userChCfg->phaseShift + counterStart));
    /* Configure Trailing Edge in reg B */
    Emios_Pwm_Ip_SetUCRegB(base, userChCfg->channelId, (trailingEdge + counterStart));
    /* Configure Triggerpoint in reg ALTA */
    Emios_Pwm_Ip_SetTrigger(base, userChCfg->channelId, (userChCfg->triggerPosition + counterStart));
    /* To avoid spike pulse
    If duty cycle = 100%, when enter mode, EDPOL bit get complement of polarity
    after that, EDPOL bit is restored valid value */
    if (counterBusPeriod == userChCfg->dutyCycle)
    {
         Emios_Pwm_Ip_SetEdgePolarity(base, userChCfg->channelId,(userChCfg->outputPolarity == EMIOS_PWM_ACTIVE_HIGH) ? EMIOS_PWM_ACTIVE_LOW : EMIOS_PWM_ACTIVE_HIGH );
    }
    else
    {
        Emios_Pwm_Ip_SetEdgePolarity(base, userChCfg->channelId, userChCfg->outputPolarity);
    }
    /* Transition from GPIO mode to OPWMT mode */
    Emios_Pwm_Ip_SetPwmMode(base, userChCfg->channelId, userChCfg->mode);
    /* Configure output pin polarity */
    Emios_Pwm_Ip_SetEdgePolarity(base, userChCfg->channelId, userChCfg->outputPolarity);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_SetDutyCycleOpwmt
 * Description   : Set new duty cycle for the channel in OPWMT mode
 * This function will check the specific duty cycle and set new duty cycle for
 * this channel
 *
 *END**************************************************************************/
static Emios_Pwm_Ip_StatusType Emios_Pwm_Ip_SetDutyCycleOpwmt(uint8  instance,
                                                              uint8  channel,
                                                              uint16 newDutyCycle)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    Emios_Pwm_Ip_StatusType ret = EMIOS_PWM_STATUS_SUCCESS;
    uint16 chPeriod = Emios_Pwm_Ip_GetCounterBusPeriod(instance, channel, Emios_Pwm_Ip_GetCounterBus(base, channel));

    /* OPWMT mode */
    if (newDutyCycle > chPeriod)
    { /* Duty cycle value should not be greater than the channel Period. */
        ret = EMIOS_PWM_STATUS_ERROR;
    }
    else
    {
        if (chPeriod == newDutyCycle)
        {   /* 100% dutyCycle is desired. Trailing edge must be placed outside counter bus period. */
            /* Disable and clear interrupt flag */
            Emios_Pwm_Ip_SetInterruptRequest(base, channel, FALSE);
            Emios_Pwm_Ip_ClearFlagEvent(base, channel);

            Emios_Pwm_Ip_SetUCRegB(base, channel, (newDutyCycle + 1U));
            Emios_Pwm_Ip_aNotif[instance][channel] = (uint8)1U;
        }
        else if(0U == newDutyCycle)
        {
            /* 0% dutyCycle is desired. */
            /* Disable and clear interrupt flag */
            Emios_Pwm_Ip_SetInterruptRequest(base, channel, FALSE);
            Emios_Pwm_Ip_ClearFlagEvent(base, channel);

            Emios_Pwm_Ip_SetUCRegB(base, channel, Emios_Pwm_Ip_aRegA[instance][channel]);
            Emios_Pwm_Ip_aNotif[instance][channel] = (uint8)1U;
        }
        else
        { /* Calculate trailing edge postion. Wrap-around if dutyCycle extends the signal past the counterbus period. */
            Emios_Pwm_Ip_SetUCRegB(base, channel, (Emios_Pwm_Ip_aRegA[instance][channel] + newDutyCycle) % chPeriod);
            Emios_Pwm_Ip_aNotif[instance][channel] = (uint8)0U;
            Emios_Pwm_Ip_SetInterruptRequest(base, channel, (Emios_Pwm_Ip_aCheckEnableNotif[instance][channel] == 0U)? FALSE : TRUE);
        }
    }

    return ret;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_InitDoubleCompareMode
 * Description   : Initial Double Action Output Compare (DAOC) Mode.
 * This mode provides waveforms with variable duty cycle and frequency.
 * In DAOC mode, at the end of period, the A register and B register need re-calculated to
 * enable next match A. This calculation and first pulse must be done by software.
 * Calculate the duty tick follow period and Duty cycle
 * Always enable interrupt. Because in this mode, the A register and B register is re-calculated
 * with period and duty at the end of period by software.
 *
 *END**************************************************************************/
static void Emios_Pwm_Ip_InitDoubleCompareMode(uint8 instance,
                                               Emios_Pwm_Ip_ChannelConfigType const *userChCfg)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(NULL_PTR != userChCfg);
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > userChCfg->channelId);
    /* Check Selected channel is set for DAOC mode */
    DevAssert((userChCfg->mode == EMIOS_PWM_MODE_DAOC_FLAG) ||
              (userChCfg->mode == EMIOS_PWM_MODE_DAOC_FLAG_BOTH));
    /* Validate opwfmb parametter */
    DevAssert(EMIOS_PWM_MIN_CNT_VAL < userChCfg->periodCount);
    DevAssert(userChCfg->dutyCycle <= userChCfg->periodCount);
#endif

    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    Emios_Pwm_Ip_aPeriod[instance][userChCfg->channelId] = userChCfg->periodCount;
    Emios_Pwm_Ip_aPolarity[instance][userChCfg->channelId] = (userChCfg->outputPolarity == EMIOS_PWM_ACTIVE_HIGH)? 1U : 0U;
    uint16 daocRegA = 0U;
    uint16 counterMax = Emios_Pwm_Ip_GetUCRegA(base, Emios_Pwm_Ip_GetMasterBusChannel(instance, userChCfg->channelId));

    /* FLAG event enabled */
    Emios_Pwm_Ip_SetInterruptRequest(base, userChCfg->channelId, TRUE);
    /* Configure Counter Bus used by this channel */
    Emios_Pwm_Ip_SetCounterBus(base, userChCfg->channelId, userChCfg->timebase);

    if (userChCfg->periodCount == userChCfg->dutyCycle)
    {
        Emios_Pwm_Ip_SetEdgePolarity(base, userChCfg->channelId,(userChCfg->outputPolarity == EMIOS_PWM_ACTIVE_HIGH) ? EMIOS_PWM_ACTIVE_LOW : EMIOS_PWM_ACTIVE_HIGH );
    }
    else
    {
        Emios_Pwm_Ip_SetEdgePolarity(base, userChCfg->channelId, userChCfg->outputPolarity);
    }
    /* Transition from GPIO mode to DAOC mode */
    Emios_Pwm_Ip_SetPwmMode(base, userChCfg->channelId, userChCfg->mode);
    /* Configure output pin polarity */
    Emios_Pwm_Ip_SetEdgePolarity(base, userChCfg->channelId, userChCfg->outputPolarity);
    /* With Duty cycle 0% */
    if(0U == userChCfg->dutyCycle)
    {
        daocRegA = 1U;
        Emios_Pwm_Ip_aDaocDuty[instance][userChCfg->channelId] = 0U;

        Emios_Pwm_Ip_SetForceMatchB(base, userChCfg->channelId, TRUE);
        /* Configure Leading Edge in reg A */
        Emios_Pwm_Ip_SetUCRegA(base, userChCfg->channelId, daocRegA);
        /* Configure Trailing Edge in reg B */
        Emios_Pwm_Ip_SetUCRegB(base, userChCfg->channelId, (userChCfg->dutyCycle + 1U));

        Emios_Pwm_Ip_SetEdgePolarity(base, userChCfg->channelId, userChCfg->outputPolarity);

        Emios_Pwm_Ip_aNotif[instance][userChCfg->channelId] = (uint8)1U;

    }
    else if(userChCfg->dutyCycle == userChCfg->periodCount)
    {
        daocRegA = (Emios_Pwm_Ip_aPeriod[instance][userChCfg->channelId] + Emios_Pwm_Ip_GetUCRegA(base, userChCfg->channelId)) % counterMax;

        Emios_Pwm_Ip_aDaocDuty[instance][userChCfg->channelId] = 0U;

        Emios_Pwm_Ip_SetForceMatchA(base, userChCfg->channelId, TRUE);
        /* Configure Leading Edge in reg A */
        Emios_Pwm_Ip_SetUCRegA(base, userChCfg->channelId, (daocRegA == 0U)? counterMax : daocRegA);
        /* Configure Trailing Edge in reg B */
        Emios_Pwm_Ip_SetUCRegB(base, userChCfg->channelId, (daocRegA == 0U)? counterMax : daocRegA);
        /* Invert the EDGE POLARITY in control register */
        Emios_Pwm_Ip_SetEdgePolarity(base, userChCfg->channelId,(userChCfg->outputPolarity == EMIOS_PWM_ACTIVE_HIGH) ? EMIOS_PWM_ACTIVE_LOW : EMIOS_PWM_ACTIVE_HIGH);

        Emios_Pwm_Ip_aNotif[instance][userChCfg->channelId] = (uint8)1U;
    }
    else
    {
        daocRegA = 1U;
        Emios_Pwm_Ip_aDaocDuty[instance][userChCfg->channelId] = userChCfg->dutyCycle;

        /* Configure Leading Edge in reg A */
        Emios_Pwm_Ip_SetUCRegA(base, userChCfg->channelId, daocRegA);
        /* Configure Trailing Edge in reg B */
        Emios_Pwm_Ip_SetUCRegB(base, userChCfg->channelId, (userChCfg->dutyCycle + 1U));

        Emios_Pwm_Ip_SetEdgePolarity(base, userChCfg->channelId, userChCfg->outputPolarity);

        Emios_Pwm_Ip_aNotif[instance][userChCfg->channelId] = (uint8)0U;
    }

}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_SetDutyCycleDaoc
 * Description   : Set new duty cycle for the channel in DAOC mode
 * This function will check the specific duty cycle and set new duty cycle for
 * this channel
 *
 *END**************************************************************************/
static Emios_Pwm_Ip_StatusType Emios_Pwm_Ip_SetDutyCycleDaoc(uint8  instance,
                                                             uint8  channel,
                                                             uint16 newDutyCycle)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    Emios_Pwm_Ip_StatusType ret = EMIOS_PWM_STATUS_SUCCESS;
    uint16 daocRegA = 0U;
    uint16 counterMax = Emios_Pwm_Ip_GetUCRegA(base, Emios_Pwm_Ip_GetMasterBusChannel(instance, channel));

    /* DAOC mode */
    if ((newDutyCycle > Emios_Pwm_Ip_aPeriod[instance][channel]) && ((uint16)0U != Emios_Pwm_Ip_aPeriod[instance][channel]))
    {   /* Duty cycle value should not be greater than the channel Period. */
        ret = EMIOS_PWM_STATUS_ERROR;
    }
    else if (((uint16)0U == Emios_Pwm_Ip_aPeriod[instance][channel]) || ((uint16)0U == newDutyCycle))
    {
        /* Disable and clear interrupt flag */
        Emios_Pwm_Ip_SetInterruptRequest(base, channel, FALSE);
        Emios_Pwm_Ip_ClearFlagEvent(base, channel);

        /* If new period is 0, set duty cycle to 0 */
        Emios_Pwm_Ip_aDaocDuty[instance][channel] = 0U;

        Emios_Pwm_Ip_SetForceMatchB(base, channel, TRUE);
        /* Configure Leading Edge in reg A */
        Emios_Pwm_Ip_SetUCRegA(base, channel, 1U);
        /* Configure Trailing Edge in reg B */
        Emios_Pwm_Ip_SetUCRegB(base, channel, (newDutyCycle + 1U));

        Emios_Pwm_Ip_SetEdgePolarity(base, channel, (Emios_Pwm_Ip_aPolarity[instance][channel] == 1U)? EMIOS_PWM_ACTIVE_HIGH : EMIOS_PWM_ACTIVE_LOW);

        Emios_Pwm_Ip_aNotif[instance][channel] = (uint8)1U;
    }
    else if(newDutyCycle == Emios_Pwm_Ip_aPeriod[instance][channel])
    {
        /* Disable and clear interrupt flag */
        Emios_Pwm_Ip_SetInterruptRequest(base, channel, FALSE);
        Emios_Pwm_Ip_ClearFlagEvent(base, channel);

        Emios_Pwm_Ip_aDaocDuty[instance][channel] = 0U;
        daocRegA = (Emios_Pwm_Ip_aPeriod[instance][channel] + Emios_Pwm_Ip_GetUCRegA(base, channel)) % counterMax;

        Emios_Pwm_Ip_SetForceMatchA(base, channel, TRUE);
        /* Configure Leading Edge in reg A */
        Emios_Pwm_Ip_SetUCRegA(base, channel, (daocRegA == 0U)? counterMax : daocRegA);
        /* Configure Trailing Edge in reg B */
        Emios_Pwm_Ip_SetUCRegB(base, channel, (daocRegA == 0U)? counterMax : daocRegA);
        /* Invert the EDGE POLARITY in control register */
        Emios_Pwm_Ip_SetEdgePolarity(base, channel,(Emios_Pwm_Ip_aPolarity[instance][channel] == 1U)? EMIOS_PWM_ACTIVE_LOW : EMIOS_PWM_ACTIVE_HIGH);

        Emios_Pwm_Ip_aNotif[instance][channel] = (uint8)1U;
    }
    else
    {
        Emios_Pwm_Ip_aDaocDuty[instance][channel] = newDutyCycle;
        /* Configure Leading Edge in reg A */
        Emios_Pwm_Ip_SetUCRegA(base, channel, 1U);
        /* Configure Trailing Edge in reg B */
        Emios_Pwm_Ip_SetUCRegB(base, channel, newDutyCycle + 1U);

        Emios_Pwm_Ip_SetEdgePolarity(base, channel, (Emios_Pwm_Ip_aPolarity[instance][channel] == 1U)? EMIOS_PWM_ACTIVE_HIGH : EMIOS_PWM_ACTIVE_LOW);

        Emios_Pwm_Ip_aNotif[instance][channel] = (uint8)0U;

    }

    return ret;
}
/*==================================================================================================
*                                        GLOBAL FUNCTIONS
==================================================================================================*/

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_InitChannel
 * Description   : Initialize PWM mode.
 * Select main mode
 *     - EMIOS OPWFMB
 *       Initialize Output Pulse Width and Frequency Modulation Buffered (OPWFMB) Mode.
 *       This mode provides waveforms with variable duty cycle and frequency. The internal channel counter
 *       is automatically selected as the time base when this mode is selected.
 *
 *     - EMIOS OPWMB
 *       Initialize Output Pulse Width Modulation Buffered (OPWMB) Mode.
 *       OPWMB mode is used to generate pulses with programmable leading and trailing edge placement.
 *       An external counter driven in MCB Up mode must be selected from one of the counter buses.
 *       userChCfg defines the first edge and the second edge. The output signal polarity is defined
 *       by outputPolarity in userChCfg.
 *
 *     - EMIOS OPWMCB
 *       Initialize Center Aligned Output Pulse Width Modulation with Dead Time Insertion Buffered (OPWMCB) Mode.
 *       This operation mode generates a center aligned PWM with dead time insertion to the leading or trailing edge.
 *       Allow smooth output signal generation when changing duty cycle and deadtime values.
 *
 *     - EMIOS OPWMT
 *       Initialize Output Pulse Width Modulation with Trigger (OPWMT) Mode
 *       OPWMT mode is intended to support the generation of Pulse Width Modulation signals where
 *       the period is not modified while the signal is being output, but where the duty cycle will
 *       be varied and must not create glitches. The mode is intended to be used in conjunction with
 *       other channels executing in the same mode and sharing a common timebase. It will support each
 *       channel with a fixed PWM leading edge position with respect to the other channels and the
 *       ability to generate a trigger signal at any point in the period that can be output from
 *       the module to initiate activity in other parts of the SoC such as starting ADC conversions.
 * Implements    : Emios_Pwm_Ip_InitChannel_Activity
 *END**************************************************************************/
void Emios_Pwm_Ip_InitChannel(uint8 instance,
                              Emios_Pwm_Ip_ChannelConfigType const *userChCfg)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(NULL_PTR != userChCfg);
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);

    /* Check that a valid notification structure is defined for interrupt mode */
    if (EMIOS_PWM_INTERRUPT_REQUEST == userChCfg->irqMode)
    {
        DevAssert(NULL_PTR != userChCfg->userCallback.cbFunction);
    }
#endif

    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    uint8 channel = userChCfg->channelId;

    /* Disable channel pre-scaler (reset default) */
    Emios_Pwm_Ip_aBasePtr[instance]->CH.UC[userChCfg->channelId].C = 0UL;

    /* Enable the Output Update for channel */
    Emios_Pwm_Ip_SetOutputUpdate(base, channel, TRUE);

#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    /* Configure debug freeze enable */
    if ((FALSE == Emios_Pwm_Ip_GetDebugMode(base)) &&
        (TRUE == userChCfg->debugMode))
    {
        DevAssert(FALSE);
    }
    else
    {
        Emios_Pwm_Ip_SetFreezeEnable(base, userChCfg->channelId, userChCfg->debugMode);
    }
#endif

    /* Configure output disable feature */
    if (EMIOS_PWM_OUTPUT_DISABLE_NONE != userChCfg->outputDisableSource)
    {
        Emios_Pwm_Ip_SetOutDisable(base, userChCfg->channelId, TRUE);
        Emios_Pwm_Ip_SetOutDisableSource(base, userChCfg->channelId, userChCfg->outputDisableSource);
    }

    /* Configure Interrupt/DMA request */
    if (EMIOS_PWM_NOTIFICATION_DISABLED != userChCfg->irqMode)
    {
        if (EMIOS_PWM_INTERRUPT_REQUEST == userChCfg->irqMode)
        {
            /* Register the notification structure */
            Emios_Pwm_Ip_aNotificationPtr[instance][userChCfg->channelId] = &(userChCfg->userCallback);
        }
        else
        {
            Emios_Pwm_Ip_SetDMARequest(base, userChCfg->channelId, TRUE);
        }
    }

    /* Configure counterBus, dutyCycle, period, trigger, phase shift for selected mode */
    switch (userChCfg->mode)
    {
        case EMIOS_PWM_MODE_OPWFMB_FLAG:
        case EMIOS_PWM_MODE_OPWFMB_FLAG_BOTH:
            /* OPWFMB mode initialization */
            Emios_Pwm_Ip_InitPeriodDutyCycleMode(instance, userChCfg);
            break;
        case EMIOS_PWM_MODE_OPWMCB_TRAIL_EDGE_FLAG:
        case EMIOS_PWM_MODE_OPWMCB_TRAIL_EDGE_FLAG_BOTH:
        case EMIOS_PWM_MODE_OPWMCB_LEAD_EDGE_FLAG:
        case EMIOS_PWM_MODE_OPWMCB_LEAD_EDGE_FLAG_BOTH:
            /* OPWMCB mode initialization */
            Emios_Pwm_Ip_InitDeadTimeMode(instance, userChCfg);
            break;
        case EMIOS_PWM_MODE_OPWMB_FLAG:
        case EMIOS_PWM_MODE_OPWMB_FLAG_BOTH:
            /* OPWMB mode initialization */
            Emios_Pwm_Ip_InitEdgePlacementMode(instance, userChCfg);
            break;
        case EMIOS_PWM_MODE_OPWMT:
            /* OPWMT mode initialization */
            Emios_Pwm_Ip_InitTriggerMode(instance, userChCfg);
            break;
        case EMIOS_PWM_MODE_DAOC_FLAG:
        case EMIOS_PWM_MODE_DAOC_FLAG_BOTH:
            /* DAOC mode initialization */
            Emios_Pwm_Ip_InitDoubleCompareMode(instance, userChCfg);
            break;
        default:
            /* Nothing to do. All Pwm mode are already treated. */
            break;
    }

    /* Configure internal prescaler */
    if (EMIOS_PWM_CLOCK_NONE != userChCfg->internalPs)
    {
        Emios_Pwm_Ip_SetExtendedPrescaler(base, userChCfg->channelId, userChCfg->internalPs);
        Emios_Pwm_Ip_SetPrescalerSource(base, userChCfg->channelId, userChCfg->internalPsSrc);
        Emios_Pwm_Ip_SetPrescalerEnable(base, userChCfg->channelId, TRUE);
    }
    /* Confirm the channel is active*/
    Emios_Pwm_Ip_aCheckState[instance][userChCfg->channelId] = (uint8)1U;

}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_DeInitChannel
 * Description   : Reset eMIOS channel to GPIO mode (reset default)
 * Implements    : Emios_Pwm_Ip_DeInitChannel_Activity
 *END**************************************************************************/
void Emios_Pwm_Ip_DeInitChannel(uint8 instance,
                                uint8 channel)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];

    /* Clear control register 2 and stop clock for channel */
    base->CH.UC[channel].C2 = 0UL;
    /* Clear control register for channel */
    base->CH.UC[channel].C = 0UL;
    /* Clear An and Bn registers */
    Emios_Pwm_Ip_SetUCRegA(base, channel, 0U);
    Emios_Pwm_Ip_SetUCRegB(base, channel, 0U);
    /* Clear ALTAn if in PWM Trigger mode */
    if (Emios_Pwm_Ip_GetPwmMode(base, channel) == EMIOS_PWM_MODE_OPWMT)
    {
        Emios_Pwm_Ip_SetTrigger(base, channel, 0U);
    }

    Emios_Pwm_Ip_aCheckEnableNotif[instance][channel] = (uint8)0U;

    /* Confirm the channel is inactive*/
    Emios_Pwm_Ip_aCheckState[instance][channel] = (uint8)0U;

}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_ForceMatchLeadingEdge
 * Description   : Force the output flip-flop to the level corresponding to a match on Leading edge
 *      In Center Aligned Output Pulse Width Modulation with Dead Time Insertion Buffered (OPWMCB) Mode
 *      FORCMA has different behaviors depending upon the selected dead time
 *      insertion mode, lead or trail. In lead dead time insertion FORCMA force a transition
 *      in the output flipflop to the opposite of EDPOL. In trail dead time insertion the
 *      output flip-flop is forced to the value of EDPOL bit.
 *      FORCMA bit set does not set the internal time-base to 0x1 as a regular A1 match.
 * Implements    : Emios_Pwm_Ip_ForceMatchLeadingEdge_Activity
 *END**************************************************************************/
void Emios_Pwm_Ip_ForceMatchLeadingEdge(uint8 instance,
                                        uint8 channel,
                                        boolean enable)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];

    SchM_Enter_Pwm_PWM_EXCLUSIVE_AREA_14();
    /* Force Match A bit */
    Emios_Pwm_Ip_SetForceMatchA(base, channel, enable);
    SchM_Exit_Pwm_PWM_EXCLUSIVE_AREA_14();
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_ForceMatchTrailingEdge
 * Description   : Force the output flipflop to the level corresponding to a match on Trailing edge
 *
 * In Center Aligned Output Pulse Width Modulation with Dead Time Insertion Buffered (OPWMCB) Mode
 *       If FORCMB bit is set, the output flip-flop value depends upon the selected dead time
 *       insertion mode. In lead dead time insertion FORCMB forces the output flip-flop to transition to EDPOL
 *       bit value. In trail dead time insertion the output flip-flop is forced to the opposite of EDPOL bit value.
 * Implements    : Emios_Pwm_Ip_ForceMatchTrailingEdge_Activity
 *END**************************************************************************/
void Emios_Pwm_Ip_ForceMatchTrailingEdge(uint8 instance,
                                         uint8 channel,
                                         boolean enable)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif

    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    SchM_Enter_Pwm_PWM_EXCLUSIVE_AREA_15();
    /* Force Match B bit */
    Emios_Pwm_Ip_SetForceMatchB(base, channel, enable);
    SchM_Exit_Pwm_PWM_EXCLUSIVE_AREA_15();
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_GetPeriod
 * Description   : Get period of waveforms in PWM mode.
 * Implements    : Emios_Pwm_Ip_GetPeriod_Activity
 *END**************************************************************************/
uint16 Emios_Pwm_Ip_GetPeriod(uint8 instance,
                              uint8 channel)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    const Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    Emios_Pwm_Ip_PwmModeType chMode = Emios_Pwm_Ip_GetPwmMode(base, channel);
    uint16 chPeriod = 0x00U;

    if ((chMode == EMIOS_PWM_MODE_OPWFMB_FLAG) ||
        (chMode == EMIOS_PWM_MODE_OPWFMB_FLAG_BOTH))
    { /* OPWFMB mode */
        chPeriod = Emios_Pwm_Ip_GetUCRegB(base, channel);
    }
    else if ((chMode == EMIOS_PWM_MODE_DAOC_FLAG) ||
             (chMode == EMIOS_PWM_MODE_DAOC_FLAG_BOTH))
    { /* DAOC mode */
        chPeriod = Emios_Pwm_Ip_aPeriod[instance][channel];
    }
    else
    { /* OPWMCB mode or OPWMB or OPWMT mode */
        chPeriod = Emios_Pwm_Ip_GetCounterBusPeriod(instance, channel, Emios_Pwm_Ip_GetCounterBus(base, channel));
    }

    return chPeriod;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_SetPeriod
 * Description   : Setup period of waveforms in OPWFMB mode.
 * With PWM mode, the OPWFMB(Output Pulse Width and Frequency Modulation Buffered) can set
 * period. All other PWM modes can not, because OPWFMB mode using internal counter. All other
 * modes use external timebase and their period is timebase period.
 * Implements    : Emios_Pwm_Ip_SetPeriod_Activity
 *END**************************************************************************/
void Emios_Pwm_Ip_SetPeriod(uint8 instance,
                            uint8 channel,
                            uint16 newPeriod)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif

    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    Emios_Pwm_Ip_PwmModeType chMode = Emios_Pwm_Ip_GetPwmMode(base, channel);
#endif

#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    /* Check channel mode is OPWFMB */
    DevAssert((EMIOS_PWM_MODE_OPWFMB_FLAG == chMode) ||
              (EMIOS_PWM_MODE_OPWFMB_FLAG_BOTH == chMode) ||
              (EMIOS_PWM_MODE_DAOC_FLAG == chMode) ||
              (EMIOS_PWM_MODE_DAOC_FLAG_BOTH == chMode));
#endif

    SchM_Enter_Pwm_PWM_EXCLUSIVE_AREA_16();
    /* If new period is 0, No change the period */
    if((uint16)0U == newPeriod)
    {
        /* Do Nothing */
    }
    else
    {
        /* Set new period */
        Emios_Pwm_Ip_SetUCRegB(base, channel, newPeriod);
    }
    /* Store new period */
    Emios_Pwm_Ip_aPeriod[instance][channel] = newPeriod;
    SchM_Exit_Pwm_PWM_EXCLUSIVE_AREA_16();
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_GetDutyCycle
 * Description   : Get duty cycle of waveforms in PWM mode. Duty cycle is signal active time in a period.
 * Implements    : Emios_Pwm_Ip_GetDutyCycle_Activity
 *END**************************************************************************/
uint16 Emios_Pwm_Ip_GetDutyCycle(uint8 instance,
                                 uint8 channel)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif

    const Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    Emios_Pwm_Ip_PwmModeType chMode = Emios_Pwm_Ip_GetPwmMode(base, channel);
    uint16 regAValue = Emios_Pwm_Ip_GetUCRegA(base, channel);
    uint16 regBValue = Emios_Pwm_Ip_GetUCRegB(base, channel);
    uint16 chPeriod = 0U;
    uint16 dutyCycle = 0U;

    switch (chMode)
    {
        case EMIOS_PWM_MODE_OPWFMB_FLAG:
        case EMIOS_PWM_MODE_OPWFMB_FLAG_BOTH:
        case EMIOS_PWM_MODE_OPWMCB_TRAIL_EDGE_FLAG:
        case EMIOS_PWM_MODE_OPWMCB_TRAIL_EDGE_FLAG_BOTH:
        case EMIOS_PWM_MODE_OPWMCB_LEAD_EDGE_FLAG:
        case EMIOS_PWM_MODE_OPWMCB_LEAD_EDGE_FLAG_BOTH:
            /* OPWFMB or OPWMCB mode */
            dutyCycle = regAValue;
            break;
        case EMIOS_PWM_MODE_OPWMB_FLAG:
        case EMIOS_PWM_MODE_OPWMB_FLAG_BOTH:
            /* OPWMB mode */
            dutyCycle = regBValue - regAValue;
            break;
        case EMIOS_PWM_MODE_OPWMT:
            /* OPWMT mode */
            /* Get channel period */
            chPeriod = Emios_Pwm_Ip_GetCounterBusPeriod(instance, channel, Emios_Pwm_Ip_GetCounterBus(base, channel));
            if (regBValue > chPeriod)
            { /* 100% dutyCycle when B value is greater than channel period. */
                dutyCycle = regBValue;
            }
            else if (regBValue < regAValue)
            { /* PhaseShift of signal wrapped around the duty cycle */
                dutyCycle = (chPeriod - regAValue) + regBValue;
            }
            else
            {
                dutyCycle = regBValue - regAValue;
            }
            break;
        case EMIOS_PWM_MODE_DAOC_FLAG:
        case EMIOS_PWM_MODE_DAOC_FLAG_BOTH:
            /* DAOC mode */
            dutyCycle = Emios_Pwm_Ip_aDaocDuty[instance][channel];
            break;
        default:
            /* Nothing to do */
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
            DevAssert(FALSE);
#endif
            break;
    }

    return dutyCycle;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_SetDutyCycle
 * Description   : Setup duty cycle of waveforms in OPWFMB mode.
 * Duty cycle should be not greater period value. When set duty cycle value greater period value
 * (and do not over 16 bits counter register) 100% duty cycle signal generated.
 * Implements    : Emios_Pwm_Ip_SetDutyCycle_Activity
 *END**************************************************************************/
Emios_Pwm_Ip_StatusType Emios_Pwm_Ip_SetDutyCycle(uint8 instance,
                                                  uint8 channel,
                                                  uint16 newDutyCycle)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif

    const Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    Emios_Pwm_Ip_StatusType ret = EMIOS_PWM_STATUS_SUCCESS;
    Emios_Pwm_Ip_PwmModeType chMode = Emios_Pwm_Ip_GetPwmMode(base, channel);

    SchM_Enter_Pwm_PWM_EXCLUSIVE_AREA_17();
    if ((chMode == EMIOS_PWM_MODE_OPWFMB_FLAG) ||
        (chMode == EMIOS_PWM_MODE_OPWFMB_FLAG_BOTH))
    {
        /* OPWFMB mode */
        ret = Emios_Pwm_Ip_SetDutyCycleOpwfmb(instance, channel, newDutyCycle);
    }
    else if ((chMode == EMIOS_PWM_MODE_OPWMCB_TRAIL_EDGE_FLAG) ||
             (chMode == EMIOS_PWM_MODE_OPWMCB_TRAIL_EDGE_FLAG_BOTH) ||
             (chMode == EMIOS_PWM_MODE_OPWMCB_LEAD_EDGE_FLAG) ||
             (chMode == EMIOS_PWM_MODE_OPWMCB_LEAD_EDGE_FLAG_BOTH))
    {
        /* OPWMCB mode */
        ret = Emios_Pwm_Ip_SetDutyCycleOpwmcb(instance, channel, newDutyCycle);
    }
    else if ((chMode == EMIOS_PWM_MODE_OPWMB_FLAG) ||
             (chMode == EMIOS_PWM_MODE_OPWMB_FLAG_BOTH))
    {
        /* OPWMB mode */
        ret = Emios_Pwm_Ip_SetDutyCycleOpwmb(instance, channel, newDutyCycle);
    }
    else if((chMode == EMIOS_PWM_MODE_DAOC_FLAG) ||
            (chMode == EMIOS_PWM_MODE_DAOC_FLAG_BOTH))
    {
        /* DAOC mode */
        ret = Emios_Pwm_Ip_SetDutyCycleDaoc(instance, channel, newDutyCycle);
    }
    else
    {
        /* OPWMT mode */
        ret = Emios_Pwm_Ip_SetDutyCycleOpwmt(instance, channel, newDutyCycle);
    }
    SchM_Exit_Pwm_PWM_EXCLUSIVE_AREA_17();

    return ret;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_GetPhaseShift
 * Description   : Get Leading edge position of waveforms in OPWMB & OPWMT mode.
 * Implements    : Emios_Pwm_Ip_GetPhaseShift_Activity
 *END**************************************************************************/
uint16 Emios_Pwm_Ip_GetPhaseShift(uint8 instance,
                                  uint8 channel)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif

    const Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    Emios_Pwm_Ip_PwmModeType chMode = Emios_Pwm_Ip_GetPwmMode(base, channel);

    DevAssert((EMIOS_PWM_MODE_OPWMB_FLAG == chMode) ||
              (EMIOS_PWM_MODE_OPWMB_FLAG_BOTH == chMode) ||
              (EMIOS_PWM_MODE_OPWMT == chMode));
#endif

    return Emios_Pwm_Ip_GetUCRegA(base, channel);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_SetPhaseShift
 * Description   : Set Leading edge position of waveforms in OPWMB & OPWMT mode.
 * DutyCycle will be kept the same value.
 * Implements    : Emios_Pwm_Ip_SetPhaseShift_Activity
 *END**************************************************************************/
Emios_Pwm_Ip_StatusType Emios_Pwm_Ip_SetPhaseShift(uint8 instance,
                                                   uint8 channel,
                                                   uint16 phaseShift)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif

    Emios_Pwm_Ip_StatusType status = EMIOS_PWM_STATUS_SUCCESS;
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    Emios_Pwm_Ip_PwmModeType chMode = Emios_Pwm_Ip_GetPwmMode(base, channel);
    uint16 chPeriod = 0U;
    uint16 dutyCycle = 0U;
    uint8  counterStart = 0U;

#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert((EMIOS_PWM_MODE_OPWMB_FLAG == chMode) ||
              (EMIOS_PWM_MODE_OPWMB_FLAG_BOTH == chMode) ||
              (EMIOS_PWM_MODE_OPWMT == chMode));
#endif

    SchM_Enter_Pwm_PWM_EXCLUSIVE_AREA_18();
    chPeriod = Emios_Pwm_Ip_GetCounterBusPeriod(instance, channel, Emios_Pwm_Ip_GetCounterBus(base, channel));
    dutyCycle = Emios_Pwm_Ip_GetDutyCycle(instance, channel);

    if (EMIOS_PWM_IP_MCB_UP_COUNTER == Emios_Pwm_Ip_GetCounterBusMode(instance, channel, Emios_Pwm_Ip_GetCounterBus(base, channel)))
    {
        counterStart = 1U;
    }
    else
    {
        counterStart = 0U;
    }

    Emios_Pwm_Ip_aRegA[instance][channel] = phaseShift + counterStart;

    /* Check that phase shift can be applied to the selected channel */
    if ((EMIOS_PWM_MODE_OPWMB_FLAG == chMode) ||
        (EMIOS_PWM_MODE_OPWMB_FLAG_BOTH == chMode))
    {
        if ((phaseShift + dutyCycle) > chPeriod)
        {
            status = EMIOS_PWM_STATUS_ERROR;
        }
        else
        {
            /* Set the new phase shift */
            Emios_Pwm_Ip_SetUCRegA(base, channel, (phaseShift + counterStart));
            /* Move trailing edge to keep the same duty cycle */
            Emios_Pwm_Ip_SetUCRegB(base, channel, (phaseShift + dutyCycle + counterStart));
        }
    }
    else if (EMIOS_PWM_MODE_OPWMT == chMode)
    {
        if (phaseShift > chPeriod)
        {
            status = EMIOS_PWM_STATUS_ERROR;
        }
        else
        {
            /* Set the new phase shift */
            Emios_Pwm_Ip_SetUCRegA(base, channel, (phaseShift + counterStart));
            /* Move trailing edge to keep the same duty cycle */
            if (dutyCycle < (chPeriod + 1U))
            {
                Emios_Pwm_Ip_SetUCRegB(base, channel, (((phaseShift + dutyCycle) % chPeriod) + counterStart));
            }
        }
    }
    else
    {
        status = EMIOS_PWM_STATUS_ERROR;
    }
    SchM_Exit_Pwm_PWM_EXCLUSIVE_AREA_18();

    return status;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_GetDeadTime
 * Description   : Get Dead time value of waveforms in OPWMCB mode.
 * Implements    : Emios_Pwm_Ip_GetDeadTime_Activity
 *END**************************************************************************/
uint16 Emios_Pwm_Ip_GetDeadTime(uint8 instance,
                                uint8 channel)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif

    const Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    Emios_Pwm_Ip_PwmModeType chMode = Emios_Pwm_Ip_GetPwmMode(base, channel);

    DevAssert((chMode == EMIOS_PWM_MODE_OPWMCB_TRAIL_EDGE_FLAG) ||
              (chMode == EMIOS_PWM_MODE_OPWMCB_TRAIL_EDGE_FLAG_BOTH) ||
              (chMode == EMIOS_PWM_MODE_OPWMCB_LEAD_EDGE_FLAG) ||
              (chMode == EMIOS_PWM_MODE_OPWMCB_LEAD_EDGE_FLAG_BOTH));
#endif
    /* Get the configured dead time */
    return Emios_Pwm_Ip_GetUCRegB(base, channel);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_SetDeadTime
 * Description   : Set Dead time value of waveforms in OPWMCB mode. New dead time should
 * be no greater than 0xFFFF (16 bits).
 * Implements    : Emios_Pwm_Ip_SetDeadTime_Activity
 *END**************************************************************************/
void Emios_Pwm_Ip_SetDeadTime(uint8 instance,
                              uint8 channel,
                              uint16 newDeadTime)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    Emios_Pwm_Ip_PwmModeType chMode = Emios_Pwm_Ip_GetPwmMode(base, channel);

    DevAssert((chMode == EMIOS_PWM_MODE_OPWMCB_TRAIL_EDGE_FLAG) ||
              (chMode == EMIOS_PWM_MODE_OPWMCB_TRAIL_EDGE_FLAG_BOTH) ||
              (chMode == EMIOS_PWM_MODE_OPWMCB_LEAD_EDGE_FLAG) ||
              (chMode == EMIOS_PWM_MODE_OPWMCB_LEAD_EDGE_FLAG_BOTH));
#endif
    SchM_Enter_Pwm_PWM_EXCLUSIVE_AREA_19();
    /* Set the new dead time */
    Emios_Pwm_Ip_SetUCRegB(base, channel, newDeadTime);
    SchM_Exit_Pwm_PWM_EXCLUSIVE_AREA_19();
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_GetTriggerPlacement
 * Description   : Get Trigger placement value in OPWMT mode
 * Implements    : Emios_Pwm_Ip_GetTriggerPlacement_Activity
 *END**************************************************************************/
uint32 Emios_Pwm_Ip_GetTriggerPlacement(uint8 instance,
                                        uint8 channel)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    const Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];

#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(Emios_Pwm_Ip_GetPwmMode(base, channel) == EMIOS_PWM_MODE_OPWMT);
#endif
    /* Get the configured trigger */
    return Emios_Pwm_Ip_GetTrigger(base, channel);
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_SetTriggerPlacement
 * Description   : Set Trigger placement value in OPWMT mode. New trigger placement
 * should be no larger than 0xFFFFFF(24 bits).
 * Implements    : Emios_Pwm_Ip_SetTriggerPlacement_Activity
 *END**************************************************************************/
void Emios_Pwm_Ip_SetTriggerPlacement(uint8 instance,
                                      uint8 channel,
                                      uint32 newTriggerPlacement)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif

    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    uint8 counterStart = 0U;

#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(Emios_Pwm_Ip_GetPwmMode(base, channel) == EMIOS_PWM_MODE_OPWMT);
    /* Check selected counter bus is configured in MCB Up Mode or MC Up mode */
    DevAssert((EMIOS_PWM_IP_MCB_UP_COUNTER == Emios_Pwm_Ip_GetCounterBusMode(instance, channel, Emios_Pwm_Ip_GetCounterBus(base, channel))) ||
              (EMIOS_PWM_IP_MC_UP_COUNTER_START == Emios_Pwm_Ip_GetCounterBusMode(instance, channel, Emios_Pwm_Ip_GetCounterBus(base, channel))) ||
              (EMIOS_PWM_IP_MC_UP_COUNTER_END == Emios_Pwm_Ip_GetCounterBusMode(instance, channel, Emios_Pwm_Ip_GetCounterBus(base, channel)))
             );
    DevAssert((Emios_Pwm_Ip_GetCounterBusPeriod(instance, channel, Emios_Pwm_Ip_GetCounterBus(base, channel))) > newTriggerPlacement);
#endif

    SchM_Enter_Pwm_PWM_EXCLUSIVE_AREA_20();
    if (EMIOS_PWM_IP_MCB_UP_COUNTER == Emios_Pwm_Ip_GetCounterBusMode(instance, channel, Emios_Pwm_Ip_GetCounterBus(base, channel)))
    {
        counterStart = 1U;
    }
    else
    {
        counterStart = 0U;
    }
    /* Set the new trigger value */
    Emios_Pwm_Ip_SetTrigger(base, channel, (uint16)(newTriggerPlacement + counterStart));
    SchM_Exit_Pwm_PWM_EXCLUSIVE_AREA_20();
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_ChannelEnterDebugMode
 * Description   : To set a channel enters freeze state, should be setting
 * Emios_Pwm_Ip_AllowEnterDebugMode first.
 * Implements    : Emios_Pwm_Ip_ChannelEnterDebugMode_Activity
 *END**************************************************************************/
Emios_Pwm_Ip_StatusType Emios_Pwm_Ip_ChannelEnterDebugMode(uint8 instance,
                                                           uint8 channel)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    Emios_Pwm_Ip_StatusType ret = EMIOS_PWM_STATUS_SUCCESS;

    SchM_Enter_Pwm_PWM_EXCLUSIVE_AREA_21();
    if (Emios_Pwm_Ip_GetDebugMode(base) == TRUE)
    {
        Emios_Pwm_Ip_SetFreezeEnable(base, channel, TRUE);
    }
    else
    {
        ret = EMIOS_PWM_STATUS_GLOBAL_FREEZE_DISABLED;
    }
    SchM_Exit_Pwm_PWM_EXCLUSIVE_AREA_21();
    return ret;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Emios_Pwm_Ip_ChannelStopDebugMode
 * Description   : Release a channel from freeze state
 * Implements    : Emios_Pwm_Ip_ChannelStopDebugMode_Activity
 *END**************************************************************************/
void Emios_Pwm_Ip_ChannelStopDebugMode(uint8 instance,
                                       uint8 channel)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];

    SchM_Enter_Pwm_PWM_EXCLUSIVE_AREA_22();
    Emios_Pwm_Ip_SetFreezeEnable(base, channel, FALSE);
    SchM_Exit_Pwm_PWM_EXCLUSIVE_AREA_22();
}

/*FUNCTION**********************************************************************
*
* Function Name : Emios_Pwm_Ip_GetFlagRequest
* Description   : Configure what the FLAG event should do. Generate Interrupt request,
*       Generate DMA request or do nothing.
* Implements    : Emios_Pwm_Ip_GetFlagRequest_Activity
*END**************************************************************************/
Emios_Pwm_Ip_InterruptType Emios_Pwm_Ip_GetFlagRequest(uint8 instance,
                                                       uint8 channel)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    const Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    Emios_Pwm_Ip_InterruptType eventType = EMIOS_PWM_NOTIFICATION_DISABLED;

    if (Emios_Pwm_Ip_GetInterruptRequest(base, channel) == TRUE)
    {
        if (Emios_Pwm_Ip_GetDMARequest(base, channel) == TRUE)
        {
            eventType = EMIOS_PWM_DMA_REQUEST;
        }
        else
        {
            eventType = EMIOS_PWM_INTERRUPT_REQUEST;
        }
    }

    return eventType;
}

/*FUNCTION**********************************************************************
*
* Function Name : Emios_Pwm_Ip_SetFlagRequest
* Description   : Configure what the FLAG event should do. Generate Interrupt request,
*       Generate DMA request or do nothing.
* Implements    : Emios_Pwm_Ip_SetFlagRequest_Activity
*END**************************************************************************/
void Emios_Pwm_Ip_SetFlagRequest(uint8 instance,
                                 uint8 channel,
                                 Emios_Pwm_Ip_InterruptType event)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];

    SchM_Enter_Pwm_PWM_EXCLUSIVE_AREA_23();
    /* Clear Interrupt flag */
    Emios_Pwm_Ip_ClearFlagEvent(base, channel);

    switch (event)
    {
    case EMIOS_PWM_INTERRUPT_REQUEST:
        if ((uint8)0U == Emios_Pwm_Ip_aNotif[instance][channel])
        {
            Emios_Pwm_Ip_SetInterruptRequest(base, channel, TRUE);
            Emios_Pwm_Ip_SetDMARequest(base, channel, FALSE);
            Emios_Pwm_Ip_aCheckEnableNotif[instance][channel] = (uint8)1U;
        }
        break;
    case EMIOS_PWM_DMA_REQUEST:
        Emios_Pwm_Ip_SetInterruptRequest(base, channel, TRUE);
        Emios_Pwm_Ip_SetDMARequest(base, channel, TRUE);
        break;
    case EMIOS_PWM_NOTIFICATION_DISABLED:
        Emios_Pwm_Ip_SetInterruptRequest(base, channel, FALSE);
        Emios_Pwm_Ip_SetDMARequest(base, channel, FALSE);
        Emios_Pwm_Ip_aCheckEnableNotif[instance][channel] = (uint8)0U;
        break;
    default:
        /*Nothig to do. All cases are treated. */
        break;
    }
    SchM_Exit_Pwm_PWM_EXCLUSIVE_AREA_23();
}

/*FUNCTION**********************************************************************
*
* Function Name : Emios_Pwm_Ip_GetOutputState
* Description   : Get the Unified Channel output pin logic level
*
* Implements    : Emios_Pwm_Ip_GetOutputState_Activity
*END**************************************************************************/
Emios_Pwm_Ip_OutputStateType Emios_Pwm_Ip_GetOutputState(uint8 instance,
                                                         uint8 channel)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    const Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];

    return (Emios_Pwm_Ip_GetOutputPinState(base, channel) == FALSE)? EMIOS_PWM_OUTPUT_STATE_LOW : EMIOS_PWM_OUTPUT_STATE_HIGH;
}

/*FUNCTION**********************************************************************
*
* Function Name : Emios_Pwm_Ip_SetOutputState
* Description   : Set the state of output pin
*
*
*END**************************************************************************/
void Emios_Pwm_Ip_SetOutputState(uint8 instance,
                                 uint8 channel,
                                 Emios_Pwm_Ip_OutputStateType outputState)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    SchM_Enter_Pwm_PWM_EXCLUSIVE_AREA_24();
    /* Set output pin polarity */
    if (EMIOS_PWM_OUTPUT_STATE_LOW == outputState)
    {
        Emios_Pwm_Ip_SetEdgePolarity(base, channel, (Emios_Pwm_Ip_PolarityType)EMIOS_PWM_ACTIVE_LOW);
    }
    else
    {
        Emios_Pwm_Ip_SetEdgePolarity(base, channel, (Emios_Pwm_Ip_PolarityType)EMIOS_PWM_ACTIVE_HIGH);
    }
    /* Enter GPIO output mode */
    Emios_Pwm_Ip_SetPwmMode(base, channel, (Emios_Pwm_Ip_PwmModeType)EMIOS_PWM_MODE_GPO);
    /* Disable channel interrupts */
    Emios_Pwm_Ip_SetInterruptRequest(base, channel, (boolean)FALSE);
    /* Clear pending interrupt flag for the channel */
    Emios_Pwm_Ip_ClearFlagEvent(base, channel);
    SchM_Exit_Pwm_PWM_EXCLUSIVE_AREA_24();
}

/*FUNCTION**********************************************************************
*
* Function Name : Emios_Pwm_Ip_SetOutputToNormal
* Description   : Set the polarity and mode for current channel as normal
*
*
*END**************************************************************************/
void Emios_Pwm_Ip_SetOutputToNormal(uint8 instance,
                                    uint8 channel,
                                    uint16 dutyPercent,
                                    Emios_Pwm_Ip_PolarityType polarity,
                                    Emios_Pwm_Ip_PwmModeType  mode)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];

    SchM_Enter_Pwm_PWM_EXCLUSIVE_AREA_25();
    if (EMIOS_PWM_MODE_GPO == Emios_Pwm_Ip_GetPwmMode(base, channel))
    {


        if ((mode == EMIOS_PWM_MODE_OPWFMB_FLAG) || (mode == EMIOS_PWM_MODE_OPWFMB_FLAG_BOTH))
        {
           Emios_Pwm_Ip_SetPwmMode(base, channel, mode);
           Emios_Pwm_Ip_SetEdgePolarity(base, channel,(polarity == EMIOS_PWM_ACTIVE_HIGH) ? EMIOS_PWM_ACTIVE_LOW : EMIOS_PWM_ACTIVE_HIGH );
        }
        else if((mode == EMIOS_PWM_MODE_OPWMB_FLAG) || (mode == EMIOS_PWM_MODE_OPWMB_FLAG_BOTH))
        {
            Emios_Pwm_Ip_SetPwmMode(base, channel, mode);
            Emios_Pwm_Ip_SetEdgePolarity(base, channel, polarity);
        }
        else
        {
            /* To avoid spike pulse
            If duty cycle = 100%, when enter mode, EDPOL bit get complement of polarity
            after that, EDPOL bit is restored valid value */
            if(dutyPercent == 0x8000U)
            {
               Emios_Pwm_Ip_SetPwmModePol(base, channel,mode, (polarity == EMIOS_PWM_ACTIVE_HIGH) ? EMIOS_PWM_ACTIVE_LOW : EMIOS_PWM_ACTIVE_HIGH);
               Emios_Pwm_Ip_SetEdgePolarity(base, channel, polarity);
            }
            else
            {
               Emios_Pwm_Ip_SetPwmModePol(base, channel,mode, polarity);
            }
        }
    }
    else
    {
        /*Do Nothing*/
        (void)polarity;
        (void)mode;
    }
    SchM_Exit_Pwm_PWM_EXCLUSIVE_AREA_25();
}

/*FUNCTION**********************************************************************
*
* Function Name : Emios_Pwm_Ip_GetChannelMode
* Description   : Get mode of operation of the Unified Channel
*
*END**************************************************************************/
Emios_Pwm_Ip_PwmModeType Emios_Pwm_Ip_GetChannelMode(uint8 instance,
                                                     uint8 channel)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    const Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    Emios_Pwm_Ip_PwmModeType channelMode = Emios_Pwm_Ip_GetPwmMode(base, channel);

    return channelMode;
}

/**
 * @brief  Get master bus channel
 *
 * @param[in] instance    The eMIOS group id
 * @param[in] channel     The channel in this eMIOS group
 * @return    Emios_Pwm_Ip_PwmModeType
 */
uint8 Emios_Pwm_Ip_GetMasterBusChannel(uint8 instance,
                                       uint8 channel)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    const Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];

    uint8 channelMaster = channel;

    Emios_Pwm_Ip_CounterBusSourceType counterBus = Emios_Pwm_Ip_GetCounterBus(base, channel);

    switch (counterBus)
    {
        case EMIOS_PWM_BUS_A:
            channelMaster = 23U;
            break;
        case EMIOS_PWM_BUS_F:
            channelMaster = 22U;
            break;
        case EMIOS_PWM_BUS_BCDE:
            channelMaster = (uint8)((channel >> 3U) * 8U);
            break;
        default:
            /* Internal bus is used */
            channelMaster = channel;
            break;
    }
    return channelMaster;
}

/*FUNCTION**********************************************************************
*
* Function Name : Emios_Pwm_Ip_SetPreEnableClock
* Description   : Set Prescaler Enable bit.
*
*END**************************************************************************/
void Emios_Pwm_Ip_SetPreEnableClock(uint8 instance,
                                    uint8 channel,
                                    boolean value)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];

    SchM_Enter_Pwm_PWM_EXCLUSIVE_AREA_26();
    /* Set Prescaler Enable bit. */
    Emios_Pwm_Ip_SetPrescalerEnable(base, channel, value);
    SchM_Exit_Pwm_PWM_EXCLUSIVE_AREA_26();
}

/*FUNCTION**********************************************************************
*
* Function Name : Emios_Pwm_Ip_SetBusSelected
* Description   : Set Bus Select bits.
*
*END**************************************************************************/
void Emios_Pwm_Ip_SetBusSelected(uint8 instance,
                                 uint8 channel,
                                 Emios_Pwm_Ip_CounterBusSourceType value)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    SchM_Enter_Pwm_PWM_EXCLUSIVE_AREA_27();
    /* Set Bus Select bits.*/
    Emios_Pwm_Ip_SetCounterBus(base, channel, value);
    SchM_Exit_Pwm_PWM_EXCLUSIVE_AREA_27();
}

/*FUNCTION**********************************************************************
*
* Function Name : Emios_Pwm_Ip_SetClockPs
* Description   : This function set the value of the prescaler on eMios channels
*
*END**************************************************************************/
void Emios_Pwm_Ip_SetClockPs(uint8 instance,
                             uint8 channel,
                             Emios_Pwm_Ip_InternalClkPsType value)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
    DevAssert(EMIOS_PWM_CHANNEL_COUNT > channel);
#endif
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];
    SchM_Enter_Pwm_PWM_EXCLUSIVE_AREA_28();
    /* Stop eMios channel - this will stop the internal counter */
    Emios_Pwm_Ip_SetPrescalerEnable(base, channel, FALSE);
    /*Set Extended Prescaler bits */
    Emios_Pwm_Ip_SetExtendedPrescaler(base, channel, value);
    /* Re-start eMios channel */
    Emios_Pwm_Ip_SetPrescalerEnable(base, channel, TRUE);
    SchM_Exit_Pwm_PWM_EXCLUSIVE_AREA_28();
}

/*FUNCTION**********************************************************************
*
* Function Name : Emios_Pwm_Ip_ComparatorTransferEnable
* Description   : The function shall enable the output update for the corresponding channel.
*
*END**************************************************************************/
void Emios_Pwm_Ip_ComparatorTransferEnable(uint8 instance, uint32 channelMask)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
#endif

    SchM_Enter_Pwm_PWM_EXCLUSIVE_AREA_29();
    /* Enable the output update for the corresponding channel.*/
    Emios_Mcl_Ip_ComparatorTransferEnable(instance, channelMask);
    SchM_Exit_Pwm_PWM_EXCLUSIVE_AREA_29();
}

/*FUNCTION**********************************************************************
*
* Function Name : Emios_Pwm_Ip_ComparatorTransferDisable
* Description   : The function shall disable the output update for the corresponding channel.
*
*END**************************************************************************/
void Emios_Pwm_Ip_ComparatorTransferDisable(uint8 instance, uint32 channelMask)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
#endif

    SchM_Enter_Pwm_PWM_EXCLUSIVE_AREA_30();
    /* Disable the output update for the corresponding channel.*/
    Emios_Mcl_Ip_ComparatorTransferDisable(instance, channelMask);
    SchM_Exit_Pwm_PWM_EXCLUSIVE_AREA_30();
}

/*FUNCTION**********************************************************************
*
* Function Name : Emios_Pwm_Ip_SyncUpdate
* Description   : This function updates the duty cycle and-or period for the specified PWM channel.
*                 The value written does not take effect until calling SyncUpdate API.
*
*END**************************************************************************/
void Emios_Pwm_Ip_SyncUpdate(uint8 instance)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(EMIOS_PWM_INSTANCE_COUNT > instance);
#endif
    Emios_Pwm_Ip_HwAddrType *const base = Emios_Pwm_Ip_aBasePtr[instance];

    /* Read OUDIS register */
    uint32 oudisRegVal = (uint32)Emios_Pwm_Ip_GetOutputUpdateInstance(base);
    /* the mask of channels */
    uint32 channelMask = (uint32)0U;
    /* Store the mode of channel */
    Emios_Pwm_Ip_PwmModeType chMode;

    uint8  oudisDisable = 0U;
    uint8  channelId;
    /* Loop all channels available on each Emios instance */
    for (channelId = 0U; channelId < EMIOS_PWM_CHANNEL_COUNT; channelId++)
    {
        oudisDisable = (uint8)((oudisRegVal & (uint32)((uint32)1U << channelId)) >> channelId);

        if (((uint8)0U != Emios_Pwm_Ip_aCheckState[instance][channelId]) && ((uint8)1U == oudisDisable))
        {
            chMode = Emios_Pwm_Ip_GetPwmMode(base, channelId);
            /* This statement is required to avoid limitation of 0% duty cycle (if call 100% to 0%) */
            if(1U == Emios_Pwm_Ip_GetUCRegA(base, channelId))
            {
                if((chMode == EMIOS_PWM_MODE_OPWMCB_TRAIL_EDGE_FLAG) ||
                   (chMode == EMIOS_PWM_MODE_OPWMCB_TRAIL_EDGE_FLAG_BOTH))
                {
                    /* Enable the output update for the corresponding channel.*/
                    Emios_Mcl_Ip_ComparatorTransferEnable(instance, (uint32)((uint32)1U << channelId));

                    Emios_Pwm_Ip_SetForceMatchB(base, channelId, TRUE);
                }
                else if ((chMode == EMIOS_PWM_MODE_OPWMCB_LEAD_EDGE_FLAG) ||
                         (chMode == EMIOS_PWM_MODE_OPWMCB_LEAD_EDGE_FLAG_BOTH))
                {
                    /* Enable the output update for the corresponding channel.*/
                    Emios_Mcl_Ip_ComparatorTransferEnable(instance, (uint32)((uint32)1U << channelId));

                    Emios_Pwm_Ip_SetForceMatchA(base, channelId, TRUE);
                }
                else
                {
                    /* Do Nothing */
                }
            }

            /* Update OUDIS register value for synchronization */
            channelMask |= (uint32)((uint32)1U << channelId);
        }
    }
    /* Write OUDIS register */
    Emios_Mcl_Ip_ComparatorTransferEnable(instance, channelMask);
}

#define PWM_STOP_SEC_CODE
#include "Pwm_MemMap.h"


#ifdef __cplusplus
}
#endif

/** @} */
