#include "bsp_adc.h"

#include "bsp_uart.h"
#include "log.h"

#undef LOG_ENABLE
#define LOG_ENABLE 1

#undef LOG_TAG
#define LOG_TAG "adc"

// https://www.cnblogs.com/gscw/p/17682385.html
// 计算公式参考手册，建议使用 “建议实际可用测量电压范围” 作为 ADC 采集的增益选择判断标准。计算公式参考手册。
// 仅使用 ADC 功能，同时降低功耗，可以将引脚的数字输入功能关闭，配置 R16_PIN_ANALOG_IE。 注：如果引脚用于模拟功能（ADC/TouchKey），建议将该引脚的数字输入功能关闭，即设置数字输入禁用，从而可以降低功耗，并有利于减少干扰。
// PA9 引脚进行 ADC 采集，在置为浮空后，过 300ms 左右再进行 ADC 的采集。因为初次烧录的时候 boot 是串口功能开启的，PA9 是输出高电平。切换到浮空会需要等待时间。

uint16_t adcBuff[40];

volatile uint8_t adclen;
volatile uint8_t DMA_end = 0;

signed short RoughCalib_Value = 0; // ADC粗调偏差值
uint32_t countadc             = 0;
uint16_t min_number           = 0;
uint16_t max_number           = 0;
double voltage                = 0;

void BSP_ADC_Init(void)
{
    uint8_t i;

#if 0
    // ±10C，没啥参考价值
    /* 温度采样并输出 */
    logDebug("\n1.Temperature sampling...\n");
    ADC_InterTSSampInit();
    for (i = 0; i < 20; i++)
    {
        adcBuff[i] = ADC_ExcutSingleConver(); // 连续采样20次
    }
    for (i = 0; i < 20; i++)
    {
        uint32_t C25 = 0;
        C25          = (*((PUINT32)ROM_CFG_TMP_25C));
        logDebug("%d %d %d \n", adc_to_temperature_celsius(adcBuff[i]), adcBuff[i], C25);
    }
#endif

#if 1
    // VBAT
    uint32_t CountBat = 0;
    ADC_InterBATSampInit();
    for (i = 0; i < 20; i++)
    {
        adcBuff[i] = ADC_ExcutSingleConver(); // 连续采样20次
    }
    for (i = 0; i < 20; i++)
    {
        CountBat += adcBuff[i];
        if (i == 0)
        {
            min_number = adcBuff[i];
            max_number = adcBuff[i];
        }
        min_number = ((min_number > adcBuff[i]) ? adcBuff[i] : min_number); // 软件滤波
        max_number = ((max_number < adcBuff[i]) ? adcBuff[i] : max_number);
    }
    logDebug("min_number = %d, max_number = %d", min_number, max_number);
    CountBat = (CountBat - min_number - max_number) / 18; // 删除最小与最大值
    logDebug("AverageCountBat = %d", CountBat);
#endif

#if 0
    // 默认情况下，ADC 引脚和所在 GPIO 引脚的数字功能是同时存在的
    // ，在进行 ADC 测量时候，需要吧 GPIO 设置为高阻输入
    // ，当 ADC 的电平处于中间态的时候，这时候往往会导致数字部分漏电
    // ，这时候我们可以通过寄存器 R16_PIN_ANALOG_IE 来禁用相关的 AIN 通道所在的数字功能:
    R32_PIN_CONFIG2 |= (1U << 13);
    /* 单通道采样：选择adc通道3做采样，对应 PA13引脚， 带数据校准功能 */
    GPIOA_ModeCfg(GPIO_Pin_13, GPIO_ModeIN_Floating);

    // -6dB (1/2 倍)	(ADC/1024-1)*Vref	3*Vref	-0.2V ～ 3.15V	1.9V ～ 3V
    // 0db (1 倍)	(ADC/2048)*Vref	2*Vref	0V ～ 2.1V	0V ～ 2V
    // 6db (2 倍)	(ADC/4096+0.5)*Vref	1.5*Vref	0.525V ～ 1.575V	0.6V ～ 1.5V
    ADC_ExtSingleChSampInit(SampleFreq_3_2, ADC_PGA_0);

    RoughCalib_Value = ADC_DataCalib_Rough(); // 用于计算ADC内部偏差，记录到全局变量 RoughCalib_Value中
    logDebug("RoughCalib_Value =%d", RoughCalib_Value);

    // 刚上电，要给电容充电
    DelayMs(300);

    logDebug("PA13:::::");
    ADC_ChannelCfg(3);

    for (i = 0; i < 20; i++)
    {
        adcBuff[i] = ADC_ExcutSingleConver() + RoughCalib_Value; // 连续采样20次
        // DelayMs(5);
    }
    logDebug("original: ");
    logHexDumpAll(adcBuff, 20);
    // 注意：由于ADC内部偏差的存在，当采样电压在所选增益范围极限附近的时候，可能会出现数据溢出的现象

    for (i = 0; i < 20; i++)
    {
        countadc += adcBuff[i];
        if (i == 0)
        {
            min_number = adcBuff[i];
            max_number = adcBuff[i];
        }
        min_number = ((min_number > adcBuff[i]) ? adcBuff[i] : min_number); // 软件滤波
        max_number = ((max_number < adcBuff[i]) ? adcBuff[i] : max_number);
    }
    logDebug("min=%d, max=%d, diff=%d", min_number, max_number, (max_number - min_number));
    countadc = (countadc - min_number - max_number) / 18; // 删除最小与最大值
    logDebug("countaveradc = %d", countadc);
    /*
    int16_t adc_raw;
    adc_raw = ADC_ExcutSingleConver() + RoughCalib_Value;
    //PGA=-12db
    voltage_mv = adc_raw*1050/512 - (3*1050);
    //PGA=-6db
    voltage_mv = adc_raw*1050/1024 - (1*1050);
    //PGA=0db
    voltage_mv = adc_raw*1050/2048;
    //PGA=6db
    voltage_mv = adc_raw*1050/4096 + (1050/2);
    */
    voltage = (double)(countadc) / 2048 * 1.05;
    logDebug("voltage=%1.3lf V", voltage);
    logDebug("VIN: %1.3lf V", voltage * 2);
#endif
}


