/******************************************************************************
 * $Revision: 425 $
 * $Date:: 2017-05-19 10:28:09 +0900#$
 *****************************************************************************/
/* __DISCLAIMER_START__                                                      */
/******************************************************************************
* (c)2017, Cypress Semiconductor Corporation
* or a subsidiary of Cypress Semiconductor Corporation. All rights
* reserved.
*
* This software, including source code, documentation and related
* materials ( "Software" ), is owned by Cypress Semiconductor
* Corporation or one of its subsidiaries ( "Cypress" ) and is protected by
* and subject to worldwide patent protection (United States and foreign),
* United States copyright laws and international treaty provisions.
* Therefore, you may use this Software only as provided in the license
* agreement accompanying the software package from which you
* obtained this Software ( "EULA" ).
*
* If no EULA applies, Cypress hereby grants you a personal, nonexclusive,
* non-transferable license to copy, modify, and compile the
* Software source code solely for use in connection with Cypress' s
* integrated circuit products. Any reproduction, modification, translation,
* compilation, or representation of this Software except as specified
* above is prohibited without the express written permission of Cypress.
*
* Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO
* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING,
* BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. Cypress reserves the right to make
* changes to the Software without notice. Cypress does not assume any
* liability arising out of the application or use of the Software or any
* product or circuit described in the Software. Cypress does not
* authorize its products for use in any products where a malfunction or
* failure of the Cypress product may reasonably be expected to result in
* significant property damage, injury or death ( "High Risk Product" ). By
* including Cypress' s product in a High Risk Product, the manufacturer
* of such system or application assumes all risk of such use and in doing
* so agrees to indemnify Cypress against all liability.
******************************************************************************/
/* __DISCLAIMER_END__                                                        */
/*****************************************************************************
 ** \file adc12b.c
 **
 ** A detailed description is available at
 ** @link Adc12bGroup Adc12b module description @endlink
 **
 ** History:
 **   - 2014-11-27  0.01  HS  Initial version for Traveo
 *****************************************************************************/

/*****************************************************************************/
/* Include files                                                             */
/*****************************************************************************/
#include "common_include.h"
#include "interrupts.h"
#include "adc12b.h"


/**
 *****************************************************************************
 ** \addtogroup AdcGroup
 *****************************************************************************/
/*! @{ */

/*****************************************************************************/
/* Local pre-processor symbols/macros ('#define')                            */
/*****************************************************************************/

/*****************************************************************************/
/* Global variable definitions (declared in header file with 'extern')       */
/*****************************************************************************/

/*****************************************************************************/
/* Local type definitions ('typedef')                                        */
/*****************************************************************************/

/**
 *****************************************************************************
 ** \brief Structure of range comparator threshold register.
 *****************************************************************************/
typedef struct stc_adc12b_rco_threshold_reg{
    un_adc12b0_rcoln_t unRCOLN;
    un_adc12b0_rcohn_t unRCOHN;
}stc_adc12b_rco_threshold_reg_t;

/*****************************************************************************/
/* Local variable definitions ('static')                                     */
/*****************************************************************************/

/*****************************************************************************/
/* Local function prototypes ('static')                                      */
/*****************************************************************************/


/*****************************************************************************/
/* Function implementation - global ('extern') and local ('static')          */
/*****************************************************************************/

/*****************************************************************************
 * Global function prototypes
 *****************************************************************************/

/**
 *****************************************************************************
 ** \brief ISR callback for ADC End of Conversion.
 **
 ** This callback is called by the global ADC ISR whenever an ADC triggers an
 ** End of Conversion interrupt. It calls the callback function that has
 ** been setup during ADC initialization.
 **  (see Adc12b_Init())
 **
 ** \param [in] pstcAdc           ADC unit instance that caused the interrupt.
 ** \param [in] pstcAdcInternData Internal data associated with the ADC instance
 **
 *****************************************************************************/
void Adc12bIrqHandlerEndOfConversion(volatile stc_adc12b0_t* pstcAdc,
                                            stc_adc12b_intern_data_t* pstcInternData)
{
    stc_adc12b_channel_list_t stcDetectList = { 0 };
    stc_adc12b_channel_list_t stcIntDetectList = { 0 };

    /* Check interrupt flags */
    (void) Adc12b_GetConversionInterruptFlag(pstcAdc, &stcDetectList);

    stcIntDetectList.stcChannel[0].u32reg =
            stcDetectList.stcChannel[0].u32reg & pstcInternData->stcEofConvIntEnableChList.stcChannel[0].u32reg;
    stcIntDetectList.stcChannel[1].u32reg =
            stcDetectList.stcChannel[1].u32reg & pstcInternData->stcEofConvIntEnableChList.stcChannel[1].u32reg;

    if (stcIntDetectList.stcChannel[0].u32reg != 0 ||
        stcIntDetectList.stcChannel[1].u32reg != 0 )
    {
        /* Do not clear interrupt flag. Those is cleared by reading conversion data. */
        /* call callback function */
        if (pstcInternData->pfnEofConversionCallback != NULL)
        {
            pstcInternData->pfnEofConversionCallback(stcIntDetectList);
        }
    }
}

/**
 *****************************************************************************
 ** \brief ISR callback for Group interrupted interrupt.
 **
 ** This callback is called by the global ADC ISR whenever an ADC triggers a
 ** pulse detection interrupt. It calls the callback function that has been
 ** setup during ADC initialization (see Adc12b_Init()).
 **
 ** \param [in] pstcAdc           ADC unit instance that caused the interrupt.
 ** \param [in] pstcAdcInternData Internal data associated with the ADC instance
 **
 *****************************************************************************/
void Adc12bIrqHandlerGroupInt(volatile stc_adc12b0_t* pstcAdc,
                                     stc_adc12b_intern_data_t* pstcInternData)
{
    stc_adc12b_channel_list_t stcDetectList = { 0 };
    stc_adc12b_channel_list_t stcIntDetectList = { 0 };

    /* Check interrupt flags */
    (void) Adc12b_GetGroupIntInterruptFlag(pstcAdc, &stcDetectList);

    stcIntDetectList.stcChannel[0].u32reg =
            stcDetectList.stcChannel[0].u32reg & pstcInternData->stcGrpIntEnableChList.stcChannel[0].u32reg;
    stcIntDetectList.stcChannel[1].u32reg =
            stcDetectList.stcChannel[1].u32reg & pstcInternData->stcGrpIntEnableChList.stcChannel[1].u32reg;

    if (stcIntDetectList.stcChannel[0].u32reg != 0 ||
        stcIntDetectList.stcChannel[1].u32reg != 0 )
    {
        /* Clear interrupt flags */
        Adc12b_ClearGroupIntInterruptFlag(pstcAdc, stcIntDetectList);
        if (pstcInternData->pfnGrpIntCallback != NULL)
        {
            pstcInternData->pfnGrpIntCallback(stcIntDetectList);
        }
    }
}

/**
 *****************************************************************************
 ** \brief ISR callback for Pulse Detection.
 **
 ** This callback is called by the global ADC ISR whenever an ADC triggers a
 ** pulse detection interrupt. It calls the callback function that has been
 ** setup during ADC initialization (see Adc12b_Init()).
 **
 ** \param [in] pstcAdc           ADC unit instance that caused the interrupt.
 ** \param [in] pstcAdcInternData Internal data associated with the ADC instance
 **
 *****************************************************************************/
void Adc12bIrqHandlerPulseDetection(volatile stc_adc12b0_t* pstcAdc,
                                           stc_adc12b_intern_data_t* pstcInternData)
{
    stc_adc12b_channel_list_t stcDetectList = { 0 };
    stc_adc12b_channel_list_t stcIntDetectList = { 0 };

    /* Check interrupt flags */
    (void) Adc12b_GetPulseDetectionInterruptFlag(pstcAdc, &stcDetectList);

    stcIntDetectList.stcChannel[0].u32reg =
            stcDetectList.stcChannel[0].u32reg & pstcInternData->stcPulseDetectionIntEnableChList.stcChannel[0].u32reg;
    stcIntDetectList.stcChannel[1].u32reg =
            stcDetectList.stcChannel[1].u32reg & pstcInternData->stcPulseDetectionIntEnableChList.stcChannel[1].u32reg;

    if (stcIntDetectList.stcChannel[0].u32reg != 0 ||
        stcIntDetectList.stcChannel[1].u32reg != 0 )
    {
        /* Clear interrupt flags */
        Adc12b_ClearPulseDetectionInterruptFlag(pstcAdc, stcIntDetectList);
        if (pstcInternData->pfnPulseDetectionCallback != NULL)
        {
            pstcInternData->pfnPulseDetectionCallback(stcIntDetectList);
        }
    }
}

/**
 *****************************************************************************
 ** \brief ISR callback for Range Comparison.
 **
 ** This callback is called by the global ADC ISR whenever an ADC triggers a
 ** Range Comparison interrupt. It calls the callback function that has been
 ** setup during ADC initialization (see Adc12b_Init()).
 **
 ** \param [in] pstcAdc           ADC unit instance that caused the interrupt.
 ** \param [in] pstcAdcInternData Internal data associated with the ADC instance
 **
 *****************************************************************************/
void Adc12bIrqHandlerRangeComparator(volatile stc_adc12b0_t* pstcAdc,
                                            stc_adc12b_intern_data_t* pstcInternData)
{
    stc_adc12b_channel_list_t stcDetectList = { 0 };
    stc_adc12b_channel_list_t stcExcessFlags = { 0 };
    stc_adc12b_channel_list_t stcIntDetectList = { 0 };

    (void) Adc12b_GetRangeCompInterruptFlag(pstcAdc, &stcDetectList,
                                            &stcExcessFlags);

    stcIntDetectList.stcChannel[0].u32reg =
            stcDetectList.stcChannel[0].u32reg & pstcInternData->stcRangeCompIntEnableChList.stcChannel[0].u32reg;
    stcIntDetectList.stcChannel[1].u32reg =
            stcDetectList.stcChannel[1].u32reg & pstcInternData->stcRangeCompIntEnableChList.stcChannel[1].u32reg;

    /* Check interrupt flags (Mask only interrupt enabled channels) */
    if (stcIntDetectList.stcChannel[0].u32reg != 0 ||
        stcIntDetectList.stcChannel[1].u32reg != 0)
    {
        /* clear range comparator interrupt flag */
        (void) Adc12b_ClearRangeCompInterruptFlag(pstcAdc, stcIntDetectList);

        /* call callback function */
        if (pstcInternData->pfnRangeComparatorCallback != NULL)
        {
            pstcInternData->pfnRangeComparatorCallback(stcIntDetectList,
                                                       stcExcessFlags);
        }
    }
}

/**
 *****************************************************************************
 ** \brief Initialize the ADC.
 **
 ** This function sets the mode parameters of the global ADC configuration that are needed
 ** for doing conversions.
 ** Configurations for comparison time, resumption time, sampling time
 ** and other compensation settings are done with follows:
 **     -Adc12b_SetComparisonTime()
 **     -Adc12b_SetResumptionTime()
 **     -Adc12b_SetSamplingTime()
 **     -Adc12b_SetOffsetCompensation()
 **     -Adc12b_SetGainCompensation()
 ** The configuration for range comparison is done with follows:
 **     -Adc12b_SetRangeCompConfig()
 **     -Adc12b_SetRangeCompThresholds()
 **     -Adc12b_SetFullRangeCompThresholds()
 ** The configuration for each channels is done with follows:
 **     -Adc12b_SetChannelConfig()
 **
 ** \param [in]  pstcAdc    ADC unit instance.
 ** \param [in]  pstcConfig ADC configuration. See #stc_adc12b_config_t.
 **
 ** \retval Ok              ADC has been initialized.
 ** \retval ErrorInvalidParameter If one of the following conditions is met:
 **             - pstcConfig == NULL
 **             - pstcAdc == NULL
 **             - pstcInternData == NULL (pstcAdc is an invalid address)
 **                 i.e. invalid or disabled ADC unit (PDL_PERIPHERAL_ENABLE_ADC12B)
 *****************************************************************************/
en_result_t Adc12b_Init(volatile stc_adc12b0_t* pstcAdc,
                        const stc_adc12b_config_t* pstcConfig)
{
    stc_adc12b_intern_data_t* pstcInternData;
    un_adc12b0_ctrl_t unCTRL = { 0 };

    /* check parameters */
    if ((pstcAdc == NULL) || (pstcConfig == NULL))
    {
        return ErrorInvalidParameter;
    }

    pstcInternData = Adc12bGetInternDataPtr(pstcAdc);
    if (pstcInternData == NULL)
    {
        return ErrorInvalidParameter;
    }

    /* store callback functions */
    pstcInternData->pfnEofConversionCallback =
            pstcConfig->pfnEofConversionCallback;
    pstcInternData->pfnGrpIntCallback =
            pstcConfig->pfnGprIntCallback;
    pstcInternData->pfnPulseDetectionCallback =
            pstcConfig->pfnPulseDetectionCallback;
    pstcInternData->pfnRangeComparatorCallback =
            pstcConfig->pfnRangeComparatorCallback;

    /* Stop all channels for initializing*/
    pstcAdc->unTRGCL0.u32Register = 0xFFFFFFFF;
    pstcAdc->unTRGCL1.u32Register = 0xFFFFFFFF;

    /* TODO: Is this method for waiting valid? */
    while ((pstcAdc->unTRGST0.u32Register == 0) && (pstcAdc->unTRGST0.u32Register == 1))
    {
        /* wait until conversion end. */
    }

    /* Clear all (interrupt) flags */
    /* AD conversion done interrupt flag */
    pstcAdc->unCDONEIRQC0.u32Register = 0xFFFFFFFF;
    pstcAdc->unCDONEIRQC1.u32Register = 0xFFFFFFFF;
    /* Group interrupted interrupt flags */
    pstcAdc->unGRPIRQC0.u32Register = 0xFFFFFFFF;
    pstcAdc->unGRPIRQC1.u32Register = 0xFFFFFFFF;
    /* Range comparator interrupt flags */
    pstcAdc->unRCIRQC0.u32Register = 0xFFFFFFFF;
    pstcAdc->unRCIRQC1.u32Register = 0xFFFFFFFF;
    /* Pulse Counter Interrupt flags */
    pstcAdc->unPCIRQC0.u32Register = 0xFFFFFFFF;
    pstcAdc->unPCIRQC1.u32Register = 0xFFFFFFFF;
    /* Trigger overrun flags */
    pstcAdc->unTRGORC0.u32Register = 0xFFFFFFFF;
    pstcAdc->unTRGORC1.u32Register = 0xFFFFFFFF;

    /* CTRL settings */
    /* Power down disable mode */
    unCTRL.stcField.u1PDDMD = (pstcConfig->bPowerDownDisable != FALSE) ? 1 : 0;
    /* Full Range Comparator mode */
    unCTRL.stcField.u1FRCMD = pstcConfig->enRangeComparatorMode;
    /* Forced stop mode */
    unCTRL.stcField.u1FSMD = (pstcConfig->bEnableForcedStop != FALSE) ? 1 : 0;
    /* ACH mode */
    unCTRL.stcField.u1ACHMD = pstcConfig->enAchMode;
    /* Debug mode */
    unCTRL.stcField.u1DBGE = (pstcConfig->bEnableDebugMode != FALSE) ? 1 : 0;
    /* Resolution */
    unCTRL.stcField.u2RES = pstcConfig->enResolution;
    /* Finally set to hardware register */
    pstcAdc->unCTRL.u16Register = unCTRL.u16Register;

    return Ok;
}

/**
 *****************************************************************************
 ** \brief Set channel individual configurations.
 **
 ** This function sets the configurations for a channel.
 **
 ** \pre  ADC must be in idle state. (otherwise ErrorOperationInProgress is returned)
 **
 ** \param [in]  pstcAdc            ADC unit instance.
 ** \param [in]  u8Channel          Analog channel (0.. ADC12B_MAX_CHANNEL_COUNT -1)
 ** \param [in]  pstcConfig         Channel configurations. See #stc_adc12b_channel_config_t.
 **
 ** \retval Ok                       Successfully done.
 ** \retval ErrorOperationInProgress If ADC is not idle.
 ** \retval ErrorInvalidParameter    If one of the following conditions are met:
 **                                     - pstcAdc == NULL.
 **                                     - pstcConfig == NULL
 **                                     - u8Channel is over maximum channel number.
 **                                     - u8SamplingTimeRegNum is over maximum register number.
 **                                     - pstcInternData == NULL (pstcAdc is an invalid address)
 **                                       i.e. invalid or disabled ADC unit (PDL_PERIPHERAL_ENABLE_ADC12B)
 *****************************************************************************/
en_result_t Adc12b_SetChannelConfig(volatile stc_adc12b0_t* pstcAdc,
                                    uint8_t u8Channel,
                                    const stc_adc12b_channel_config_t* pstcConfig)
{
    stc_adc12b_intern_data_t *pstcInternData;
    volatile un_adc12b0_chctrln_t * punCHCTRL;

    /* check parameters */
    if (pstcAdc == NULL || pstcConfig == NULL || u8Channel >= ADC12B_MAX_CHANNEL_COUNT)
    {
        return ErrorInvalidParameter;
    }
    pstcInternData = Adc12bGetInternDataPtr(pstcAdc);
    if (pstcInternData == NULL)
    {
        return ErrorInvalidParameter;
    }

    /* check parameters */
    if (pstcAdc == NULL || pstcConfig == NULL || u8Channel >= ADC12B_MAX_CHANNEL_COUNT)
    {
        return ErrorInvalidParameter;
    }

    /* Check if conversion is in progress */
    if (pstcAdc->unTRGST0.u32Register != 0 || pstcAdc->unTRGST1.u32Register != 0)
    {
        return ErrorOperationInProgress;
    }
    if (pstcConfig->u8SamplingTimeRegNum >= ADC12B_SAMPLING_TIME_REGISTER_NUM)
    {
        return ErrorInvalidParameter;
    }

    /* set CHCTRL pointer */
    punCHCTRL = &pstcAdc->unCHCTRL0;

    /* Physical channel selection */
    punCHCTRL[u8Channel].stcField.u6ANIN = pstcConfig->u8PhysicalCh;
    /* Trigger type selection */
    punCHCTRL[u8Channel].stcField.u2TRGTYP = pstcConfig->enTriggerType;
    /* Set priority */
    punCHCTRL[u8Channel].stcField.u4CHPRI = pstcConfig->u8Priority;
    /* Set resume mode */
    punCHCTRL[u8Channel].stcField.u2RSMRST = pstcConfig->enResumeMode;
    /* Set data protection */
    punCHCTRL[u8Channel].stcField.u1DP = (pstcConfig->bDataProtection != FALSE) ? 1 : 0;
    /* Select sampling time */
    punCHCTRL[u8Channel].stcField.u2SMTIME = pstcConfig->u8SamplingTimeRegNum;

    /* Set interrupt setting */
    if (u8Channel < ADC12B_MAX_CHANNEL_PER_REG)
    {
        /* Lower 32ch */
        /* Conversion done interrupt setting */
        if (pstcConfig->bUseConversionDoneInterrupt != FALSE)
        {
            pstcAdc->unCDONEIRQE0.u32Register |= (1 << u8Channel);
            pstcInternData->stcEofConvIntEnableChList.stcChannel[0].u32reg |= (1 << u8Channel);
        }
        else
        {
            pstcAdc->unCDONEIRQE0.u32Register &= ~((uint32_t)1 << u8Channel);
            pstcInternData->stcEofConvIntEnableChList.stcChannel[0].u32reg &= ~((uint32_t)1 << u8Channel);
        }
        /* Group interrupted interrupt setting */
        if (pstcConfig->bUseGroupInterruptedInterrupt != FALSE)
        {
            pstcAdc->unGRPIRQE0.u32Register |= (1 << u8Channel);
            pstcInternData->stcGrpIntEnableChList.stcChannel[0].u32reg |= (1 << u8Channel);
        }
        else
        {
            pstcAdc->unGRPIRQE0.u32Register &= ~((uint32_t)1 << u8Channel);
            pstcInternData->stcGrpIntEnableChList.stcChannel[0].u32reg &= ~((uint32_t)1 << u8Channel);
        }
    }
    else
    {
        /* Upper 32ch */
        /* Conversion done interrupt setting */
        if (pstcConfig->bUseConversionDoneInterrupt != FALSE)
        {
            pstcAdc->unCDONEIRQE1.u32Register |= (1 << (u8Channel - ADC12B_MAX_CHANNEL_PER_REG));
            pstcInternData->stcEofConvIntEnableChList.stcChannel[1].u32reg |= (1 << (u8Channel - ADC12B_MAX_CHANNEL_PER_REG));
        }
        else
        {
            pstcAdc->unCDONEIRQE1.u32Register &= ~((uint32_t)1 << (u8Channel - ADC12B_MAX_CHANNEL_PER_REG));
            pstcInternData->stcEofConvIntEnableChList.stcChannel[1].u32reg &= ~((uint32_t)1 << (u8Channel - ADC12B_MAX_CHANNEL_PER_REG));
        }
        /* Group interrupted interrupt setting */
        if (pstcConfig->bUseGroupInterruptedInterrupt != FALSE)
        {
            pstcAdc->unGRPIRQE1.u32Register |= (1 << (u8Channel - ADC12B_MAX_CHANNEL_PER_REG));
            pstcInternData->stcGrpIntEnableChList.stcChannel[1].u32reg |= (1 << (u8Channel - ADC12B_MAX_CHANNEL_PER_REG));
        }
        else
        {
            pstcAdc->unGRPIRQE1.u32Register &= ~((uint32_t)1 << (u8Channel - ADC12B_MAX_CHANNEL_PER_REG));
            pstcInternData->stcGrpIntEnableChList.stcChannel[1].u32reg &= ~((uint32_t)1 << (u8Channel - ADC12B_MAX_CHANNEL_PER_REG));
        }
    }

    return Ok;
}


/**
 *****************************************************************************
 ** \brief Set comparison time.
 **
 ** This function sets comparison time.
 **
 ** \param [in]  pstcAdc             ADC unit instance.
 ** \param [in]  u16ComparisonTime   Comparison time.
 **                                  For valid setting, please refer device data sheet.
 **
 ** \retval Ok                       Successfully done.
 ** \retval ErrorOperationInProgress ADC conversion is in progress.
 ** \retval ErrorInvalidParameter    If pstcAdc == NULL.
 **                                  u16ComparisonTime < ADC12B_MIN_COMPARISON_TIME
 *****************************************************************************/
en_result_t Adc12b_SetComparisonTime(volatile stc_adc12b0_t* pstcAdc,
                                     uint16_t u16ComparisonTime)
{
    /* check parameters */
    if (pstcAdc == NULL)
    {
        return ErrorInvalidParameter;
    }
    if (u16ComparisonTime < ADC12B_MIN_COMPARISON_TIME)
    {
        return ErrorInvalidParameter;
    }
    /* Check if conversion is in progress */
    if (pstcAdc->unTRGST0.u32Register != 0 || pstcAdc->unTRGST1.u32Register != 0)
    {
        return ErrorOperationInProgress;
    }

    pstcAdc->unCT.u16Register = u16ComparisonTime;

    return Ok;
}

/**
 *****************************************************************************
 ** \brief Set resumption time.
 **
 ** This function sets resumption time.
 **
 ** \param [in]  pstcAdc             ADC unit instance.
 ** \param [in]  u8ResumptionTime    Resumption time.
 **                                  For valid setting, please refer device data sheet.
 **
 ** \retval Ok                       Successfully done.
 ** \retval ErrorOperationInProgress ADC conversion is in progress.
 ** \retval ErrorInvalidParameter    If pstcAdc == NULL.
 **                                  u16ComparisonTime < ADC12B_MIN_RESUMPTION_TIME
 *****************************************************************************/
en_result_t Adc12b_SetResumptionTime(volatile stc_adc12b0_t* pstcAdc,
                                     uint8_t u8ResumptionTime)
{
    /* check parameters */
    if (pstcAdc == NULL)
    {
        return ErrorInvalidParameter;
    }
    if (u8ResumptionTime < ADC12B_MIN_RESUMPTION_TIME)
    {
        return ErrorInvalidParameter;
    }
    /* Check if conversion is in progress */
    if (pstcAdc->unTRGST0.u32Register != 0 || pstcAdc->unTRGST1.u32Register != 0)
    {
        return ErrorOperationInProgress;
    }

    pstcAdc->unRT.u16Register= (uint16_t)u8ResumptionTime;

    return Ok;
}


/**
 *****************************************************************************
 ** \brief Set sampling time.
 **
 ** This function sets sampling time.
 **
 ** \param [in]  pstcAdc             ADC unit instance.
 ** \param [in]  u8RegNum            Register number to set sampling time.
 ** \param [in]  u16SamplingTime     Sampling time.
 **                                  For valid setting, please refer device data sheet.
 **
 ** \retval Ok                       Successfully done.
 ** \retval ErrorOperationInProgress ADC conversion is in progress.
 ** \retval ErrorInvalidParameter    If pstcAdc == NULL.
 **                                  u16ComparisonTime < ADC12B_MIN_SAMPLING_TIME
 **                                  u8RegNum >= ADC12B_SAMPLING_TIME_REGISTER_NUM
 *****************************************************************************/
en_result_t Adc12b_SetSamplingTime(volatile stc_adc12b0_t* pstcAdc,
                                   uint8_t u8RegNum,
                                   uint16_t u16SamplingTime)
{
    volatile un_adc12b0_stn_t *unST;

    /* check parameters */
    if (pstcAdc == NULL)
    {
        return ErrorInvalidParameter;
    }
    if (u8RegNum >= ADC12B_SAMPLING_TIME_REGISTER_NUM)
    {
        return ErrorInvalidParameter;
    }
    if (u16SamplingTime < ADC12B_MIN_SAMPLING_TIME)
    {
        return ErrorInvalidParameter;
    }
    /* Check if conversion is in progress */
    if (pstcAdc->unTRGST0.u32Register != 0 || pstcAdc->unTRGST1.u32Register != 0)
    {
        return ErrorOperationInProgress;
    }

    unST = &pstcAdc->unST0;
    unST[u8RegNum].u16Register = u16SamplingTime;

    return Ok;
}

/**
 *****************************************************************************
 ** \brief Set offset compensation value.
 **
 ** This function sets offset compensation value.
 **
 ** \param [in]  pstcAdc             ADC unit instance.
 ** \param [in]  u8OffsetCompensationValue    Offset compensation value.
 **                                           For setting value calculation, please refer device HWM.
 **
 ** \retval Ok                       Successfully done.
 ** \retval ErrorInvalidParameter    If pstcAdc == NULL.
 *****************************************************************************/
en_result_t Adc12b_SetOffsetCompensation(volatile stc_adc12b0_t* pstcAdc,
                                         uint8_t u8OffsetCompensationValue)
{
    /* check parameters */
    if (pstcAdc == NULL)
    {
        return ErrorInvalidParameter;
    }

    pstcAdc->unOCV.u16Register = (uint16_t)u8OffsetCompensationValue;
    return Ok;
}

/**
 *****************************************************************************
 ** \brief Set gain compensation value.
 **
 ** This function sets gain compensation value.
 **
 ** \param [in]  pstcAdc             ADC unit instance.
 ** \param [in]  u8GainCompensationValue    gain compensation value.
 **                                         For setting value calculation, please refer device HWM.
 **
 ** \retval Ok                       Successfully done.
 ** \retval ErrorInvalidParameter    If pstcAdc == NULL.
 **                                  u8GainCompensationValue > ADC12B_MAX_GAIN_COMP_VALUE
 *****************************************************************************/
en_result_t Adc12b_SetGainCompensation(volatile stc_adc12b0_t* pstcAdc,
                                       uint8_t u8GainCompensationValue)
{
    /* check parameters */
    if (pstcAdc == NULL)
    {
        return ErrorInvalidParameter;
    }
    if (u8GainCompensationValue > ADC12B_MAX_GAIN_COMP_VALUE)
    {
        return ErrorInvalidParameter;
    }

    pstcAdc->unGCV.u16Register = (uint16_t)u8GainCompensationValue;
    return Ok;
}

/**
 *****************************************************************************
 ** \brief Get conversion completion status.
 **
 ** \param [in]  pstcAdc                ADC unit instance.
 ** \param [out] pstcChannelStatusList  Conversion completion status list.
 **                                     If a bit = 1, indicates conversion of corresponding
 **                                     channel has completed.
 **
 ** \retval Ok                      Successfully done.
 ** \retval ErrorInvalidParameter   If one of the following conditions is met:
 **             - pstcAdc == NULL
 **             - pstcChannelStatusList == NULL
 *****************************************************************************/
en_result_t Adc12b_GetConversionInterruptFlag(volatile stc_adc12b0_t* pstcAdc,
                                              stc_adc12b_channel_list_t *pstcChannelStatusList)
{
    if ((pstcAdc == NULL) || (pstcChannelStatusList == NULL))
    {
        return ErrorInvalidParameter;
    }

    /* Check conversion status */
    pstcChannelStatusList->stcChannel[0].u32reg = pstcAdc->unCDONEIRQ0.u32Register;
    pstcChannelStatusList->stcChannel[1].u32reg = pstcAdc->unCDONEIRQ1.u32Register;

    return Ok;
}

/**
 *****************************************************************************
 ** \brief Clear end of conversion interrupt flag.
 **
 ** \param [in]  pstcAdc            ADC unit instance.
 ** \param [in]  stcClearChList     Channel list of interrupt flag clear target.
 **                                 If a bit = 1, end of conversion interrupt flag of corresponding
 **                                 channel will be cleared.
 **
 ** \retval Ok                      Successfully done.
 ** \retval ErrorInvalidParameter   pstcAdc == NULL
 *****************************************************************************/
en_result_t Adc12b_ClearConversionInterruptFlag(volatile stc_adc12b0_t* pstcAdc,
                                                stc_adc12b_channel_list_t stcClearChList)
{
    /* check parameters */
    if (pstcAdc == NULL)
    {
        return ErrorInvalidParameter;
    }
    pstcAdc->unCDONEIRQC0.u32Register = stcClearChList.stcChannel[0].u32reg;
    pstcAdc->unCDONEIRQC1.u32Register = stcClearChList.stcChannel[1].u32reg;

    return Ok;
}

/**
 *****************************************************************************
 ** \brief Get trigger overrun status.
 **
 ** \param [in]  pstcAdc                ADC unit instance.
 ** \param [out] pstcChannelStatusList  Trigger overrun status list.
 **                                     If a bit = 1,
 **                                     trigger overrun has occurred.
 **
 ** \retval Ok                      Successfully done.
 ** \retval ErrorInvalidParameter   If one of the following conditions is met:
 **             - pstcAdc == NULL
 **             - pstcChannelStatusList == NULL
 *****************************************************************************/
en_result_t Adc12b_GetTriggerOverrunStatus(volatile stc_adc12b0_t* pstcAdc,
                                           stc_adc12b_channel_list_t *pstcChannelStatusList)
{
    if ((pstcAdc == NULL) || (pstcChannelStatusList == NULL))
    {
        return ErrorInvalidParameter;
    }

    /* Check conversion status */
    pstcChannelStatusList->stcChannel[0].u32reg = pstcAdc->unTRGOR0.u32Register;
    pstcChannelStatusList->stcChannel[1].u32reg = pstcAdc->unTRGOR1.u32Register;

    return Ok;
}

/**
 *****************************************************************************
 ** \brief Clear trigger overrun status flag.
 **
 ** \param [in]  pstcAdc            ADC unit instance.
 ** \param [in]  stcClearChList     Channel list to clear trigger overrun status.
 **                                 If a bit = 1, trigger overrun flag of corresponding
 **                                 channel will be cleared.
 **
 ** \retval Ok                      Successfully done.
 ** \retval ErrorInvalidParameter   pstcAdc == NULL
 *****************************************************************************/
en_result_t Adc12b_ClearTriggerOverrunStatus(volatile stc_adc12b0_t* pstcAdc,
                                             stc_adc12b_channel_list_t stcClearChList)
{
    /* check parameters */
    if (pstcAdc == NULL)
    {
        return ErrorInvalidParameter;
    }
    pstcAdc->unTRGORC0.u32Register = stcClearChList.stcChannel[0].u32reg;
    pstcAdc->unTRGORC1.u32Register = stcClearChList.stcChannel[1].u32reg;

    return Ok;
}

/**
 *****************************************************************************
 ** \brief Get conversion data.
 **
 ** \param [in]  pstcAdc            ADC unit instance.
 ** \param [in]  u8Channel          Analog channel (0.. ADC12B_MAX_CHANNEL_COUNT -1)
 ** \param [out] pu16Result         Conversion data pointer.
 **
 ** \retval Ok                      Successfully done.
 ** \retval ErrorInvalidParameter   If one of the following conditions is met:
 **             - pstcAdc == NULL
 **             - pu16Result == NULL
 **             - u8Channel is over maximum channel number
 *****************************************************************************/
en_result_t Adc12b_GetConversionData(volatile stc_adc12b0_t* pstcAdc,
                                     uint8_t u8Channel,
                                     uint16_t *pu16Result)
{
    volatile un_adc12b0_cdn_t *punCDN;

    /* check parameters */
    /* check parameters */
    if (pstcAdc == NULL || pu16Result == NULL || u8Channel >= ADC12B_MAX_CHANNEL_COUNT)
    {
        return ErrorInvalidParameter;
    }

    /* copy result */
    punCDN = &pstcAdc->unCD0;
    *pu16Result = punCDN[u8Channel].u16Register;

    return Ok;
}

/**
 *****************************************************************************
 ** \brief Trigger ADC conversion by software.
 **
 ** \param [in]  pstcAdc            ADC unit instance. ADC0_Type or ADC1_Type are valid.
 ** \param [in]  u8Channel          Logical channel to trigger conversion.
 **
 ** \retval Ok                      Successfully done.
 ** \return ErrorInvalidParameter   If one of the following conditions are met:
 **                                 - pstcAdc == NULL.
 *****************************************************************************/
en_result_t Adc12b_TriggerConversion(volatile stc_adc12b0_t* pstcAdc,
                                  uint8_t u8Channel)
{
    volatile un_adc12b0_chctrln_t *punCHCTRLN;

    /* check parameters */
    if (pstcAdc == NULL)
    {
        return ErrorInvalidParameter;
    }

    punCHCTRLN = &pstcAdc->unCHCTRL0;
    /* Trigger conversion */
    punCHCTRLN[u8Channel].stcField.u1SWTRG = 1;

    return Ok;
}


/**
 *****************************************************************************
 ** \brief Clear trigger status.
 **
 ** \param [in]  pstcAdc            ADC unit instance.
 ** \param [in]  stcChannelList     List of channels to clear trigger status.
 **                                 If a bit = 1, corresponding channel trigger status will be
 **                                 cleared.
 **
 ** \retval Ok                      Successfully done.
 ** \return ErrorInvalidParameter   If pstcAdc == NULL.
 *****************************************************************************/
en_result_t Adc12b_ClearTrigger(volatile stc_adc12b0_t* pstcAdc,
                                stc_adc12b_channel_list_t stcClearChList)
{
    /* check parameters */
    if (pstcAdc == NULL)
    {
        return ErrorInvalidParameter;
    }
    pstcAdc->unTRGCL0.u32Register = stcClearChList.stcChannel[0].u32reg;
    pstcAdc->unTRGCL1.u32Register = stcClearChList.stcChannel[1].u32reg;

    return Ok;
}


/**
 *****************************************************************************
 ** \brief Force stop.
 **
 ** This function force stop ADC.
 **
 ** \param [in]  pstcAdc            ADC unit instance.
 **
 ** \retval Ok                       Successfully done.
 ** \retval ErrorInvalidMode         ADC FSMD mode is not force stop mode.
 ** \retval ErrorInvalidParameter    If pstcAdc == NULL.
 *****************************************************************************/
en_result_t Adc12b_ForceStop(volatile stc_adc12b0_t* pstcAdc)
{
    /* check parameters */
    if (pstcAdc == NULL)
    {
        return ErrorInvalidParameter;
    }
    if (pstcAdc->unCTRL.stcField.u1FSMD == 0)
    {
        return ErrorInvalidMode;
    }
    pstcAdc->unCTRL.stcField.u1FSTP = 1;
    return Ok;
}

/**
 *****************************************************************************
 ** \brief Configure ADC Range Comparator for one channel.
 **
 ** This function sets the configuration for the Range Comparator for a channel.
 ** It assigns one of the available range comparators to the specified channel.
 ** Adc12b_SetRangeCompThresholds() or Adc12b_SetFullRangeCompThresholds()
 ** should be called as well to set the bounds for the range comparison.
 **
 ** \param [in]  pstcAdc        ADC unit instance.
 ** \param [in]  u8Channel      analog channel (0.. ADC12B_MAX_CHANNEL_COUNT -1)
 ** \param [in]  pstcConfig     ADC channel configuration. See #stc_adc12b_range_comparator_config_t
 **
 ** \retval Ok                  Channel was configured.
 ** \retval ErrorInvalidParameter     If one of the following conditions is met:
 **             - u8Channel >= ADC12B_MAX_CHANNEL_COUNT
 **             - pstcAdc == NULL
 **             - pstcConfig == NULL
 **             - pstcInternData == NULL (pstcAdc is an invalid address)
 **                 i.e. invalid or disabled ADC unit (PDL_PERIPHERAL_ENABLE_ADC12B)
 **             - pstcConfig->u8RangeComparator >= ADC12B_RANGE_COMP_REGISTER_NUM
 *****************************************************************************/
en_result_t Adc12b_SetRangeCompConfig(volatile stc_adc12b0_t* pstcAdc,
        uint8_t u8Channel, const stc_adc12b_range_comparator_config_t* pstcConfig)
{
    stc_adc12b_intern_data_t *pstcInternData;
    volatile un_adc12b0_chctrln_t *punCHCTRL;
    un_adc12b0_rcirqe0_t unRCIRQE0;
    un_adc12b0_rcirqe1_t unRCIRQE1;

    /* check parameters */
    if (pstcAdc == NULL || pstcConfig == NULL || u8Channel >= ADC12B_MAX_CHANNEL_COUNT)
    {
        return ErrorInvalidParameter;
    }
    pstcInternData = Adc12bGetInternDataPtr(pstcAdc);
    if (pstcInternData == NULL)
    {
        return ErrorInvalidParameter;
    }
    if (pstcConfig->u8RangeComparator >= ADC12B_RANGE_COMP_REGISTER_NUM)
    {
        return ErrorInvalidParameter;
    }

    /* set CHCTRL pointer */
    punCHCTRL = &pstcAdc->unCHCTRL0;

    if (pstcConfig->bEnable != FALSE)
    {
        /* Enable range comparator */
        /* Read modify write not to change other bits */
        punCHCTRL[u8Channel].stcField.u1RCEN = 1;

        /* Select thresholds pair */
        punCHCTRL[u8Channel].stcField.u3RCSEL = pstcConfig->u8RangeComparator;

        /* Select comparison mode */
        punCHCTRL[u8Channel].stcField.u1RCINVSEL = (pstcConfig->bInsideRangeComparison != FALSE) ? 1 : 0;

        /* Set interrupt setting */
        if (u8Channel < ADC12B_MAX_CHANNEL_PER_REG)
        {
            unRCIRQE0.u32Register = pstcAdc->unRCIRQE0.u32Register;
            unRCIRQE0.u32Register &= ~((uint32_t)1 << u8Channel);
            unRCIRQE0.u32Register |= (pstcConfig->bUseInterrupt != FALSE) ? (1 << u8Channel) : 0;
            pstcAdc->unRCIRQE0.u32Register = unRCIRQE0.u32Register;

            pstcInternData->stcRangeCompIntEnableChList.stcChannel[0].u32reg &= ~((uint32_t)1 << u8Channel);
            pstcInternData->stcRangeCompIntEnableChList.stcChannel[0].u32reg |= (pstcConfig->bUseInterrupt != FALSE) ? (1 << u8Channel) : 0;
        }
        else
        {
            unRCIRQE1.u32Register = pstcAdc->unRCIRQE1.u32Register;
            unRCIRQE1.u32Register &= ~((uint32_t)1 << (u8Channel - ADC12B_MAX_CHANNEL_PER_REG));
            unRCIRQE1.u32Register |= (pstcConfig->bUseInterrupt != FALSE) ? (1 << (u8Channel - ADC12B_MAX_CHANNEL_PER_REG)) : 0;
            pstcAdc->unRCIRQE1.u32Register = unRCIRQE1.u32Register;

            pstcInternData->stcRangeCompIntEnableChList.stcChannel[1].u32reg &= ~((uint32_t)1 << u8Channel);
            pstcInternData->stcRangeCompIntEnableChList.stcChannel[1].u32reg |= (pstcConfig->bUseInterrupt != FALSE) ? (1 << u8Channel) : 0;
        }
    }
    else
    {
        /* Disable range comparator */
        /* Read modify write not to change other bits */
        punCHCTRL[u8Channel].stcField.u1RCEN = 0;
    }

    return Ok;
}

/**
 *****************************************************************************
 ** \brief Set thresholds for a Full Range Comparator(12bit mode).
 **
 ** This function sets the thresholds for the a specified Range Comparator.
 **
 ** \param [in]  pstcAdc            ADC unit instance.
 ** \param [in]  u8RegNum           Number of Range comparator register to be configured.
 ** \param [in]  u16UpperThreshold  Upper threshold.
 ** \param [in]  u16LowerThreshold  Lower threshold.
 **
 ** \retval Ok                       Thresholds were set.
 ** \retval ErrorOperationInProgress If ADC is not idle.
 ** \retval ErrorInvalidParameter    If pstcAdc == NULL.
 **                                  u8RegNum >= ADC12B_RANGE_COMP_REGISTER_NUM
 **                                  u16UpperThreshold or u16LowerThreshold
 **                                  over 12bits.
 *****************************************************************************/
en_result_t Adc12b_SetFullRangeCompThresholds(volatile stc_adc12b0_t* pstcAdc,
                                              uint8_t  u8RegNum,
                                              uint16_t u16UpperThreshold,
                                              uint16_t u16LowerThreshold)
{
    volatile un_adc12b0_frcohn_t *punFRCOHN;
    volatile un_adc12b0_frcoln_t *punFRCOLN;

    if (pstcAdc == NULL)
    {
        return ErrorInvalidParameter;
    }
    if (u8RegNum >= ADC12B_RANGE_COMP_REGISTER_NUM)
    {
        return ErrorInvalidParameter;
    }
    if ((u16UpperThreshold > ADC12B_FULL_RANGE_COMP_THRESHOLD_MAX) ||
        (u16LowerThreshold > ADC12B_FULL_RANGE_COMP_THRESHOLD_MAX))
    {
        return ErrorInvalidParameter;
    }

    punFRCOHN = &pstcAdc->unFRCOH0;
    punFRCOLN = &pstcAdc->unFRCOL0;

    punFRCOHN[u8RegNum].u16Register = u16UpperThreshold;
    punFRCOLN[u8RegNum].u16Register = u16LowerThreshold;

    return Ok;
}

/**
 *****************************************************************************
 ** \brief Set thresholds for a Range Comparator (8bit mode).
 **
 ** This function sets the thresholds for the a specified Range Comparator.
 **
 ** \param [in]  pstcAdc             ADC unit instance.
 ** \param [in]  u8RegNum            Number of Range comparator register to be configured.
 ** \param [in]  u8UpperThreshold    Upper threshold.
 ** \param [in]  u8LowerThreshold    Lower threshold.
 **
 ** \retval Ok                       Thresholds were set.
 ** \retval ErrorInvalidParameter    If pstcAdc == NULL.
 **                                  u8RegNum >= ADC12B_RANGE_COMP_REGISTER_NUM
 *****************************************************************************/
en_result_t Adc12b_SetRangeCompThresholds(volatile stc_adc12b0_t* pstcAdc,
                                          uint8_t u8RegNum,
                                          uint8_t u8UpperThreshold,
                                          uint8_t u8LowerThreshold)
{
    volatile stc_adc12b_rco_threshold_reg_t *pstcRCOREG;

    if (pstcAdc == NULL)
    {
        return ErrorInvalidParameter;
    }
    if (u8RegNum >= ADC12B_RANGE_COMP_REGISTER_NUM)
    {
        return ErrorInvalidParameter;
    }

    pstcRCOREG = (volatile stc_adc12b_rco_threshold_reg_t *)&pstcAdc->unRCOL0;
    pstcRCOREG[u8RegNum].unRCOHN.u8Register = u8UpperThreshold;
    pstcRCOREG[u8RegNum].unRCOLN.u8Register = u8LowerThreshold;

    return Ok;
}


/**
 *****************************************************************************
 ** \brief Get range comparator status.
 **
 ** \param [in]  pstcAdc            ADC unit instance.
 ** \param [out] pstcDetectChList   Range comparison interrupt detection channel list.
 **                                 If a bit = 1, range comparison interrupt of corresponding
 **                                 channel has detected.
 **                                 If a bit = 0, range comparison interrupt of corresponding
 **                                 channel has not detected.
 ** \param [out] pstcExcessFlags    List of Range comparison threshold excess status list.
 **                                 If a bit = 1, corresponding channel detected over threshold.
 **                                 If a bit = 0, corresponding channel detected under threshold.
 **                                 This value is effective only when stc_adc12b_range_comparator_config_t
 **                                 bInsideRangeComparison = false.

 ** \retval Ok                      Getting of range comparator status is successfully done.
 ** \retval ErrorInvalidParameter   If one of the following conditions is met:
 **             - pstcAdc == NULL
 **             - pstcDetectChList == NULL
 **             - pstcExcessFlags == NULL
 *****************************************************************************/
en_result_t Adc12b_GetRangeCompInterruptFlag(volatile stc_adc12b0_t* pstcAdc,
                                             stc_adc12b_channel_list_t* pstcDetectChList,
                                             stc_adc12b_channel_list_t* pstcExcessFlags)
{
    if ((pstcAdc == NULL) || (pstcDetectChList == NULL)
            || (pstcExcessFlags == NULL))
    {
        return ErrorInvalidParameter;
    }

    pstcDetectChList->stcChannel[0].u32reg = pstcAdc->unRCIRQ0.u32Register;
    pstcDetectChList->stcChannel[1].u32reg = pstcAdc->unRCIRQ1.u32Register;
    pstcExcessFlags->stcChannel[0].u32reg = pstcAdc->unRCOTF0.u32Register;
    pstcExcessFlags->stcChannel[1].u32reg = pstcAdc->unRCOTF1.u32Register;

    return Ok;
}

/**
 *****************************************************************************
 ** \brief Clear range comparator interrupt flag.
 **
 ** \param [in]  pstcAdc            ADC unit instance.
 ** \param [in]  stcClearChList     Channel list of range comparison interrupt flag clear target.
 **                                 If a bit = 1, range comparison interrupt flag of corresponding
 **                                 channel will be cleared.
 **
 ** \retval Ok                      Successfully done.
 ** \retval ErrorInvalidParameter   pstcAdc == NULL
 *****************************************************************************/
en_result_t Adc12b_ClearRangeCompInterruptFlag(volatile stc_adc12b0_t* pstcAdc,
                                               stc_adc12b_channel_list_t stcClearChList)
{
    if (pstcAdc == NULL)
    {
        return ErrorInvalidParameter;
    }

    PDL_WRITE_REG_SYNC(pstcAdc->unRCIRQC0.u32Register, stcClearChList.stcChannel[0].u32reg);
    PDL_WRITE_REG_SYNC(pstcAdc->unRCIRQC1.u32Register, stcClearChList.stcChannel[1].u32reg);
    return Ok;
}

/**
 *****************************************************************************
 ** \brief Configure pulse detection for one channel.
 **
 ** This function sets the configuration for the pulse detection for a channel.
 ** Adc12b_SetRangeCompThresholds() or Adc12b_SetFullRangeCompThresholds should be
 ** called as well to set the bounds.
 **
 ** \param [in]  pstcAdc        ADC unit instance.
 ** \param [in]  u8Channel      analog channel (0.. ADC12B_MAX_CHANNEL_COUNT -1)
 ** \param [in]  pstcConfig     ADC channel configuration. See #stc_adc12b_pulse_detection_config_t
 **
 ** \retval Ok                  Channel was configured.
 ** \retval ErrorInvalidParameter     If one of the following conditions is met:
 **             - u8Channel >= ADC12B_MAX_CHANNEL_COUNT
 **             - pstcAdc == NULL
 **             - pstcConfig == NULL
 **             - pstcInternData == NULL (pstcAdc is an invalid address)
 **                 i.e. invalid or disabled ADC unit (PDL_PERIPHERAL_ENABLE_ADC12B)
 **             - u8PositiveCounterReloadValue or u8NegativeCounterReloadValue == 0
 **               (Can not be set 0.)
 *****************************************************************************/
en_result_t Adc12b_SetPulseDetectionConfig(volatile stc_adc12b0_t* pstcAdc,
                                           uint8_t u8Channel,
                                           const stc_adc12b_pulse_detection_config_t* pstcConfig)
{
    stc_adc12b_intern_data_t *pstcInternData;
    volatile un_adc12b0_pcctrln_t *punPCCTRLN;
    un_adc12b0_pcctrln_t    unPCCTRLN = { 0 };

    /* check parameters */
    if (pstcAdc == NULL || pstcConfig == NULL || u8Channel >= ADC12B_MAX_CHANNEL_COUNT)
    {
        return ErrorInvalidParameter;
    }

    pstcInternData = Adc12bGetInternDataPtr(pstcAdc);
    if (pstcInternData == NULL)
    {
        return ErrorInvalidParameter;
    }

    if (pstcConfig->u8PositiveCounterReloadValue == 0 ||
        pstcConfig->u8NegativeCounterReloadValue == 0)
    {
        return ErrorInvalidParameter;
    }

    /* set CHCTRL pointer */
    punPCCTRLN = &pstcAdc->unPCCTRL0;

    unPCCTRLN.stcField.u8PCTPRL = pstcConfig->u8PositiveCounterReloadValue;
    unPCCTRLN.stcField.u5PCTNRL = pstcConfig->u8NegativeCounterReloadValue;
    punPCCTRLN[u8Channel].u32Register = unPCCTRLN.u32Register;

    /* Set interrupt setting and reload counter*/
    if (u8Channel < ADC12B_MAX_CHANNEL_PER_REG)
    {
        /* reload counter */
        pstcAdc->unPCIRQC0.u32Register = 1 << u8Channel;

        if (pstcConfig->bUseInterrupt != FALSE)
        {
            pstcAdc->unPCIRQE0.u32Register |= 1 << u8Channel;
            pstcInternData->stcPulseDetectionIntEnableChList.stcChannel[0].u32reg |= 1 << u8Channel;
        }
        else
        {
            pstcAdc->unPCIRQE0.u32Register &= ~((uint32_t)1 << u8Channel);
            pstcInternData->stcPulseDetectionIntEnableChList.stcChannel[0].u32reg &= ~((uint32_t)1 << u8Channel);
        }
    }
    else
    {
        /* reload counter */
        pstcAdc->unPCIRQC1.u32Register = 1 << (u8Channel - ADC12B_MAX_CHANNEL_PER_REG);
        if (pstcConfig->bUseInterrupt != FALSE)
        {
            pstcAdc->unPCIRQE1.u32Register |= 1 << u8Channel;
            pstcInternData->stcPulseDetectionIntEnableChList.stcChannel[1].u32reg |= 1 << (u8Channel - ADC12B_MAX_CHANNEL_PER_REG);
        }
        else
        {
            pstcAdc->unPCIRQE1.u32Register &= ~((uint32_t)1 << u8Channel);
            pstcInternData->stcPulseDetectionIntEnableChList.stcChannel[1].u32reg &= ~((uint32_t)1 << (u8Channel - ADC12B_MAX_CHANNEL_PER_REG));
        }
    }

    return Ok;
}

/**
 *****************************************************************************
 ** \brief Get pulse detection interrupt status.
 **
 ** \param [in]  pstcAdc                ADC unit instance.
 ** \param [out] pstcDetectChList       Pulse detection status list.
 **                                     If a bit = 1,
 **                                     pulse detection interrupt has occurred.
 **
 ** \retval Ok                      Successfully done.
 ** \retval ErrorInvalidParameter   If one of the following conditions is met:
 **             - pstcAdc == NULL
 **             - pstcDetectChList == NULL
 *****************************************************************************/
en_result_t Adc12b_GetPulseDetectionInterruptFlag(volatile stc_adc12b0_t* pstcAdc,
                                                  stc_adc12b_channel_list_t* pstcDetectChList)
{
    if ((pstcAdc == NULL) || (pstcDetectChList == NULL))
    {
        return ErrorInvalidParameter;
    }

    pstcDetectChList->stcChannel[0].u32reg = pstcAdc->unPCIRQ0.u32Register;
    pstcDetectChList->stcChannel[1].u32reg = pstcAdc->unPCIRQ1.u32Register;

    return Ok;

}

/**
 *****************************************************************************
 ** \brief Clear pulse detection interrupt status flag.
 **
 ** \param [in]  pstcAdc            ADC unit instance.
 ** \param [in]  stcClearChList     Channel list to clear pulse detection status.
 **                                 If a bit = 1, pulse detection flag of corresponding
 **                                 channel will be cleared and will be reload
 **                                 positive/negative counter value.
 **
 ** \retval Ok                      Successfully done.
 ** \retval ErrorInvalidParameter   pstcAdc == NULL
 *****************************************************************************/
en_result_t Adc12b_ClearPulseDetectionInterruptFlag(volatile stc_adc12b0_t* pstcAdc,
                                                    stc_adc12b_channel_list_t stcClearChList)
{
    if (pstcAdc == NULL)
    {
        return ErrorInvalidParameter;
    }

    PDL_WRITE_REG_SYNC(pstcAdc->unPCIRQC0.u32Register, stcClearChList.stcChannel[0].u32reg);
    PDL_WRITE_REG_SYNC(pstcAdc->unPCIRQC1.u32Register, stcClearChList.stcChannel[1].u32reg);
    return Ok;
}


/**
 *****************************************************************************
 ** \brief Get Group interrupted interrupt status.
 **
 ** \param [in]  pstcAdc                ADC unit instance.
 ** \param [out] pstcChannelStatusList  Group interrupted interrupt status list.
 **                                     If a bit = 1,
 **                                     Group interrupted interrupt has occurred.
 **
 ** \retval Ok                      Successfully done.
 ** \retval ErrorInvalidParameter   If one of the following conditions is met:
 **             - pstcAdc == NULL
 **             - pstcDetectChList == NULL
 *****************************************************************************/
en_result_t Adc12b_GetGroupIntInterruptFlag(volatile stc_adc12b0_t* pstcAdc,
                                            stc_adc12b_channel_list_t* pstcDetectChList)
{
    if ((pstcAdc == NULL) || (pstcDetectChList == NULL))
    {
        return ErrorInvalidParameter;
    }

    pstcDetectChList->stcChannel[0].u32reg = pstcAdc->unGRPIRQ0.u32Register;
    pstcDetectChList->stcChannel[1].u32reg = pstcAdc->unGRPIRQ1.u32Register;

    return Ok;

}

/**
 *****************************************************************************
 ** \brief Clear Group interrupted interrupt flag.
 **
 ** \param [in]  pstcAdc            ADC unit instance.
 ** \param [in]  stcClearChList     Channel list to clear Group interrupted interrupt status.
 **                                 If a bit = 1, Group interrupted interrupt flag of corresponding
 **                                 channel will be cleared.
 **
 ** \retval Ok                      Successfully done.
 ** \retval ErrorInvalidParameter   pstcAdc == NULL
 *****************************************************************************/
en_result_t Adc12b_ClearGroupIntInterruptFlag(volatile stc_adc12b0_t* pstcAdc,
                                              stc_adc12b_channel_list_t stcClearChList)
{
    if (pstcAdc == NULL)
    {
        return ErrorInvalidParameter;
    }

    PDL_WRITE_REG_SYNC(pstcAdc->unGRPIRQC0.u32Register, stcClearChList.stcChannel[0].u32reg);
    PDL_WRITE_REG_SYNC(pstcAdc->unGRPIRQC1.u32Register, stcClearChList.stcChannel[1].u32reg);
    return Ok;
}

/**
 *****************************************************************************
 ** \brief Set multiple conversion configurations.
 **
 ** This function sets multiple conversion configurations for a channel.
 **
 ** \param [in]  pstcAdc            ADC unit instance.
 ** \param [in]  u8Channel          Analog channel (0.. ADC12B_MULTIPLE_CONVERSION_NUM -1)
 **                                 Only first some channels support multiple conversion.
 ** \param [in]  pstcConfig         Channel configurations. See #stc_adc12b_multi_conversion_config_t.
 **
 ** \retval Ok                       Successfully done.
 ** \retval ErrorOperationInProgress If ADC is not idle.
 ** \retval ErrorInvalidParameter    If one of the following conditions are met:
 **                                     - pstcAdc == NULL.
 **                                     - pstcConfig == NULL
 **                                     - u8Channel >= ADC12B_MULTIPLE_CONVERSION_NUM.
 **                                     - u8NumOfConversion >= ADC12B_MAX_MULTIPLE_CONVERSION_COUNT
 *****************************************************************************/
en_result_t Adc12b_SetMultipleConversion(volatile stc_adc12b0_t* pstcAdc,
                                         uint8_t u8Channel,
                                         const stc_adc12b_multi_conversion_config_t* pstcConfig)
{
    volatile un_adc12b0_mcctrln_t *punMCCTRLN;
    un_adc12b0_mcctrln_t unMCCTRLN = {0};

    /* check parameters */
    if (pstcAdc == NULL || pstcConfig == NULL)
    {
        return ErrorInvalidParameter;
    }
    if (u8Channel >= ADC12B_MULTIPLE_CONVERSION_NUM)
    {
        return ErrorInvalidParameter;
    }
    if (pstcConfig->u8NumOfConversion >= ADC12B_MAX_MULTIPLE_CONVERSION_COUNT)
    {
        return ErrorInvalidParameter;
    }

    punMCCTRLN = &pstcAdc->unMCCTRL0;
    unMCCTRLN.stcField.u1AVRHSEL = (pstcConfig->bConvertAvrhVoltage != FALSE) ? 1 : 0;
    unMCCTRLN.stcField.u1AVRLSEL = (pstcConfig->bConvertAvrlVoltage != FALSE) ? 1 : 0;
    unMCCTRLN.stcField.u1ICIRQY = (pstcConfig->bDisableIntraChannelInterrupt != FALSE) ? 1 : 0;
    unMCCTRLN.stcField.u4CNVNUM = pstcConfig->u8NumOfConversion;

    punMCCTRLN[u8Channel].u8Register = unMCCTRLN.u8Register;

    return Ok;
}


/**
 *****************************************************************************
 ** \brief Set DMA configuration.
 **
 ** This function sets DMA configurations.
 **
 ** \param [in]  pstcAdc            ADC unit instance.
 ** \param [in]  u8RegNum           Number of register to configure.
 ** \param [in]  pstcConfig         Channel configurations. See #stc_adc12b_dma_config_t.
 **
 ** \retval Ok                       Successfully done.
 ** \retval ErrorInvalidParameter    If one of the following conditions are met:
 **                                     - pstcAdc == NULL.
 **                                     - pstcConfig == NULL
 **                                     - u8RegNum >= ADC12B_DMA_REGISTER_NUM.
 **                                     - u8TriggeringLogcalChNum >= ADC12B_MAX_CHANNEL_COUNT
 *****************************************************************************/
en_result_t Adc12b_SetDmaConfig(volatile stc_adc12b0_t* pstcAdc,
                                uint8_t u8RegNum,
                                const stc_adc12b_dma_config_t* pstcConfig)
{
    volatile un_adc12b0_cddsn_t *punCDDSN;
    un_adc12b0_cddsn_t unCDDSN = { 0 };

    /* check parameters */
    if (pstcAdc == NULL || pstcConfig == NULL)
    {
        return ErrorInvalidParameter;
    }
    if (u8RegNum >= ADC12B_DMA_REGISTER_NUM)
    {
        return ErrorInvalidParameter;
    }
    if (pstcConfig->u8TriggeringLogcalChNum >= ADC12B_MAX_CHANNEL_COUNT)
    {
        return ErrorInvalidParameter;
    }

    punCDDSN = &pstcAdc->unCDDS0;
    unCDDSN.stcField.u1CDCHEN = (pstcConfig->bEnableDmaDidicatedInterrupt != FALSE) ? 1 : 0;
    unCDDSN.stcField.u6CDCHNUM = pstcConfig->u8TriggeringLogcalChNum;
    punCDDSN[u8RegNum].u16Register = unCDDSN.u16Register;

    return Ok;
}

/*****************************************************************************/
/* EOF (not truncated)                                                       */
/*****************************************************************************/
