/****************************************************************************
 * @file     pan_adc.h
 * @version  V1.00
 * $Revision: 2 $
 * $Date: 2023/11/08 16:08 $  
 * @brief    Panchip series ADC driver header file
 *
 * @note
 * Copyright (C) 2023 Panchip Technology Corp. All rights reserved.
 *****************************************************************************/

#ifndef __PAN_ADC_H__
#define __PAN_ADC_H__

/**
 * @brief Adc Interface
 * @defgroup adc_interface Adc Interface
 * @{
 */

#ifdef __cplusplus
extern "C"
{
#endif

#include "pan271x.h"

#define TRIG_BY_PWM_CH0_FLAG                (0)	/*!< pwm channel 0 trigger selected */
#define TRIG_BY_PWM_CH1_FLAG                (1)	/*!< pwm channel 1 trigger selected */

#define HW_TRIG_BY_FALLING_EDGE             (0)	/*!< falling edge trig */
#define HW_TRIG_BY_RISING_EDGE              (1)	/*!< rising edge trig */

#define HW_TRIG_SRC_EXT_PIN             	(0)	/*!< trig source is ext pin */
#define HW_TRIG_SRC_PWM                  	(1)	/*!< trig source is pwm */

#define ADC_SAMPLE_CLK_DIVIDER_128         	(0)	/*!< trig source is ext pin */
#define ADC_SAMPLE_CLK_DIVIDER_64         	(1)	/*!< trig source is pwm */
#define ADC_SAMPLE_CLK_DIVIDER_32        	(2)	/*!< trig source is ext pin */
#define ADC_SAMPLE_CLK_DIVIDER_16         	(3)	/*!< trig source is pwm */

#define CAP_SIDE_SEL_N_SIDE                 (0)	/*!< N side */
#define CAP_SIDE_SEL_P_SIDE                 (1)	/*!< P side */

#define ADC_VREF_VOL_SEL_EXT                (0)	/*!< ref ext vbat */
#define ADC_VREF_VOL_SEL_VBG                (1)	/*!< ref vbg */
#define ADC_VREF_VOL_SEL_VBAT               (2)	/*!< ref vbat */

#define ADC_CHANNEL_SEL_EXT         	(0)	/*!< ext channel */
#define ADC_CHANNEL_SEL_VDD_1P4        	(1)	/*!< 1/4 vdd channel */
#define ADC_CHANNEL_SEL_VBG          	(2)	/*!< vbg channel */
#define ADC_CHANNEL_SEL_TEMP         	(3)	/*!< temp channel */

#define HW_TIMER_CMP_SEL_8K             (0)	/*!< 8k Hz */
#define HW_TIMER_CMP_SEL_16K            (1)	/*!< 16k Hz */
#define HW_TIMER_CMP_SEL_32K            (2)	/*!< 32k Hz */
#define HW_TIMER_CMP_SEL_64K            (3)	/*!< 64k Hz */

typedef struct
{
    union{
        uint32_t weight_difference_1;
        struct {
            uint32_t S0     : 5;
            uint32_t S11    : 11;
            uint32_t Rsv    : 11;
            uint32_t S1     : 5;
        }weight_difference_bit;
    }weight_difference_1_t;
	
    union{
        uint32_t weight_difference_2;
        struct {
            uint32_t S6     : 8;
            uint32_t S9     : 10;
            uint32_t S15    : 14;
        }weight_difference_bit;
    }weight_difference_2_t;
	
    union{
        uint32_t weight_difference_3;
        struct {
            uint32_t S7     : 9;
            uint32_t S8     : 10;
            uint32_t S14    : 13;
        }weight_difference_bit;
    }weight_difference_3_t;
	
    union{
        uint32_t weight_difference_4;
        struct {
            uint32_t S5     : 7;
            uint32_t S12    : 12;
            uint32_t S13    : 13;
        }weight_difference_bit;
    }weight_difference_4_t;
	
    union{
        uint32_t weight_difference_5;
        struct {
			uint32_t Rsv    : 2;
            uint32_t S2     : 6;
            uint32_t S3     : 6;
            uint32_t S4     : 7;
            uint32_t S10    : 11;
        }weight_difference_bit;
    }weight_difference_5_t;
}ADC_WEIGHT_OPT_T;



//extern ADC_OPT_T m_adc_opt;
//extern uint32_t global_calc_vbat_mv;

//extern void ADC_SetCalirationParams(OTP_STRUCT_T *opt);
/**
  * @brief Get the latest ADC conversion data
  * @param[in] ADCx Base address of ADC module
  * @return  Latest ADC conversion data
  * \hideinitializer
  */
__STATIC_INLINE uint32_t ADC_GetConversionData(ADC_T *ADCx)
{
    return ADCx->ADC_DAT;
} 

/**
  * @brief Get raw status flag
  * @param[in] ADCx Base address of ADC module
  * @param[in] StatusMask The combination of following status bits. Each bit corresponds to a status flag.
  *                     - \ref ADC_STATUS_ADC_FLAG_Msk      
  *                     - \ref ADC_STATUS_FIFO_HALF_FALG_Msk      
  *                     - \ref ADC_STATUS_FIFO_OV_FALG_Msk   
  *                     - \ref ADC_STATUS_FIFO_EMPTY_FALG_Msk   
  *                     - \ref ADC_STATUS_FIFO_FULL_FALG_Msk 
  *                     - \ref ADC_STATUS_OV_Msk
  * @return  True or false
  */
__STATIC_INLINE bool ADC_StatusFlag(ADC_T *ADCx,uint32_t StatusMask)
{
    return (ADCx->ADC_STATUS & StatusMask)?(true):(false);
}

/**
  * @brief Clear specified adc flag
  * @param[in] ADCx Base address of ADC module
  * @param[in] IntMask The combination of following status bits. Each bit corresponds to a status flag.
  *                     - \ref ADC_STATUS_ADC_FLAG_Msk      
  * @return  None
  */
__STATIC_INLINE void ADC_ClearStatusFlag(ADC_T *ADCx,uint32_t IntMask)
{
    ADCx->ADC_STATUS |= IntMask;
}

/**
  * @brief Enable read decimal places or not
  * @param[in] ADCx Base address of ADC module
  * @param[in] NewState: new stare of decimal places
  * @return  None
  */
__STATIC_INLINE void ADC_DecimalReadEnable(ADC_T *ADCx,FunctionalState NewState)
{
    (NewState == ENABLE)?(ADCx->ADC_CTL |= ADC_CTL_DWIDTH_SEL_Msk):(ADCx->ADC_STATUS &= ~ADC_CTL_DWIDTH_SEL_Msk);
}

/**
  * @brief The compare value of hardware timer selection
  * @param[in] ADCx Base address of ADC module
  * @param[in] CmpValue: compare value, include: 
  *              \ref HW_TIMER_CMP_SEL_8K 
  *              \ref HW_TIMER_CMP_SEL_16K
  *              \ref HW_TIMER_CMP_SEL_32K
  *              \ref HW_TIMER_CMP_SEL_64K
  * @return  None
  */
__STATIC_INLINE void ADC_HwTimerCmpSel(ADC_T *ADCx,uint32_t CmpValue)
{
    ADCx->ADC_CTL = (ADCx->ADC_CTL & ~ADC_CTL_HW_TMR_SEL_Msk) | CmpValue;
}

/**
  * @brief Enable hardware timer or not
  * @param[in] ADCx Base address of ADC module
  * @param[in] NewState: new state of hardware timer
  * @return  None
  */
__STATIC_INLINE void ADC_HwTimerEnable(ADC_T *ADCx,FunctionalState NewState)
{
    (NewState == ENABLE)?(ADCx->ADC_CTL |= ADC_CTL_HW_TMR_EN_Msk):(ADCx->ADC_STATUS &= ~ADC_CTL_HW_TMR_EN_Msk);
}

/**
  * @brief Enable interrupt,if enabled,interrupt will not be happened
  * @param[in] ADCx Base address of ADC module
  * @param[in] u32Mask The combination of following interrupt mask bits. Each bit corresponds to a interrupt mask flag.
  *                     - \ref ADC_CTL_HALF_INT_EN_Msk  
  *                     - \ref ADC_CTL_OV_INT_EN_Msk 
  *                     - \ref ADC_CTL_EMPTY_INT_EN_Msk  
  *                     - \ref ADC_CTL_FULL_INT_EN_Msk  
  *                     - \ref ADC_CTL_ADCIEN_Msk  
  * @param[in] NewState: new state of adc interrupt mask
  * @return  none
  * \hideinitializer
  */
__STATIC_INLINE void ADC_IntEnable(ADC_T *ADCx,uint32_t IntMask,FunctionalState NewState)
{
    (NewState == ENABLE)?(ADCx->ADC_CTL |= IntMask):(ADCx->ADC_STATUS &= ~IntMask);
}

/**
  * @brief Adjust weather interrupt is enabled
  * @param[in] ADCx Base address of ADC module
  * @param[in] u32Mask The combination of following interrupt mask bits. Each bit corresponds to a interrupt mask flag.
  *                     - \ref ADC_CTL_HALF_INT_EN_Msk  
  *                     - \ref ADC_CTL_OV_INT_EN_Msk 
  *                     - \ref ADC_CTL_EMPTY_INT_EN_Msk  
  *                     - \ref ADC_CTL_FULL_INT_EN_Msk  
  *                     - \ref ADC_CTL_ADCIEN_Msk  
  * @return  true or false
  * \hideinitializer
  */
__STATIC_INLINE bool ADC_IsIntEnabled(ADC_T *ADCx,uint32_t IntMask)
{
    return (ADCx->ADC_CTL & IntMask)?(true):(false);
}

/**
  * @brief Adjust weather interrupt flag is valid
  * @param[in] ADCx Base address of ADC module
  * @param[in] u32Mask The combination of following interrupt mask bits. Each bit corresponds to a interrupt mask flag.
  *                     - \ref ADC_STATUS_ADC_FLAG_Msk      
  *                     - \ref ADC_STATUS_FIFO_HALF_FALG_Msk      
  *                     - \ref ADC_STATUS_FIFO_OV_FALG_Msk   
  *                     - \ref ADC_STATUS_FIFO_EMPTY_FALG_Msk   
  *                     - \ref ADC_STATUS_FIFO_FULL_FALG_Msk 
  * @return  true or false
  * \hideinitializer
  */
bool ADC_IsIntOccurred(ADC_T *ADCx,uint32_t IntFlag, uint32_t IntMask);


/**
  * @brief Get the busy state of ADC
  * @param[in] ADCx Base address of ADC module
  * @return busy state of ADC
  * @retval 0 ADC is not busy
  * @retval 1 ADC is busy
  * \hideinitializer
  */
__STATIC_INLINE bool ADC_IsBusy(ADC_T *ADCx)
{
    return (ADCx->ADC_STATUS & ADC_STATUS_BUSY_Msk)?(true):(false);
}     
/**
  * @brief Check if the ADC conversion data is over written or not
  * @param[in] ADCx Base address of ADC module
  * @return Over run state of ADC data
  * @retval 0 ADC data is not overrun
  * @retval 1 ADC data is overrun
  * \hideinitializer
  */     
__STATIC_INLINE bool ADC_IsDataOverrun(ADC_T *ADCx)
{
    return (ADCx->ADC_STATUS & ADC_STATUS_OV_Msk)?(true):(false);
} 
/**
  * @brief Check if the ADC conversion data is valid or not
  * @param[in] ADCx Base address of ADC module
  * @return Valid state of ADC data
  * @retval 0 ADC data is not valid
  * @retval 1 ADC data us valid
  * \hideinitializer
  */  
__STATIC_INLINE bool ADC_IsDataValid(ADC_T *ADCx)
{
    return (ADCx->ADC_STATUS & ADC_STATUS_VALID_Msk)?(true):(false);
}
/**
  * @brief Power down ADC module
  * @param[in] ADCx Base address of ADC module
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_PowerDown(ADC_T *ADCx)
{
    ADCx->ADC_CTL = ADCx->ADC_CTL & ~ADC_CTL_ADCEN_Msk;
} 
/**
  * @brief Power on ADC module
  * @param[in] ADCx Base address of ADC module
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_PowerOn(ADC_T *ADCx)
{
    ADCx->ADC_CTL  = ADCx->ADC_CTL | ADC_CTL_ADCEN_Msk;
}
/**
  * @brief  ADC fifo enable
  * @param[in] ADCx Base address of ADC module
  * @param[in] NewState: new state of adc fifo
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_EnableFifo(ADC_T *ADCx, FunctionalState NewState)
{
    (NewState == ENABLE)?(ADCx->ADC_CTL |= ADC_CTL_FIFO_EN_Msk):(ADCx->ADC_CTL &= ~ADC_CTL_FIFO_EN_Msk);
}

/**
  * @brief Start the A/D conversion.
  * @param[in] ADCx Base address of ADC module
  * @return None
  */
__STATIC_INLINE void ADC_StartConvert(ADC_T *ADCx)
{
    ADCx->ADC_CTL  = ADCx->ADC_CTL | ADC_CTL_SWTRG_Msk;
}
/**
  * @brief Stop the A/D conversion.
  * @param[in] ADCx Base address of ADC module
  * @return None
  */
__STATIC_INLINE void ADC_StopConvert(ADC_T *ADCx)
{
    ADCx->ADC_CTL  &= ~ADC_CTL_SWTRG_Msk;
}

/**
  * @brief Enable the A/D test mode.
  * @param[in] ADCx Base address of ADC module
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_TestModeEnable(ADC_T *ADCx)
{
    ADCx->ADC_CTL2  |= ADC_CTL2_TEST_MODE_Msk;
}
/**
  * @brief Disable the A/D test mode.
  * @param[in] ADCx Base address of ADC module
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_TestModeDisable(ADC_T *ADCx)
{
    ADCx->ADC_CTL2  &= ~ADC_CTL2_TEST_MODE_Msk;
}

/**
  * @brief Adc pwm trig source selection.
  * @param[in] ADCx Base address of ADC module
  * @param[in] TrigSrc pwm trig source
  *			\ref TRIG_BY_PWM_CH0_FLAG
  *			\ref TRIG_BY_PWM_CH1_FLAG
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_PwmTrigSrcSelect(ADC_T *ADCx, uint32_t TrigSrc)
{
    ADCx->ADC_CTL  = (ADCx->ADC_CTL & ~ADC_CTL_PWM_CH_SEL_Msk) | (TrigSrc << ADC_CTL_PWM_CH_SEL_Pos);
}

/**
  * @brief Adc hardware trig enable.
  * @param[in] ADCx Base address of ADC module
  * @param[in] NewState: new state of adc hardware trig
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_HwTrigEnable(ADC_T *ADCx, FunctionalState NewState)
{
    (NewState == ENABLE)?(ADCx->ADC_CTL |= ADC_CTL_HWTRGEN_Msk):(ADCx->ADC_CTL &= ~ADC_CTL_HWTRGEN_Msk);
}

/**
  * @brief Adc hardware trig edge selection.
  * @param[in] ADCx Base address of ADC module
  * @param[in] EdgeSel trig edge
  *			\ref HW_TRIG_BY_FALLING_EDGE
  *			\ref HW_TRIG_BY_RISING_EDGE
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_HwTrigEdgeSelect(ADC_T *ADCx, uint32_t EdgeSel)
{
    ADCx->ADC_CTL  = (ADCx->ADC_CTL & ~ADC_CTL_HWTRGCOND_Msk) | (EdgeSel << ADC_CTL_HWTRGCOND_Pos);
}

/**
  * @brief Adc hardware trig source selection.
  * @param[in] ADCx Base address of ADC module
  * @param[in] TrigSrc hardware trig source
  *			\ref HW_TRIG_SRC_EXT_PIN
  *			\ref HW_TRIG_SRC_PWM
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_HwTrigSrcSelect(ADC_T *ADCx, uint32_t TrigSrc)
{
    ADCx->ADC_CTL  = (ADCx->ADC_CTL & ~ADC_CTL_HWTRGSEL_Msk) | (TrigSrc << ADC_CTL_HWTRGSEL_Pos);
}

/**
  * @brief Set the A/D clock division.
  * @param[in] ADCx Base address of ADC module
  * @param[in] Divider Adc clk divider
  * 			adc clk = pclk / (divider + 1)
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_SetClockDivider(ADC_T *ADCx,uint32_t Divider)
{
    ADCx->ADC_CTL2  = (ADCx->ADC_CTL2 & ~ADC_CTL2_CLK_DIV_Msk) | (Divider << ADC_CTL2_CLK_DIV_Pos);
}

/**
  * @brief Set the A/D sample clock division.
  * @param[in] ADCx Base address of ADC module
  * @param[in] Divider Adc sample clk divider
  * 			\ref ADC_SAMPLE_CLK_DIVIDER_128
  * 			\ref ADC_SAMPLE_CLK_DIVIDER_64
  * 			\ref ADC_SAMPLE_CLK_DIVIDER_32
  * 			\ref ADC_SAMPLE_CLK_DIVIDER_16
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_SetSampleClockDivider(ADC_T *ADCx,uint32_t Divider)
{
    ADCx->ADC_CTL2  = (ADCx->ADC_CTL2 & ~ADC_CTL2_CLK_SEL_Msk) | (Divider << ADC_CTL2_CLK_SEL_Pos);
}



/**
  * @brief Select gpadc channel.
  * @param[in] ADCx Base address of ADC module
  * @param[in] Ch Adc channel selection, such as:
  * 			\ref ADC_CHANNEL_SEL_EXT
  * 			\ref ADC_CHANNEL_SEL_VDD_1P4
  * 			\ref ADC_CHANNEL_SEL_VBG
  * 			\ref ADC_CHANNEL_SEL_TEMP
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_ChannelSel(ADC_T *ADCx, uint8_t Ch)
{
    ADCx->ADC_CTL2  = (ADCx->ADC_CTL2 & ~ADC_CTL2_GPADC_CHANNEL_SEL_Msk) | (Ch << ADC_CTL2_GPADC_CHANNEL_SEL_Pos);
}

/**
  * @brief Set gpadc vbg voltage trim code.
  * @param[in] ADCx Base address of ADC module
  * @param[in] Trim Adc vbg voltage trim code
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_SetVbgTrim(ADC_T *ADCx, uint8_t Trim)
{
    ADCx->ADC_CTL2  = (ADCx->ADC_CTL2 & ~ADC_CTL2_GPADC_VBG_TRIM_Msk) | (Trim << ADC_CTL2_GPADC_VBG_TRIM_Pos);
}

/**
  * @brief ADC channel BUF enable for single ended DC mode.
  * @param[in] ADCx: Base address of ADC module
  * @param[in] NewState: buffer state
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_EnableBuffer(ADC_T *ADCx, FunctionalState NewState)
{
    (NewState == ENABLE)?(ADCx->ADC_CTL2 |= ADC_CTL2_BUFFER_EN_Msk):(ADCx->ADC_CTL2 &= ~ADC_CTL2_BUFFER_EN_Msk);
}

/**
  * @brief Set the A/D sample count.
  * @param[in] ADCx Base address of ADC module
  * @param[in] Count Adc sample count value, count = 1 << count + 2
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_SetSampleCount(ADC_T *ADCx,uint32_t Count)
{
    ADCx->ADC_CTL2  = (ADCx->ADC_CTL2 & ~ADC_CTL2_DC_TIMES_Msk) | (Count << ADC_CTL2_DC_TIMES_Pos);
}

/**
  * @brief Set output value discard count.
  * @param[in] ADCx Base address of ADC module
  * @param[in] Count Adc sample count value, count = 1 << count + 2
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_SetDiscardCount(ADC_T *ADCx,uint32_t DiscardCount)
{
    ADCx->ADC_CTL2  = (ADCx->ADC_CTL2 & ~ADC_CTL2_DISC_NUM_Msk) | (DiscardCount << ADC_CTL2_DISC_NUM_Pos);
}

/**
  * @brief Enable adc continue sample function.
  * @param[in] ADCx: Base address of ADC module
  * @param[in] NewState: continue function state 
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_EnableContinueSample(ADC_T *ADCx, FunctionalState NewState)
{
    (NewState == ENABLE)?(ADCx->ADC_CTL2 |= ADC_CTL2_CON_SAMPLE_Msk):(ADCx->ADC_CTL2 &= ~ADC_CTL2_CON_SAMPLE_Msk);
}

/**
  * @brief Enable adc output value average function.
  * @param[in] ADCx: Base address of ADC module
  * @param[in] NewState: average function state 
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_EnableAverage(ADC_T *ADCx, FunctionalState NewState)
{
    (NewState == ENABLE)?(ADCx->ADC_CTL2 |= ADC_CTL2_AVERAGE_Msk):(ADCx->ADC_CTL2 &= ~ADC_CTL2_AVERAGE_Msk);
}

/**
  * @brief Controls whether the ADC is affected by the trigger signal.
  * @param[in] ADCx: Base address of ADC module
  * @param[in] NewState: analog work state 
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_EnableAnalogWork(ADC_T *ADCx, FunctionalState NewState)
{
    (NewState == ENABLE)?(ADCx->ADC_CTL2 |= ADC_CTL2_ANA_WORK_Msk):(ADCx->ADC_CTL2 &= ~ADC_CTL2_ANA_WORK_Msk);
}



/**
  * @brief Enable Automatic capacitor calibration funciton.
  * @param[in] ADCx: Base address of ADC module
  * @param[in] NewState: capacitor auto calculate state 
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_EnableAutoCalCap(ADC_T *ADCx, FunctionalState NewState)
{
    (NewState == ENABLE)?(ADCx->ADC_TEMP |= ADC_TEMP_GPADC_CAL_CAP_EN_Msk):(ADCx->ADC_TEMP &= ~ADC_TEMP_GPADC_CAL_CAP_EN_Msk);
}
/**
  * @brief Enable Automatic comparator calibration funciton.
  * @param[in] ADCx: Base address of ADC module
  * @param[in] NewState: Comparator auto calculate state 
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_EnableAutoCalComparator (ADC_T *ADCx, FunctionalState NewState)
{
    (NewState == ENABLE)?(ADCx->ADC_TEMP |= ADC_TEMP_GPADC_CAL_CMP_EN_Msk):(ADCx->ADC_TEMP &= ~ADC_TEMP_GPADC_CAL_CMP_EN_Msk);
}
/**
  * @brief Set capacitor trim.
  * @param[in] ADCx: Base address of ADC module
  * @param[in] CapTrim: capacitor trim value 
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_SetCapTrim (ADC_T *ADCx, uint32_t CapTrim)
{
    ADCx->ADC_TEMP = (ADCx->ADC_TEMP & ~ADC_TEMP_GPADC_CALCAP_SEL_Msk)|(CapTrim << ADC_TEMP_GPADC_CALCAP_SEL_Pos);
}
/**
  * @brief Set capacitor trim.
  * @param[in] ADCx: Base address of ADC module
  * @param[in] Side: N side or P side 
  *			\ref CAP_SIDE_SEL_N_SIDE
  *			\ref CAP_SIDE_SEL_P_SIDE
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_CapSideSelect (ADC_T *ADCx, uint32_t Side)
{
    ADCx->ADC_TEMP = (ADCx->ADC_TEMP & ~ADC_TEMP_GPADC_CALCAP_SIDE_SEL_Msk) |(Side << ADC_TEMP_GPADC_CALCAP_SIDE_SEL_Pos);
}
/**
  * @brief Set comparator trim.
  * @param[in] ADCx: Base address of ADC module
  * @param[in] ComparatorTrim: comparator trim value 
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_SetComparatorTrim (ADC_T *ADCx, uint32_t ComparatorTrim)
{
    ADCx->ADC_TEMP = (ADCx->ADC_TEMP & ~ADC_TEMP_GPADC_CALCMP_VOS_Msk)|(ComparatorTrim << ADC_TEMP_GPADC_CALCMP_VOS_Pos);
}


/**
  * @brief Enable gpadc vref voltage as vbat.
  * @param[in] ADCx: Base address of ADC module
  * @param[in] NewState: state of gpadc vref vbat 
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_VrefVbatEnable (ADC_T *ADCx, FunctionalState NewState)
{
    (NewState == ENABLE)?(ADCx->ADC_TEMP |= ADC_TEMP_GPADC_VREFP_BYP_EN_Msk):(ADCx->ADC_TEMP &= ~ADC_TEMP_GPADC_VREFP_BYP_EN_Msk);
}

/**
  * @brief Enable gpadc vref voltage as vbg.
  * @param[in] ADCx: Base address of ADC module
  * @param[in] NewState: state of gpadc vref vbg 
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_VrefVbgEnable (ADC_T *ADCx, FunctionalState NewState)
{
    (NewState == ENABLE)?(ADCx->ADC_TEMP |= ADC_TEMP_GPADC_VREFP_VBG_EN_Msk):(ADCx->ADC_TEMP &= ~ADC_TEMP_GPADC_VREFP_VBG_EN_Msk);
}

/**
  * @brief Enable gpadc Differential Mode or Single-ended Mode.
  * @param[in] ADCx: Base address of ADC module
  * @param[in] NewState: state 1 --> Differential Mode, state 0 --> Single-ended Mode 
  * @return None
  * \hideinitializer
  */
__STATIC_INLINE void ADC_DifferentialModeEnable (ADC_T *ADCx, FunctionalState NewState)
{
    (NewState == ENABLE)?(ADCx->ADC_TEMP |= ADC_TEMP_GPADC_DIFFMODE_Msk):(ADCx->ADC_TEMP &= ~ADC_TEMP_GPADC_DIFFMODE_Msk);
}



/**
  * @brief Init ADC config parameters
  * @param[in] ADCx Base address of ADC module
  * @param[in] buf_en Enable or disable buffer
  * @return None
  */
bool ADC_Init(ADC_T *ADCx, bool buf_en);
/**
  * @brief Prepare ADC VBG fitting curve paramters due to SoC VBAT level
  * @param[in] ADCx Base address of ADC module
  * @return None
  */
void ADC_PrepareVbgCalibData(ADC_T *ADCx);
/**
  * @brief Convert adc code to voltage in uV
  * @param[in] ADCx Base address of ADC module
  * @param[in] adc_code Code sampled by ADC module
  * @return ADC sample voltage output in uV
  */
float ADC_OutputVoltage(ADC_T *ADCx, uint32_t adc_code);
/**
  * @brief Start sampling many data codes, trim several largest and smallest codes and calculate average valu
  * @param[in] ADCx         Base address of ADC module
  * @param[in] sample_buf   Buffer to temporarily store ADC sample code
  * @param[in] sample_cnt   Total sampling count
  * @param[in] trim_cnt     Total trim count, that means throw away the smallest trim_cnt/2 and largest trim_cnt/2 sample codes
  * @return ADC sample voltage output in mV
  */
uint32_t ADC_SamplingCodeTrimMean(ADC_T *ADCx, uint16_t *sample_buf, uint32_t sample_cnt, uint32_t trim_cnt);
/**
  * @brief Measure SoC Temperature using the ADC internal Channel 9
  * @param[in] ADCx Base address of ADC module
  * @return ADC measured temperature in Celsius
  */
float ADC_MeasureSocTemperature(ADC_T *ADCx);
/**
  * @brief Measure SoC Temperature More Fast using the ADC internal Channel 9
  * @param[in] ADCx Base address of ADC module
  * @return ADC measured temperature in Celsius
  */
float ADC_MeasureSocTemperatureFast(ADC_T *ADCx);
/**
  * @brief Measure SoC VBAT using the ADC internal Channel 10
  * @param[in] ADCx Base address of ADC module
  * @return ADC measured VBAT voltage in mV
  */
uint16_t ADC_MeasureSocVbat(ADC_T *ADCx);

/**
  * @brief ADC reference voltage selection
  * @param[in] ADCx Base address of ADC module
  * @param[in] Vref reference voltage
  *			\ref ADC_VREF_VOL_SEL_VBAT
  *			\ref ADC_VREF_VOL_SEL_VBG
  * @return none
  */
void ADC_VrefVoltageSelect(ADC_T *ADCx, uint32_t Vref);

/**
  * @brief Set adc weight difference
  * @param[in] ADCx Base address of ADC module
  * @param[in] WeightOpt weight difference configuration
  * @return none
  */
void ADC_SetWeightRatio(ADC_T *ADCx, ADC_WEIGHT_OPT_T WeightOpt);

/**
  * @brief Read adc fifo data
  * @param[in] ADCx Base address of ADC module
  * @param[in] Data read data pointer
  * @return none
  */
void ADC_ReadFifo(ADC_T *ADCx, uint16_t *Data);
/**@} */

#ifdef __cplusplus
}
#endif

#endif //__PAN_ADC_H__

/*** (C) COPYRIGHT 2016 Panchip Technology Corp. ***/
