/*
  ******************************************************************************
  * Copyright (c)  2008 - 2024, Shanghai AisinoChip Co.,Ltd .
  * @file    temp_sensor.c 
  * @version V1.0.0
  * @date    2024
  * @author  Aisinochip Firmware Team  
  * @brief   ADC Temperature sensor source code.
  ******************************************************************************        
*/
#include "temp_sensor.h"
#include "bsp_adc.h"

uint32_t g32NVR_Val, g32ReferenceVol;
uint32_t g32VrefP, g32Vrefp_val;

extern uint32_t ADC_GetVrefP(void);

/*********************************************************************************
* Function    : ADC_Temperature_Init
* Description : ADC Temperature sensor initialize
* Input       : None
* Output      : None
**********************************************************************************/
void ADC_TemperatureSensor_Init(void)
{
    ADC_Init_Gpio();
    
    ADC_DeInit(ADC);
    ADC_InitStruct.ADC_ClockDiv = ADC_CLOCK_DIV8;
    ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStruct.ADC_ExternalTrigConv = ADC_SOFTWARE_START;
    /* The total adc regular channels number */
    ADC_InitStruct.ADC_NbrOfChannel = 16;
        
    System_Module_Enable(EN_ADC);
    ADC_Init(ADC, &ADC_InitStruct);
    
    /* Add adc channels */
    ADC_RegularChannelConfig(ADC, ADC_CHANNEL_TEMP,  1,  ADC_SMP_CLOCK_320, DISABLE);

    
}

/*********************************************************************************
* Function    : ADC_GetTemperature
* Description : get ADC Temperature sensor value
* Input       : None
* Output      : ADC Temperature sensor value
**********************************************************************************/
uint32_t ADC_GetTemperature(void)
{
    uint32_t adc_val_temp[5];
    uint32_t IPckenr1, IPckenr2;
    uint32_t ADC_Vol, Cur_TempVal;
    
    IPckenr1 = SCU->IPCKENR1;
    IPckenr2 = SCU->IPCKENR2;
    
    SCU->IPCKENR1 = BIT14;
    SCU->IPCKENR2 = 0;
    
    System_Delay(1000);
    ADC_Polling(&adc_val_temp[0], 1, 0);
    System_Delay(1000);
    ADC_Polling(&adc_val_temp[1], 1, 0);
    System_Delay(1000);
    ADC_Polling(&adc_val_temp[2], 1, 0);
    System_Delay(1000);
    ADC_Polling(&adc_val_temp[3], 1, 0);
    System_Delay(1000);
    ADC_Polling(&adc_val_temp[4], 1, 0);
    
    SCU->IPCKENR1 = IPckenr1;
    SCU->IPCKENR2 = IPckenr2;
    
    Bubble_Sort(adc_val_temp, 5); 
    
    ADC_Vol = (adc_val_temp[2] & 0xfff) * g32VrefP / 4096;
    Cur_TempVal = ADC_TemperatureSelfCalibrate(ADC_Vol);

    printfS("T:%f (°C), ADC:%d[%d mV], NVR:%d[%d mV], Vrefp = %d[%d mV]\r\n", \
            (Cur_TempVal/10.0), (adc_val_temp[2] & 0xfff), ADC_Vol, (g32NVR_Val & 0xfff), \
            g32ReferenceVol, g32Vrefp_val, g32VrefP);	

    return  Cur_TempVal;
}


/************************************************************************
 * function   : ADC_TemperatureSelfCalibrate
 * Description: ADC temperature self calibrate.
 * input      : ActualVol : Voltage value of ADC temperature sensor, unit: 1mV
 * return     : Temperature value, unit: 0.1 °C; fail-0xFFFFFFFF
 ************************************************************************/
uint32_t ADC_TemperatureSelfCalibrate(uint32_t ActualVol)
{
    uint32_t CurTempVal;    
    /*
        FT标定值为基准值，记录在NVR区域（0x80258）
        当实测值小于基准值时，温度系数为5.96 mV/°C
        当实测值大于等于基准值时，温度系数为6.02mV/°C
        当前温度（单位摄氏度） = 基准温度 + (实测电压-基准电压) ÷ 温度系数     
    */ 
    uint32_t LowTempRate = 596;     //当实测值小于基准值时，温度系数为5.96 mV/°C
    uint32_t HighTempRate = 602;    //当实测值大于等于基准值时，温度系数为6.02mV/°C    
 
    CurTempVal = 0xFFFFFFFF;
    g32NVR_Val = *(volatile uint32_t *)(0x80258);
    if(0xFFFFFFFF != g32NVR_Val)
    {
        /* FT has been calibrated, and there are valid values in the NVR area */
        g32ReferenceVol = (g32NVR_Val & 0xfff) * 3000 / 4096;	
      
        if(ActualVol > g32ReferenceVol)
        {
            CurTempVal = 250 + (ActualVol - g32ReferenceVol) * 1000 / HighTempRate ;
        }
        else
        {
            CurTempVal = 250 - (g32ReferenceVol - ActualVol) * 1000 / LowTempRate ;
        }
    }
    else
    {
        /* FT not calibrated, no valid values in NVR area */
        printfS("Not calibrated at the factory, unable to use\n");    
    }    
    
    return CurTempVal;             
}

/*********************************************************************************
* Function    : Bubble_Sort
* Description : Bubble Sort
* Input       : arr: Sort array
* Input       : n: Sort array length 
* Output      : None
**********************************************************************************/
void Bubble_Sort(uint32_t *arr, uint16_t n) 
{
    uint16_t i, j, temp;
    for (i = 0; i<n - 1; i++)
	{
        for (j = 0; j < n - i - 1; j++)
        {
            //如果前面的数比后面大，进行交换
            if (arr[j] > arr[j + 1]) 
            {
                temp = arr[j]; 
                arr[j] = arr[j + 1]; 
                arr[j + 1] = temp;
            }
        }
	}
}


void ADC_TemperatureSensor_Test(void)
{
    g32VrefP = ADC_GetVrefP();
    ADC_TemperatureSensor_Init();
    
    while(1)
    {
        ADC_GetTemperature();
        System_Delay_MS(1000);        
    }
}


