/**
  ******************************************************************************
  * @file    lcm32f06x_adc.c
  * @author  System R&D Team
  * @version V2.0.2
  * @date    10-April-2025
  * @brief   This file provides all the adc firmware functions.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) Hangzhou Lingxin Microelectronics Co.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "lcm32f06x_adc.h"

/**
  * @name   ADC_DeInit
  * @brief  EN: Deinitializes ADC peripheral registers to their default reset values.
  *         CN: 将ADC外围寄存器初始化为其默认重置值。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @retval None
  */
void ADC_DeInit(ADC_TypeDef *ADCx)
{
  if (ADCx == ADC)
  {
    /* Release ADC1 from reset state */
    RCC_APB0PeriphResetCmd(RCC_APB0Periph_ADC, ENABLE);
    /* Enable ADC1 reset state */
    RCC_APB0PeriphResetCmd(RCC_APB0Periph_ADC, DISABLE);
  }
}

/**
  * @name   ADC_Cmd
  * @brief  EN: Enables or disables the specified ADC peripheral.
  *         CN: 启用或禁用指定的ADC外围设备。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  NewState: 
  *         EN: New state of the ADC peripheral.
  *         CN: ADC外围设备的新状态。
  *             @arg ENABLE
  *             @arg DISABLE
  * @retval None
  */
void ADC_Cmd(ADC_TypeDef *ADCx, FunctionalState State)
{
  if (State != DISABLE)
  {
    /* Set the ADEN bit to Enable the ADC peripheral */
    ADCx->ANA_b.PD_ADC = 0;
    ADCx->ANA_b.PD_REF = 0;
    ADCx->ANA_b.PD_SHA = 0;
    ADCx->ANA_b.PD_SHB = 0;
    ADCx->CR_b.EN = 1;
    do
    {
      __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    } while (ADCx->SR_b.READY == 0);
  }
  else
  {
    /* Set the ADDIS to Disable the ADC peripheral */
    ADCx->CR_b.STOP = 1;
    do
    {
      __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    } while (ADCx->CR_b.STOP);
    ADCx->CR_b.DIS = 1;
    do
    {
      __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    } while (ADCx->CR_b.EN);
    ADCx->ANA_b.PD_ADC = 1;
    ADCx->ANA_b.PD_REF = 1;
    ADCx->ANA_b.PD_SHA = 1;
    ADCx->ANA_b.PD_SHB = 1;
  }
}

/**
  * @name   ADC_StructInit
  * @brief  EN: Fills each ADC_InitStruct member with its default value.
  *         CN: 用默认值填充每个ADC_InitStruct成员。
  * @param  ADC_InitStruct: 
  *         EN: pointer to an ADC_InitTypeDef structure which will be initialized.
  *         CN: 指向将被初始化的ADC_InitTypeDef结构的指针。
  * @retval None
  */
void ADC_StructInit(ADC_InitTypeDef *ADC_InitStruct)
{
  /* Reset ADC init structure parameters values */
  ADC_InitStruct->ADC_ClkMode = ADC_ClockMode_SynClkDiv1;
  ADC_InitStruct->ADC_ReferenceVoltage = ADC_ReferenceVoltage_3V2;
  ADC_InitStruct->ADC_VCCChanelMapping = ADC_VCCChanel_DISABLE;
  ADC_InitStruct->ADC_TempChanelMapping = ADC_TempChanel_DISABLE;
  ADC_InitStruct->ADC_WorkMode = ADC_WorkMode_Normal;
  ADC_InitStruct->ADC_OverFlowMode = ADC_OverFlow_New;
  ADC_InitStruct->ADC_LowPowerMode = DISABLE;
  ADC_InitStruct->ADC_DataAlign = ADC_DataAlign_Right;
  
  ADC_InitStruct->ADC_SampleTime = 7;       // 取值范围0-7;AD 采样信号脉冲宽度 默认值为 010，脉冲宽度=(x+1)*CLK
  ADC_InitStruct->ADC_AdjustTime = 7;       // 取值范围0-7;AD 上电准备阶段脉冲宽度 默认值为 010，脉冲宽度=(x+1)*CLK
  ADC_InitStruct->ADC_ConvertTime = 0;      // 取值范围0-15;采样周期
  ADC_InitStruct->ADC_ConvertPulseTime = 0; // 取值范围0-1;启动转换脉冲宽度 默认值为 0，脉冲宽度=(x+3)*CLK
  ADC_InitStruct->ADC_TempPulseTime = 0;    // 取值范围0-15;温度采样脉冲宽度
}

/**
  * @name   ADC_Init
  * @brief  EN: Initializes the ADCx peripheral according to the specified parameters in the ADC_InitStruct.
  *         CN: 根据指定的参数初始化ADCx外围设备在ADC_InitStruct中。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  ADC_InitStruct: 
  *         EN: Pointer to an ADC_InitTypeDef structure that contains the configuration information for the specified ADC peripheral.
  *         CN: 指向ADC_InitTypeDef结构的指针，该结构包含指定ADC外围设备的配置信息。
  * @retval None
  */
void ADC_Init(ADC_TypeDef *ADCx, ADC_InitTypeDef *ADC_InitStruct)
{
  uint32_t tmpreg0 = 0;
  uint32_t tmpreg1 = 0;
  uint32_t AD_TRIM_temp = 0;
  uint32_t ADCG;
  uint32_t ADCV;
  uint32_t AD_SELECT_DATA = 0;
  tmpreg0 = ADCx->CFGR;
  tmpreg1 = ADCx->SMPR;

  tmpreg0 &= 0x00000000;
  tmpreg1 &= 0x00000000;
  if(ADC_InitStruct->ADC_WorkMode == ADC_WorkMode_Stable)
  {
    if (ADC_InitStruct->ADC_ConvertTime >= 0xF)
      ADC_InitStruct->ADC_ConvertTime = 0xF;
    else
      ADC_InitStruct->ADC_ConvertTime += 1;
  }
  tmpreg0 |= (uint32_t)(ADC_InitStruct->ADC_ClkMode | ADC_InitStruct->ADC_ReferenceVoltage | \
                        ADC_InitStruct->ADC_VCCChanelMapping | ADC_InitStruct->ADC_TempChanelMapping | \
                        ADC_InitStruct->ADC_WorkMode | ADC_InitStruct->ADC_OverFlowMode | \
                        (uint32_t)((ADC_InitStruct->ADC_LowPowerMode) << 16) | ADC_InitStruct->ADC_DataAlign);


  tmpreg1 |= (uint32_t)((ADC_InitStruct->ADC_AdjustTime) | ((ADC_InitStruct->ADC_TempPulseTime) << 20) | ((ADC_InitStruct->ADC_SampleTime) << 4) |
                        ((ADC_InitStruct->ADC_ConvertPulseTime) << 8) | ((ADC_InitStruct->ADC_ConvertTime) << 12));

  ADCx->CFGR = tmpreg0;
  ADCx->SMPR = tmpreg1;
  AD_SELECT_DATA = ADC_InitStruct->ADC_ReferenceVoltage;

  if (AD_SELECT_DATA==ADC_ReferenceVoltage_4V9)// VREF=4V9
  {
    if (ADC_InitStruct->ADC_LowPowerMode == ENABLE)
    {
      AD_TRIM_temp = (*(volatile uint32_t *)(0x1FFFF7A8));
    }
    else
    {
      AD_TRIM_temp = (*(volatile uint32_t *)(0x1FFFF7A0));
    }

    if (AD_TRIM_temp == 0xffffffff)
    {
      ADCx->TRIM = 0x009700A3;
    }
    else
    {
        ADCx->TRIM = AD_TRIM_temp;
    }
  }
  else //VREF=3.2 / VDD
  {
    if (ADC_InitStruct->ADC_LowPowerMode == ENABLE)
    {
        AD_TRIM_temp = (*(volatile uint32_t *)(0x1FFFF7A4));
    }
    else
    {
        AD_TRIM_temp = (*(volatile uint32_t *)(0x1FFFF70C));     
    }

    if (AD_TRIM_temp == 0xffffffff)
    {
      ADCx->TRIM = 0x009700A3;
    }
    else
    {
      if (ADC_InitStruct->ADC_LowPowerMode == ENABLE)
      {
        ADCx->TRIM = AD_TRIM_temp;
      }
      else
      {
        ADCG=((AD_TRIM_temp^0x005c0000)>>16)&0x000000ff;
        ADCV=(( AD_TRIM_temp^0x00000068)<<16)&0x00ff0000;
        ADCx->TRIM =ADCG+ADCV;
      }
    }
  }
}

/**
  * @name   ADC_ExternTrigger_Config
  * @brief  EN: Configure the delay time for external triggering of X.
  *         CN: 配置外部触发X的延迟时间。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  ExternTigger: 
  *         EN: Select an external trigger x.
  *         CN: 选择外部触发 x。
  *             @arg ADC_ExternTrigeer0
  *             @arg ADC_ExternTrigeer1
  *             @arg ADC_ExternTrigeer2
  *             @arg ADC_ExternTrigeer3
  * @param  Delay: 
  *         EN: Delay time.
  *         CN: 延迟时间。
  * @retval None
  */
void ADC_ExternTrigger_Config (ADC_TypeDef *ADCx, uint8_t ExternTigger, uint8_t Delay)
{
  assert_param(IS_ADC_EXTERNT_TRIGGER(ExternTigger));
  uint32_t Temp = 0;
  if(ExternTigger == ADC_ExternTrigeer0)
  {
    Temp = ADCx->EXTCFGR0 & (~ADC_EXTCFGR0_DLY0_Msk);
    Temp |= Delay << ADC_EXTCFGR0_DLY0_Pos;
  }
  else if (ExternTigger == ADC_ExternTrigeer1)
  {
    Temp = ADCx->EXTCFGR0 & (~ADC_EXTCFGR0_DLY1_Msk);
    Temp |= Delay << ADC_EXTCFGR0_DLY1_Pos;
  }
  else if (ExternTigger == ADC_ExternTrigeer2)
  {
    Temp = ADCx->EXTCFGR0 & (~ADC_EXTCFGR0_DLY2_Msk);
    Temp |= Delay << ADC_EXTCFGR0_DLY2_Pos;
  }
  else if (ExternTigger == ADC_ExternTrigeer3)
  {
    Temp = ADCx->EXTCFGR0 & (~ADC_EXTCFGR0_DLY3_Msk);
    Temp |= Delay << ADC_EXTCFGR0_DLY3_Pos;
  }
  ADCx->EXTCFGR0 = Temp;
}

/**
  * @name   ADC_StopOfConversion
  * @brief  EN: ADC stops current conversion.
  *         CN: ADC停止当前转换。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @retval None
  */

void ADC_StopOfConversion(ADC_TypeDef *ADCx)
{
  if (ADCx->CR & ADC_CR_START_Msk)
  {
    ADCx->CR = (uint32_t)ADC_CR_STOP_Msk;
  }
  while (ADCx->CR & ADC_CR_STOP_Msk)  /* 等待硬件自动清除stop */
  {
      __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
  };
}

/**
  * @name   ADC_StartOfConversion
  * @brief  EN: ADC begins conversion.
  *         CN: ADC开始转换。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @retval None
  */
void ADC_StartOfConversion(ADC_TypeDef *ADCx)
{
  while (!(ADCx->SR & ADC_SR_READY_Msk))
  {
    __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
  };
  ADCx->CR = (uint32_t)ADC_CR_START_Msk; // ADSTART
  delay10us(1);
  while (!(ADCx->CR & ADC_CR_START_Msk))
  {
    __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
  }
}

/**
  * @name   ADC_CloseAdc
  * @brief  EN: Stop or shut down the ADC module.
  *         CN: 停止或关闭 ADC模块。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @retval None
  */
void ADC_CloseAdc(ADC_TypeDef *ADCx)
{
  if (ADCx->CR & ADC_CR_START_Msk)
  {
    ADCx->CR = ADC_CR_STOP_Msk;
  }
  while (ADCx->CR & ADC_CR_STOP_Msk)
  {
      __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
  };
  ADCx->CR = ADC_CR_DIS_Msk;
  while (ADCx->CR & ADC_CR_EN_Msk)
  {
      __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
  };
}

/**
  * @name   ADC_GetConversionValue
  * @brief  EN: Obtain ADC SOC conversion value.
  *         CN: 获取ADC SOC转换值。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  SOCx:
  *         EN: where x can be from 0 to 15 to select the SOC channel
  *         CN: 其中 x 可以是 0 至 15 以选择 SOC 通道。
  * @retval uint16_t
  */
uint16_t ADC_GetConversionValue(ADC_TypeDef *ADCx ,uint32_t SOCx)
{

  while (!(ADCx->SOCISR & (1 << SOCx)))
  {
      __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
  };
  return (uint16_t)(DR(SOCx));
}

/**
  * @name   ADC_GetDMAValue
  * @brief  EN: Obtain ADC DMA conversion value.
  *         CN: 获取ADC DMA 转换值。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @retval uint16_t
  */
uint16_t ADC_GetDMAValue(ADC_TypeDef *ADCx )
{
  return (uint16_t)ADCx->DADDR;
}

/**
  * @name   ADC_SOC_Config
  * @brief  EN: ADC SOC configuration.
  *         CN: ADC SOC配置。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  SOCx:
  *         EN: where x is 0 to 15 to select the SOCx.
  *         CN: 其中 x 是 0 到 15 以选择 ADC 外设。
  * @param  TriggerSource:
  *         EN: Specify trigger source selection.
  *         CN: 指定触发源选择。
  *             @arg TriggerSelect0
  *             @arg TriggerSelect1
  *             @arg TriggerSelect2
  *             @arg TriggerSelect3
  *             @arg TriggerSelectNone
  * @param  ADCIN:
  *         EN: Specify external ADIN selection.
  *         CN: 指定外部ADIN选择。
  * @param  SOC_SAMP:
  *         EN: Specify sampling mode.
  *         CN: 指定采样模式。
  *             @arg SOC_SAMP_SINGLE
  *             @arg SOC_SAMP_DOUBLE
  * @retval uint16_t
  */
void ADC_SOC_Config_New(ADC_TypeDef *ADCx, uint32_t SOCx, uint32_t TriggerSource, uint32_t ADCIN, uint32_t SOC_SAMP)
{
  if (SOCx <= SOC15) {
    ADCSOC(ADCx, SOCx) = (TriggerSource | ADCIN | SOC_SAMP);
  }
}
void ADC_SOC_Config(ADC_TypeDef *ADCx, uint32_t SOCx, uint32_t TriggerSource ,uint32_t ADCIN, uint32_t SOC_SAMP)
{
  if(SOCx == SOC0)
    ADCx->ADCSOC0 = (TriggerSource|ADCIN|SOC_SAMP);
  else if(SOCx == SOC1)
    ADCx->ADCSOC1 = (TriggerSource|ADCIN|SOC_SAMP);
  else if(SOCx == SOC2)
    ADCx->ADCSOC2 = (TriggerSource|ADCIN|SOC_SAMP);
  else if(SOCx == SOC3)
    ADCx->ADCSOC3 = (TriggerSource|ADCIN|SOC_SAMP);
  else if(SOCx == SOC4)
    ADCx->ADCSOC4 = (TriggerSource|ADCIN|SOC_SAMP);
  else if(SOCx == SOC5)
    ADCx->ADCSOC5 = (TriggerSource|ADCIN|SOC_SAMP);
  else if(SOCx == SOC6)
    ADCx->ADCSOC6 = (TriggerSource|ADCIN|SOC_SAMP);
  else if(SOCx == SOC7)
    ADCx->ADCSOC7 = (TriggerSource|ADCIN|SOC_SAMP);
  else if(SOCx == SOC8)
    ADCx->ADCSOC8 = (TriggerSource|ADCIN|SOC_SAMP);
  else if(SOCx == SOC9)
    ADCx->ADCSOC9 = (TriggerSource|ADCIN|SOC_SAMP);
  else if(SOCx == SOC10)
    ADCx->ADCSOC10 = (TriggerSource|ADCIN|SOC_SAMP);
  else if(SOCx == SOC11)
    ADCx->ADCSOC11 = (TriggerSource|ADCIN|SOC_SAMP);
  else if(SOCx == SOC12)
    ADCx->ADCSOC12 = (TriggerSource|ADCIN|SOC_SAMP);
  else if(SOCx == SOC13)
    ADCx->ADCSOC13 = (TriggerSource|ADCIN|SOC_SAMP);
  else if(SOCx == SOC14)
    ADCx->ADCSOC14 = (TriggerSource|ADCIN|SOC_SAMP);
  else if(SOCx == SOC15)
    ADCx->ADCSOC15 = (TriggerSource|ADCIN|SOC_SAMP);
}

/**
  * @name   TrigSelect_Config
  * @brief  EN: ADC SOC trigger source configuration.
  *         CN: ADC SOC触发源配置。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  TriggerSelect:
  *         EN: Select hardware trigger source.
  *         CN: 选择硬件触发源。
  *             @arg TriggerSelect0
  *             @arg TriggerSelect1
  *             @arg TriggerSelect2
  *             @arg TriggerSelect3
  * @param  AdcExtsel:
  *         EN: Trigger source selection.
  *         CN: 触发源选择。
  *             @arg TriggerSelect0_TIM1_TRIG_OC1...
  *             @arg TriggerSelect1_TIM1_TRIG_OC2...
  *             @arg TriggerSelect2_TIM1_TRIG_OC3...
  *             @arg TriggerSelect3_TIM1_TRIG_OC4...
  * @param  Triggermode:
  *         EN: Trigger mode selection.
  *         CN: 触发模式选择。
  *             @arg Triggermode_rising
  *             @arg Triggermode_falling
  *             @arg Triggermode_rising_falling
  *             @arg Triggermode_Dis
  * @retval None
  */
void TrigSelect_Config(ADC_TypeDef *ADCx, uint32_t TriggerSelect ,uint32_t AdcExtsel, uint32_t Triggermode)
{
  if (TriggerSelect == TriggerSelect0)
  {
    sysctrl_access();
    SYSCTRL->EDU_CFG11 &= 0xFFFF0000;
    SYSCTRL->EDU_CFG11 |= (uint32_t) (AdcExtsel) | (Triggermode << 8);
    __dekey();
  }
  else if (TriggerSelect == TriggerSelect1)
  {
    sysctrl_access();
    SYSCTRL->EDU_CFG11 &= 0x0000FFFF;
    SYSCTRL->EDU_CFG11 |= (uint32_t) (AdcExtsel << 16) | (Triggermode << 24);
    __dekey();
  }
  else if (TriggerSelect == TriggerSelect2)
  {
    sysctrl_access();
    SYSCTRL->EDU_CFG12 &= 0xFFFF0000;
    SYSCTRL->EDU_CFG12 |= (uint32_t) (AdcExtsel) | (Triggermode << 8);
    __dekey();
  }
  else if (TriggerSelect == TriggerSelect3)
  {
    sysctrl_access();
    SYSCTRL->EDU_CFG12 &= 0x0000FFFF;
    SYSCTRL->EDU_CFG12 |= (uint32_t) (AdcExtsel << 16) | (Triggermode << 24);
    __dekey();
  }
}

/**
  * @name   ADC_DMA_Cmd
  * @brief  EN: Enable DMA data transmission corresponding to SOC.
  *         CN: SOC 对应的 DMA 数据传输使能。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  SOCx_DMA:
  *         EN: where x can be from 0 to 15 to select the SOC channel
  *         CN: 其中 x 可以是 0 至 15 以选择 SOC DMA 通道。
  * @param  NewState: 
  *         EN: New state of SOC DMA transmission.
  *         CN: SOC DMA 传输的新状态。
  *             @arg ENABLE
  *             @arg DISABLE
  * @retval None
  */
void ADC_DMA_Cmd(ADC_TypeDef *ADCx,uint32_t SOCx_DMA,FunctionalState NewState)
{
  if (NewState != DISABLE)
  {
    ADCx->DMACFG |= (SOCx_DMA << 16);
  }
  else
  {
    ADCx->DMACFG  &= ~(SOCx_DMA << 16);
  }
}

/**
  * @name   ADC_DMA_TransReq
  * @brief  EN: DMA data transfer request corresponding to SOC.
  *         CN: SOC 对应的 DMA 数据传输请求。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  SOCx_DMA:
  *         EN: where x can be from 0 to 15 to select the SOC channel
  *         CN: 其中 x 可以是 0 至 15 以选择 SOC DMA 通道。
  * @param  NewState: 
  *         EN: New state of SOC DMA transmission request.
  *         CN: SOC DMA 传输请求的新状态。
  *             @arg ENABLE
  *             @arg DISABLE
  * @retval None
  */
void ADC_DMA_TransReq(ADC_TypeDef *ADCx, uint32_t SOCx_DMA, FunctionalState NewState)
{
  if (NewState != DISABLE)
  {
    ADCx->DMACFG |= SOCx_DMA;
  }
  else
  {
    ADCx->DMACFG  &= ~SOCx_DMA;
  }
}

/**
  * @name   ADC_ITConfig
  * @brief  EN: Enables or disables the specified ADC interrupts.
  *         CN: 启用或禁用指定的ADC中断。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  ADC_IT: 
  *         EN: Specifies the ADC interrupt sources to be enabled or disabled.
  *         CN: 指定要启用或禁用的ADC中断源。
  *             @arg ADC_IT_DOF
  *             @arg ADC_IT_AWD0
  *             @arg ADC_IT_AWD1
  * @param  NewState: 
  *         EN: new state of the specified ADC interrupts.
  *         CN: 指定ADC中断的新状态。
  *             @arg ENABLE
  *             @arg DISABLE
  * @retval None
  */
void ADC_ITConfig(ADC_TypeDef* ADCx, uint32_t ADC_IT, FunctionalState NewState)
{
  assert_param(IS_ADC_IT(ADC_IT));
  /* Check the parameters */
  if (NewState != DISABLE)
  {
    /* Enable the selected ADC interrupts */
    ADCx->IER |= ADC_IT;
  }
  else
  {
    /* Disable the selected ADC interrupts */
    ADCx->IER &= (~(uint32_t)ADC_IT);
  }
}

/**
  * @name   ADC_SOC_ITConfig
  * @brief  EN: Enables or disables the specified ADC interrupts.
  *         CN: 启用或禁用指定的ADC SOC中断。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  SOC_IT: 
  *         EN: Specifies the ADC SOC interrupt sources to be enabled or disabled.
  *         CN: 指定要启用或禁用的ADC SOC中断源。
  *             @arg ADC_IT_EOC0...ADC_IT_EOC15
  *             @arg ADC_IT_POF0...ADC_IT_POF15
  * @param  NewState: 
  *         EN: new state of the specified ADC interrupts.
  *         CN: 指定ADC中断的新状态。
  *             @arg ENABLE
  *             @arg DISABLE
  * @retval None
  */
void ADC_SOC_ITConfig(ADC_TypeDef* ADCx, uint32_t ADC_SOC_IT, FunctionalState NewState)
{
  assert_param(IS_ADC_SOC_IT(ADC_SOC_IT));
  /* Check the parameters */
  if (NewState != DISABLE)
  {
    /* Enable the selected ADC interrupts */
    ADCx->SOCIER |= ADC_SOC_IT;
  }
  else
  {
    /* Disable the selected ADC interrupts */
    ADCx->SOCIER &= (~(uint32_t)ADC_SOC_IT);
  }
}

/**
  * @name   ADC_GetFlagStatus
  * @brief  EN: Read ADC status flags.
  *         CN: 读取 ADC 状态标志。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  ADC_FLAG: 
  *         EN: Specify the ADC flag to be read.
  *         CN: 指定ADC要读取的标志。
  *             @arg ADC_FLAG_READY
  *             @arg ADC_FLAG_BUSY
  *             @arg ADC_FLAG_PENDING0
  *             @arg ...
  *             @arg ADC_FLAG_PENDING15
  * @retval FlagStatus
  */
FlagStatus ADC_GetFlagStatus(ADC_TypeDef *ADCx, uint32_t ADC_FLAG)
{
  FlagStatus bitstatus = RESET;
  uint32_t tmpreg = 0;

  /* Check the parameters */
  assert_param(IS_ADC_FLAG(ADC_FLAG));

  tmpreg = ADCx->SR;

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

/**
  * @name   ADC_GetITStatus
  * @brief  EN: Read the specified ADC interrupt status.
  *         CN: 读取指定的ADC中断状态。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  ADC_IT: 
  *         EN: Specifies the ADC interrupt sources to be read.
  *         CN: 指定要读取的ADC中断源。
  *             @arg ADC_IT_DOF
  *             @arg ADC_IT_AWD0
  *             @arg ADC_IT_AWD1
  * @retval ITStatus
  */
ITStatus ADC_GetITStatus(ADC_TypeDef *ADCx, uint32_t ADC_IT)
{
  ITStatus bitstatus = RESET;
  uint32_t enablestatus = 0;

  /* Check the parameters */
  assert_param(IS_ADC_IT(ADC_IT));

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

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

/**
  * @name   ADC_GetSOCITStatus
  * @brief  EN: Read the specified ADC SOC interrupt status.
  *         CN: 读取指定的ADC SOC中断状态。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  ADC_IT: 
  *         EN: Specifies the ADC SOC interrupt sources to be enabled or disabled.
  *         CN: 指定要启用或禁用的ADC SOC 中断源。
  *             @arg ADC_IT_POF0
  *             @arg ...
  *             @arg ADC_IT_POF15
  *             @arg ADC_IT_EOC0
  *             @arg ...
  *             @arg ADC_IT_EOC15
  * @param  NewState: 
  *         EN: new state of the specified ADC SOC interrupts.
  *         CN: 指定ADC SOC中断的新状态。
  *             @arg ENABLE
  *             @arg DISABLE
  * @retval ITStatus
  */
ITStatus ADC_GetSOCITStatus(ADC_TypeDef *ADCx, uint32_t ADC_SOC_IT)
{
  ITStatus bitstatus = RESET;
  uint32_t enablestatus = 0;

  /* Check the parameters */
  assert_param(IS_ADC_SOC_IT(ADC_SOC_IT));

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

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

/**
  * @name   ADC_ClearITPendingBit
  * @brief  EN: Clears the ADCx's interrupt pending bits.
  *         CN: 清除ADCx的中断挂起位。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  ADC_IT: 
  *         EN: Specifies the ADC interrupt sources to be enabled or disabled.
  *         CN: 指定要启用或禁用的ADC中断源。
  *             @arg ADC_IT_DOF
  *             @arg ADC_IT_AWD0
  *             @arg ADC_IT_AWD1
  * @retval None
  */
void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint32_t ADC_IT)
{
  /* Check the parameters */
  assert_param(IS_ADC_IT(ADC_IT));

  /* Clear the selected ADC interrupt pending bits */
  ADCx->ISR = (uint32_t)ADC_IT; 
}

/**
  * @name   ADC_ClearSOCITPendingBit
  * @brief  EN: Clears the ADCx's SOC interrupt pending bits.
  *         CN: 清除ADCx的SOC中断挂起位。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  ADC_IT: 
  *         EN: Specifies the ADC SOC interrupt sources to be enabled or disabled.
  *         CN: 指定要启用或禁用的ADC SOC中断源。
  *             @arg ADC_IT_POF0
  *             @arg ...
  *             @arg ADC_IT_POF15
  *             @arg ADC_IT_EOC0
  *             @arg ...
  *             @arg ADC_IT_EOC15
  * @retval None
  */
void ADC_ClearSOCITPendingBit(ADC_TypeDef* ADCx, uint32_t ADC_SOC_IT)
{
  /* Check the parameters */
  assert_param(IS_ADC_SOC_IT(ADC_SOC_IT));

  /* Clear the selected ADC interrupt pending bits */
  ADCx->SOCISR = (uint32_t)ADC_SOC_IT; 
}


/**
  * @name   ADC_Trim
  * @brief  EN: ADC calibration value writing.
  *         CN: ADC 校准值写入。
  * @param  VosTrim:
  *         EN: ADC offset.
  *         CN: ADC 偏移。
  * @param  GainTrim: 
  *         EN: ADC gain.
  *         CN: ADC 增益。
  * @retval None
  */
void ADC_Trim(ADC_TypeDef *ADCx, uint8_t VosTrim, uint8_t GainTrim)
{
  /* Write Trim Value*/
  ADCx->TRIM_b.VOS_TRIM = VosTrim;
  ADCx->TRIM_b.GAIN_TRIM = GainTrim;
}

/**
  * @name   ADC_SoftTrig
  * @brief  EN: ADC software triggering.
  *         CN: ADC 软件触发。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  SofTrig: 
  *         EN: ADC SOC software trigger bit.
  *         CN: ADC SOC 软件触发位。
  *         @arg SOC0_TRIG
  *         @arg ...
  *         @arg SOC15_TRIG
  * @retval None
  */
void ADC_SoftTrig(ADC_TypeDef *ADCx, uint32_t SofTrig)
{
    ADCx->CR = SofTrig;
    while (!(ADCx->SR & SofTrig))
    {
        __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    };
}


/**
  * @name   ADC_AnalogWatchdogThresholdsConfg
  * @brief  EN: ADC Analog Watchdog Thresholds Config.
  *         CN: ADC模拟看门狗阈值配置。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  AWDx_SEL: 
  *         EN: Analog watchdog selection.
  *         CN: 模拟看门狗选择。
  *             @arg AWD0
  *             @arg AWD1
  * @param  HighThreshold: 
  *         EN: Analog watchdog monitoring high threshold.
  *         CN: 模拟看门狗监控高阈值。
  * @param  LowThreshold: 
  *         EN: Analog watchdog monitoring low threshold.
  *         CN: 模拟看门狗监控低阈值。
  * @retval None
  */
void ADC_AnalogWatchdogThresholdsConfg(ADC_TypeDef *ADCx, uint8_t AWDx_SEL, uint16_t HighThreshold, uint16_t LowThreshold)
{
  /* Set the ADCx high and low threshold */
  if(AWDx_SEL == AWD0)
  {
    ADCx->AWD0_TR = LowThreshold | ((uint32_t)HighThreshold << 16);
  }
  else if (AWDx_SEL == AWD1)
  {
    ADCx->AWD1_TR = LowThreshold | ((uint32_t)HighThreshold << 16);
  }
}

/**
  * @name   ADC_AnalogWatchdogSingleChannelConfig
  * @brief  EN: ADC Configure monitoring channels for analog watchdog.
  *         CN: ADC配置模拟看门狗的监控通道。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  AWDx_SEL: 
  *         EN: Analog watchdog selection.
  *         CN: 模拟看门狗选择。
  *             @arg AWD0
  *             @arg AWD1
  * @param  ADC_AWD_Channel: 
  *         EN: Analog watchdog monitoring channel selection.
  *         CN: 模拟看门狗监控通道选择。
  *             @arg ADC_AWD_Channel_0
  *             @arg ADC_AWD_Channel_1
  *             @arg ...
  *             @arg ADC_AWD_Channel_15
  * @param  NewState: 
  *         EN: Analog watchdog monitoring channel enable.
  *         CN: 模拟看门狗监控通道使能。
  * @retval None
  */
void ADC_AnalogWatchdogSingleChannelConfig(ADC_TypeDef *ADCx, uint8_t AWDx_SEL, uint32_t ADC_AWD_Channel, FunctionalState NewState)
{

  if(AWDx_SEL == AWD0)
  {
    if (NewState != DISABLE)
    {
      ADCx->AWD0_CFGR |= (uint32_t)ADC_AWD_Channel;
    }
    else
    {
      ADCx->AWD0_CFGR &= (~(uint32_t)ADC_AWD_Channel);
    }
  }
  else if (AWDx_SEL == AWD1)
  {
    if (NewState != DISABLE)
    {
      ADCx->AWD1_CFGR |= (uint32_t)ADC_AWD_Channel;
    }
    else
    {
      ADCx->AWD1_CFGR &= (~(uint32_t)ADC_AWD_Channel);
    }
  }
}


/**
  * @name   ADC_Vref_Cmd
  * @brief  EN: Reference voltage module of the designated ADC for power on or off.
  *         CN: 上电或掉电指定的ADC的参考电压模块。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @param  NewState: 
  *         EN: The new state of the reference voltage module of ADC.
  *         CN: ADC的参考电压模块的新状态。
  *             @arg ENABLE
  *             @arg DISABLE
  * @retval None
  */
void ADC_Vref_Cmd(ADC_TypeDef *ADCx, FunctionalState State)
{
  if (State != DISABLE)
  {
    /* Set the PD_REF bit to Power on the ADC reference voltage module */
    while (ADCx->CR & ADC_CR_START_Msk)
    {
      __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    };
    ADCx->ANA &= ~ADC_ANA_PD_REF_Msk;
  }
  else
  {
    ADCx->CR_b.STOP = 1;
    do
    {
      __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    } while (ADCx->CR_b.STOP);
    while (ADCx->CR & ADC_CR_START_Msk)
    {
      __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
    };
    ADCx->ANA |= ADC_ANA_PD_REF_Msk;
  }
}

/**
  * @name   ADC_ForExternVref_Cmd(仅提供给其他需要ADC参考电压的外设使用)
  * @brief  EN: When other peripherals besides ADC require ADC reference voltage, the reference voltage module of the designated ADC is used for power on.
  *         CN: 除ADC外其他外设需要ADC参考电压时，上电指定的ADC的参考电压模块。
  * @param  ADCx:
  *         EN: where x is 0 to select the ADC peripheral.
  *         CN: 其中 x 是 0 以选择 ADC 外设。
  * @retval None
  */
void ADC_ForExternVref_Cmd(ADC_TypeDef *ADCx)
{
  /* Set the PD_REF bit to Power on the ADC reference voltage module */
  while (ADCx->CR & ADC_CR_START_Msk)
  {
      __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
  };
  ADCx->ANA &= ~ADC_ANA_PD_REF_Msk;
}

/**
  * @name   ADC_GetVTStemperature
  * @brief  EN: ADC temperature sampling value converted to temperature.
  *         CN: ADC 温度采样值转化为温度。
  * @param  ADCValueNow:
  *         EN: ADC current sampling temperature value.
  *         CN: ADC 当前采样温度值。
  * @param  Vref: 
  *         EN: Reference voltage selection.
  *         CN: 参考电压选择。
  *             @arg ADC_ReferenceVoltage_3V2
  *             @arg ADC_ReferenceVoltage_4V9
  * @retval None
  */
int ADC_GetVTStemperature(int ADCValueNow, uint32_t Vref)
{
  int temperatureNormalADC4V9_3V2, temperatureHighADC4V9_3V2;
  int slope, temperatureNormal, temperatureHigh, temperatureNormalADC, temperatureHighADC, temperatureNow;
  temperatureNormal = (*(int *)(0x1FFFF780));
  temperatureHigh = (*(int *)(0x1FFFF784));
  temperatureNormalADC4V9_3V2 = (*(int *)(0x1FFFF7E0)); // 4.9V和3.2V做参考的AD值常温
  temperatureHighADC4V9_3V2 = (*(int *)(0x1FFFF7E4));   // 4.9V和3.2V做参考的AD值高温
  if (temperatureNormalADC4V9_3V2 != 0xFFFFFFFF)
  {
    switch (Vref)
    {
    case ADC_ReferenceVoltage_3V2:
      temperatureNormalADC = temperatureNormalADC4V9_3V2 & 0x0000FFFF; // 低16位参考为3.2V
      temperatureHighADC = temperatureHighADC4V9_3V2 & 0x0000FFFF;
      break;

    case ADC_ReferenceVoltage_4V9:
      temperatureNormalADC = (temperatureNormalADC4V9_3V2 & 0x0FFF0000) >> 16; // 高16位参考为4.9V
      temperatureHighADC = (temperatureHighADC4V9_3V2 & 0x0FFF0000) >> 16;
      break;

    default:
      break;
    }
    slope = ((temperatureHighADC - temperatureNormalADC) * 100) / (temperatureHigh - temperatureNormal);
    temperatureNow = (ADCValueNow - temperatureHighADC) * 100 / slope + temperatureHigh;
  }
  return temperatureNow;
}
