/*
  ******************************************************************************
  * 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"


uint32_t g32NVR_Val, g32ReferenceVol;
uint32_t g32VrefP, g32Vrefp_val;

ADC_HandleTypeDef ADC_Handle_TS;

extern uint32_t ADC_GetVrefP(uint8_t Pre_Channel);

/*********************************************************************************
* Function    : ADC_Temperature_Init
* Description : ADC Temperature sensor initialize
* Input       : None
* Output      : None
**********************************************************************************/
void ADC_TemperatureSensor_Init(void)
{
    ADC_ChannelConfTypeDef ADC_ChannelConf;
    
    ADC_Handle_TS.Init.ClockDiv = ADC_CLOCK_DIV8;
    ADC_Handle_TS.Init.ConConvMode = ADC_CONCONVMODE_DISABLE;
    ADC_Handle_TS.Init.JChannelMode = ADC_JCHANNELMODE_DISABLE;
    ADC_Handle_TS.Init.DiffMode = ADC_DIFFMODE_DISABLE;
    ADC_Handle_TS.Init.DMAMode = ADC_DMAMODE_DISABLE;
    ADC_Handle_TS.Init.OverMode = ADC_OVERMODE_DISABLE;
    ADC_Handle_TS.Init.AnalogWDGEn = ADC_ANALOGWDGEN_DISABLE;
    ADC_Handle_TS.Init.ExTrigMode.ExTrigSel = ADC_SOFTWARE_START;
    
    ADC_Handle_TS.Init.OverSampMode = ADC_OVERSAMPMODE_DISABLE;
    ADC_Handle_TS.Init.Oversampling.Ratio = 5;
    ADC_Handle_TS.Init.Oversampling.RightBitShift = 6;
    
    ADC_Handle_TS.Init.ChannelEn = ADC_CHANNEL_TEMP_EN;
    ADC_Handle_TS.Instance = ADC;
        
    HAL_ADC_Init(&ADC_Handle_TS);

    /* The total adc regular channels number */
    ADC_Handle_TS.ChannelNum = 1;
    
    /* Add adc channels */
    ADC_ChannelConf.Channel = ADC_CHANNEL_TEMP;
    ADC_ChannelConf.RjMode = 0;
    ADC_ChannelConf.Sq = ADC_SEQUENCE_SQ1;
    ADC_ChannelConf.Smp = ADC_SMP_CLOCK_320;    
    HAL_ADC_ConfigChannel(&ADC_Handle_TS,&ADC_ChannelConf);
    
}

/*********************************************************************************
* 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);
    HAL_ADC_Polling(&ADC_Handle_TS, &adc_val_temp[0], ADC_Handle_TS.ChannelNum, 0);
    System_Delay(1000);
    HAL_ADC_Polling(&ADC_Handle_TS, &adc_val_temp[1], ADC_Handle_TS.ChannelNum, 0);
    System_Delay(1000);
    HAL_ADC_Polling(&ADC_Handle_TS, &adc_val_temp[2], ADC_Handle_TS.ChannelNum, 0);
    System_Delay(1000);
    HAL_ADC_Polling(&ADC_Handle_TS, &adc_val_temp[3], ADC_Handle_TS.ChannelNum, 0);
    System_Delay(1000);
    HAL_ADC_Polling(&ADC_Handle_TS, &adc_val_temp[4], ADC_Handle_TS.ChannelNum, 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; 0xFFFFFFFF-FT not calibrated
 ************************************************************************/
uint32_t ADC_TemperatureSelfCalibrate(uint32_t ActualVol)
{
    uint32_t CurTempVal;    
    /*
        FT标定值为基准值，记录在NVR区域（0x80258）
        当前温度（单位摄氏度） = 基准温度 + (实测电压-基准电压) ÷ 温度系数     
    */ 
    uint32_t LowTempRate = 584;     //当实测值小于基准值时，温度系数为5.84 mV/°C
    uint32_t HighTempRate = 596;    //当实测值大于等于基准值时，温度系数为5.96mV/°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_CHANNEL_8);
    printfS("Vrefp = %dmV\r\n", g32VrefP);
    ADC_TemperatureSensor_Init();
    
    while(1)
    {
        ADC_GetTemperature();
        System_Delay_MS(1000);        
    }
}


