/************************************************************************************************/
/**
* @file               std_adc.c
* @author             MCU Ecosystem Development Team
* @brief              ADC STD库驱动。
*                     实现ADC初始化配置等功能API。
*
*
**************************************************************************************************
* @attention
* Copyright (c) CEC Huada Electronic Design Co.,Ltd. All rights reserved.
*
**************************************************************************************************
*/

/************************************************************************************************/
/**
* @addtogroup STD_Driver
* @{
*/

/**
* @addtogroup ADC 
* @{
*
*/
/************************************************************************************************/


/*-------------------------------------------includes-------------------------------------------*/
#include "std.h"

#ifdef STD_ADC_PERIPHERAL_USED

/*-------------------------------------------functions------------------------------------------*/

/************************************************************************************************/
/**
* @addtogroup ADC_External_Functions 
* @{
*
*/
/************************************************************************************************/

/** 
* @brief  ADC初始化
* @param  adc_init_param ADC初始化结构体
* @retval 无
*/
void std_adc_init(std_adc_init_t *adc_init_param)
{  
    if(adc_init_param->trigger_edge != ADC_TRIG_SW)
    {
        /* 配置外部触发源 */
        std_adc_external_trig_source_config(adc_init_param->trigger_source);
    }
   
    /* 设置软件触发方式、硬件触发极性、转换模式选择、数据溢出管理和扫描方向配置 */
    MODIFY_REG(ADC->CFG1, 
                (ADC_CFG1_TRIGEN| ADC_CFG1_CONV_MOD | ADC_CFG1_OVRN_MOD | ADC_CFG1_SDIR), 
                (adc_init_param->trigger_edge | adc_init_param->conver_mode | adc_init_param->overrun_mode | adc_init_param->scan_dir));
    
    /* 采样时间参数配置 */
    std_adc_sampt_time_config(adc_init_param->sampt);
    
    /* 配置ADC_CLK时钟预分频系数 */
    std_adc_set_clock_config(adc_init_param->clock_presc);
}


/** 
* @brief  ADC结构体初始化
* @param  adc_init_struct ADC初始化结构体
* @retval 无
*/
void std_adc_struct_init(std_adc_init_t *adc_init_struct)
{
    adc_init_struct->clock_presc = ADC_CLK_DIV1;
    adc_init_struct->trigger_edge = ADC_TRIG_SW;
    adc_init_struct->trigger_source = ADC_EXTRIG_TIM1_TRGO;
    adc_init_struct->sampt = ADC_SAMPTIME_3CYCLES;
    adc_init_struct->overrun_mode = ADC_OVRN_MODE_OVERWRITTEN;
    adc_init_struct->conver_mode = ADC_SINGLE_CONVER_MODE;
    adc_init_struct->scan_dir = ADC_SCAN_DIR_FORWARD;
}

/**
* @brief  ADC校准
* @param  calibration_num ADC校准次数，用于求和取平均
* @note   调用ADC校准函数时，需要保证ADC使能,工作时钟频率≤16MHz
* @note   ADC校准函数使用的是软件触发，查询的方式获取ADC校准系数，需要ADC配置成软件触发，并禁止ADC的EOC/EOS/EOSAMP中断
* @retval 无
*/
void std_adc_calibrate(uint32_t calibration_num)
{  
    int32_t get_calibration_value = 0;
    uint8_t i;

    /* 使能校准 */
    std_adc_calibration_enable();
    
    /* 求和取平均 */
    for(i = 0; i < calibration_num; i++)
    {
        /* 启动ADC转换 */
        std_adc_start_conversion();
        
        /* 等待通道转换结束完成 */
        while(!std_adc_get_flag(ADC_FLAG_EOC));
        
        /* 清除转换结束标志 */
        std_adc_clear_flag(ADC_FLAG_EOC);
        
        /* 获取ADC采样值 */
        get_calibration_value += std_adc_get_conversion_value();
    }
    
    /* 计算平均值 */
    get_calibration_value = get_calibration_value / calibration_num;
    
    /* 0x800减去平均值，得到校准系数 */
    get_calibration_value = 0x800 - get_calibration_value;
    
    /* 判断校准系数是否超限 */
    if(get_calibration_value > CALFACT_MAX)
    {
        get_calibration_value = CALFACT_MAX;
    }
    else if(get_calibration_value < CALFACT_MIN)
    {
        get_calibration_value = CALFACT_MIN;
    }
    /* 禁止ADC校准 */
    std_adc_calibration_disable();
    
    /* 配置ADC校准系数 */
    std_adc_calibration_factor_config(get_calibration_value);
}

/** 
* @brief  ADC去初始化
* @retval 无
*/
void std_adc_deinit(void)
{
    /* 复位ADC外设 */
    std_rcc_apb2_reset(RCC_PERIPH_RESET_ADC); 

    /* 禁止ADC外设时钟 */
    std_rcc_apb2_clk_disable(RCC_PERIPH_CLK_ADC);
}


/** 
* @} 
*/

#endif /* STD_ADC_PERIPHERAL_USED */

/** 
* @} 
*/

/** 
* @} 
*/
