/******************************************************************************
 * @file     main.c
 * @brief    Main program body
 * @version  V1.8.0
 * @date     31-Dec-2021
 *
 * @note
 * Copyright (C) 2021 Spintrol Limited Corporation. All rights reserved.
 *
 * @attention
 * THIS SOFTWARE JUST PROVIDES CUSTOMERS WITH CODING INFORMATION REGARDING
 * THEIR PRODUCTS, WHICH AIMS AT SAVING TIME FOR THEM. SPINTROL SHALL NOT BE
 * LIABLE FOR THE USE OF THE SOFTWARE. SPINTROL DOES NOT GUARANTEE THE
 * CORRECTNESS OF THIS SOFTWARE AND RESERVES THE RIGHT TO MODIFY THE SOFTWARE
 * WITHOUT NOTIFICATION.
 *
 ******************************************************************************/

#include"spc1168.h"
#include<stdio.h>

#define                 LSB                         29257                           /* Ideal ADC LSB Votage: 0.44643mV * 65536 */
#define                 PGAGAINSEL                  PGA_SCALE_4X                    /* the gain value selected */
                                                                                    // ( for single-ended mode : 0:1x 1:2x 2:4x 3:8x 4:12x 5:16x 6:24x 7:32x 
                                                                                    //   for differential mode : 0:2x 1:4x 2:8x 3:16x 4:24x 5:32x 6:48x 7:64x)
#define                 PGACHANNELSEL               PGA0                            /* the PGA channel to be calibrated */
#define                 VOLTAGE_1_6_5_v             512                             /* 1.65v code for DAC */

volatile                uint32_t CODE1[8]            = {913,866,800,759,706,663,614,573};
volatile                uint32_t CODE2[8]            = {483,433,389,336,286,236,196,172};

int32_t                 i32result_in1;
int32_t                 i32result_out1;
int32_t                 i32result_in2;
int32_t                 i32result_out2;
float                   fgain_measure;
float                   foffset_measure;

int32_t ADC_Measure_ADCCHANNEL_CODE(uint32_t nAvg)
{
  int32_t result_code=0;
  uint32_t i;

  ADC->ADCSOCCTL[0].bit.SAMPCNT = 255;                     // 8us sample time (set as the max)

  for(i=0; i<nAvg; i++)
  {
    ADC_SoftwareTrigger(ADC_SOC_0);
    while(ADC->ADCIF.bit.INT0 != 1) {};
    result_code = result_code + ADC_GetResult(ADC_SOC_0);
  }
  result_code = (int32_t)(result_code)/(int32_t)(nAvg);

  return result_code;
 }


 /*************************************************************************************************************************
 *
 * @brief      ADC Calibration Function to get PGA calibration parameter
 *             Step :
 *                   (1) give ADC3 1.65V voltage
 *                   (2) give DAC1 a code value1 (near by but not equal to 1.65V)
 *                   (3) set the PGA as bypass mode, then measure the value with ADC and save as 'i32result_in1'
 *                   (4) set the PGA as no bypass mode, the measure the value with ADC and save as 'i32result_out1'
 *                   (5) give DAC1 another code value2 (near by but not equal to 1.65V and value1)
 *                   (6) set the PGA as bypass mode, then measure the value with ADC and save as 'i32result_in2'
 *                   (7) set the PGA as no bypass mode, the measure the value with ADC and save as 'i32result_out2'
 *
 *             Keep in mind, give 1.65V(AVDD/2) voltage to ADC3(for PGA0~2)/ADC15(for PGA3~5), each PGA channel and GAIN value 
 *             bouth have a different calibration parameter, so, GAIN value must be set before the test. For example, GAIN value was
 *             'PGAGAINSEL' and PGA channel was 'PGACHANNELSEL' in this demo code.
 *
 * @param[in]  
 *
 * @return none
 *
 * PGA calibration function 
 *
 *************************************************************************************************************************/


int main()
{
  FLASH_WALLOW();
  FLASH_SetTiming(200000000);
  FLASH_WDIS();
  
  CLOCK_InitWithRCO(CLOCK_HCLK_200MHZ);
  
  Delay_Init();

  /*
   * Init the UART
   *
   * 1.Set the GPIO34/35 as UART FUNC
   *
   * 2.Enable the UART CLK
   *
   * 3.Set the rest para
   */
  GPIO_SetPinChannel(GPIO_34,GPIO34_UART_TXD);
  GPIO_SetPinChannel(GPIO_35,GPIO35_UART_RXD);
  CLOCK_EnableModule(UART_MODULE);
  UART_Init(UART,38400);

  printf("\n\n************** PGA Calibration Test Start ******************\n");
  
  /* the PGA channle to be calibrated */
  /* Enbale COMP model */
  CLOCK_EnableModule(COMP_MODULE);

  /* Direct mode, DAC code immediately update */
  COMP_SetDACCodeLoadTiming(DAC1, DAC0CTL_BIT_CODELOAD_DIRECT_MODE);

  /* Enable DAC1 */
  COMP_EnableDAC(DAC1);
  
  /* Init PGA mode (DAC1 as the positive input and ADC3 as the negtive input) */
  switch(PGACHANNELSEL)
  {
    case PGA0:
          PGA_DifferentialInit(PGACHANNELSEL, PGA0_CH_P_DAC1, PGA0_CH_N_ADC3, PGAGAINSEL);
          /*ADC Init*/
          ADC_EasyInit2(ADC_SOC_0,ADCx_PGA0P,ADCx_PGA0N, ADCTRIG_Software);
          break;
    case PGA1:
          PGA_DifferentialInit(PGACHANNELSEL, PGA1_CH_P_DAC1, PGA1_CH_N_ADC3, PGAGAINSEL);
          /*ADC Init*/
          ADC_EasyInit2(ADC_SOC_0,ADCx_PGA1P,ADCx_PGA1N, ADCTRIG_Software);
          break;
    case PGA2:
          PGA_DifferentialInit(PGACHANNELSEL, PGA2_CH_P_DAC1, PGA2_CH_N_ADC3, PGAGAINSEL);
          /*ADC Init*/
          ADC_EasyInit2(ADC_SOC_0,ADCx_PGA2P,ADCx_PGA2N, ADCTRIG_Software);
          break;
  }

  switch(PGACHANNELSEL)
  {
    case PGA0:
      PGA->PGA0CTL.bit.BYPP = 1;                                                         /* set positive path as bypass mode */
      PGA->PGA0CTL.bit.BYPN = 1;                                                         /* set negtive path as bypass mode */
      break;
    case PGA1:
      PGA->PGA1CTL.bit.BYPP = 1;                                                         /* set positive path as bypass mode */
      PGA->PGA1CTL.bit.BYPN = 1;                                                         /* set negtive path as bypass mode */
      break;
    case PGA2:
      PGA->PGA2CTL.bit.BYPP = 1;                                                         /* set positive path as bypass mode */
      PGA->PGA2CTL.bit.BYPN = 1;                                                         /* set negtive path as bypass mode */
      break;
  }
  
  COMP_SetDACValue10Bit(DAC1,CODE1[PGAGAINSEL]);
  Delay_Ms(10);

  i32result_in1 = ADC_Measure_ADCCHANNEL_CODE(1000);                                     /* measure input value first time */

  COMP_SetDACValue10Bit(DAC1,CODE2[PGAGAINSEL]);
  Delay_Ms(10);
  
  i32result_in2 = ADC_Measure_ADCCHANNEL_CODE(1000);                                     /* measure input value second time */
  
  switch(PGACHANNELSEL)
  {
    case PGA0:
      PGA->PGA0CTL.bit.BYPP = 0;                                                         /* set positive path as no bypass mode */
      PGA->PGA0CTL.bit.BYPN = 0;                                                         /* set negtive path as no bypass mode */
      break;
    case PGA1:
      PGA->PGA1CTL.bit.BYPP = 0;                                                         /* set positive path as no bypass mode */
      PGA->PGA1CTL.bit.BYPN = 0;                                                         /* set negtive path as no bypass mode */
      break;
    case PGA2:
      PGA->PGA2CTL.bit.BYPP = 0;                                                         /* set positive path as no bypass mode */
      PGA->PGA2CTL.bit.BYPN = 0;                                                         /* set negtive path as no bypass mode */
      break;
  }
      
  COMP_SetDACValue10Bit(DAC1,CODE1[PGAGAINSEL]);
  Delay_Ms(10);
      
  i32result_out1 = ADC_Measure_ADCCHANNEL_CODE(1000);                                   /* measure output value first time */
  
  COMP_SetDACValue10Bit(DAC1,CODE2[PGAGAINSEL]);
  Delay_Ms(10);
      
  i32result_out2 = ADC_Measure_ADCCHANNEL_CODE(1000);                                   /* measure output value second time */
  
  fgain_measure = (float) (i32result_out2-i32result_out1)/(i32result_in2-i32result_in1);  /* the gain value after calibration */
  foffset_measure = (int32_t)(i32result_out1-i32result_in1*fgain_measure)*LSB/65536;      /* the offset value after calibration */
  
  printf("\n**************(in1:%d in2:%d out1:%d out2:%d) GAIN : %0.3f, OFFSET : %0.3f **************\n",
                                           i32result_in1,i32result_in2,i32result_out1,i32result_out2,fgain_measure,foffset_measure);
  
  printf("\n************** PGA Calibration Test End ******************\n");	
}
