

/**
 ******************************************************************************
 *
 * @file        BSP_8_VariableResistor.c
 * @brief       This is Variable Resistor C file(use middleware).
 
 * @par         Project
 *              MG32
 * @version     V1.01
 * @date        2021/05/24
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2017 MegaWin Technology Co., Ltd.
 *              All rights reserved.
 * 
 ******************************************************************************* 
 * @par Disclaimer
 * The Demo software is provided "AS IS" without any warranty, either
 * expressed or implied, including, but not limited to, the implied warranties
 * of merchantability and fitness for a particular purpose. The author will
 * not be liable for any special, incidental, consequential or indirect
 * damages due to loss of data or any other reason.
 * These statements agree with the world wide and local dictated laws about
 * authorship and violence against these laws.
 *******************************************************************************
 *******************************************************************************
 */
 
/*==============================================================================
                                 User Notes
How To use this function:
-----------------------
    1. Use BSP_VR_Init() function to inital.
    2. Periodic call BSP_VR_main() function to get variable resistor status.
       (1) After call BSP_VR_main() VR_CTR.ChangeFlag != 0 represent the variable resistor status
           change.
           A. Bit0 of VR_CTR.ChangeFlag = 1 represent variable resistor 1 status change.
           B. Bit1 of VR_CTR.ChangeFlag = 1 represent variable resistor 2 status change.           
       (2) When getting variable resistor status change can get VR_Status or VR_ADCData value.
           A. VR_Status : The value is percentage ( By BSP_VR_GETPERCENTAGE()).
           B. VR_ADCata : The value is ADC raw data ( By BSP_VR_GETADCData()). 

--------------------
    + MG32_GPIO_DRV
    + MG32_ADC_DRV
    + MG32_GPL_DRV

Known Limitations:
------------------

Require parameter
------------------
    Require module : CSC / GPIO / TM10 
    
    GPIO pin configuration : 
        Pin  / IO mode / AFS
        ---  --------  -----
        PA6 / AIO     / GPIO
        PA7 / AIO     / GPIO
        
    ADC Module :
        Mode   :        12 bit One shot mode
        
    GPL Module :
        Use Function :  Hardware divider
       
Example codes:
------------------

==============================================================================*/ 
 
 
/* Includes ------------------------------------------------------------------*/
#include "BSP_8_VariableResistor.h"

/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
//GPIO
#define VR1_PIN             PX_Pin_6
#define VR2_PIN             PX_Pin_7
#define VR_PIN_MODE         PINX_Mode_Analog_IO
#define VR_PIN_AFS          0
#define VR_IOM              IOMA

//ADC
#define VR_ADC              ADC0
#define VR1_ADC_CHANNEL     6                       /*!< VR1 use ADC channel.*/
#define VR2_ADC_CHANNEL     7                       /*!< VR2 use ADC channel.*/

//Variable Resistor
#define ADC_VREF            5000                    /*!< ADC Vref voltage is 5V.*/
#define VR_VCC              5000                    /*!< Variable register voltage is 3.3V.*/
#define VR_ADC_MAX          (4095*VR_VCC)/ADC_VREF  /*!< ADC conversion max value.*/
#define VR_ADC_DIFRANGE     50                     
#define VR_ADC_SMPTIME      5


/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
VRCTR_TypeDef VR_CTR;          /*!< Variable resistor control parameter.*/

static uint8_t  VR_ADC_Index;
static uint8_t  VR_ADC_SampleCount[2];
static uint32_t VR_ADC_SampleData[2];

/* Private function prototypes -----------------------------------------------*/
static void BSP_VR_ADCCalibration(void);

/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* External vairables --------------------------------------------------------*/

/**
 *******************************************************************************
 * @brief	    Variable resistor inital. 
 * @details     
 * @return      
 * @exception   No
 * @note        No
 *******************************************************************************
 */
void BSP_VR_Init(void)
{
    PIN_InitTypeDef    VR_Pin;
    
    /*Inital GPIO*/
    VR_Pin.PINX_Pin                = ( VR1_PIN | VR2_PIN);
    VR_Pin.PINX_Mode               = VR_PIN_MODE;
    VR_Pin.PINX_PUResistant        = PINX_PUResistant_Disable;
    VR_Pin.PINX_Speed              = PINX_Speed_Low;
    VR_Pin.PINX_Inverse            = PINX_Inverse_Disable;
    VR_Pin.PINX_OUTDrive           = PINX_OUTDrive_Level0;
    VR_Pin.PINX_FilterDivider      = PINX_FilterDivider_Bypass;
    VR_Pin.PINX_Alternate_Function = VR_PIN_AFS;
    GPIO_PortMode_Config( VR_IOM ,&VR_Pin);
    
    /*ADC Inital.*/
    ADC_DeInit(VR_ADC);
    
    ADC_Cmd(VR_ADC,ENABLE);
    
    ADC_ClockSource_Select(VR_ADC,ADC_CKADC);
    
    ADC_SetInternalClockDivider(VR_ADC,ADC_IntDIV4);
    ADC_DataResolution_Select(VR_ADC,ADC_12BitData);
    ADC_WaitDataReadOut(VR_ADC,DISABLE);
    
    ADC_PGA_Cmd(VR_ADC,DISABLE);
    ADC_SetPGAGain(VR_ADC,0);
    
    ADC_DataOverrunMode_Select(VR_ADC,ADC_DataOverWritten);
    ADC_DataAlignment_Select(VR_ADC,ADC_RightJustified);
    
    ADC_TriggerSource_Select(VR_ADC,ADC_START);
    ADC_TriggerEdge_Select(VR_ADC,ADC_DisableTrg);
    ADC_ContinueMode_Cmd(VR_ADC,DISABLE);
    ADC_MainConversionMode_Select(VR_ADC,ADC_OneShot);
    
    
    ADC_SetExtendSampling(VR_ADC,30);
    
    
    ADC_SetConversionTime(VR_ADC,ADC_FastCONV);
    ADC_SetOperationCurrent(VR_ADC,ADC_BIAS_LVL3);
    ADC_SampleClockPhase_Select(VR_ADC,ADC_CK_PHASE2);
    
    //ADC calibration
    BSP_VR_ADCCalibration();
    
    // Conversion channel selection
    ADC_ChannelMUX_Select(VR_ADC,ADC_ExternalChannel);
    ADC_ExternalChannel_Select(VR_ADC,(ADC_ExtChannelDef)VR1_ADC_CHANNEL);
    
    // 1. clear ADC E1CNVF flag.
    // 2. Start ADC conversion.
    ADC_ClearFlag(VR_ADC,ADC_E1CNVF);

    /*Get VR1 and VR2 first data.*/
    ADC_ExternalChannel_Select(VR_ADC,(ADC_ExtChannelDef)VR1_ADC_CHANNEL);
    ADC_ClearFlag(VR_ADC,ADC_E1CNVF);
    ADC_SoftwareConversion_Cmd(VR_ADC,ENABLE);
    while((ADC_GetAllFlagStatus(VR_ADC) & ADC_E1CNVF)==0);
    VR_CTR.VR_ADCData[VR1_DATA] = (uint16_t)ADC_GetDAT0Data(VR_ADC);

    ADC_ExternalChannel_Select(VR_ADC,(ADC_ExtChannelDef)VR2_ADC_CHANNEL);
    ADC_ClearFlag(VR_ADC,ADC_E1CNVF);
    ADC_SoftwareConversion_Cmd(VR_ADC,ENABLE);
    while((ADC_GetAllFlagStatus(VR_ADC) & ADC_E1CNVF)==0);
    VR_CTR.VR_ADCData[VR2_DATA] = (uint16_t)ADC_GetDAT0Data(VR_ADC);

    /*Trigger next VR1 ADC data.*/
    VR_ADC_Index = 1;
    ADC_ClearFlag(VR_ADC,ADC_E1CNVF);
    ADC_SoftwareConversion_Cmd(VR_ADC,ENABLE);

    /*Inital parameter*/
    VR_ADC_SampleCount[0] = 0;
    VR_ADC_SampleData[0]  = 0;
    VR_ADC_SampleCount[1] = 0;
    VR_ADC_SampleData[1]  = 0;
}
/**
 *******************************************************************************
 * @brief	    Variable resistor main flow. 
 * @details     
 * @return      
 * @exception   No
 * @note        No
 *******************************************************************************
 */
void BSP_VR_main(void)
{
    uint16_t  BSP_VR_ADCDataTmp;
    uint16_t BSP_VR_ADCDataDif;
    uint32_t BSP_VR_DataTmp;

    /*Check ADC conversion whether complete or not.*/
    if((ADC_GetAllFlagStatus(VR_ADC)&ADC_STA_E1CNVF_happened_w)==0) 
    {
        return;
    }    
    
    /*Get ADC conversion data and check status whether change or not.*/
    

    if(VR_ADC_SampleCount[VR_ADC_Index]==VR_ADC_SMPTIME)
    {
        GPL->DIVD.W       = VR_ADC_SampleData[VR_ADC_Index];
        GPL->DIVS.W       = VR_ADC_SMPTIME;
        GPL->CR1.W       |= GPL_CR1_DIV_START_mask_w;
        
        VR_ADC_SampleCount[VR_ADC_Index] = 0;
        VR_ADC_SampleData[VR_ADC_Index]  = 0;
        while( GPL->CR1.W & GPL_CR1_DIV_START_mask_w);
        
        BSP_VR_ADCDataTmp = (uint16_t)GPL->QUT.W;
        
        if( BSP_VR_ADCDataTmp > VR_CTR.VR_ADCData [VR_ADC_Index])
        {
            BSP_VR_ADCDataDif = BSP_VR_ADCDataTmp - VR_CTR.VR_ADCData [VR_ADC_Index];
        }
        else
        {
            BSP_VR_ADCDataDif = VR_CTR.VR_ADCData [VR_ADC_Index] - BSP_VR_ADCDataTmp;
        }
        
        if( BSP_VR_ADCDataDif > VR_ADC_DIFRANGE)
        {
            VR_CTR.VR_ADCData[VR_ADC_Index] = (uint16_t)BSP_VR_ADCDataTmp;
            
            /*Get Variable resistor percentage*/
            BSP_VR_DataTmp = (uint32_t)(BSP_VR_ADCDataTmp * 100);
            GPL->DIVD.W    = BSP_VR_DataTmp;
            GPL->DIVS.W    = VR_ADC_MAX;
            GPL->CR1.W    |= GPL_CR1_DIV_START_mask_w;
            while( GPL->CR1.W & GPL_CR1_DIV_START_mask_w);
            VR_CTR.VR_Status[VR_ADC_Index]  = (uint8_t)GPL->QUT.W;
            
            /*Set change flag.*/
            VR_CTR.ChangeFlag |= ( 1 << VR_ADC_Index);
        }
    }
    else
    {
        BSP_VR_ADCDataTmp = (uint16_t)ADC_GetDAT0Data(VR_ADC);
        VR_ADC_SampleData[VR_ADC_Index] = VR_ADC_SampleData[VR_ADC_Index] + BSP_VR_ADCDataTmp;
        
        VR_ADC_SampleCount[VR_ADC_Index] = VR_ADC_SampleCount[VR_ADC_Index] + 1;
    }
    
    /*Change ADC conversion channel and start conversion*/
    if( VR_ADC_Index == 0)
    {
        VR_ADC_Index    = 1;
        ADC_ExternalChannel_Select(VR_ADC,(ADC_ExtChannelDef)VR2_ADC_CHANNEL);
    }
    else
    {
        VR_ADC_Index     = 0;
        ADC_ExternalChannel_Select(VR_ADC,(ADC_ExtChannelDef)VR1_ADC_CHANNEL);
    }        

    ADC_ClearFlag(VR_ADC,ADC_E1CNVF);                      //Clear one-time conversion end flag
    ADC_SoftwareConversion_Cmd(VR_ADC,ENABLE);             //ADC start conversion
}

/**
 *******************************************************************************
 * @brief	    ADC start Calibration routine.
 * @details     
 * @return      
 * @exception   No
 * @note        No
 *******************************************************************************
 */
static void BSP_VR_ADCCalibration(void)
{
    int16_t  ADC_CONV = 0;
    uint8_t  i, OFFT_ADC_MinIDX, ADC_CALI_Complete = 0;
    uint32_t rADC_MSK, rADC_START, rADC_CR0, rADC_CR1;
    uint32_t rSUM0, rSUM1, rSUM2;
   
    // RESAVE
    rADC_MSK   = VR_ADC->MSK.W;
    rADC_START = VR_ADC->START.W;
    rADC_CR0   = VR_ADC->CR0.W;    
    rADC_CR1   = VR_ADC->CR1.W;    
    rSUM0      = VR_ADC->SUM0.W;
    rSUM1      = VR_ADC->SUM1.W;
    rSUM2      = VR_ADC->SUM2.W;
   
    // reset SUM_NUM & window detect
    VR_ADC->CR1.W &= ~(ADC_CR1_SUM_NUM_mask_w | ADC_CR1_WIND_EN_enable_w);

    // config ADC mode for calibration
    VR_ADC->CR0.W = ADC_CR0_RES_SEL_12_bit_w | ADC_CR0_EN_enable_w;
   
    VR_ADC->START.W = ADC_START_CONV_MDS_one_w | ADC_START_TRG_SEL_disable_w | \
                              ADC_START_START_SEL_sw_w;
   
    // start calibration
    // ------------------------------------------------------------------------
    // start calibration - Offset issue
    // ------------------------------------------------------------------------
    ADC_ChannelMUX_Select(VR_ADC,ADC_InternalChannel);
    ADC_InternalChannel_Select(VR_ADC,ADC_INT_VSSA);    // select internal channel VSSA
   
    OFFT_ADC_MinIDX = 0;

    // ------------------------------------------------------------------------
    // 1. Scan minimum index when ADC sample not equal '0'
    // ------------------------------------------------------------------------
    while(1)
    {
        // set ADC_GAIN_OFFT
        VR_ADC->GAIN.W &= ~(ADC_GAIN_OFFT_ADC_mask_w);
        VR_ADC->GAIN.W |= (uint32_t) (OFFT_ADC_MinIDX << ADC_GAIN_OFFT_ADC_shift_w);
       
        // sample internal VSS
        VR_ADC->START.W |= ADC_START_START_mask_w;                             
        while((ADC_GetAllFlagStatus(VR_ADC) & ADC_E1CNVF)==0);
        ADC_ClearFlag(VR_ADC,(ADC_E1CNVF|ADC_ESMPF));
        ADC_CONV += ADC_GetDAT0Data(VR_ADC);
        
        // check ADC_CONV data (search ADC_CONV==1 or 2)  
        if (ADC_CONV == 0)
        {
            OFFT_ADC_MinIDX ++;
        }
        else
        {
            if(OFFT_ADC_MinIDX < 2)     // No trimming range in this issue
            {
                OFFT_ADC_MinIDX = 0;
                break;        
            }
            OFFT_ADC_MinIDX -= 2;
            break;
        }

        if (OFFT_ADC_MinIDX == 31)
            break;
       
    }
    // ------------------------------------------------------------------------
    // 2. average ADC conversion data -> decide the optimum
    // ------------------------------------------------------------------------
    while(1)
    {
        // set ADC_GAIN_OFFT
        ADC0->GAIN.MBIT.OFFT_ADC = OFFT_ADC_MinIDX;
               
        // Average ADC conversion
       
        for (i=0, ADC_CONV=0 ; i<8; i++)
        {
            VR_ADC->START.W |= ADC_START_START_mask_w;                              
            while((ADC_GetAllFlagStatus(VR_ADC) & ADC_E1CNVF)==0);
            ADC_ClearFlag(VR_ADC,(ADC_E1CNVF|ADC_ESMPF));
            ADC_CONV += ADC_GetDAT0Data(VR_ADC);
        }        
       
        // check ADC_CONV data (search ADC_CONV==1 or 2)  
        if (ADC_CONV == 0)
        {
            OFFT_ADC_MinIDX ++;
        }
        else if (ADC_CONV < 8)
        {
            break;
        }
        else
        {
            if(OFFT_ADC_MinIDX == 0)
            {
                ADC_CALI_Complete = 0;
                break;         // No trimming range in this issue
            }
            OFFT_ADC_MinIDX --;         // make sure -> ADC can convert '0'
            ADC_CALI_Complete = 1;
            break;
        }
        //
        if (OFFT_ADC_MinIDX == 31)
        {
            ADC_CALI_Complete = 0;
            break;
        }
    }
    // desire ADC_GAIN_OFFT
    VR_ADC->GAIN.W &= ~(ADC_GAIN_OFFT_ADC_mask_w);
    VR_ADC->GAIN.W |= (uint32_t) (OFFT_ADC_MinIDX << ADC_GAIN_OFFT_ADC_shift_w);
   
    // restore
    VR_ADC->MSK.W   = rADC_MSK;
    VR_ADC->START.W = rADC_START;
    VR_ADC->CR0.W   = rADC_CR0;    
    VR_ADC->CR1.W   = rADC_CR1;    
    VR_ADC->SUM0.W  = rSUM0;
    VR_ADC->SUM1.W  = rSUM1;
    VR_ADC->SUM2.W  = rSUM2;

    if (ADC_CALI_Complete == 1)
        VR_CTR.ADCCalibration_Complete = 1;
    else
        VR_CTR.ADCCalibration_Complete = 0;
    
}

