
/******************************************************************************
* @file      : spl_adc.c
* @version   : 1.0
* @date      : 2023.01.30
* @brief     : ADC SPL module driver
*   
* @history   :	
*   2023.01.30    lwq    create
*   
******************************************************************************/
#include "acm32g103_spl_conf.h" 


//#ifdef SPL_ADC_MODULE_ENABLED



/******************************************************************************
* @brief:  Deinitializes ADC registers to their default reset values.
* @param:  None.
* @return: None
******************************************************************************/
void ADC_DeInit(void)
{
    /* Release all ADCs from reset state */
    __RCC_ADC12_RESET();
}


/******************************************************************************
* @brief:  Initializes the ADCx peripheral according to the specified parameters 
*          in the ADC_InitStruct.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  ADC_InitStruct: pointer to an ADC_InitTypeDef structure that contains
*          the configuration information for the specified ADC peripheral.
* @return: None
******************************************************************************/
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_RESOLUTION(ADC_InitStruct->ADC_Resolution)); 
    assert_param(IS_ADC_CONT(ADC_InitStruct->ADC_ContinuousConvMode)); 
    assert_param(IS_ADC_EXT_TRIG_EDGE(ADC_InitStruct->ADC_ExternalTrigConvEdge)); 
    assert_param(IS_ADC_EXT_TRIG(ADC_InitStruct->ADC_ExternalTrigConv));    
    assert_param(IS_ADC_DATA_ALIGN(ADC_InitStruct->ADC_DataAlign)); 
    assert_param(IS_ADC_REGULAR_LENGTH(ADC_InitStruct->ADC_NbrOfConversion));

    /* Enable ADC CLK */
    __RCC_ADC12_CLK_ENABLE();
    
    /*---------------------------- ADCx CR2 Configuration -----------------*/
    /* Reset ADC AFE */
    ADCx->CR2 |= ADC_CR2_AFERSTN;
    
    /* Clear ALIGN, Resolution bits */
    ADCx->CR2 &= (~(ADC_CR2_RES_Msk | ADC_CR2_ALIGN_Msk));
  
    /* set Resolution */
    /* Set ADC data alignment */
    ADCx->CR2 |= ADC_InitStruct->ADC_DataAlign | ADC_InitStruct->ADC_Resolution ;

               
    /*---------------------------- ADCx CR1 Configuration -----------------*/
    /* Clear CONT, EXTEN and EXTSEL bits */
    ADCx->CR1 &= (~(ADC_CR1_CONT_Msk | ADC_CR1_EXTEN_Msk | ADC_CR1_EXTSEL_Msk));
    
    //Set continued convert mode
    ADCx->CR1 |= ADC_InitStruct->ADC_ContinuousConvMode | \
               (ADC_InitStruct->ADC_ExternalTrigConvEdge << ADC_CR1_EXTEN_Pos) | \
               (ADC_InitStruct->ADC_ExternalTrigConv << ADC_CR1_EXTSEL_Pos);

    /*---------------------------- ADCx SQR1 Configuration -----------------*/
    /* Clear L bits */
    ADCx->SQR1 &= (~ADC_SQR1_L_Msk);

    /* Configure ADCx: regular channel sequence length */
    /* Set L bits according to ADC_NbrOfConversion value */
    ADCx->SQR1 |= (ADC_InitStruct->ADC_NbrOfConversion - 1);

}


/******************************************************************************
* @brief:  Fills each ADC_InitStruct member with its default value.
* @param:  ADC_InitStruct: pointer to an ADC_InitTypeDef structure which will 
*          be initialized.
* @return: None
******************************************************************************/
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct)
{
    /* Initialize the ADC_Mode member */
    ADC_InitStruct->ADC_Resolution = ADC_RESOLUTION_12B;

    /* Initialize the ADC_ContinuousConvMode member */
    ADC_InitStruct->ADC_ContinuousConvMode = DISABLE;

    /* Initialize the ADC_ExternalTrigConvEdge member */
    ADC_InitStruct->ADC_ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;

    /* Initialize the ADC_ExternalTrigConv member */
    ADC_InitStruct->ADC_ExternalTrigConv = ADC_EXTERNAL_TIG0;

    /* Initialize the ADC_DataAlign member */
    ADC_InitStruct->ADC_DataAlign = ADC_DATAALIGN_RIGHT;

    /* Initialize the ADC_NbrOfConversion member */
    ADC_InitStruct->ADC_NbrOfConversion = 1;
}


/******************************************************************************
* @brief:  Initializes the ADCs peripherals according to the specified parameters 
*          in the ADC_CommonInitStruct.
* @param:  ADC_CommonInitStruct: pointer to an ADC_CommonInitTypeDef structure 
*          that contains the configuration information for  All ADCs peripherals.
* @return: None
******************************************************************************/
void ADC_CommonInit(ADC_CommonInitTypeDef* ADC_CommonInitStruct)
{
    /* Check the parameters */
    assert_param(IS_ADC_MODE(ADC_CommonInitStruct->ADC_Mode));
    assert_param(IS_ADC_CLOCKDIV(ADC_CommonInitStruct->ADC_Prescaler));
    assert_param(IS_ADC_DMA_ACCESS_MODE(ADC_CommonInitStruct->ADC_DMAAccessMode));
    assert_param(IS_ADC_SAMPLING_DELAY(ADC_CommonInitStruct->ADC_TwoSamplingDelay));
    /*---------------------------- ADC CCR Configuration -----------------*/
    /* Clear MULTI, DELAY, DMA and ADCDIV bits */
    ADC12_COMMON->CCR &= (~(ADC_CCR_ADCDIV_Msk | ADC_CCR_DMADUAL_Msk | ADC_CCR_DELAY_Msk | ADC_CCR_DUALMOD_Msk));

    /* Configure ADCx: Multi mode, Delay between two sampling time, ADC prescaler,and DMA access mode for multimode */
    /* Set MULTI ADCDIV DMA DELAY bits */    
    ADC12_COMMON->CCR |= (ADC_CommonInitStruct->ADC_Mode | 
                ADC_CommonInitStruct->ADC_Prescaler | 
                ADC_CommonInitStruct->ADC_DMAAccessMode | 
                ADC_CommonInitStruct->ADC_TwoSamplingDelay);        
}


/******************************************************************************
* @brief:  Fills each ADC_CommonInitStruct member with its default value.
* @param:  ADC_CommonInitStruct: pointer to an ADC_CommonInitTypeDef structure
*          which will be initialized.
* @return: None
******************************************************************************/
void ADC_CommonStructInit(ADC_CommonInitTypeDef* ADC_CommonInitStruct)
{
    /* Initialize the ADC_Mode member */
    ADC_CommonInitStruct->ADC_Mode = ADC_MODE_INDEPENDENT;

    /* initialize the ADC_Prescaler member */
    ADC_CommonInitStruct->ADC_Prescaler = ADC_CLOCK_DIV2;

    /* Initialize the ADC_DMAAccessMode member */
    ADC_CommonInitStruct->ADC_DMAAccessMode = ADC_DMAACCESSMODE_DISABLED;

    /* Initialize the ADC_TwoSamplingDelay member */
    ADC_CommonInitStruct->ADC_TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
}

/******************************************************************************
* @brief:  Enables or disables the specified ADC peripheral.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  NewState: new state of the ADCx peripheral. 
*          This parameter can be: ENABLE or DISABLE.
* @return: None
******************************************************************************/
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_FUNCTIONAL_STATE(NewState));
    if (NewState != DISABLE)
    {
        /* Set the ADC_EN bit to wake up the ADC from power down mode */
        ADCx->CR2 |= ADC_CR2_ADCEN;
        /* Wait ADC ready */
        while(!(ADCx->SR & ADC_SR_ADRDY));
    }
    else
    {
        /* Disable the selected ADC peripheral */
        ADCx->CR2 &= (uint32_t)(~ADC_CR2_ADCEN);
    }
}

/******************************************************************************
* @brief:  Enables or disables the ADC fast conversion.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  NewState: new state of the ADC fast conversion. 
*          This parameter can be: ENABLE or DISABLE.
* @return: None
******************************************************************************/
void ADC_FastModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_FUNCTIONAL_STATE(NewState));
    if (NewState != DISABLE)
    {
        /* Enable the ADC fast conversion */
        ADCx->CR2 |= ADC_CR2_FASTMOD;
    }
    else
    {
        /* Disable the ADC fast conversion */
        ADCx->CR2 &= (~ADC_CR2_FASTMOD);
    }
}

/******************************************************************************
* @brief:  Enables or disables the ADC stop control.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  NewState: new state of the ADC stop control. 
*          This parameter can be: ENABLE or DISABLE.
* @return: None
******************************************************************************/
void ADC_StopControlCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_FUNCTIONAL_STATE(NewState));
    if (NewState != DISABLE)
    {
        /* Enable the ADC stop control */
        ADCx->CR2 |= ADC_CR2_ADCSTP;
    }
    else
    {
        /* Disable the ADC stop control */
        ADCx->CR2 &= (~ADC_CR2_ADCSTP);
    }
}

/******************************************************************************
* @brief:  Enables or disables the ADC stop control.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  Overflowmode: Specifies whether ADC saves the new sampling data 
           or the last sampling data when overflow occurs. 
* @return: None
******************************************************************************/
void ADC_OverflowmodeConfig(ADC_TypeDef* ADCx, uint32_t Overflowmode)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_OVERFLOW_MODE(Overflowmode));
    
    /* Clear OVRMOD bits */
    ADCx->CR2 &= (~ADC_CR2_OVRMOD_Msk);
    
    /* Store the new register value */
    ADCx->CR2 |= Overflowmode;
    
}

/******************************************************************************
* @brief:  Configure single-ended/differential conversion mode.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  Channel: the channel is set with single terminal or differential. 
* @param:  mode: single-ended/differential conversion mode.
* @return: None
******************************************************************************/
void ADC_DifferentialConfig(ADC_TypeDef* ADCx, uint8_t Channel, uint8_t Differential)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_DIFF_SIGN_CHANNEL(Channel));
    assert_param(IS_ADC_DIFF(Differential));

    /* Clear the old single-ended/differential conversion mode */
    ADCx->DIFF &= (~(ADC_DIFF_DIFF010_Msk << Channel));

    /* Set the new single-ended/differential conversion mode */
    ADCx->DIFF |= (Differential << Channel);
}

/******************************************************************************
* @brief:  Signed or unsigned number selection.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  Channel: the channel is set with Signed or unsigned. 
* @param:  Sign: Signed or unsigned.
* @return: None
******************************************************************************/
void ADC_SignConfig(ADC_TypeDef* ADCx, uint8_t Channel, uint8_t Sign)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_DIFF_SIGN_CHANNEL(Channel));
    assert_param(IS_ADC_SIGN(Sign));

    /* Clear the old single-ended/differential conversion mode */
    ADCx->SIGN &= (~(ADC_SIGN_SIGN010_Pos << Channel));

    /* Set the new single-ended/differential conversion mode */
    ADCx->SIGN |= (Sign << Channel);
}

/******************************************************************************
* @brief:  Set the injected or regular channels conversion value offset
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  Channel: the ADC channel to set its offset. 
* @param:  Offset_InitStruct: pointer to an ADC_OffsetConfTypeDef structure that contains
*          the configuration information for Offset Register.
* @return: None
******************************************************************************/
void ADC_OffsetConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, ADC_OffsetConfTypeDef *Offset_InitStruct)
{
    uint32_t tmpreg1 = 0;
    __IO uint32_t tmpADC_OFR = 0;
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_CHANNEL(ADC_Channel));
    assert_param(IS_ADC_OFFSET_NUMBER(Offset_InitStruct->OffsetNumber));
    assert_param(IS_ADC_OFFSET(Offset_InitStruct->Offset));
    assert_param(IS_ADC_OFFSET_CALCULATE(Offset_InitStruct->OffsetCalculate));
    assert_param(IS_ADC_OFFSET_SIGN(Offset_InitStruct->Offsetsign));

    /*---------------------------- ADCx OFRx Configuration -----------------*/
    tmpADC_OFR = (uint32_t)ADCx;
    tmpADC_OFR += (uint32_t)(ADC_OFR1_ADDR_OFFSET + 4 * (Offset_InitStruct->OffsetNumber -1));

    /* Set the new sample time */
    tmpreg1 = Offset_InitStruct->Offset | \
              Offset_InitStruct->OffsetCalculate | \
              Offset_InitStruct->Offsetsign | \
              (ADC_Channel << ADC_OFRX_OFFSETXCH_Pos) |\
              ADC_OFRX_OFFSETXEN;

    /* Store the new register value */
    *(__IO uint32_t*)(tmpADC_OFR) = tmpreg1;
}

/******************************************************************************
* @brief:  Configure oversampling
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  Ratio: ADC oversampling ratio.                   
* @param:  Shift: ADC oversampling shift.
* @return: None
******************************************************************************/
void ADC_OverSamplingConfig(ADC_TypeDef* ADCx, uint8_t Ratio, uint8_t Shift)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_OVERSAMPLING_RATIO(Ratio));
    assert_param(IS_ADC_RIGHTBITSHIFT(Shift));
    
    /* Clear OVSS OVSR bits */
    ADCx->CR2 &= (~(ADC_CR2_OVSR_Msk | ADC_CR2_OVSS_Msk));
    
    /* Set the new ratio and Shift */
    ADCx->CR2 |= ((Ratio << ADC_CR2_OVSR_Pos) | (Shift << ADC_CR2_OVSS_Pos));
}

/******************************************************************************
* @brief:  Enables or disables the Regular group oversampling
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  NewState: new state of the Regular group oversampling.
*          This parameter can be: ENABLE or DISABLE.
* @return: None
******************************************************************************/
void ADC_OverSamplingCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_FUNCTIONAL_STATE(NewState));
    if (NewState != DISABLE)
    {
        /* Enable the Regular group oversampling */
        ADCx->CR2 |= ADC_CR2_OVSE;
    }
    else
    {
        /* Disable the Regular group oversampling */
        ADCx->CR2 &= (~ADC_CR2_OVSE);
    }
}

/******************************************************************************
* @brief:  Enables or disables the Regular group oversampling
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  NewState: new state of the Regular group oversampling.
*          This parameter can be: ENABLE or DISABLE.
* @return: None
******************************************************************************/
void ADC_OverSamplingTrigerConfig(ADC_TypeDef* ADCx, uint32_t TrigerMode)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_OVERSAMPLING_TRIGER(TrigerMode));
    
    /* Clear TROVS bits */
    ADCx->CR2 &= (~ADC_CR2_TROVS_Msk);
    
    /* Set the new Triger Modet */
    ADCx->CR2 |= TrigerMode;
}

/******************************************************************************
* @brief:  Enables or disables the Inject group oversampling
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  NewState: new state of the Inject group oversampling.
*          This parameter can be: ENABLE or DISABLE.
* @return: None
******************************************************************************/
void ADC_InjectOverSamplingCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_FUNCTIONAL_STATE(NewState));
    if (NewState != DISABLE)
    {
        /* Enable the Inject group oversampling */
        ADCx->CR2 |= ADC_CR2_JOVSE;
    }
    else
    {
        /* Disable the Inject group oversampling */
        ADCx->CR2 &= (~ADC_CR2_JOVSE);
    }
}

/******************************************************************************
* @brief:  Enables or disables the analog watchdog on single/all regular or 
*          injected channels
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  ADC_AnalogWatchdog: the ADC analog watchdog configuration.
* @return: None	  
******************************************************************************/
void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_ANALOG_WATCHDOG(ADC_AnalogWatchdog));

    /* Clear AWDEN, JAWDEN and AWDSGL bits */
    ADCx->CR1 &= (~(ADC_CR1_AWDSGL_Msk | ADC_CR1_JAWDEN_Msk | ADC_CR1_AWDEN_Msk));

    /* Set the analog watchdog enable mode */
    ADCx->CR1 |= ADC_AnalogWatchdog;

}


/******************************************************************************
* @brief:  Configure the high threshold and low threshold of single channel analog watchdog.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  HighThreshold: the ADC analog watchdog High threshold value.
*          This parameter must be a 12-bit value.
* @param:  LowThreshold:  the ADC analog watchdog Low threshold value.
*          This parameter must be a 12-bit value.
* @return: None
******************************************************************************/
void ADC_AnalogWatchdogThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, uint16_t LowThreshold)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_THRESHOLD(HighThreshold));
    assert_param(IS_ADC_THRESHOLD(LowThreshold));

    /* Clear the Analog watchdog HT bits */
    ADCx->HTR &= (~ADC_HTR_HT_Msk);
    
    /* Set the ADCx high threshold */
    ADCx->HTR |= HighThreshold;

   /* Clear the Analog watchdog LT bits */
    ADCx->LTR &= (~ADC_LTR_LT_Msk);
    
    /* Set the ADCx low threshold */
    ADCx->LTR |= LowThreshold;
}

/******************************************************************************
* @brief:  Configure the high threshold and low threshold of differential channel analog watchdog.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  HighThreshold: the ADC analog watchdog High threshold value.
*          This parameter must be a 12-bit value.
* @param:  LowThreshold:  the ADC analog watchdog Low threshold value.
*          This parameter must be a 12-bit value.
* @return: None
******************************************************************************/
void ADC_AnalogWatchdogThresholdsOfDifferConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, uint16_t LowThreshold)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_THRESHOLD(HighThreshold));
    assert_param(IS_ADC_THRESHOLD(LowThreshold));

    /* Clear the Analog watchdog DHT bits */
    ADCx->HTR &= (~ADC_HTR_DHT_Msk);
    
    /* Set the ADCx high threshold */
    ADCx->HTR |= HighThreshold << ADC_HTR_DHT_Pos;

    /* Clear the Analog watchdog DLT bits */
    ADCx->LTR &= (~ADC_LTR_DLT_Msk);
    
    /* Set the ADCx low threshold */
    ADCx->LTR |= LowThreshold << ADC_LTR_DLT_Pos;
}

/******************************************************************************
* @brief:  Configures the analog watchdog Regular channel
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  ADC_Channel: the ADC channel to configure for the analog watchdog. 
* @return: None
******************************************************************************/
void ADC_AnalogWatchdogRegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_CHANNEL(ADC_Channel));

    /* Clear the Analog watchdog channel select bits */
    ADCx->CR1 &= (~ADC_CR1_AWDCH_Msk);

    /* Set the Analog watchdog channel */
    ADCx->CR1 |= ADC_Channel;

}

/******************************************************************************
* @brief:  Configures the analog watchdog Inject channel
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  ADC_Channel: the ADC channel to configure for the analog watchdog. 
* @return: None
******************************************************************************/
void ADC_AnalogWatchdogInjectChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_CHANNEL(ADC_Channel));

    /* Clear the Analog watchdog channel select bits */
    ADCx->CR1 &= (~ADC_CR1_AWDJCH_Msk);

    /* Set the Analog watchdog channel */
    ADCx->CR1 |= (ADC_Channel << ADC_CR1_AWDJCH_Pos);

}

/******************************************************************************
* @brief:  Configures for the selected ADC regular channel its corresponding
*          rank in the sequencer and its sample time.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  ADC_Channel: the ADC channel to configure.                   
* @param:  Rank: The rank in the regular group sequencer.
*          This parameter must be between 1 to 16.
* @param:  ADC_SampleTime: The sample time value to be set for the selected channel. 
* @return: None
******************************************************************************/
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_CHANNEL(ADC_Channel));
    assert_param(IS_ADC_SEQUENCE(Rank));
    assert_param(IS_ADC_SMPCLOCK(ADC_SampleTime));
    
    /*---------------------------- ADCx SMPR3 Configuration -----------------*/
    if (ADC_Channel > ADC_CHANNEL_15)/* ADC_Channel include in ADC_Channel_[16..19] */
    {
        /* Clear the old sample time */
        ADCx->SMPR3 &= (~(ADC_SMPR3_SMP16_Msk << (4 * (ADC_Channel - 16))));

        /* Set the new sample time */
        ADCx->SMPR3 |= (ADC_SampleTime << (4 * (ADC_Channel - 16)));
    }
    /*---------------------------- ADCx SMPR1 Configuration -----------------*/
    else if(ADC_Channel < ADC_CHANNEL_8)/* ADC_Channel include in ADC_Channel_[0..7] */
    {
        /* Clear the old sample time */
        ADCx->SMPR1 &= (~(ADC_SMPR1_SMP0_Msk << (4 * ADC_Channel)));

        /* Set the new sample time */
        ADCx->SMPR1 |= (ADC_SampleTime << (4 * ADC_Channel));
    }
    /*---------------------------- ADCx SMPR2 Configuration -----------------*/
    else /* ADC_Channel include in ADC_Channel_[8..15] */
    {
        /* Clear the old sample time */
        ADCx->SMPR2 &= (~(ADC_SMPR2_SMP8_Msk << (4 * (ADC_Channel - 8))));
        
        /* Set the new sample time */
        ADCx->SMPR2 |= (ADC_SampleTime << (4 * (ADC_Channel - 8)));
    }
    /*---------------------------- ADCx SQR1 Configuration -----------------*/
    if (Rank < 6)/* For Rank 1 to 5 */
    {
        /* Clear the old SQx bits for the selected rank */
        ADCx->SQR1 &= (~(ADC_SQR1_SQ1_Msk << (5 * (Rank - 1))));

        /* Set the SQx bits for the selected rank */
        ADCx->SQR1 |= (ADC_Channel << (5 * Rank));
    }
    /*---------------------------- ADCx SQR3 Configuration -----------------*/
    else if(Rank > 11)/* For Rank 12 to 16 */
    {
        /* Clear the old SQx bits for the selected rank */
        ADCx->SQR3 &= (~(ADC_SQR3_SQ12_Msk << (5 * (Rank - 12))));

        /* Set the SQx bits for the selected rank */
        ADCx->SQR3 |= (ADC_Channel << (5 * (Rank - 12)));

    }
    /*---------------------------- ADCx SQR1 Configuration -----------------*/
    else/* For Rank 6 to 11 */
    {
        /* Clear the old SQx bits for the selected rank */
        ADCx->SQR2 &= (~(ADC_SQR2_SQ6_Msk << (5 * (Rank - 6))));

        /* Set the SQx bits for the selected rank */
        ADCx->SQR2 |= (ADC_Channel << (5 * (Rank - 6)));
    }
}

/******************************************************************************
* @brief:  Enables the selected ADC software start conversion of the regular channels.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @return: None
******************************************************************************/
void ADC_SoftwareStartConv(ADC_TypeDef* ADCx)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));

    /* Enable the selected ADC conversion for regular group */
    ADCx->CR1 |= ADC_CR1_SWSTART;
}

/******************************************************************************
* @brief:  Gets the selected ADC Software start regular conversion Status.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @return: The new state of ADC software start conversion (SET or RESET).
******************************************************************************/
FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx)
{
    FlagStatus bitstatus = RESET;
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));

    /* Check the status of SWSTART bit */
    if ((ADCx->CR1 & ADC_CR1_SWSTART) != RESET)
    {
        /* SWSTART bit is set */
        bitstatus = SET;
    }
    else
    {
        /* SWSTART bit is reset */
        bitstatus = RESET;
    }

    /* Return the SWSTART bit status */
    return  bitstatus;
}

/******************************************************************************
* @brief:  Enables or disables the ADC continuous conversion mode 
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  NewState: new state of the selected ADC continuous conversion mode
*          This parameter can be: ENABLE or DISABLE.
* @return: None
******************************************************************************/
void ADC_ContinuousModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        /* Enable the selected ADC continuous conversion mode */
        ADCx->CR1 |= ADC_CR1_CONT;
    }
    else
    {
        /* Disable the selected ADC continuous conversion mode */
        ADCx->CR1 &= (~ADC_CR1_CONT);
    }
}

/******************************************************************************
* @brief:  Configures the discontinuous mode for the selected ADC regular group 
*          channel.
* @param:  ADCx: where x can be 1, 2 or 3 to select the ADC peripheral.
* @param:  Number: specifies the discontinuous mode regular channel count value.
*          This number must be between 1 and 8.
* @return: None
******************************************************************************/
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_REGULAR_DISC_NUMBER(Number));

    /* Clear the old discontinuous mode channel count */
    ADCx->CR1 &= (~ADC_CR1_DISCNUM_Msk);

    /* Set the discontinuous mode channel count */
    ADCx->CR1 |= ((Number - 1) << ADC_CR1_DISCNUM_Pos);
}

/******************************************************************************
* @brief:  Enables or disables the discontinuous mode on regular group channel 
*          for the specified ADC
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  NewState: new state of the selected ADC discontinuous mode on 
*          regular group channel.
*          This parameter can be: ENABLE or DISABLE.
* @return: None
******************************************************************************/
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        /* Enable the selected ADC regular discontinuous mode */
        ADCx->CR1 |= ADC_CR1_DISCEN;
    }
    else
    {
        /* Disable the selected ADC regular discontinuous mode */
        ADCx->CR1 &= (~ADC_CR1_DISCEN);
    }
}

/******************************************************************************
* @brief:  Returns the last ADCx conversion result data for regular channel.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @return: Data conversion value and channel number.
******************************************************************************/
uint32_t ADC_GetConversionValue(ADC_TypeDef* ADCx)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));

    /* Return the selected ADC conversion value */
    return ADCx->DR;
}

/******************************************************************************
* @brief:  Enables or disables the VBAT (Voltage Battery) channel.   
* @param:  NewState: new state of the VBAT channel.
*          This parameter can be: ENABLE or DISABLE.
* @return: None
******************************************************************************/
void ADC_VBATCmd(FunctionalState NewState)                             
{
    /* Check the parameters */
    assert_param(IS_FUNCTIONAL_STATE(NewState));
    if (NewState != DISABLE)
    {    
        ADC12_COMMON->CTSREF &= (~ADC_TSREF_BUFADDR_Msk);
        /* BUF channel function selection VBAT/4 */
        ADC12_COMMON->CTSREF |= ADC_TSREF_BUFADDR_0;
        /* Enable the VBAT channel */
        ADC12_COMMON->CTSREF |= ADC_TSREF_VBATEN;
    }
    else
    {
        /* Disable the VBAT channel */
        ADC12_COMMON->CTSREF &= (~ADC_TSREF_VBATEN);
    }
}

/******************************************************************************
* @brief:  Enables or disables the temperature sensor channel.
* @param:  NewState: new state of the temperature sensor channel.
*          This parameter can be: ENABLE or DISABLE.
* @return: None
******************************************************************************/
void ADC_TempSensorCmd(FunctionalState NewState)                
{
    /* Check the parameters */
    assert_param(IS_FUNCTIONAL_STATE(NewState));
    if (NewState != DISABLE)
    {
        /* BUF channel function selection temperature sensor */
        ADC12_COMMON->CTSREF &= (~ADC_TSREF_BUFADDR_Msk);
        /* Enable the temperature sensor channel */
        ADC12_COMMON->CTSREF |= ADC_TSREF_ENTS;
    }
    else
    {
        /* Disable the temperature sensor channel */
        ADC12_COMMON->CTSREF &= (~ADC_TSREF_ENTS);
    }
}

/******************************************************************************
* @brief:  Enables or disables the specified ADC DMA request.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  NewState: new state of the selected ADC DMA transfer.
*          This parameter can be: ENABLE or DISABLE.
* @return: None
******************************************************************************/
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_FUNCTIONAL_STATE(NewState));
    if (NewState != DISABLE)
    {
        /* Enable the selected ADC DMA request */
        ADCx->CR1 |= ADC_CR1_DMA;
    }
    else
    {
        /* Disable the selected ADC DMA request */
        ADCx->CR1 &= (~ADC_CR1_DMA);
    }
}

/******************************************************************************
* @brief:  Configures for the selected ADC injected channel its corresponding
*          rank in the sequencer and its sample time.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  ADC_Channel: the ADC channel to configure.                     
* @param:  Rank: The rank in the regular group sequencer.
*          This parameter must be between 1 to 4.
* @param:  ADC_SampleTime: The sample time value to be set for the selected channel. 
* @return: None
******************************************************************************/
void ADC_InjectedChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_CHANNEL(ADC_Channel));
    assert_param(IS_ADC_INJECTED_RANK(Rank));
    assert_param(IS_ADC_SMPCLOCK(ADC_SampleTime));
    /*---------------------------- ADCx SMPR3 Configuration -----------------*/
    if (ADC_Channel > ADC_CHANNEL_15)/* ADC_Channel include in ADC_Channel_[16..19] */
    {
        /* Clear the old sample time */
        ADCx->SMPR3 &= (~(ADC_SMPR3_SMP16_Msk << (4 * (ADC_Channel - 16))));

        /* Set the new sample time */
        ADCx->SMPR3 |= (ADC_SampleTime << (4 * (ADC_Channel - 16)));
    }
    /*---------------------------- ADCx SMPR1 Configuration -----------------*/
    else if(ADC_Channel < ADC_CHANNEL_8)/* ADC_Channel include in ADC_Channel_[0..7] */
    {
        /* Clear the old sample time */
        ADCx->SMPR1 &= (~(ADC_SMPR1_SMP0_Msk << (4 * ADC_Channel)));
        
        /* Set the new sample time */
        ADCx->SMPR1 |= (ADC_SampleTime << (4 * ADC_Channel));

    }
    /*---------------------------- ADCx SMPR2 Configuration -----------------*/
    else /* ADC_Channel include in ADC_Channel_[8..15] */
    {
        /* Clear the old sample time */
        ADCx->SMPR2 &= (~(ADC_SMPR2_SMP8_Msk << (4 * (ADC_Channel - 8))));

        /* Set the new sample time */
        ADCx->SMPR2 |= (ADC_SampleTime << (4 * (ADC_Channel - 8)));
    }
  
    /*---------------------------- ADCx JSQR Configuration -----------------*/
    /* Rank configuration */
    /* Clear the old JSQx bits for the selected rank */
    ADCx->JSQR &= (~(ADC_JSQR_JSQ1_Msk << (5 * Rank)));

    /* Set the JSQx bits for the selected rank */
    ADCx->JSQR |= ((ADC_Channel << (5 * Rank)));

}

/******************************************************************************
* @brief:  Configures the sequencer length for injected channels
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  Length: The sequencer length. 
*          This parameter must be a number between 1 to 4.
* @return: None
******************************************************************************/
void ADC_InjectedSequencerLengthConfig(ADC_TypeDef* ADCx, uint8_t Length)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_INJECTED_LENGTH(Length));

    /* Clear the old injected sequence length JL bits */
    ADCx->JSQR &= (~ADC_JSQR_JL_Msk);

    /* Set the injected sequence length JL bits */
    ADCx->JSQR |= (Length - 1); 
}



/******************************************************************************
* @brief:  Configures the ADCx external trigger for injected channels conversion.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  ADC_ExternalTrigInjecConv: specifies the ADC trigger to start injected conversion.                        
* @return: None
******************************************************************************/
void ADC_ExternalTrigInjectedConvConfig(ADC_TypeDef* ADCx, uint32_t ADC_ExternalTrigInjecConv)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_EXT_TRIG(ADC_ExternalTrigInjecConv));

    /* Clear the old external event selection for injected group */
    ADCx->JSQR &= (~ADC_JSQR_JEXTSEL_Msk);

    /* Set the external event selection for injected group */
    ADCx->JSQR |= (ADC_ExternalTrigInjecConv << ADC_JSQR_JEXTSEL_Pos);
}

/******************************************************************************
* @brief:  Configures the ADCx external trigger edge for injected channels conversion.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  ADC_ExternalTrigInjecConvEdge: specifies the ADC external trigger edge
*          to start injected conversion. 
* @return: None
******************************************************************************/
void ADC_ExternalTrigInjectedConvEdgeConfig(ADC_TypeDef* ADCx, uint32_t ADC_ExternalTrigInjecConvEdge)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_EXT_TRIG_EDGE(ADC_ExternalTrigInjecConvEdge));    
    
    /* Clear the old external trigger edge for injected group */
    ADCx->JSQR &= (~ADC_JSQR_JEXTEN_Msk);
    
    /* Set the new external trigger edge for injected group */
    ADCx->JSQR |= (ADC_ExternalTrigInjecConvEdge << ADC_JSQR_JEXTEN_Pos);
}

/******************************************************************************
* @brief:  Enables the selected ADC software start conversion of the injected channels.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @return: None
******************************************************************************/
void ADC_SoftwareStartInjectedConv(ADC_TypeDef* ADCx)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    
    /* Enable the selected ADC conversion for injected group */
    ADCx->CR1 |= ADC_CR1_JSWSTART;
}

/******************************************************************************
* @brief:  Gets the selected ADC Software start injected conversion Status.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @return: None
******************************************************************************/
FlagStatus ADC_GetSoftwareStartInjectedConvCmdStatus(ADC_TypeDef* ADCx)
{
    FlagStatus bitstatus = RESET;
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));

    /* Check the status of JSWSTART bit */
    if ((ADCx->CR1 & ADC_CR1_JSWSTART) != RESET)
    {
        /* JSWSTART bit is set */
        bitstatus = SET;
    }
    else
    {
        /* JSWSTART bit is reset */
        bitstatus = RESET;
    }
    /* Return the JSWSTART bit status */
    return  bitstatus;
}

/******************************************************************************
* @brief:  Enables or disables the selected ADC automatic injected group 
*          conversion after regular one.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  NewState: new state of the selected ADC auto injected conversion
*          This parameter can be: ENABLE or DISABLE.
* @return: None
******************************************************************************/
void ADC_AutoInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_FUNCTIONAL_STATE(NewState));
    if (NewState != DISABLE)
    {
        /* Enable the selected ADC automatic injected group conversion */
        ADCx->CR1 |= ADC_CR1_JAUTO;
    }
    else
    {
        /* Disable the selected ADC automatic injected group conversion */
        ADCx->CR1 &= (~ADC_CR1_JAUTO);
    }
}

/******************************************************************************
* @brief:  Enables or disables the discontinuous mode for injected group 
*          channel for the specified ADC
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  NewState: new state of the selected ADC auto injected conversion
*          This parameter can be: ENABLE or DISABLE.
* @return: None
******************************************************************************/
void ADC_InjectedDiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_FUNCTIONAL_STATE(NewState));
    if (NewState != DISABLE)
    {
        /* Enable the selected ADC injected discontinuous mode */
        ADCx->CR1 |= ADC_CR1_JDISCEN;
    }
    else
    {
        /* Disable the selected ADC injected discontinuous mode */
        ADCx->CR1 &= (~ADC_CR1_JDISCEN);
    }
}

/******************************************************************************
* @brief:  Returns the ADC injected channel conversion result
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  JDRNumber: Injection data register number.
* @return: Data conversion value and channel number.
******************************************************************************/
uint32_t ADC_GetInjectedConversionValue(ADC_TypeDef* ADCx, uint8_t JDRNumber)
{
    __IO uint32_t tmpreg = 0;

    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_JDR_NUMBER(JDRNumber));

    tmpreg = (uint32_t)ADCx;
    
    tmpreg += (uint32_t)(ADC_JDR1_ADDR_OFFSET + 4 * (JDRNumber -1));

    /* Returns the selected injected channel conversion data value */
    return (uint32_t) (*(__IO uint32_t*) tmpreg); 
}



/******************************************************************************
* @brief:  Enables or disables the specified ADC interrupts.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  ADC_IT: specifies the ADC interrupt sources to be enabled or disabled.                   
* @param:  NewState: new state of the specified ADC interrupts.
*          This parameter can be: ENABLE or DISABLE.
* @return: None.
******************************************************************************/
void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState)  
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_FUNCTIONAL_STATE(NewState));
    assert_param(IS_ADC_IT_FLAG(ADC_IT));    

    if (NewState != DISABLE)
    {
        /* Enable the selected ADC interrupts */
        ADCx->IE |= ADC_IT;
    }
    else
    {
        /* Disable the selected ADC interrupts */
        ADCx->IE &= (~ADC_IT);
    }
}

/******************************************************************************
* @brief:  Checks whether the specified ADC flag is set or not.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  ADC_FLAG: specifies the flag to check.                                               
* @return: The new state of ADC_FLAG (SET or RESET).
******************************************************************************/
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG)
{
    FlagStatus bitstatus = RESET;
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_IT_FLAG(ADC_FLAG));

    /* Check the status of the specified ADC flag */
    if ((ADCx->SR & ADC_FLAG) != RESET)
    {
        /* ADC_FLAG is set */
        bitstatus = SET;
    }
    else
    {
        /* ADC_FLAG is reset */
        bitstatus = RESET;
    }
    /* Return the ADC_FLAG status */
    return  bitstatus;
}

/******************************************************************************
* @brief:  Clears the ADCx's pending flags.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  ADC_FLAG: specifies the flag to clear.                       
* @return: None
******************************************************************************/
void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_IT_FLAG(ADC_FLAG));

    /* Clear the selected ADC flags */
    ADCx->SR = ADC_FLAG;
}

/******************************************************************************
* @brief:  Checks whether the specified ADC interrupt has occurred or not.
* @param:  ADCx: where x can be 1 or 2 to select the ADC peripheral.
* @param:  ADC_IT: specifies the ADC interrupt source to check.                       
* @return: The new state of ADC_FLAG (SET or RESET).
******************************************************************************/
ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT)
{
    ITStatus bitstatus = RESET;
    uint32_t enablestatus = 0;

    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_IT_FLAG(ADC_IT));

    /* Get the ADC_IT enable bit status */
    enablestatus = (ADCx->IE & ADC_IT) ;

    /* Check the status of the specified ADC interrupt */
    if (((ADCx->SR & ADC_IT) != RESET) && enablestatus)
    {
        /* ADC_IT is set */
        bitstatus = SET;
    }
    else
    {
        /* ADC_IT is reset */
        bitstatus = RESET;
    }
    /* Return the ADC_IT status */
    return  bitstatus;
}

/******************************************************************************
* @brief:  Clears the ADC's interrupt pending bits.
* @param:  ADC_IT: specifies the ADC interrupt pending bit to clear.
* @return: none
******************************************************************************/
void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint32_t ADC_IT)
{
    /* Check the parameters */
    assert_param(IS_ADC_INSTANCE(ADCx));
    assert_param(IS_ADC_IT_FLAG(ADC_IT));
    
    if((ADCx->IE & ADC_IT)!= RESET)
    {
        /* Clear the interrupt pending bits in the RTC_SR register */
        ADCx->SR = ADC_IT;
    } 
}
                
/******************************************************************************
* @brief:  Returns the last ADC1, ADC2 regular conversions results 
*          data in the selected multi mode.
* @param:  None  
* @return: The Data conversion value.         
******************************************************************************/
uint32_t ADC_GetMultiModeConversionValue(void)
{
    /* Return the multi mode conversion value */
    return ADC12_COMMON->CDR;
}



//#endif    /* SPL_ADC_MODULE_ENABLED */


/************************ (C) COPYRIGHT AISINOCHIP *****END OF FILE****/
