Post Go back to editing

Measurement Error Below 1Hz

Category: Software
Product Number: AD5941BATZ
Software Version: Keil MicroVision

Hi, I've been using AD5941BATZ with ADICUP2039 for EIS Battery Analyzing, I used Keil MicroVision. Somehow after I uploaded the program and do several test and study about it, I have produced a quite good result from 1Hz-1kHz but this results to incomplete spectrum to analyze the battery. The nyquist plot is not completed without the tail. We are struggling to measure below 1Hz. Honestly, we the test below 1Hz and it gives me a chaotic results which I think cannot be useful for analyzation, Is there any recommendation? We are thinking about finding a raw data from registers before it go the DFT engine, the raw data that will be gathered will be use for manual DFT computation, Is this possible? Thank you for your attention.

Parents
  • Hi,

    May I know if you have referred to below example which shows how the AFE can be configured for measuring at very low frequencies:

    github.com/.../AD5940_Impedance_Adjustable_with_frequency

  • Below is a modified code for very low frequency battery EIS measurement:

    /*!
    *****************************************************************************
    @file:    AD5940Main.c
    @author:  M.Lambe
    @brief:   Used to control specific application and process data.
    -----------------------------------------------------------------------------
    Copyright (c) 2017-2019 Analog Devices, Inc. All Rights Reserved.
    This software is proprietary to Analog Devices, Inc. and its licensors.
    By using this software you agree to the terms of the associated
    Analog Devices Software License Agreement.
    
    *****************************************************************************/
    
    #include "ad5940.h"
    #include <stdio.h>
    #include "string.h"
    #include "math.h"
    #include "BATImpedance.h"
    
    #include "ADuCM3029.h"
    #define APPBUFF_SIZE 512
    uint32_t AppBuff[APPBUFF_SIZE];
    
    
    /* It's your choice here how to do with the data. Here is just an example to print them to UART */
    int32_t BATShowResult(uint32_t *pData, uint32_t DataCount)
    {
    	AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
    	if(pBATCfg->state == STATE_BATTERY)
    	{
    		fImpCar_Type *pImp = (fImpCar_Type*)pData;
    		float freq;
    		AppBATCtrl(BATCTRL_GETFREQ, &freq);
    		/*Process data*/
    		for(int i=0;i<DataCount;i++)
    		{
    			printf("Result, %f , %f , %f \n",freq, pImp[i].Real,pImp[i].Image);
    		}
    		}
    	else if(pBATCfg->state == STATE_MEASVOLT)
    	{
    		printf("Result, %f \n", pBATCfg->BatVolt );
    	}
    	
    	pBATCfg->state = STATE_IDLE;
      return 0;
    }
    float LFOSCFreq;    /* Measured LFOSC frequency */
    /* Initialize AD5940 basic blocks like clock */
    static int32_t AD5940PlatformCfg(void)
    {
      CLKCfg_Type clk_cfg;
      FIFOCfg_Type fifo_cfg;
      AGPIOCfg_Type gpio_cfg;
    	LFOSCMeasure_Type LfoscMeasure;
      /* Use hardware reset */
      AD5940_HWReset();
      /* Platform configuration */
      AD5940_Initialize();
      /* Step1. Configure clock */
      clk_cfg.ADCClkDiv = ADCCLKDIV_1;
      clk_cfg.ADCCLkSrc = ADCCLKSRC_XTAL;
      clk_cfg.SysClkDiv = SYSCLKDIV_1;
      clk_cfg.SysClkSrc = SYSCLKSRC_XTAL; //on battery board, there is a 32MHz crystal.
      clk_cfg.HfOSC32MHzMode = bFALSE;
      clk_cfg.HFOSCEn = bFALSE;
      clk_cfg.HFXTALEn = bTRUE;
      clk_cfg.LFOSCEn = bTRUE;
      AD5940_CLKCfg(&clk_cfg);
      /* Step2. Configure FIFO and Sequencer*/
      fifo_cfg.FIFOEn = bFALSE;
      fifo_cfg.FIFOMode = FIFOMODE_FIFO;
      fifo_cfg.FIFOSize = FIFOSIZE_4KB;                       /* 4kB for FIFO, The reset 2kB for sequencer */
      fifo_cfg.FIFOSrc = FIFOSRC_DFT;
      fifo_cfg.FIFOThresh = 4;       /* DFT result. One pair for RCAL, another for Rz. One DFT result have real part and imaginary part */
      AD5940_FIFOCfg(&fifo_cfg);                             /* Disable to reset FIFO. */
      fifo_cfg.FIFOEn = bTRUE;  
      AD5940_FIFOCfg(&fifo_cfg);                             /* Enable FIFO here */
      
      /* Step3. Interrupt controller */
      AD5940_INTCCfg(AFEINTC_1, AFEINTSRC_ALLINT, bTRUE);           /* Enable all interrupt in Interrupt Controller 1, so we can check INTC flags */
      AD5940_INTCCfg(AFEINTC_0, AFEINTSRC_DFTRDY, bTRUE);   /* Interrupt Controller 0 will control GP0 to generate interrupt to MCU */
      AD5940_INTCClrFlag(AFEINTSRC_ALLINT);
      /* Step4: Reconfigure GPIO */
      gpio_cfg.FuncSet = GP0_INT|GP2_SYNC|GP1_TRIG;
      gpio_cfg.InputEnSet = 0;
      gpio_cfg.OutputEnSet = AGPIO_Pin0|AGPIO_Pin2|AGPIO_Pin1;
      gpio_cfg.OutVal = 0;
      gpio_cfg.PullEnSet = 0;
      AD5940_AGPIOCfg(&gpio_cfg);
    	
    	SeqGpioTrig_Cfg seq_gpio_cfg;
    	seq_gpio_cfg.bEnable = bTRUE;
    	seq_gpio_cfg.PinSel = AGPIO_Pin1;
    	seq_gpio_cfg.SeqPinTrigMode = SEQPINTRIGMODE_FALLING;
    	AD5940_SEQGpioTrigCfg(&seq_gpio_cfg);
    	
    	/* Measure LFOSC frequency */
      LfoscMeasure.CalDuration = 1000.0;  /* 1000ms used for calibration. */
      LfoscMeasure.CalSeqAddr = 0;
      LfoscMeasure.SystemClkFreq = 16000000.0f; /* 16MHz in this firmware. */
      AD5940_LFOSCMeasure(&LfoscMeasure, &LFOSCFreq);
      printf("Freq:%f\n", LFOSCFreq);
    
      return 0;
    }
    
    void AD5940BATStructInit(void)
    {
      AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
      pBATCfg->SeqStartAddr = 0;
      pBATCfg->MaxSeqLen = 512;
    	pBATCfg->WuptClkFreq = LFOSCFreq;    /* Measured LFOSC frequency */
    	
    	/* Excitation Parameters */
      pBATCfg->RcalVal = 50.0;  							/* Value of RCAL on EVAL-AD5941BATZ board is 50mOhm */
      pBATCfg->ACVoltPP = 200.0f;							/* Pk-pk amplitude is 600mV */
      pBATCfg->DCVolt = 1200.0f;							/* Offset voltage of 1.2V*/
      
    	/* Sampliong parameters */
    	pBATCfg->SampleRate = 10;
    	pBATCfg->DftNum = DFTNUM_256;
    	pBATCfg->ADCSinc2Osr = ADCSINC2OSR_22;
    	pBATCfg->ADCSinc3Osr = ADCSINC3OSR_4;
    	pBATCfg->DftSrc = DFTSRC_SINC3;
    	
    	pBATCfg->FifoThresh = 4;      					/* 2 results in FIFO, real and imaginary part. */  
      pBATCfg->SinFreq = 0.5;									/* Sin wave frequency. THis value has no effect if sweep is enabled */
       
    }
    void do_measurement(void);
    uint8_t bStartMeasurement = 0;
    uint8_t bStartVoltageMeasurement = 0;
    
    void AD5940_StopTrigTimer(void);
    
    void AD5940_Main(void)
    { 
    	uint32_t temp = 0;
      uint32_t help(uint32_t para1, uint32_t para2);
      AD5940_Delay10us(10000);
    
      AD5940PlatformCfg();
    
      help(0,0);
      AD5940BATStructInit(); /* Configure your parameters in this function */
      AppBATInit(AppBuff, APPBUFF_SIZE);    /* Initialize BAT application. Provide a buffer, which is used to store sequencer commands */
    	
    	while(1)
    	{
    		if(bStartMeasurement == 1)
    		{
    			bStartMeasurement = 0;
    			do_measurement();
    		}
    		if(bStartVoltageMeasurement)
    		{
    				bStartVoltageMeasurement = 0;
    				while(AD5940_GetMCUIntFlag() == bFALSE);
    				AD5940_ClrMCUIntFlag(); 				/* Clear this flag */
    				temp = APPBUFF_SIZE;
    				AppBATISR(AppBuff, &temp); 			/* Deal with it and provide a buffer to store data we got */  
    				BATShowResult(AppBuff, temp);		/* Print measurement results over UART */	
    		}
    	}		
    }
    
    /* Depending on frequency of Sin wave set optimum filter settings */
    AD5940Err AppBATCheckFreq(void)
    {
      DFTCfg_Type dfp_cfg;
    	ADCFilterCfg_Type adc_cfg;
      uint32_t WaitClks;
      ClksCalInfo_Type clks_cal;
    	AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
    	
      uint32_t SeqCmdBuff[2];
      uint32_t SRAMAddr = 0;
    
    
      adc_cfg.ADCAvgNum = ADCAVGNUM_16;  /* Don't care because it's disabled */
      adc_cfg.ADCRate = ADCRATE_800KHZ;
      adc_cfg.ADCSinc2Osr = pBATCfg->ADCSinc2Osr;
      adc_cfg.ADCSinc3Osr = pBATCfg->ADCSinc3Osr;
      adc_cfg.BpSinc3 = bFALSE;
      adc_cfg.BpNotch = bTRUE;
      adc_cfg.Sinc2NotchEnable = bTRUE;
    	AD5940_ADCFilterCfgS(&adc_cfg);
    	
      dfp_cfg.DftNum = pBATCfg->DftNum;
      dfp_cfg.DftSrc = pBATCfg->DftSrc;
      dfp_cfg.HanWinEn = pBATCfg->HanWinEn;
    	AD5940_DFTCfgS(&dfp_cfg);
      
      /* Step 3: Calculate clocks needed to get result to FIFO and update sequencer wait command */
    	if(pBATCfg->DftSrc == DFTSRC_SINC3)
    		clks_cal.DataType = DATATYPE_SINC3;
    	else
    		clks_cal.DataType = DATATYPE_SINC2;
      clks_cal.DataCount = 1; /* 2^(DFTNUMBER+2) */
      clks_cal.ADCSinc2Osr = pBATCfg->ADCSinc2Osr;
      clks_cal.ADCSinc3Osr = pBATCfg->ADCSinc3Osr;
      clks_cal.ADCAvgNum = ADCAVGNUM_16;
      clks_cal.RatioSys2AdcClk = pBATCfg->SysClkFreq/pBATCfg->AdcClkFreq;
      clks_cal.ADCRate = ADCRATE_800KHZ;
      clks_cal.BpNotch = bFALSE;
      AD5940_ClksCalculate(&clks_cal, &WaitClks);	
      
    
      /* Find start address of sequence in SRAM 
      Update WaitClks */
      SRAMAddr = pBATCfg->ImpedanceSeqInfo.SeqRamAddr;
      SeqCmdBuff[0] = SEQ_WAIT(WaitClks);
      AD5940_SEQCmdWrite(SRAMAddr+4, SeqCmdBuff, 1);
      
      return AD5940ERR_OK;
    }
    
    void do_measurement(void)
    {
    	uint32_t temp;
    	//Step One measure RCAL
    	AD5940_Delay10us(100000);
    	AppBATCheckFreq();
    	AppBATCtrl(BATCTRL_MEASRCAL, 0);
    	while(AD5940_GetMCUIntFlag() == bFALSE);
    	//while(AD5940_INTCTestFlag(AFEINTC_1, AFEINTSRC_DFTRDY) == bFALSE);
    	// Stop TImer
    	AD5940_StopTrigTimer();
    //	AD5940_WUPTCtrl(bFALSE);
    //	AD5940_WUPTCtrl(bFALSE);
    	AD5940_AFECtrlS(AFECTRL_DFT, bFALSE);
    	AD5940_ClrMCUIntFlag(); 				/* Clear this flag */
    	AD5940_INTCClrFlag(AFEINTSRC_DFTRDY);
      
    	//Step2: Measure Battery
      AppBATCtrl(BATCTRL_MEASIMP, 0);
    	while(AD5940_GetMCUIntFlag() == 0);
    	AD5940_StopTrigTimer();
    //	AD5940_WUPTCtrl(bFALSE);
    //	AD5940_WUPTCtrl(bFALSE);
    	AD5940_AFECtrlS(AFECTRL_DFT, bFALSE);
    	AD5940_ClrMCUIntFlag(); 				/* Clear this flag */
    	temp = APPBUFF_SIZE;
    	AppBATISR(AppBuff, &temp); 			/* Deal with it and provide a buffer to store data we got */  
    	BATShowResult(AppBuff, temp);		/* Print measurement results over UART */	
    }
    
    
    uint32_t batz_rst(uint32_t *para1)
    {
    	AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
      pBATCfg->BATInited = bFALSE;
      AD5940PlatformCfg();  
      AppBATInit(AppBuff, APPBUFF_SIZE);    /* Initialize BAT application. Provide a buffer, which is used to store sequencer commands */
    	bStartMeasurement = 0;
    	bStartVoltageMeasurement = 0;
      #ifdef ADI_DEBUG
      printf("DEBUG: Board Reset\n");
    	#endif
      return 0;
    }
    
    uint32_t batz_start(float para1, float para2)
    {
      if(para1<0.015)
      {
        para1 = 0.015;
        
      }
      if(para2<10)
      {
        para2 = 10;
      }
      printf("START\n");
      AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
      pBATCfg->SinFreq = para1;
    	#ifdef ADI_DEBUG
      printf("DEBUG: Start Command Received\n");
    	#endif
      AppBATConnect(bTRUE);
      AD5940_WGFreqCtrlS(para1, 16e6);
    	#ifdef ADI_DEBUG
      printf("DEBUG: Waveform Generator Updated\n");
    	#endif
    	bStartMeasurement = 1;
      return 0;
    }
    
    uint32_t batz_get_volt(float para1)
    {
    //	bStartVoltageMeasurement = 1;
    //  AppBATCtrl(BATCTRL_MEASVOLT, 0);
      return 0;
    }
    
    uint32_t batz_set_rcal(float para1)
    {
      AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
      pBATCfg->RcalVal = para1;
    	#ifdef ADI_DEBUG
      printf("DEBUG: Rcal set to %f \n", para1);
    	#endif
      return 0;
    }
    
    uint32_t batz_disconnect(float para1)
    {
      AppBATConnect(bFALSE);
      return 0;
    }
    
    uint32_t batz_connect(float para1)
    {
      AppBATConnect(bTRUE);
    	AD5940_AFECtrlS(AFECTRL_WG, bTRUE);
      return 0;
    }
    
    uint32_t batz_set_dcvolt(float para1)
    {
      LPDACCfg_Type lpdac_cfg;
      /* Check Parameter */
      if(para1 >2000)
      {
        para1=2000;
    		#ifdef ADI_DEBUG
        printf("DEBUG: Invalid Voltage. DC Volt set to 2V\n");
    		#endif
      }
      if(para1<300)
      {
        para1=300;
    #ifdef ADI_DEBUG		
        printf("DEBUG: Invalid Voltage. DC VOlt set to 0.3V\n");
    		#endif
      }
      lpdac_cfg.DacData12Bit = (uint32_t)((para1-200)/DAC12BITVOLT_1LSB);
      lpdac_cfg.DacData6Bit = 31;  //not used. Set it to middle value.
      AD5940_LPDAC0WriteS(lpdac_cfg.DacData12Bit, lpdac_cfg.DacData6Bit);
    	#ifdef ADI_DEBUG
      printf("DEBUG: DC voltage updated \n");
    	#endif
      return 0;
    }
    
    uint32_t batz_set_acamplitude(float para1)
    {
    	
    	HSDACCfg_Type hsdac_cfg;
    	float gain_factor = 0;
    	float voltage = 0;
      /* Check Parameter */
      if(para1 >400) 
      {
        para1=400;
    		#ifdef ADI_DEBUG
        printf("DEBUG: Invalid Voltage. Amplitude set to 400mV\n");
    		#endif
      }
      if(para1<0)
      {
        para1=30;
    		#ifdef ADI_DEBUG
        printf("DEBUG: Invalid Voltage. Amplitude set to 30mV\n");
    		#endif
      }
    	/* Select Attenuator and gain settings based on selected ac amplitude */
    	if(para1 <15.14) 
    	{
    		hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_0P25;
    		hsdac_cfg.HsDacGain = HSDACGAIN_0P2;
    		gain_factor = 0.05;
    	}else if(para1 <75) 
    	{
    		hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_0P25;
    		hsdac_cfg.HsDacGain = HSDACGAIN_1;
    		gain_factor = 0.25;
    	}else if(para1 < 121.2) 
    	{
    		hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_2;
    		hsdac_cfg.HsDacGain = HSDACGAIN_0P2;
    		gain_factor = 0.4;
    	}else 
    	{
    		hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_2;
    		hsdac_cfg.HsDacGain = HSDACGAIN_1;
    		gain_factor = 2;
    	}
    	hsdac_cfg.HsDacUpdateRate = 0x1B;
    	AD5940_HSDacCfgS(&hsdac_cfg);
    	
    	voltage = para1/gain_factor;
      uint32_t SinAmplitudeWord = 0;
      AD5940_AFECtrlS(AFECTRL_WG, bFALSE);
      SinAmplitudeWord = (uint32_t)((voltage)/808.15f*2047 + 0.5f);
      AD5940_WriteReg(REG_AFE_WGAMPLITUDE, SinAmplitudeWord);
    	AD5940_AFECtrlS(AFECTRL_WG, bTRUE);
    	#ifdef ADI_DEBUG
      printf("DEBUG: Sin amplitude updated \n");
    	#endif
    
      return 0;
    }
    
    uint32_t batz_set_adc_sample_rate(float para1, float para2)
    {
    	AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
      pBATCfg->SampleRate = para1;
    	#ifdef ADI_DEBUG
      printf("DEBUG: ADC Sample Rate set to %f\n", para1);
    	#endif
    }
    
    //void UpdateSequence(
    uint32_t batz_set_sinc_filter(float para1, float para2)
    {
    	const uint32_t sinc2osr_table[] = {1, 22,44,89,178,267,533,640,667,800,889,1067,1333};
      const uint32_t sinc3osr_table[] = {2, 4, 5};
    	AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
    	// Check Parameter and find it's index in the table
    	for(uint32_t i = 0; i<sizeof(sinc3osr_table) / sizeof(uint32_t); i++)
    	{
    		if(para2 == sinc3osr_table[i])
    		{
    			pBATCfg->ADCSinc3Osr = i;
    		}
    	}
    	
    	if(para2 > 0)
    	{
    		for(uint32_t i = 0; i<sizeof(sinc2osr_table) / sizeof(uint32_t); i++)
    		{
    			if(para2 == sinc2osr_table[i])
    			{
    				pBATCfg->ADCSinc2Osr = i;
    			}
    		}
    	}
    	#ifdef ADI_DEBUG
      printf("DEBUG: ADC Filters Updated\n");
    	#endif
    	
    }
    
    
    uint32_t batz_set_dft(float para1, float para2)
    {	
    	const uint32_t dft_table[] = {4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384};
      AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
    	
    	// Check Parameter and find it's index in the table
    	for(uint32_t i = 0; i<sizeof(dft_table) / sizeof(uint32_t); i++)
    	{
    		if(para2 == dft_table[i])
    		{
    			pBATCfg->DftNum = i;
    		}
    	}
    	if(para2 == 0)
    		pBATCfg->DftSrc = DFTSRC_SINC3;
    	else
    		pBATCfg->DftSrc = DFTSRC_SINC2NOTCH;	
    	#ifdef ADI_DEBUG
      printf("DEBUG: DFT Num set to %f\n", para1);
    	#endif
    }
    
    
    
     

    /*!
    *****************************************************************************
    @file:    BATImpedance.c
    @author: MLambe
    @brief:   Battery impedance measurement sequences.
    -----------------------------------------------------------------------------
    Copyright (c) 2017-2019 Analog Devices, Inc. All Rights Reserved.
    This software is proprietary to Analog Devices, Inc. and its licensors.
    By using this software you agree to the terms of the associated
    Analog Devices Software License Agreement.
    
    *****************************************************************************/
    #include "BATImpedance.h"
    
    /* 
    Application configuration structure. Specified by user from template.
    The variables are usable in this whole application.
    It includes basic configuration for sequencer generator and application related parameters
    */
    AppBATCfg_Type AppBATCfg = 
    {
      .bParaChanged = bFALSE,
      .SeqStartAddr = 0,
      .MaxSeqLen = 0,
      
      .SeqStartAddrCal = 0,
      .MaxSeqLenCal = 0,
      
      .SysClkFreq = 16000000.0,
      .WuptClkFreq = 32000.0,
      .AdcClkFreq = 16000000.0,
      .NumOfData = -1,
      
      .PwrMod = AFEPWR_LP,
      .ACVoltPP = 800.0,
      .DCVolt = 1100.0f,
      .SinFreq = 50000.0, /* 50kHz */
      .RcalVal = 50.0, /* 50mOhm */
      
      .ADCSinc3Osr = ADCSINC3OSR_4,
      .ADCSinc2Osr = ADCSINC2OSR_22,
      
      .DftNum = DFTNUM_16384,
      .DftSrc = DFTSRC_SINC3,
      .HanWinEn = bTRUE,
      
      .FifoThresh = 4,
      .BATInited = bFALSE,
      .StopRequired = bFALSE,
     
    };
    
    /**
    This function is provided for upper controllers that want to change 
    application parameters specially for user defined parameters.
    */
    AD5940Err AppBATGetCfg(void *pCfg)
    {
      if(pCfg){
        *(AppBATCfg_Type**)pCfg = &AppBATCfg;
        return AD5940ERR_OK;
      }
      return AD5940ERR_PARA;
    }
    
    /* This function uses an external switch to bypass the 2Mohm resistors on teh high pass fileter
    on the input to the measurement channel to increase settle time */
    static void PreCharge(unsigned char channel) 
    {
      void Arduino_WriteDn(uint32_t Dn, BoolFlag bHigh);
      switch(channel)
      {
      case PRECHARGE_CH1: //00
        Arduino_WriteDn(1<<3, bFALSE);  //d3
        Arduino_WriteDn(1<<4, bFALSE);  //d4
        break;
      case PRECHARGE_CH2: //01
        Arduino_WriteDn(1<<3, bTRUE);
        Arduino_WriteDn(1<<4, bFALSE);
        break;
      case PRECHARGE_CH3://10
        Arduino_WriteDn(1<<3, bFALSE);
        Arduino_WriteDn(1<<4, bTRUE);
        break;
      default:
        break;
      }
      AD5940_Delay10us(PRECHARGE_WAIT_MS*100);
      Arduino_WriteDn(1<<3, bTRUE);  //d3
      Arduino_WriteDn(1<<4, bTRUE);  //d4
    }
    
    void AD5940_StartTrigTimer(float freq);
    AD5940Err AppBATCtrl(int32_t BatCtrl, void *pPara)
    {
      switch (BatCtrl)
      {
      case BATCTRL_MEASIMP:
        {
    			WUPTCfg_Type wupt_cfg;
          if(AD5940_WakeUp(10) > 10)  /* Wakeup AFE by read register, read 10 times at most */
            return AD5940ERR_WAKEUP;  /* Wakeup Failed */
          if(AppBATCfg.BATInited == bFALSE)
            return AD5940ERR_APPERROR;
    			
    			AD5940_WriteReg(REG_AFE_SYNCEXTDEVICE, 0x0);
          PreCharge(PRECHARGE_BAT);
          PreCharge(PRECHARGE_AMP);
          PreCharge(PRECHARGE_RCAL);
    //      AD5940_FIFOCtrlS(FIFOSRC_DFT, bFALSE);
    //      AD5940_FIFOThrshSet(AppBATCfg.FifoThresh);  /* DFT result contains both real and image. */
    //      AD5940_FIFOCtrlS(FIFOSRC_DFT, bTRUE);
    			
    			AppBATCfg.state = STATE_BATTERY;
    			
          AD5940_AFECtrlS(AFECTRL_DFT, bTRUE);
    			/* Start it */
    //      wupt_cfg.WuptEn = bTRUE;
    //      wupt_cfg.WuptEndSeq = WUPTENDSEQ_A;
    //      wupt_cfg.WuptOrder[0] = SEQID_0;
    //      wupt_cfg.SeqxSleepTime[SEQID_0] = (uint32_t)(AppBATCfg.WuptClkFreq/AppBATCfg.SampleRate)-2-4;
    //      wupt_cfg.SeqxWakeupTime[SEQID_0] = 4; /* The minimum value is 1. Do not set it to zero. Set it to 1 will spend 2 32kHz clock. */
    //      AD5940_WUPTCfg(&wupt_cfg);
    			
          AD5940_StartTrigTimer(AppBATCfg.SampleRate);
          break;
        }
    	case BATCTRL_MEASRCAL:
        {
    			WUPTCfg_Type wupt_cfg;
          if(AD5940_WakeUp(10) > 10)  /* Wakeup AFE by read register, read 10 times at most */
            return AD5940ERR_WAKEUP;  /* Wakeup Failed */
          if(AppBATCfg.BATInited == bFALSE)
            return AD5940ERR_APPERROR;
          PreCharge(PRECHARGE_BAT);
          PreCharge(PRECHARGE_AMP);
          PreCharge(PRECHARGE_RCAL);
          AD5940_FIFOCtrlS(FIFOSRC_DFT, bFALSE);
          AD5940_FIFOThrshSet(AppBATCfg.FifoThresh);  /* DFT result contains both real and image. */
          AD5940_FIFOCtrlS(FIFOSRC_DFT, bTRUE);
    			
    			AD5940_WriteReg(REG_AFE_SYNCEXTDEVICE, 0x4);
    			AppBATCfg.state = STATE_RCAL;
    			
          AD5940_AFECtrlS(AFECTRL_DFT, bTRUE);
    			/* Start it */
    //      wupt_cfg.WuptEn = bTRUE;
    //      wupt_cfg.WuptEndSeq = WUPTENDSEQ_A;
    //      wupt_cfg.WuptOrder[0] = SEQID_0;
    //      wupt_cfg.SeqxSleepTime[SEQID_0] = (uint32_t)(AppBATCfg.WuptClkFreq/AppBATCfg.SampleRate)-2-4;
    //      wupt_cfg.SeqxWakeupTime[SEQID_0] = 4; /* The minimum value is 1. Do not set it to zero. Set it to 1 will spend 2 32kHz clock. */
    //      AD5940_WUPTCfg(&wupt_cfg);
    		AD5940_StartTrigTimer(AppBATCfg.SampleRate);
          
          break;
        }
    	case BATCTRL_MEASVOLT:
    	{
    	 if(AD5940_WakeUp(10) > 10)  /* Wakeup AFE by read register, read 10 times at most */
            return AD5940ERR_WAKEUP;  /* Wakeup Failed */
          if(AppBATCfg.BATInited == bFALSE)
            return AD5940ERR_APPERROR;
    		AppBATCfg.state = STATE_MEASVOLT;
          /* Configure FIFO for temperature measurement */
          AD5940_FIFOCtrlS(FIFOSRC_DFT, bFALSE);
          AD5940_FIFOThrshSet(1);
          AD5940_FIFOCtrlS(FIFOSRC_SINC2NOTCH, bTRUE); //enable FIFO
          AD5940_INTCClrFlag(AFEINTSRC_ALLINT);
    			AD5940_SEQMmrTrig(AppBATCfg.VoltMeasureSeqInfo.SeqId);
    	break;
    	}
      case BATCTRL_GETFREQ:
        if(pPara)
        {
            *(float*)pPara = AppBATCfg.SinFreq;
        }
        break;
      case BATCTRL_SHUTDOWN:
        {
          /* Turn off LPloop related blocks which are not controlled automatically by sleep operation */
          AFERefCfg_Type aferef_cfg;
          LPLoopCfg_Type lp_loop;
          memset(&aferef_cfg, 0, sizeof(aferef_cfg));
          AD5940_REFCfgS(&aferef_cfg);
          memset(&lp_loop, 0, sizeof(lp_loop));
          AD5940_LPLoopCfgS(&lp_loop);
          AD5940_EnterSleepS();  /* Enter Hibernate */
        }
        break;
      default:
        break;
      }
      return AD5940ERR_OK;
    }
    
    void AppBATConnect(BoolFlag bConnect)
    {
      SWMatrixCfg_Type sw_cfg;
      if(bConnect)
      {
        sw_cfg.Dswitch = SWD_CE0;
        sw_cfg.Pswitch = SWP_AIN1;
        sw_cfg.Nswitch = SWN_AIN0;  //AIN0 is connected to AIN4 externally by JP3.
        sw_cfg.Tswitch = 0; //T switch is not used.
      }else{
        sw_cfg.Dswitch = SWD_OPEN;
        sw_cfg.Pswitch = SWP_OPEN;
        sw_cfg.Nswitch = SWN_OPEN;  //AIN0 is connected to AIN4 externally by JP3.
        sw_cfg.Tswitch = 0; //T switch is not used.
      }
      AD5940_SWMatrixCfgS(&sw_cfg);
    	#ifdef ADI_DEBUG
    	printf("DEBUG: Switch Matrick Configured \n"); 
    	#endif
    }
    /* Generate init sequence */
    static AD5940Err AppBATSeqCfgGen(void)
    {
      AD5940Err error = AD5940ERR_OK;
      uint32_t const *pSeqCmd;
      uint32_t SeqLen;
      AFERefCfg_Type aferef_cfg;
      HSLoopCfg_Type hs_loop;
      LPLoopCfg_Type lp_loop;
      DSPCfg_Type dsp_cfg;
      float sin_freq;
      
      /* Start sequence generator here */
      AD5940_SEQGenCtrl(bTRUE);
      
      AD5940_AFECtrlS(AFECTRL_ALL, bFALSE);  /* Disable all firstly. */
      aferef_cfg.HpBandgapEn = bTRUE;
      aferef_cfg.Hp1V1BuffEn = bTRUE;
      aferef_cfg.Hp1V8BuffEn = bTRUE;
      aferef_cfg.Disc1V1Cap = bFALSE;
      aferef_cfg.Disc1V8Cap = bFALSE;
      aferef_cfg.Hp1V8ThemBuff = bFALSE;
      aferef_cfg.Hp1V8Ilimit = bFALSE;
      aferef_cfg.Lp1V1BuffEn = bFALSE;
      aferef_cfg.Lp1V8BuffEn = bFALSE;
      /* LP reference control, Use LP loop to provide DC Bias voltage. */
      aferef_cfg.LpBandgapEn = bTRUE;
      aferef_cfg.LpRefBufEn = bTRUE;
      aferef_cfg.LpRefBoostEn = bFALSE;
      AD5940_REFCfgS(&aferef_cfg);
      /* Determine buffer gain according to ACVoltPP */
      hs_loop.HsDacCfg.ExcitBufGain = EXCITBUFGAIN_2;
      hs_loop.HsDacCfg.HsDacGain = HSDACGAIN_1;
      hs_loop.HsDacCfg.HsDacUpdateRate = 0x1B; //the maximum update rate is 16MHz/7
      
      hs_loop.HsTiaCfg.DiodeClose = bFALSE;
      hs_loop.HsTiaCfg.HstiaBias = HSTIABIAS_1P1;
      hs_loop.HsTiaCfg.HstiaCtia = 31;  //HSTIA is not used.
      hs_loop.HsTiaCfg.HstiaDeRload = HSTIADERLOAD_OPEN;
      hs_loop.HsTiaCfg.HstiaDeRtia = HSTIADERTIA_OPEN;
      hs_loop.HsTiaCfg.HstiaRtiaSel = HSTIARTIA_10K;
      
      hs_loop.SWMatCfg.Dswitch = SWD_CE0;
      hs_loop.SWMatCfg.Pswitch = SWP_AIN1;
      hs_loop.SWMatCfg.Nswitch = SWN_AIN0;  //AIN0 is connected to AIN4 externally by JP3.
      hs_loop.SWMatCfg.Tswitch = 0; //T switch is not used.
      
      hs_loop.WgCfg.WgType = WGTYPE_SIN;
      hs_loop.WgCfg.GainCalEn = bFALSE;
      hs_loop.WgCfg.OffsetCalEn = bFALSE;
       sin_freq = AppBATCfg.SinFreq;
        AppBATCfg.FreqofData = sin_freq;
      hs_loop.WgCfg.SinCfg.SinFreqWord = AD5940_WGFreqWordCal(sin_freq, AppBATCfg.SysClkFreq);
      hs_loop.WgCfg.SinCfg.SinAmplitudeWord = (uint32_t)(AppBATCfg.ACVoltPP/800.0f*2047 + 0.5f);
      hs_loop.WgCfg.SinCfg.SinOffsetWord = 0;
      hs_loop.WgCfg.SinCfg.SinPhaseWord = 0;
      AD5940_HSLoopCfgS(&hs_loop);
      //Use LP loop to output bias voltage on AIN4 pin, which provides voltage on AIN0(N switch).
      lp_loop.LpDacCfg.LpdacSel = LPDAC0;
      lp_loop.LpDacCfg.LpDacSrc = LPDACSRC_MMR;
      lp_loop.LpDacCfg.LpDacSW = LPDACSW_VZERO2LPTIA|LPDACSW_VZERO2PIN;
      lp_loop.LpDacCfg.LpDacVzeroMux = LPDACVZERO_12BIT;
      lp_loop.LpDacCfg.LpDacVbiasMux = LPDACVBIAS_6BIT;
      lp_loop.LpDacCfg.LpDacRef = LPDACREF_2P5;
      lp_loop.LpDacCfg.DataRst = bFALSE;
      lp_loop.LpDacCfg.PowerEn = bTRUE;
      lp_loop.LpDacCfg.DacData12Bit = (uint32_t)((AppBATCfg.DCVolt-200)/2200.0f*4095);
      lp_loop.LpDacCfg.DacData6Bit = 31;  //not used. Set it to middle value.
      
      lp_loop.LpAmpCfg.LpAmpSel = LPAMP0;
      lp_loop.LpAmpCfg.LpAmpPwrMod = LPAMPPWR_NORM;
      lp_loop.LpAmpCfg.LpPaPwrEn = bFALSE;
      lp_loop.LpAmpCfg.LpTiaPwrEn = bTRUE;
      lp_loop.LpAmpCfg.LpTiaRf = LPTIARF_20K; //External cap is 1uF.
      lp_loop.LpAmpCfg.LpTiaRload = LPTIARLOAD_SHORT;
      lp_loop.LpAmpCfg.LpTiaRtia = LPTIARTIA_OPEN;
      lp_loop.LpAmpCfg.LpTiaSW = LPTIASW(7)|LPTIASW(5)|LPTIASW(9);
      AD5940_LPLoopCfgS(&lp_loop);
      
      dsp_cfg.ADCBaseCfg.ADCMuxN = ADCMUXN_AIN2;
      dsp_cfg.ADCBaseCfg.ADCMuxP = ADCMUXP_AIN3;
      dsp_cfg.ADCBaseCfg.ADCPga = ADCPGA_2;
      memset(&dsp_cfg.ADCDigCompCfg, 0, sizeof(dsp_cfg.ADCDigCompCfg));
      dsp_cfg.ADCFilterCfg.ADCAvgNum = ADCAVGNUM_16;  /* Don't care because it's disabled */
      dsp_cfg.ADCFilterCfg.ADCRate = ADCRATE_800KHZ;
      dsp_cfg.ADCFilterCfg.ADCSinc2Osr = AppBATCfg.ADCSinc2Osr;
      dsp_cfg.ADCFilterCfg.ADCSinc3Osr = AppBATCfg.ADCSinc3Osr;
      dsp_cfg.ADCFilterCfg.BpSinc3 = bFALSE;
      dsp_cfg.ADCFilterCfg.BpNotch = bTRUE;
      dsp_cfg.ADCFilterCfg.Sinc2NotchEnable = bTRUE;
      dsp_cfg.DftCfg.DftNum = AppBATCfg.DftNum;
      dsp_cfg.DftCfg.DftSrc = AppBATCfg.DftSrc;
      dsp_cfg.DftCfg.HanWinEn = AppBATCfg.HanWinEn;
      memset(&dsp_cfg.StatCfg, 0, sizeof(dsp_cfg.StatCfg)); /* Don't care about Statistic */
      AD5940_DSPCfgS(&dsp_cfg);
      /* Enable all of them. They are automatically turned off during hibernate mode to save power */
      AD5940_AFECtrlS(AFECTRL_HPREFPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\
        AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\
          AFECTRL_SINC2NOTCH|AFECTRL_DFT, bTRUE);
      /* Sequence end. */
      AD5940_SEQGenInsert(SEQ_STOP()); /* Add one external command to disable sequencer for initialization sequence because we only want it to run one time. */
      
      /* Stop here */
      error = AD5940_SEQGenFetchSeq(&pSeqCmd, &SeqLen);
      AD5940_SEQGenCtrl(bFALSE); /* Stop sequencer generator */
      if(error == AD5940ERR_OK)
      {
        AppBATCfg.InitSeqInfo.SeqId = SEQID_3;
        AppBATCfg.InitSeqInfo.SeqRamAddr = AppBATCfg.SeqStartAddr;
        AppBATCfg.InitSeqInfo.pSeqCmd = pSeqCmd;
        AppBATCfg.InitSeqInfo.SeqLen = SeqLen;
        /* Write command to SRAM */
        AD5940_SEQCmdWrite(AppBATCfg.InitSeqInfo.SeqRamAddr, pSeqCmd, SeqLen);
      }
      else
        return error; /* Error */
      return AD5940ERR_OK;
    }
    
    //the sequence used to measure battery response voltage.
    static AD5940Err AppBATSeqMeasureGen(void)
    {
      AD5940Err error = AD5940ERR_OK;
      uint32_t const *pSeqCmd;
      uint32_t SeqLen;
      uint32_t WaitClks;
      ClksCalInfo_Type clks_cal;
      
      clks_cal.DataType = DATATYPE_SINC3;
      clks_cal.DataCount = 1;
      clks_cal.ADCSinc2Osr = AppBATCfg.ADCSinc2Osr;
      clks_cal.ADCSinc3Osr = AppBATCfg.ADCSinc3Osr;
      clks_cal.ADCAvgNum = 0;
      clks_cal.RatioSys2AdcClk = AppBATCfg.SysClkFreq/AppBATCfg.AdcClkFreq;
      AD5940_ClksCalculate(&clks_cal, &WaitClks);
    
      /* Start sequence generator here */
      AD5940_SEQGenCtrl(bTRUE);
      AD5940_SEQGenInsert(SEQ_WAIT(16*250));  /* wait 250us for reference power up from hibernate mode. */
      AD5940_AFECtrlS(AFECTRL_WG|AFECTRL_ADCPWR|AFECTRL_SINC2NOTCH, bTRUE);  /* Enable Waveform generator, ADC power */
      AD5940_SEQGenInsert(SEQ_WAIT(16*50));   /* Wait for ADC ready. */
      AD5940_AFECtrlS(AFECTRL_ADCCNV, bTRUE);  /* Start ADC convert and DFT */
      AD5940_SEQGenInsert(SEQ_WAIT(WaitClks));  /* wait for first data ready */  
    //	AD5940_
      AD5940_AFECtrlS(AFECTRL_ADCCNV/*|AFECTRL_DFT|AFECTRL_WG*/|AFECTRL_ADCPWR|AFECTRL_SINC2NOTCH, bFALSE);  /* Stop ADC convert and DFT */
      
      /* Sequence end. */
      error = AD5940_SEQGenFetchSeq(&pSeqCmd, &SeqLen);
      AD5940_SEQGenCtrl(bFALSE); /* Stop sequencer generator */
      if(error == AD5940ERR_OK)
      {
        AppBATCfg.ImpedanceSeqInfo.SeqId = SEQID_1;
        AppBATCfg.ImpedanceSeqInfo.SeqRamAddr = AppBATCfg.InitSeqInfo.SeqRamAddr + AppBATCfg.InitSeqInfo.SeqLen ;
        AppBATCfg.ImpedanceSeqInfo.pSeqCmd = pSeqCmd;
        AppBATCfg.ImpedanceSeqInfo.SeqLen = SeqLen;
        /* Write command to SRAM */
        AD5940_SEQCmdWrite(AppBATCfg.ImpedanceSeqInfo.SeqRamAddr, pSeqCmd, SeqLen);
      }
      else
        return error; /* Error */
      return AD5940ERR_OK;
    }
    
    /* M<easure battery voltage through amplifier */
    //the sequence used to measure battery response voltage.
    static AD5940Err AppBATVoltSeqMeasureGen(void)
    {
      AD5940Err error = AD5940ERR_OK;
      uint32_t const *pSeqCmd;
      uint32_t SeqLen;
      uint32_t WaitClks;
      ClksCalInfo_Type clks_cal;
      ADCFilterCfg_Type adc_filt;
    
    
      clks_cal.DataType = DATATYPE_SINC2;
      clks_cal.DataCount = 1; 
      clks_cal.ADCSinc2Osr = ADCSINC2OSR_22;
      clks_cal.ADCSinc3Osr = ADCSINC3OSR_4;
      clks_cal.ADCAvgNum = 0;
      clks_cal.RatioSys2AdcClk = AppBATCfg.SysClkFreq/AppBATCfg.AdcClkFreq;
      AD5940_ClksCalculate(&clks_cal, &WaitClks);
    		
      /* Start sequence generator here */
      AD5940_SEQGenCtrl(bTRUE);
    
    	adc_filt.ADCAvgNum = ADCAVGNUM_16;  /* Don't care because it's disabled */
      adc_filt.ADCRate = ADCRATE_800KHZ;
      adc_filt.ADCSinc2Osr = ADCSINC2OSR_22;
      adc_filt.ADCSinc3Osr = ADCSINC3OSR_4;
      adc_filt.BpSinc3 = bFALSE;
      adc_filt.BpNotch = bTRUE;
      adc_filt.Sinc2NotchEnable = bTRUE;
    	AD5940_ADCFilterCfgS(&adc_filt);
    	
    	
      AD5940_ADCMuxCfgS(ADCMUXP_VAFE3, ADCMUXN_VSET1P1);
      AD5940_SEQGenInsert(SEQ_WAIT(16*250));  /* wait 250us for reference power up from hibernate mode. */
      AD5940_AFECtrlS(AFECTRL_ADCPWR|AFECTRL_SINC2NOTCH, bTRUE);  /* Enable Waveform generator, ADC power */
      AD5940_SEQGenInsert(SEQ_WAIT(16*50));   /* Wait for ADC ready. */
      AD5940_AFECtrlS(AFECTRL_ADCCNV, bTRUE);  /* Start ADC convert and DFT */
    		
      AD5940_SEQGenInsert(SEQ_WAIT(WaitClks));  /* wait for first data ready */  	
      AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_ADCPWR|AFECTRL_SINC2NOTCH, bFALSE);  /* Stop ADC convert and DFT */
      AD5940_ADCMuxCfgS(ADCMUXP_AIN2, ADCMUXN_AIN3);
    
      /* Sequence end. */
      error = AD5940_SEQGenFetchSeq(&pSeqCmd, &SeqLen);
      AD5940_SEQGenCtrl(bFALSE); /* Stop sequencer generator */
      if(error == AD5940ERR_OK)
      {
        AppBATCfg.VoltMeasureSeqInfo.SeqId = SEQID_0;
        AppBATCfg.VoltMeasureSeqInfo.SeqRamAddr = AppBATCfg.ImpedanceSeqInfo.SeqRamAddr + AppBATCfg.ImpedanceSeqInfo.SeqLen ;
        AppBATCfg.VoltMeasureSeqInfo.pSeqCmd = pSeqCmd;
        AppBATCfg.VoltMeasureSeqInfo.SeqLen = SeqLen;
        /* Write command to SRAM */
        AD5940_SEQCmdWrite(AppBATCfg.VoltMeasureSeqInfo.SeqRamAddr, pSeqCmd, SeqLen);
      }
      else
        return error; /* Error */
      return AD5940ERR_OK;
    }
    
    /* This function provide application initialize.   */
    AD5940Err AppBATInit(uint32_t *pBuffer, uint32_t BufferSize)
    {
      AD5940Err error = AD5940ERR_OK;
      SEQCfg_Type seq_cfg;
      FIFOCfg_Type fifo_cfg;
      
      if(AD5940_WakeUp(10) > 10)  /* Wakeup AFE by read register, read 10 times at most */
        return AD5940ERR_WAKEUP;  /* Wakeup Failed */
      
      /* Configure sequencer and stop it */
      seq_cfg.SeqMemSize = SEQMEMSIZE_2KB;  /* 2kB SRAM is used for sequencer, others for data FIFO */
      seq_cfg.SeqBreakEn = bFALSE;
      seq_cfg.SeqIgnoreEn = bFALSE;
      seq_cfg.SeqCntCRCClr = bTRUE;
      seq_cfg.SeqEnable = bFALSE;
      seq_cfg.SeqWrTimer = 0;
      AD5940_SEQCfg(&seq_cfg);
      
      /* Reconfigure FIFO */
      AD5940_FIFOCtrlS(FIFOSRC_DFT, bFALSE);									/* Disable FIFO firstly */
      fifo_cfg.FIFOEn = bTRUE;
      fifo_cfg.FIFOMode = FIFOMODE_FIFO;
      fifo_cfg.FIFOSize = FIFOSIZE_4KB;                       /* 4kB for FIFO, The reset 2kB for sequencer */
      fifo_cfg.FIFOSrc = FIFOSRC_DFT;
      fifo_cfg.FIFOThresh = AppBATCfg.FifoThresh;              /* DFT result. One pair for RCAL, another for Rz. One DFT result have real part and imaginary part */
      AD5940_FIFOCfg(&fifo_cfg);
      
      AD5940_INTCClrFlag(AFEINTSRC_ALLINT);
      
      /* Start sequence generator */
      /* Initialize sequencer generator */
      if((AppBATCfg.BATInited == bFALSE)||\
        (AppBATCfg.bParaChanged == bTRUE))
      {
        if(pBuffer == 0)  return AD5940ERR_PARA;
        if(BufferSize == 0) return AD5940ERR_PARA;   
        AD5940_SEQGenInit(pBuffer, BufferSize);
        /* Generate initialize sequence */
        error = AppBATSeqCfgGen(); /* Application initialization sequence using either MCU or sequencer */
        if(error != AD5940ERR_OK) return error;
        /* Generate measurement sequence */
        error = AppBATSeqMeasureGen();
        if(error != AD5940ERR_OK) return error;
        AppBATCfg.bParaChanged = bFALSE; /* Clear this flag as we already implemented the new configuration */
    		
    		 error = AppBATVoltSeqMeasureGen();
        if(error != AD5940ERR_OK) return error;
        AppBATCfg.bParaChanged = bFALSE; /* Clear this flag as we already implemented the new configuration */
    		
      }
      /* Initialization sequencer  */
      AppBATCfg.InitSeqInfo.WriteSRAM = bFALSE;
      AD5940_SEQInfoCfg(&AppBATCfg.InitSeqInfo);
      seq_cfg.SeqEnable = bTRUE;
      AD5940_SEQCfg(&seq_cfg);  /* Enable sequencer */
      AD5940_SEQMmrTrig(AppBATCfg.InitSeqInfo.SeqId);
      while(AD5940_INTCTestFlag(AFEINTC_1, AFEINTSRC_ENDSEQ) == bFALSE);
    
      /* Measurement sequence  */
      AppBATCfg.ImpedanceSeqInfo.WriteSRAM = bFALSE;
      AD5940_SEQInfoCfg(&AppBATCfg.ImpedanceSeqInfo);
    	/* Voltage Measurement Sequence  */
      AppBATCfg.VoltMeasureSeqInfo.WriteSRAM = bFALSE;
      AD5940_SEQInfoCfg(&AppBATCfg.VoltMeasureSeqInfo);
    	
      seq_cfg.SeqEnable = bTRUE;
      AD5940_SEQCfg(&seq_cfg);  /* Enable sequencer, and wait for trigger */
      AD5940_ClrMCUIntFlag();   /* Clear interrupt flag generated before */
      AD5940_AFEPwrBW(AppBATCfg.PwrMod, AFEBW_250KHZ);
      AD5940_WriteReg(REG_AFE_SWMUX, 1<<1);
      AppBATCfg.BATInited = bTRUE;  /* BAT application has been initialized. */
      return AD5940ERR_OK;
    }
    
    /* Modify registers when AFE wakeup */
    static AD5940Err AppBATRegModify(int32_t * const pData, uint32_t *pDataCount)
    {
      if(AppBATCfg.NumOfData > 0)
      {
        AppBATCfg.FifoDataCount += *pDataCount/4;
        if(AppBATCfg.FifoDataCount >= AppBATCfg.NumOfData)
        {
          AD5940_WUPTCtrl(bFALSE);
          return AD5940ERR_OK;
        }
      }
      if(AppBATCfg.StopRequired == bTRUE)
      {
        AD5940_WUPTCtrl(bFALSE);
        return AD5940ERR_OK;
      }
      return AD5940ERR_OK;
    }
    
    /* Depending on the data type, do appropriate data pre-process before return back to controller */
    static AD5940Err AppBATDataProcess(int32_t * const pData, uint32_t *pDataCount)
    {
      uint32_t DataCount = *pDataCount;
      
      *pDataCount = 0;
     // DataCount = (DataCount/4)*4;  /* We expect both Real and imaginary result.  */
      
      if(AppBATCfg.state == STATE_BATTERY)
      {
    	uint32_t DftResCount = DataCount/4;
      
      fImpCar_Type * const pOut = (fImpCar_Type*)pData;
      iImpCar_Type * pSrcData = (iImpCar_Type*)pData;
      
        /* Convert DFT result to int32_t type */
        for(uint32_t i=0; i<DataCount; i++)
        {
          pData[i] &= 0x3ffff;
          if(pData[i]&(1<<17)) /* Bit17 is sign bit */
          {
            pData[i] |= 0xfffc0000; /* Data is 18bit in two's complement, bit17 is the sign bit */
          }
        }
      for(uint32_t i=0; i<DftResCount; i++)
      {
        fImpCar_Type BatImp, BatVolt, RcalVolt;
        RcalVolt.Real = pSrcData->Real;
        RcalVolt.Image = pSrcData->Image;
        pSrcData ++;
        BatVolt.Real = pSrcData->Real;
        BatVolt.Image = pSrcData->Image;
        pSrcData ++;
        BatImp = AD5940_ComplexDivFloat(&BatVolt, &RcalVolt); //ratio measurement, Zbat = Vbat/Vrcal * Rcal;
        BatImp.Image *= AppBATCfg.RcalVal;
        BatImp.Real *= AppBATCfg.RcalVal;
        pOut[i] = BatImp;
      }
      *pDataCount = DftResCount;
    
    //  AppBATCfg.state = STATE_IDLE;
      }
    
    	else if(AppBATCfg.state == STATE_MEASVOLT)
      {
    	AppBATCfg.BatVolt = 0.0;
        for(int i=0; i<DataCount; i++)
    		{
          pData[i] &= 0xffff;
    			float temp, voltage = 0;
          voltage = AD5940_ADCCode2Volt(pData[i], ADCPGA_2, 1820) + 1110;
    			temp = ((V_DIVIDER_R1 + V_DIVIDER_R2)*voltage) /V_DIVIDER_R2;
          AppBATCfg.BatVolt += temp;
        }
    	AppBATCfg.BatVolt /= DataCount;
      //  AppBATCfg.state = STATE_IDLE;
        *pDataCount = 0;  /* Report no result to upper application */
      }
      return AD5940ERR_OK;
    }
    
    /**
    */
    AD5940Err AppBATISR(void *pBuff, uint32_t *pCount)
    {
      uint32_t FifoCnt;
      if(AppBATCfg.BATInited == bFALSE)
        return AD5940ERR_APPERROR;
      if(AD5940_WakeUp(10) > 10)  /* Wakeup AFE by read register, read 10 times at most */
        return AD5940ERR_WAKEUP;  /* Wakeup Failed */
      AD5940_SleepKeyCtrlS(SLPKEY_LOCK);  /* Don't enter hibernate */
      *pCount = 0;
      
      if(AD5940_INTCTestFlag(AFEINTC_1, AFEINTSRC_DFTRDY) == bTRUE)
      {
        FifoCnt = AD5940_FIFOGetCnt();
        AD5940_FIFORd((uint32_t *)pBuff, FifoCnt);
        AD5940_INTCClrFlag(AFEINTSRC_DFTRDY);
        AppBATRegModify(pBuff, &FifoCnt);   /* If there is need to do AFE re-configure, do it here when AFE is in active state */
        //AD5940_EnterSleepS();  /* Manually put AFE back to hibernate mode. */
        AD5940_SleepKeyCtrlS(SLPKEY_UNLOCK);  /* Allow AFE to enter hibernate mode */
        /* Process data */ 
        AppBATDataProcess((int32_t*)pBuff,&FifoCnt); 
        *pCount = FifoCnt;
        return 0;
      }
      
      return 0;
    }
    
    
    /**
    * @}
    */
    

    /*!
    *****************************************************************************
    @file:    BATImpedance.h
    @author: MLambe
    @brief:   BATImpedance.c header file.
    -----------------------------------------------------------------------------
    Copyright (c) 2017-2019 Analog Devices, Inc. All Rights Reserved.
    This software is proprietary to Analog Devices, Inc. and its licensors.
    By using this software you agree to the terms of the associated
    Analog Devices Software License Agreement.
    
    *****************************************************************************/
    
    #ifndef _BAT_IMPEDANCE_H_
    #define _BAT_IMPEDANCE_H_
    #include "ad5940.h"
    #include "stdio.h"
    #include "string.h"
    #include "math.h"
    
    #define PRECHARGE_WAIT_MS   400    //precharge time in ms.
    
    #define PRECHARGE_CH1       1
    #define PRECHARGE_CH2       2
    #define PRECHARGE_CH3       3
    
    #define PRECHARGE_RCAL      PRECHARGE_CH1
    #define PRECHARGE_BAT       PRECHARGE_CH2
    #define PRECHARGE_AMP       PRECHARGE_CH3
    
    #define DAC12BITVOLT_1LSB   (2200.0f/4095)  //mV
    #define DAC6BITVOLT_1LSB    (DAC12BITVOLT_1LSB*64)  //mV
    
    
    #define STATE_IDLE        			0   /**< Initial state. */
    #define STATE_BATTERY     	1   /**< Measure battery response voltage. */
    #define STATE_MEASVOLT		2	 /**< Measure battery Voltage. */
    #define STATE_RCAL	3
    
    #define V_DIVIDER_R1	1e6
    #define V_DIVIDER_R2	750e3
    
    typedef struct
    {
    /* Common configurations for all kinds of Application. */
      BoolFlag bParaChanged;        /* Indicate to generate sequence again. It's auto cleared by AppBATInit */
      uint32_t SeqStartAddr;        /* Initialaztion sequence start address in SRAM of AD5940  */
      uint32_t MaxSeqLen;           /* Limit the maximum sequence.   */
      uint32_t SeqStartAddrCal;     /* Measurement sequence start address in SRAM of AD5940 */
      uint32_t MaxSeqLenCal;
    	uint32_t SampleRate;
    /* Application related parameters */ 
    	uint32_t state;               /* 0: Init, 1: measure Rcal, 2: Measure Battery. */
      float SysClkFreq;             /* The real frequency of system clock */
      float WuptClkFreq;            /* The clock frequency of Wakeup Timer in Hz. Typically it's 32kHz. Leave it here in case we calibrate clock in software method */
      float AdcClkFreq;             /* The real frequency of ADC clock */
      uint32_t FifoThresh;           /* FIFO threshold. Should be N*4 */   
      int32_t NumOfData;            /* By default it's '-1'. If you want the engine stops after get NumofData, then set the value here. Otherwise, set it to '-1' which means never stop. */
      uint32_t PwrMod;              /* Control Chip power mode(LP/HP) */
      float ACVoltPP;               /* Final AC excitation voltage on pin AIN1 in mV peak to peak unit. */
      float DCVolt;                 /* The DC bias voltage on AIN1 pin. Unit is mV. */
      float RcalVal;                /* Rcal value in mOhm */
      float SinFreq;                /* Frequency of excitation signal */
      uint8_t ADCSinc3Osr;          /* SINC3 OSR selection. ADCSINC3OSR_2, ADCSINC3OSR_4 */
      uint8_t ADCSinc2Osr;          /* SINC2 OSR selection. ADCSINC2OSR_22...ADCSINC2OSR_1333 */
      uint32_t DftNum;              /* DFT number */
      uint32_t DftSrc;              /* DFT Source */
      BoolFlag HanWinEn;            /* Enable Hanning window */
    float BatVolt;
    /* Private variables for internal usage */
      float FreqofData;  
      BoolFlag BATInited;           /* If the program run firstly, generated sequence commands */
      SEQInfo_Type InitSeqInfo;
      SEQInfo_Type ImpedanceSeqInfo;
    	SEQInfo_Type VoltMeasureSeqInfo;
    	
    	
      BoolFlag StopRequired;        /* After FIFO is ready, stop the measurement sequence */
      uint32_t FifoDataCount;       /* Count how many times impedance have been measured */
    /* End */
    }AppBATCfg_Type;
    
    #define BATCTRL_MEASIMP          0
    #define BATCTRL_SHUTDOWN  1   /* Note: shutdown here means turn off everything and put AFE to hibernate mode. The word 'SHUT DOWN' is only used here. */
    #define BATCTRL_GETFREQ			2
    #define BATCTRL_MEASVOLT   3
    #define BATCTRL_MEASRCAL	4
    
    AD5940Err AppBATGetCfg(void *pCfg);
    AD5940Err AppBATInit(uint32_t *pBuffer, uint32_t BufferSize);
    AD5940Err AppBATISR(void *pBuff, uint32_t *pCount);
    AD5940Err AppBATCtrl(int32_t BatCtrl, void *pPara);
    void AppBATConnect(BoolFlag bConnect);
    
    
    #endif
    

    /*!
     *****************************************************************************
     @file:    UARTCmd.c
     @author:  $Author: nxu2 $
     @brief:   UART Command process
     @version: $Revision: 766 $
     @date:    $Date: 2017-08-21 14:09:35 +0100 (Mon, 21 Aug 2017) $
     -----------------------------------------------------------------------------
    
    Copyright (c) 2017-2019 Analog Devices, Inc. All Rights Reserved.
    
    This software is proprietary to Analog Devices, Inc. and its licensors.
    By using this software you agree to the terms of the associated
    Analog Devices Software License Agreement.
     
    *****************************************************************************/
    #include "stdint.h"
    #include "string.h"
    #include "stdio.h"
    #include <stdlib.h>
    
    #define LINEBUFF_SIZE 128
    #define CMDTABLE_SIZE 13
    
    uint32_t help(uint32_t para1, uint32_t para2);
    uint32_t say_hello(uint32_t para1, uint32_t para2);
    uint32_t batz_start(float para1, float para2);
    uint32_t batz_rst(uint32_t para1, uint32_t para2);
    uint32_t batz_set_rcal(float para1);
    uint32_t batz_set_dcvolt(float para1);
    uint32_t batz_set_acamplitude(float para1);
    uint32_t batz_connect(float para1);
    uint32_t batz_get_volt(uint32_t para1);
    uint32_t batz_disconnect(float para1);
    uint32_t batz_set_sinc_filter(float para1, float para2);
    uint32_t batz_set_dft(float para1, float para2);
    uint32_t batz_set_adc_sample_rate(float para1, float para2);
    
    struct __uartcmd_table
    {
      void *pObj;
      const char *cmd_name;
      const char *pDesc;
    }uart_cmd_table[CMDTABLE_SIZE]=
    {
      {(void*)help, "help", "print supported commands"},
      {(void*)help, "?", "print supported commands"},
      {(void*)batz_start, "batz_start", "Do 1 EIS measurement.  \"batz_start 10\" 10Hz "},
      {(void*)batz_rst, "batz_reset", "Reset hardware"},
    	{(void*)batz_set_rcal, "batz_set_rcal", "Set RFCAL value "},
    	{(void*)batz_set_dcvolt, "batz_set_dcvolt", "Set the common mode voltage "},
    	{(void*)batz_set_acamplitude, "batz_set_acamplitude", "Set amplitude of ac signal "},
    	{(void*)batz_disconnect, "batz_disconnect", "Disconnect battery from AD5941"},
    	{(void*)batz_connect, "batz_connect", "Connect battery to AD5941 signal"},
    	{(void*)batz_get_volt, "batz_get_volt", "Measure Battery Voltage"},
    	{(void*)batz_set_sinc_filter, "batz_set_sinc_filter", "Set Sinc filters OSR. Para1 = Sinc3 OSR, Para2 = Sinc3 OSR"},
    	{(void*)batz_set_dft, "batz_set_dft", "Set dft config. Para1 = DFT Number OSR, Para2 = DFT Source 0 for SINC£ 1 for SINC2 "},
    	{(void*)batz_set_adc_sample_rate, "batz_set_adc_sample_rate", "Set ADC Sample Rate."},
    };
    
    
    uint32_t help(uint32_t para1, uint32_t para2)
    {
      int i = 0;
      printf("\n*****help menu*****\nThe following are the supported commands:\n\n");
      for(;i<CMDTABLE_SIZE;i++)
      {
        if(uart_cmd_table[i].pObj)
          printf("%-8s --\t\t%s\n", uart_cmd_table[i].cmd_name, uart_cmd_table[i].pDesc);
      }
      printf("\n***table end***\n");
      return 0x87654321;
    }
    
    
    char line_buffer[LINEBUFF_SIZE];
    uint32_t line_buffer_index = 0;
    uint32_t token_count = 0;
    void *pObjFound = 0;
    float parameter1, parameter2;
    
    void UARTCmd_RemoveSpaces(void)
    {
      int i = 0;
      token_count = 0;
      char flag_found_token = 0;
      while(i<line_buffer_index)
      {
        if(line_buffer[i] == ' ') line_buffer[i] = '\0';
        else break;
        i++;
      }
      if(i == line_buffer_index) return;  /* All spaces... */
      while(i<line_buffer_index)
      {
        if(line_buffer[i] == ' ')
        {
          line_buffer[i] = '\0';
          flag_found_token = 0;
        }
        else
        { 
          if(flag_found_token == 0)
            token_count ++;
          flag_found_token = 1;
        }
        i++;
      }
    }
    
    void UARTCmd_MatchCommand(void)
    {
      char *pcmd;
      int i = 0;
      pObjFound = 0;
      while(i<line_buffer_index)
      {
        if(line_buffer[i] != '\0')
        {
          pcmd = &line_buffer[i];
          break;
        }
        i++;
      }
      for(i=0;i<CMDTABLE_SIZE;i++)
      {
        if(strcmp(uart_cmd_table[i].cmd_name, pcmd) == 0)
        {
          /* Found you! */
          pObjFound = uart_cmd_table[i].pObj;
          break;
        }
      }
    }
    
    /* Translate string 'p' to number, store results in 'Res', return error code */
    static uint32_t Str2Float(char *s, float *Res)
    {
      char *p;
       
      *Res = strtof( s, &p);
    
      return 0;
    }
    
    void UARTCmd_TranslateParas(void)
    {
      char *p = line_buffer;
      parameter1 = 0;
      parameter2 = 0;
      while(*p == '\0') p++;    /* goto command */
      while(*p != '\0') p++;    /* skip command. */
      while(*p == '\0') p++;    /* goto first parameter */
      if(Str2Float(p, &parameter1) != 0) return;
      if(token_count == 2) return;           /* Only one parameter */
      while(*p != '\0') p++;    /* skip first command. */
      while(*p == '\0') p++;    /* goto second parameter */
      Str2Float(p, &parameter2);
    }
    
    void UARTCmd_Process(char c)
    {
      if(line_buffer_index >= LINEBUFF_SIZE-1)
        line_buffer_index = 0;  /* Error: buffer overflow */
      if( (c == '\r') || (c == '\n'))
      {
        line_buffer[line_buffer_index] = '\0';
        /* Start to process command */
        if(line_buffer_index == 0) 
        {
          line_buffer_index = 0; /* Reset buffer */
          return;  /* No command inputs, return */
        }
        /* Step1, remove space */
        UARTCmd_RemoveSpaces();
        if(token_count == 0)
        {
          line_buffer_index = 0; /* Reset buffer */
          return; /* No valid input */
        }
        /* Step2, match commands */
        UARTCmd_MatchCommand();
        if(pObjFound == 0)
        {
          line_buffer_index = 0; /* Reset buffer */
          return;   /* Command not support */
        }
        if(token_count > 1)           /* There is parameters */
        {
          UARTCmd_TranslateParas();
        }
       // printf("FOund you!! %d , %d \n", parameter1, parameter2);
        /* Step3, call function */
        ((uint32_t (*)(float, float))(pObjFound))(parameter1, parameter2);
        line_buffer_index = 0;  /* Reset buffer */
      }
      else
      {
        line_buffer[line_buffer_index++] = c;
      }
    }
    

Reply
  • Below is a modified code for very low frequency battery EIS measurement:

    /*!
    *****************************************************************************
    @file:    AD5940Main.c
    @author:  M.Lambe
    @brief:   Used to control specific application and process data.
    -----------------------------------------------------------------------------
    Copyright (c) 2017-2019 Analog Devices, Inc. All Rights Reserved.
    This software is proprietary to Analog Devices, Inc. and its licensors.
    By using this software you agree to the terms of the associated
    Analog Devices Software License Agreement.
    
    *****************************************************************************/
    
    #include "ad5940.h"
    #include <stdio.h>
    #include "string.h"
    #include "math.h"
    #include "BATImpedance.h"
    
    #include "ADuCM3029.h"
    #define APPBUFF_SIZE 512
    uint32_t AppBuff[APPBUFF_SIZE];
    
    
    /* It's your choice here how to do with the data. Here is just an example to print them to UART */
    int32_t BATShowResult(uint32_t *pData, uint32_t DataCount)
    {
    	AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
    	if(pBATCfg->state == STATE_BATTERY)
    	{
    		fImpCar_Type *pImp = (fImpCar_Type*)pData;
    		float freq;
    		AppBATCtrl(BATCTRL_GETFREQ, &freq);
    		/*Process data*/
    		for(int i=0;i<DataCount;i++)
    		{
    			printf("Result, %f , %f , %f \n",freq, pImp[i].Real,pImp[i].Image);
    		}
    		}
    	else if(pBATCfg->state == STATE_MEASVOLT)
    	{
    		printf("Result, %f \n", pBATCfg->BatVolt );
    	}
    	
    	pBATCfg->state = STATE_IDLE;
      return 0;
    }
    float LFOSCFreq;    /* Measured LFOSC frequency */
    /* Initialize AD5940 basic blocks like clock */
    static int32_t AD5940PlatformCfg(void)
    {
      CLKCfg_Type clk_cfg;
      FIFOCfg_Type fifo_cfg;
      AGPIOCfg_Type gpio_cfg;
    	LFOSCMeasure_Type LfoscMeasure;
      /* Use hardware reset */
      AD5940_HWReset();
      /* Platform configuration */
      AD5940_Initialize();
      /* Step1. Configure clock */
      clk_cfg.ADCClkDiv = ADCCLKDIV_1;
      clk_cfg.ADCCLkSrc = ADCCLKSRC_XTAL;
      clk_cfg.SysClkDiv = SYSCLKDIV_1;
      clk_cfg.SysClkSrc = SYSCLKSRC_XTAL; //on battery board, there is a 32MHz crystal.
      clk_cfg.HfOSC32MHzMode = bFALSE;
      clk_cfg.HFOSCEn = bFALSE;
      clk_cfg.HFXTALEn = bTRUE;
      clk_cfg.LFOSCEn = bTRUE;
      AD5940_CLKCfg(&clk_cfg);
      /* Step2. Configure FIFO and Sequencer*/
      fifo_cfg.FIFOEn = bFALSE;
      fifo_cfg.FIFOMode = FIFOMODE_FIFO;
      fifo_cfg.FIFOSize = FIFOSIZE_4KB;                       /* 4kB for FIFO, The reset 2kB for sequencer */
      fifo_cfg.FIFOSrc = FIFOSRC_DFT;
      fifo_cfg.FIFOThresh = 4;       /* DFT result. One pair for RCAL, another for Rz. One DFT result have real part and imaginary part */
      AD5940_FIFOCfg(&fifo_cfg);                             /* Disable to reset FIFO. */
      fifo_cfg.FIFOEn = bTRUE;  
      AD5940_FIFOCfg(&fifo_cfg);                             /* Enable FIFO here */
      
      /* Step3. Interrupt controller */
      AD5940_INTCCfg(AFEINTC_1, AFEINTSRC_ALLINT, bTRUE);           /* Enable all interrupt in Interrupt Controller 1, so we can check INTC flags */
      AD5940_INTCCfg(AFEINTC_0, AFEINTSRC_DFTRDY, bTRUE);   /* Interrupt Controller 0 will control GP0 to generate interrupt to MCU */
      AD5940_INTCClrFlag(AFEINTSRC_ALLINT);
      /* Step4: Reconfigure GPIO */
      gpio_cfg.FuncSet = GP0_INT|GP2_SYNC|GP1_TRIG;
      gpio_cfg.InputEnSet = 0;
      gpio_cfg.OutputEnSet = AGPIO_Pin0|AGPIO_Pin2|AGPIO_Pin1;
      gpio_cfg.OutVal = 0;
      gpio_cfg.PullEnSet = 0;
      AD5940_AGPIOCfg(&gpio_cfg);
    	
    	SeqGpioTrig_Cfg seq_gpio_cfg;
    	seq_gpio_cfg.bEnable = bTRUE;
    	seq_gpio_cfg.PinSel = AGPIO_Pin1;
    	seq_gpio_cfg.SeqPinTrigMode = SEQPINTRIGMODE_FALLING;
    	AD5940_SEQGpioTrigCfg(&seq_gpio_cfg);
    	
    	/* Measure LFOSC frequency */
      LfoscMeasure.CalDuration = 1000.0;  /* 1000ms used for calibration. */
      LfoscMeasure.CalSeqAddr = 0;
      LfoscMeasure.SystemClkFreq = 16000000.0f; /* 16MHz in this firmware. */
      AD5940_LFOSCMeasure(&LfoscMeasure, &LFOSCFreq);
      printf("Freq:%f\n", LFOSCFreq);
    
      return 0;
    }
    
    void AD5940BATStructInit(void)
    {
      AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
      pBATCfg->SeqStartAddr = 0;
      pBATCfg->MaxSeqLen = 512;
    	pBATCfg->WuptClkFreq = LFOSCFreq;    /* Measured LFOSC frequency */
    	
    	/* Excitation Parameters */
      pBATCfg->RcalVal = 50.0;  							/* Value of RCAL on EVAL-AD5941BATZ board is 50mOhm */
      pBATCfg->ACVoltPP = 200.0f;							/* Pk-pk amplitude is 600mV */
      pBATCfg->DCVolt = 1200.0f;							/* Offset voltage of 1.2V*/
      
    	/* Sampliong parameters */
    	pBATCfg->SampleRate = 10;
    	pBATCfg->DftNum = DFTNUM_256;
    	pBATCfg->ADCSinc2Osr = ADCSINC2OSR_22;
    	pBATCfg->ADCSinc3Osr = ADCSINC3OSR_4;
    	pBATCfg->DftSrc = DFTSRC_SINC3;
    	
    	pBATCfg->FifoThresh = 4;      					/* 2 results in FIFO, real and imaginary part. */  
      pBATCfg->SinFreq = 0.5;									/* Sin wave frequency. THis value has no effect if sweep is enabled */
       
    }
    void do_measurement(void);
    uint8_t bStartMeasurement = 0;
    uint8_t bStartVoltageMeasurement = 0;
    
    void AD5940_StopTrigTimer(void);
    
    void AD5940_Main(void)
    { 
    	uint32_t temp = 0;
      uint32_t help(uint32_t para1, uint32_t para2);
      AD5940_Delay10us(10000);
    
      AD5940PlatformCfg();
    
      help(0,0);
      AD5940BATStructInit(); /* Configure your parameters in this function */
      AppBATInit(AppBuff, APPBUFF_SIZE);    /* Initialize BAT application. Provide a buffer, which is used to store sequencer commands */
    	
    	while(1)
    	{
    		if(bStartMeasurement == 1)
    		{
    			bStartMeasurement = 0;
    			do_measurement();
    		}
    		if(bStartVoltageMeasurement)
    		{
    				bStartVoltageMeasurement = 0;
    				while(AD5940_GetMCUIntFlag() == bFALSE);
    				AD5940_ClrMCUIntFlag(); 				/* Clear this flag */
    				temp = APPBUFF_SIZE;
    				AppBATISR(AppBuff, &temp); 			/* Deal with it and provide a buffer to store data we got */  
    				BATShowResult(AppBuff, temp);		/* Print measurement results over UART */	
    		}
    	}		
    }
    
    /* Depending on frequency of Sin wave set optimum filter settings */
    AD5940Err AppBATCheckFreq(void)
    {
      DFTCfg_Type dfp_cfg;
    	ADCFilterCfg_Type adc_cfg;
      uint32_t WaitClks;
      ClksCalInfo_Type clks_cal;
    	AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
    	
      uint32_t SeqCmdBuff[2];
      uint32_t SRAMAddr = 0;
    
    
      adc_cfg.ADCAvgNum = ADCAVGNUM_16;  /* Don't care because it's disabled */
      adc_cfg.ADCRate = ADCRATE_800KHZ;
      adc_cfg.ADCSinc2Osr = pBATCfg->ADCSinc2Osr;
      adc_cfg.ADCSinc3Osr = pBATCfg->ADCSinc3Osr;
      adc_cfg.BpSinc3 = bFALSE;
      adc_cfg.BpNotch = bTRUE;
      adc_cfg.Sinc2NotchEnable = bTRUE;
    	AD5940_ADCFilterCfgS(&adc_cfg);
    	
      dfp_cfg.DftNum = pBATCfg->DftNum;
      dfp_cfg.DftSrc = pBATCfg->DftSrc;
      dfp_cfg.HanWinEn = pBATCfg->HanWinEn;
    	AD5940_DFTCfgS(&dfp_cfg);
      
      /* Step 3: Calculate clocks needed to get result to FIFO and update sequencer wait command */
    	if(pBATCfg->DftSrc == DFTSRC_SINC3)
    		clks_cal.DataType = DATATYPE_SINC3;
    	else
    		clks_cal.DataType = DATATYPE_SINC2;
      clks_cal.DataCount = 1; /* 2^(DFTNUMBER+2) */
      clks_cal.ADCSinc2Osr = pBATCfg->ADCSinc2Osr;
      clks_cal.ADCSinc3Osr = pBATCfg->ADCSinc3Osr;
      clks_cal.ADCAvgNum = ADCAVGNUM_16;
      clks_cal.RatioSys2AdcClk = pBATCfg->SysClkFreq/pBATCfg->AdcClkFreq;
      clks_cal.ADCRate = ADCRATE_800KHZ;
      clks_cal.BpNotch = bFALSE;
      AD5940_ClksCalculate(&clks_cal, &WaitClks);	
      
    
      /* Find start address of sequence in SRAM 
      Update WaitClks */
      SRAMAddr = pBATCfg->ImpedanceSeqInfo.SeqRamAddr;
      SeqCmdBuff[0] = SEQ_WAIT(WaitClks);
      AD5940_SEQCmdWrite(SRAMAddr+4, SeqCmdBuff, 1);
      
      return AD5940ERR_OK;
    }
    
    void do_measurement(void)
    {
    	uint32_t temp;
    	//Step One measure RCAL
    	AD5940_Delay10us(100000);
    	AppBATCheckFreq();
    	AppBATCtrl(BATCTRL_MEASRCAL, 0);
    	while(AD5940_GetMCUIntFlag() == bFALSE);
    	//while(AD5940_INTCTestFlag(AFEINTC_1, AFEINTSRC_DFTRDY) == bFALSE);
    	// Stop TImer
    	AD5940_StopTrigTimer();
    //	AD5940_WUPTCtrl(bFALSE);
    //	AD5940_WUPTCtrl(bFALSE);
    	AD5940_AFECtrlS(AFECTRL_DFT, bFALSE);
    	AD5940_ClrMCUIntFlag(); 				/* Clear this flag */
    	AD5940_INTCClrFlag(AFEINTSRC_DFTRDY);
      
    	//Step2: Measure Battery
      AppBATCtrl(BATCTRL_MEASIMP, 0);
    	while(AD5940_GetMCUIntFlag() == 0);
    	AD5940_StopTrigTimer();
    //	AD5940_WUPTCtrl(bFALSE);
    //	AD5940_WUPTCtrl(bFALSE);
    	AD5940_AFECtrlS(AFECTRL_DFT, bFALSE);
    	AD5940_ClrMCUIntFlag(); 				/* Clear this flag */
    	temp = APPBUFF_SIZE;
    	AppBATISR(AppBuff, &temp); 			/* Deal with it and provide a buffer to store data we got */  
    	BATShowResult(AppBuff, temp);		/* Print measurement results over UART */	
    }
    
    
    uint32_t batz_rst(uint32_t *para1)
    {
    	AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
      pBATCfg->BATInited = bFALSE;
      AD5940PlatformCfg();  
      AppBATInit(AppBuff, APPBUFF_SIZE);    /* Initialize BAT application. Provide a buffer, which is used to store sequencer commands */
    	bStartMeasurement = 0;
    	bStartVoltageMeasurement = 0;
      #ifdef ADI_DEBUG
      printf("DEBUG: Board Reset\n");
    	#endif
      return 0;
    }
    
    uint32_t batz_start(float para1, float para2)
    {
      if(para1<0.015)
      {
        para1 = 0.015;
        
      }
      if(para2<10)
      {
        para2 = 10;
      }
      printf("START\n");
      AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
      pBATCfg->SinFreq = para1;
    	#ifdef ADI_DEBUG
      printf("DEBUG: Start Command Received\n");
    	#endif
      AppBATConnect(bTRUE);
      AD5940_WGFreqCtrlS(para1, 16e6);
    	#ifdef ADI_DEBUG
      printf("DEBUG: Waveform Generator Updated\n");
    	#endif
    	bStartMeasurement = 1;
      return 0;
    }
    
    uint32_t batz_get_volt(float para1)
    {
    //	bStartVoltageMeasurement = 1;
    //  AppBATCtrl(BATCTRL_MEASVOLT, 0);
      return 0;
    }
    
    uint32_t batz_set_rcal(float para1)
    {
      AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
      pBATCfg->RcalVal = para1;
    	#ifdef ADI_DEBUG
      printf("DEBUG: Rcal set to %f \n", para1);
    	#endif
      return 0;
    }
    
    uint32_t batz_disconnect(float para1)
    {
      AppBATConnect(bFALSE);
      return 0;
    }
    
    uint32_t batz_connect(float para1)
    {
      AppBATConnect(bTRUE);
    	AD5940_AFECtrlS(AFECTRL_WG, bTRUE);
      return 0;
    }
    
    uint32_t batz_set_dcvolt(float para1)
    {
      LPDACCfg_Type lpdac_cfg;
      /* Check Parameter */
      if(para1 >2000)
      {
        para1=2000;
    		#ifdef ADI_DEBUG
        printf("DEBUG: Invalid Voltage. DC Volt set to 2V\n");
    		#endif
      }
      if(para1<300)
      {
        para1=300;
    #ifdef ADI_DEBUG		
        printf("DEBUG: Invalid Voltage. DC VOlt set to 0.3V\n");
    		#endif
      }
      lpdac_cfg.DacData12Bit = (uint32_t)((para1-200)/DAC12BITVOLT_1LSB);
      lpdac_cfg.DacData6Bit = 31;  //not used. Set it to middle value.
      AD5940_LPDAC0WriteS(lpdac_cfg.DacData12Bit, lpdac_cfg.DacData6Bit);
    	#ifdef ADI_DEBUG
      printf("DEBUG: DC voltage updated \n");
    	#endif
      return 0;
    }
    
    uint32_t batz_set_acamplitude(float para1)
    {
    	
    	HSDACCfg_Type hsdac_cfg;
    	float gain_factor = 0;
    	float voltage = 0;
      /* Check Parameter */
      if(para1 >400) 
      {
        para1=400;
    		#ifdef ADI_DEBUG
        printf("DEBUG: Invalid Voltage. Amplitude set to 400mV\n");
    		#endif
      }
      if(para1<0)
      {
        para1=30;
    		#ifdef ADI_DEBUG
        printf("DEBUG: Invalid Voltage. Amplitude set to 30mV\n");
    		#endif
      }
    	/* Select Attenuator and gain settings based on selected ac amplitude */
    	if(para1 <15.14) 
    	{
    		hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_0P25;
    		hsdac_cfg.HsDacGain = HSDACGAIN_0P2;
    		gain_factor = 0.05;
    	}else if(para1 <75) 
    	{
    		hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_0P25;
    		hsdac_cfg.HsDacGain = HSDACGAIN_1;
    		gain_factor = 0.25;
    	}else if(para1 < 121.2) 
    	{
    		hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_2;
    		hsdac_cfg.HsDacGain = HSDACGAIN_0P2;
    		gain_factor = 0.4;
    	}else 
    	{
    		hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_2;
    		hsdac_cfg.HsDacGain = HSDACGAIN_1;
    		gain_factor = 2;
    	}
    	hsdac_cfg.HsDacUpdateRate = 0x1B;
    	AD5940_HSDacCfgS(&hsdac_cfg);
    	
    	voltage = para1/gain_factor;
      uint32_t SinAmplitudeWord = 0;
      AD5940_AFECtrlS(AFECTRL_WG, bFALSE);
      SinAmplitudeWord = (uint32_t)((voltage)/808.15f*2047 + 0.5f);
      AD5940_WriteReg(REG_AFE_WGAMPLITUDE, SinAmplitudeWord);
    	AD5940_AFECtrlS(AFECTRL_WG, bTRUE);
    	#ifdef ADI_DEBUG
      printf("DEBUG: Sin amplitude updated \n");
    	#endif
    
      return 0;
    }
    
    uint32_t batz_set_adc_sample_rate(float para1, float para2)
    {
    	AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
      pBATCfg->SampleRate = para1;
    	#ifdef ADI_DEBUG
      printf("DEBUG: ADC Sample Rate set to %f\n", para1);
    	#endif
    }
    
    //void UpdateSequence(
    uint32_t batz_set_sinc_filter(float para1, float para2)
    {
    	const uint32_t sinc2osr_table[] = {1, 22,44,89,178,267,533,640,667,800,889,1067,1333};
      const uint32_t sinc3osr_table[] = {2, 4, 5};
    	AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
    	// Check Parameter and find it's index in the table
    	for(uint32_t i = 0; i<sizeof(sinc3osr_table) / sizeof(uint32_t); i++)
    	{
    		if(para2 == sinc3osr_table[i])
    		{
    			pBATCfg->ADCSinc3Osr = i;
    		}
    	}
    	
    	if(para2 > 0)
    	{
    		for(uint32_t i = 0; i<sizeof(sinc2osr_table) / sizeof(uint32_t); i++)
    		{
    			if(para2 == sinc2osr_table[i])
    			{
    				pBATCfg->ADCSinc2Osr = i;
    			}
    		}
    	}
    	#ifdef ADI_DEBUG
      printf("DEBUG: ADC Filters Updated\n");
    	#endif
    	
    }
    
    
    uint32_t batz_set_dft(float para1, float para2)
    {	
    	const uint32_t dft_table[] = {4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384};
      AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
    	
    	// Check Parameter and find it's index in the table
    	for(uint32_t i = 0; i<sizeof(dft_table) / sizeof(uint32_t); i++)
    	{
    		if(para2 == dft_table[i])
    		{
    			pBATCfg->DftNum = i;
    		}
    	}
    	if(para2 == 0)
    		pBATCfg->DftSrc = DFTSRC_SINC3;
    	else
    		pBATCfg->DftSrc = DFTSRC_SINC2NOTCH;	
    	#ifdef ADI_DEBUG
      printf("DEBUG: DFT Num set to %f\n", para1);
    	#endif
    }
    
    
    
     

    /*!
    *****************************************************************************
    @file:    BATImpedance.c
    @author: MLambe
    @brief:   Battery impedance measurement sequences.
    -----------------------------------------------------------------------------
    Copyright (c) 2017-2019 Analog Devices, Inc. All Rights Reserved.
    This software is proprietary to Analog Devices, Inc. and its licensors.
    By using this software you agree to the terms of the associated
    Analog Devices Software License Agreement.
    
    *****************************************************************************/
    #include "BATImpedance.h"
    
    /* 
    Application configuration structure. Specified by user from template.
    The variables are usable in this whole application.
    It includes basic configuration for sequencer generator and application related parameters
    */
    AppBATCfg_Type AppBATCfg = 
    {
      .bParaChanged = bFALSE,
      .SeqStartAddr = 0,
      .MaxSeqLen = 0,
      
      .SeqStartAddrCal = 0,
      .MaxSeqLenCal = 0,
      
      .SysClkFreq = 16000000.0,
      .WuptClkFreq = 32000.0,
      .AdcClkFreq = 16000000.0,
      .NumOfData = -1,
      
      .PwrMod = AFEPWR_LP,
      .ACVoltPP = 800.0,
      .DCVolt = 1100.0f,
      .SinFreq = 50000.0, /* 50kHz */
      .RcalVal = 50.0, /* 50mOhm */
      
      .ADCSinc3Osr = ADCSINC3OSR_4,
      .ADCSinc2Osr = ADCSINC2OSR_22,
      
      .DftNum = DFTNUM_16384,
      .DftSrc = DFTSRC_SINC3,
      .HanWinEn = bTRUE,
      
      .FifoThresh = 4,
      .BATInited = bFALSE,
      .StopRequired = bFALSE,
     
    };
    
    /**
    This function is provided for upper controllers that want to change 
    application parameters specially for user defined parameters.
    */
    AD5940Err AppBATGetCfg(void *pCfg)
    {
      if(pCfg){
        *(AppBATCfg_Type**)pCfg = &AppBATCfg;
        return AD5940ERR_OK;
      }
      return AD5940ERR_PARA;
    }
    
    /* This function uses an external switch to bypass the 2Mohm resistors on teh high pass fileter
    on the input to the measurement channel to increase settle time */
    static void PreCharge(unsigned char channel) 
    {
      void Arduino_WriteDn(uint32_t Dn, BoolFlag bHigh);
      switch(channel)
      {
      case PRECHARGE_CH1: //00
        Arduino_WriteDn(1<<3, bFALSE);  //d3
        Arduino_WriteDn(1<<4, bFALSE);  //d4
        break;
      case PRECHARGE_CH2: //01
        Arduino_WriteDn(1<<3, bTRUE);
        Arduino_WriteDn(1<<4, bFALSE);
        break;
      case PRECHARGE_CH3://10
        Arduino_WriteDn(1<<3, bFALSE);
        Arduino_WriteDn(1<<4, bTRUE);
        break;
      default:
        break;
      }
      AD5940_Delay10us(PRECHARGE_WAIT_MS*100);
      Arduino_WriteDn(1<<3, bTRUE);  //d3
      Arduino_WriteDn(1<<4, bTRUE);  //d4
    }
    
    void AD5940_StartTrigTimer(float freq);
    AD5940Err AppBATCtrl(int32_t BatCtrl, void *pPara)
    {
      switch (BatCtrl)
      {
      case BATCTRL_MEASIMP:
        {
    			WUPTCfg_Type wupt_cfg;
          if(AD5940_WakeUp(10) > 10)  /* Wakeup AFE by read register, read 10 times at most */
            return AD5940ERR_WAKEUP;  /* Wakeup Failed */
          if(AppBATCfg.BATInited == bFALSE)
            return AD5940ERR_APPERROR;
    			
    			AD5940_WriteReg(REG_AFE_SYNCEXTDEVICE, 0x0);
          PreCharge(PRECHARGE_BAT);
          PreCharge(PRECHARGE_AMP);
          PreCharge(PRECHARGE_RCAL);
    //      AD5940_FIFOCtrlS(FIFOSRC_DFT, bFALSE);
    //      AD5940_FIFOThrshSet(AppBATCfg.FifoThresh);  /* DFT result contains both real and image. */
    //      AD5940_FIFOCtrlS(FIFOSRC_DFT, bTRUE);
    			
    			AppBATCfg.state = STATE_BATTERY;
    			
          AD5940_AFECtrlS(AFECTRL_DFT, bTRUE);
    			/* Start it */
    //      wupt_cfg.WuptEn = bTRUE;
    //      wupt_cfg.WuptEndSeq = WUPTENDSEQ_A;
    //      wupt_cfg.WuptOrder[0] = SEQID_0;
    //      wupt_cfg.SeqxSleepTime[SEQID_0] = (uint32_t)(AppBATCfg.WuptClkFreq/AppBATCfg.SampleRate)-2-4;
    //      wupt_cfg.SeqxWakeupTime[SEQID_0] = 4; /* The minimum value is 1. Do not set it to zero. Set it to 1 will spend 2 32kHz clock. */
    //      AD5940_WUPTCfg(&wupt_cfg);
    			
          AD5940_StartTrigTimer(AppBATCfg.SampleRate);
          break;
        }
    	case BATCTRL_MEASRCAL:
        {
    			WUPTCfg_Type wupt_cfg;
          if(AD5940_WakeUp(10) > 10)  /* Wakeup AFE by read register, read 10 times at most */
            return AD5940ERR_WAKEUP;  /* Wakeup Failed */
          if(AppBATCfg.BATInited == bFALSE)
            return AD5940ERR_APPERROR;
          PreCharge(PRECHARGE_BAT);
          PreCharge(PRECHARGE_AMP);
          PreCharge(PRECHARGE_RCAL);
          AD5940_FIFOCtrlS(FIFOSRC_DFT, bFALSE);
          AD5940_FIFOThrshSet(AppBATCfg.FifoThresh);  /* DFT result contains both real and image. */
          AD5940_FIFOCtrlS(FIFOSRC_DFT, bTRUE);
    			
    			AD5940_WriteReg(REG_AFE_SYNCEXTDEVICE, 0x4);
    			AppBATCfg.state = STATE_RCAL;
    			
          AD5940_AFECtrlS(AFECTRL_DFT, bTRUE);
    			/* Start it */
    //      wupt_cfg.WuptEn = bTRUE;
    //      wupt_cfg.WuptEndSeq = WUPTENDSEQ_A;
    //      wupt_cfg.WuptOrder[0] = SEQID_0;
    //      wupt_cfg.SeqxSleepTime[SEQID_0] = (uint32_t)(AppBATCfg.WuptClkFreq/AppBATCfg.SampleRate)-2-4;
    //      wupt_cfg.SeqxWakeupTime[SEQID_0] = 4; /* The minimum value is 1. Do not set it to zero. Set it to 1 will spend 2 32kHz clock. */
    //      AD5940_WUPTCfg(&wupt_cfg);
    		AD5940_StartTrigTimer(AppBATCfg.SampleRate);
          
          break;
        }
    	case BATCTRL_MEASVOLT:
    	{
    	 if(AD5940_WakeUp(10) > 10)  /* Wakeup AFE by read register, read 10 times at most */
            return AD5940ERR_WAKEUP;  /* Wakeup Failed */
          if(AppBATCfg.BATInited == bFALSE)
            return AD5940ERR_APPERROR;
    		AppBATCfg.state = STATE_MEASVOLT;
          /* Configure FIFO for temperature measurement */
          AD5940_FIFOCtrlS(FIFOSRC_DFT, bFALSE);
          AD5940_FIFOThrshSet(1);
          AD5940_FIFOCtrlS(FIFOSRC_SINC2NOTCH, bTRUE); //enable FIFO
          AD5940_INTCClrFlag(AFEINTSRC_ALLINT);
    			AD5940_SEQMmrTrig(AppBATCfg.VoltMeasureSeqInfo.SeqId);
    	break;
    	}
      case BATCTRL_GETFREQ:
        if(pPara)
        {
            *(float*)pPara = AppBATCfg.SinFreq;
        }
        break;
      case BATCTRL_SHUTDOWN:
        {
          /* Turn off LPloop related blocks which are not controlled automatically by sleep operation */
          AFERefCfg_Type aferef_cfg;
          LPLoopCfg_Type lp_loop;
          memset(&aferef_cfg, 0, sizeof(aferef_cfg));
          AD5940_REFCfgS(&aferef_cfg);
          memset(&lp_loop, 0, sizeof(lp_loop));
          AD5940_LPLoopCfgS(&lp_loop);
          AD5940_EnterSleepS();  /* Enter Hibernate */
        }
        break;
      default:
        break;
      }
      return AD5940ERR_OK;
    }
    
    void AppBATConnect(BoolFlag bConnect)
    {
      SWMatrixCfg_Type sw_cfg;
      if(bConnect)
      {
        sw_cfg.Dswitch = SWD_CE0;
        sw_cfg.Pswitch = SWP_AIN1;
        sw_cfg.Nswitch = SWN_AIN0;  //AIN0 is connected to AIN4 externally by JP3.
        sw_cfg.Tswitch = 0; //T switch is not used.
      }else{
        sw_cfg.Dswitch = SWD_OPEN;
        sw_cfg.Pswitch = SWP_OPEN;
        sw_cfg.Nswitch = SWN_OPEN;  //AIN0 is connected to AIN4 externally by JP3.
        sw_cfg.Tswitch = 0; //T switch is not used.
      }
      AD5940_SWMatrixCfgS(&sw_cfg);
    	#ifdef ADI_DEBUG
    	printf("DEBUG: Switch Matrick Configured \n"); 
    	#endif
    }
    /* Generate init sequence */
    static AD5940Err AppBATSeqCfgGen(void)
    {
      AD5940Err error = AD5940ERR_OK;
      uint32_t const *pSeqCmd;
      uint32_t SeqLen;
      AFERefCfg_Type aferef_cfg;
      HSLoopCfg_Type hs_loop;
      LPLoopCfg_Type lp_loop;
      DSPCfg_Type dsp_cfg;
      float sin_freq;
      
      /* Start sequence generator here */
      AD5940_SEQGenCtrl(bTRUE);
      
      AD5940_AFECtrlS(AFECTRL_ALL, bFALSE);  /* Disable all firstly. */
      aferef_cfg.HpBandgapEn = bTRUE;
      aferef_cfg.Hp1V1BuffEn = bTRUE;
      aferef_cfg.Hp1V8BuffEn = bTRUE;
      aferef_cfg.Disc1V1Cap = bFALSE;
      aferef_cfg.Disc1V8Cap = bFALSE;
      aferef_cfg.Hp1V8ThemBuff = bFALSE;
      aferef_cfg.Hp1V8Ilimit = bFALSE;
      aferef_cfg.Lp1V1BuffEn = bFALSE;
      aferef_cfg.Lp1V8BuffEn = bFALSE;
      /* LP reference control, Use LP loop to provide DC Bias voltage. */
      aferef_cfg.LpBandgapEn = bTRUE;
      aferef_cfg.LpRefBufEn = bTRUE;
      aferef_cfg.LpRefBoostEn = bFALSE;
      AD5940_REFCfgS(&aferef_cfg);
      /* Determine buffer gain according to ACVoltPP */
      hs_loop.HsDacCfg.ExcitBufGain = EXCITBUFGAIN_2;
      hs_loop.HsDacCfg.HsDacGain = HSDACGAIN_1;
      hs_loop.HsDacCfg.HsDacUpdateRate = 0x1B; //the maximum update rate is 16MHz/7
      
      hs_loop.HsTiaCfg.DiodeClose = bFALSE;
      hs_loop.HsTiaCfg.HstiaBias = HSTIABIAS_1P1;
      hs_loop.HsTiaCfg.HstiaCtia = 31;  //HSTIA is not used.
      hs_loop.HsTiaCfg.HstiaDeRload = HSTIADERLOAD_OPEN;
      hs_loop.HsTiaCfg.HstiaDeRtia = HSTIADERTIA_OPEN;
      hs_loop.HsTiaCfg.HstiaRtiaSel = HSTIARTIA_10K;
      
      hs_loop.SWMatCfg.Dswitch = SWD_CE0;
      hs_loop.SWMatCfg.Pswitch = SWP_AIN1;
      hs_loop.SWMatCfg.Nswitch = SWN_AIN0;  //AIN0 is connected to AIN4 externally by JP3.
      hs_loop.SWMatCfg.Tswitch = 0; //T switch is not used.
      
      hs_loop.WgCfg.WgType = WGTYPE_SIN;
      hs_loop.WgCfg.GainCalEn = bFALSE;
      hs_loop.WgCfg.OffsetCalEn = bFALSE;
       sin_freq = AppBATCfg.SinFreq;
        AppBATCfg.FreqofData = sin_freq;
      hs_loop.WgCfg.SinCfg.SinFreqWord = AD5940_WGFreqWordCal(sin_freq, AppBATCfg.SysClkFreq);
      hs_loop.WgCfg.SinCfg.SinAmplitudeWord = (uint32_t)(AppBATCfg.ACVoltPP/800.0f*2047 + 0.5f);
      hs_loop.WgCfg.SinCfg.SinOffsetWord = 0;
      hs_loop.WgCfg.SinCfg.SinPhaseWord = 0;
      AD5940_HSLoopCfgS(&hs_loop);
      //Use LP loop to output bias voltage on AIN4 pin, which provides voltage on AIN0(N switch).
      lp_loop.LpDacCfg.LpdacSel = LPDAC0;
      lp_loop.LpDacCfg.LpDacSrc = LPDACSRC_MMR;
      lp_loop.LpDacCfg.LpDacSW = LPDACSW_VZERO2LPTIA|LPDACSW_VZERO2PIN;
      lp_loop.LpDacCfg.LpDacVzeroMux = LPDACVZERO_12BIT;
      lp_loop.LpDacCfg.LpDacVbiasMux = LPDACVBIAS_6BIT;
      lp_loop.LpDacCfg.LpDacRef = LPDACREF_2P5;
      lp_loop.LpDacCfg.DataRst = bFALSE;
      lp_loop.LpDacCfg.PowerEn = bTRUE;
      lp_loop.LpDacCfg.DacData12Bit = (uint32_t)((AppBATCfg.DCVolt-200)/2200.0f*4095);
      lp_loop.LpDacCfg.DacData6Bit = 31;  //not used. Set it to middle value.
      
      lp_loop.LpAmpCfg.LpAmpSel = LPAMP0;
      lp_loop.LpAmpCfg.LpAmpPwrMod = LPAMPPWR_NORM;
      lp_loop.LpAmpCfg.LpPaPwrEn = bFALSE;
      lp_loop.LpAmpCfg.LpTiaPwrEn = bTRUE;
      lp_loop.LpAmpCfg.LpTiaRf = LPTIARF_20K; //External cap is 1uF.
      lp_loop.LpAmpCfg.LpTiaRload = LPTIARLOAD_SHORT;
      lp_loop.LpAmpCfg.LpTiaRtia = LPTIARTIA_OPEN;
      lp_loop.LpAmpCfg.LpTiaSW = LPTIASW(7)|LPTIASW(5)|LPTIASW(9);
      AD5940_LPLoopCfgS(&lp_loop);
      
      dsp_cfg.ADCBaseCfg.ADCMuxN = ADCMUXN_AIN2;
      dsp_cfg.ADCBaseCfg.ADCMuxP = ADCMUXP_AIN3;
      dsp_cfg.ADCBaseCfg.ADCPga = ADCPGA_2;
      memset(&dsp_cfg.ADCDigCompCfg, 0, sizeof(dsp_cfg.ADCDigCompCfg));
      dsp_cfg.ADCFilterCfg.ADCAvgNum = ADCAVGNUM_16;  /* Don't care because it's disabled */
      dsp_cfg.ADCFilterCfg.ADCRate = ADCRATE_800KHZ;
      dsp_cfg.ADCFilterCfg.ADCSinc2Osr = AppBATCfg.ADCSinc2Osr;
      dsp_cfg.ADCFilterCfg.ADCSinc3Osr = AppBATCfg.ADCSinc3Osr;
      dsp_cfg.ADCFilterCfg.BpSinc3 = bFALSE;
      dsp_cfg.ADCFilterCfg.BpNotch = bTRUE;
      dsp_cfg.ADCFilterCfg.Sinc2NotchEnable = bTRUE;
      dsp_cfg.DftCfg.DftNum = AppBATCfg.DftNum;
      dsp_cfg.DftCfg.DftSrc = AppBATCfg.DftSrc;
      dsp_cfg.DftCfg.HanWinEn = AppBATCfg.HanWinEn;
      memset(&dsp_cfg.StatCfg, 0, sizeof(dsp_cfg.StatCfg)); /* Don't care about Statistic */
      AD5940_DSPCfgS(&dsp_cfg);
      /* Enable all of them. They are automatically turned off during hibernate mode to save power */
      AD5940_AFECtrlS(AFECTRL_HPREFPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\
        AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\
          AFECTRL_SINC2NOTCH|AFECTRL_DFT, bTRUE);
      /* Sequence end. */
      AD5940_SEQGenInsert(SEQ_STOP()); /* Add one external command to disable sequencer for initialization sequence because we only want it to run one time. */
      
      /* Stop here */
      error = AD5940_SEQGenFetchSeq(&pSeqCmd, &SeqLen);
      AD5940_SEQGenCtrl(bFALSE); /* Stop sequencer generator */
      if(error == AD5940ERR_OK)
      {
        AppBATCfg.InitSeqInfo.SeqId = SEQID_3;
        AppBATCfg.InitSeqInfo.SeqRamAddr = AppBATCfg.SeqStartAddr;
        AppBATCfg.InitSeqInfo.pSeqCmd = pSeqCmd;
        AppBATCfg.InitSeqInfo.SeqLen = SeqLen;
        /* Write command to SRAM */
        AD5940_SEQCmdWrite(AppBATCfg.InitSeqInfo.SeqRamAddr, pSeqCmd, SeqLen);
      }
      else
        return error; /* Error */
      return AD5940ERR_OK;
    }
    
    //the sequence used to measure battery response voltage.
    static AD5940Err AppBATSeqMeasureGen(void)
    {
      AD5940Err error = AD5940ERR_OK;
      uint32_t const *pSeqCmd;
      uint32_t SeqLen;
      uint32_t WaitClks;
      ClksCalInfo_Type clks_cal;
      
      clks_cal.DataType = DATATYPE_SINC3;
      clks_cal.DataCount = 1;
      clks_cal.ADCSinc2Osr = AppBATCfg.ADCSinc2Osr;
      clks_cal.ADCSinc3Osr = AppBATCfg.ADCSinc3Osr;
      clks_cal.ADCAvgNum = 0;
      clks_cal.RatioSys2AdcClk = AppBATCfg.SysClkFreq/AppBATCfg.AdcClkFreq;
      AD5940_ClksCalculate(&clks_cal, &WaitClks);
    
      /* Start sequence generator here */
      AD5940_SEQGenCtrl(bTRUE);
      AD5940_SEQGenInsert(SEQ_WAIT(16*250));  /* wait 250us for reference power up from hibernate mode. */
      AD5940_AFECtrlS(AFECTRL_WG|AFECTRL_ADCPWR|AFECTRL_SINC2NOTCH, bTRUE);  /* Enable Waveform generator, ADC power */
      AD5940_SEQGenInsert(SEQ_WAIT(16*50));   /* Wait for ADC ready. */
      AD5940_AFECtrlS(AFECTRL_ADCCNV, bTRUE);  /* Start ADC convert and DFT */
      AD5940_SEQGenInsert(SEQ_WAIT(WaitClks));  /* wait for first data ready */  
    //	AD5940_
      AD5940_AFECtrlS(AFECTRL_ADCCNV/*|AFECTRL_DFT|AFECTRL_WG*/|AFECTRL_ADCPWR|AFECTRL_SINC2NOTCH, bFALSE);  /* Stop ADC convert and DFT */
      
      /* Sequence end. */
      error = AD5940_SEQGenFetchSeq(&pSeqCmd, &SeqLen);
      AD5940_SEQGenCtrl(bFALSE); /* Stop sequencer generator */
      if(error == AD5940ERR_OK)
      {
        AppBATCfg.ImpedanceSeqInfo.SeqId = SEQID_1;
        AppBATCfg.ImpedanceSeqInfo.SeqRamAddr = AppBATCfg.InitSeqInfo.SeqRamAddr + AppBATCfg.InitSeqInfo.SeqLen ;
        AppBATCfg.ImpedanceSeqInfo.pSeqCmd = pSeqCmd;
        AppBATCfg.ImpedanceSeqInfo.SeqLen = SeqLen;
        /* Write command to SRAM */
        AD5940_SEQCmdWrite(AppBATCfg.ImpedanceSeqInfo.SeqRamAddr, pSeqCmd, SeqLen);
      }
      else
        return error; /* Error */
      return AD5940ERR_OK;
    }
    
    /* M<easure battery voltage through amplifier */
    //the sequence used to measure battery response voltage.
    static AD5940Err AppBATVoltSeqMeasureGen(void)
    {
      AD5940Err error = AD5940ERR_OK;
      uint32_t const *pSeqCmd;
      uint32_t SeqLen;
      uint32_t WaitClks;
      ClksCalInfo_Type clks_cal;
      ADCFilterCfg_Type adc_filt;
    
    
      clks_cal.DataType = DATATYPE_SINC2;
      clks_cal.DataCount = 1; 
      clks_cal.ADCSinc2Osr = ADCSINC2OSR_22;
      clks_cal.ADCSinc3Osr = ADCSINC3OSR_4;
      clks_cal.ADCAvgNum = 0;
      clks_cal.RatioSys2AdcClk = AppBATCfg.SysClkFreq/AppBATCfg.AdcClkFreq;
      AD5940_ClksCalculate(&clks_cal, &WaitClks);
    		
      /* Start sequence generator here */
      AD5940_SEQGenCtrl(bTRUE);
    
    	adc_filt.ADCAvgNum = ADCAVGNUM_16;  /* Don't care because it's disabled */
      adc_filt.ADCRate = ADCRATE_800KHZ;
      adc_filt.ADCSinc2Osr = ADCSINC2OSR_22;
      adc_filt.ADCSinc3Osr = ADCSINC3OSR_4;
      adc_filt.BpSinc3 = bFALSE;
      adc_filt.BpNotch = bTRUE;
      adc_filt.Sinc2NotchEnable = bTRUE;
    	AD5940_ADCFilterCfgS(&adc_filt);
    	
    	
      AD5940_ADCMuxCfgS(ADCMUXP_VAFE3, ADCMUXN_VSET1P1);
      AD5940_SEQGenInsert(SEQ_WAIT(16*250));  /* wait 250us for reference power up from hibernate mode. */
      AD5940_AFECtrlS(AFECTRL_ADCPWR|AFECTRL_SINC2NOTCH, bTRUE);  /* Enable Waveform generator, ADC power */
      AD5940_SEQGenInsert(SEQ_WAIT(16*50));   /* Wait for ADC ready. */
      AD5940_AFECtrlS(AFECTRL_ADCCNV, bTRUE);  /* Start ADC convert and DFT */
    		
      AD5940_SEQGenInsert(SEQ_WAIT(WaitClks));  /* wait for first data ready */  	
      AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_ADCPWR|AFECTRL_SINC2NOTCH, bFALSE);  /* Stop ADC convert and DFT */
      AD5940_ADCMuxCfgS(ADCMUXP_AIN2, ADCMUXN_AIN3);
    
      /* Sequence end. */
      error = AD5940_SEQGenFetchSeq(&pSeqCmd, &SeqLen);
      AD5940_SEQGenCtrl(bFALSE); /* Stop sequencer generator */
      if(error == AD5940ERR_OK)
      {
        AppBATCfg.VoltMeasureSeqInfo.SeqId = SEQID_0;
        AppBATCfg.VoltMeasureSeqInfo.SeqRamAddr = AppBATCfg.ImpedanceSeqInfo.SeqRamAddr + AppBATCfg.ImpedanceSeqInfo.SeqLen ;
        AppBATCfg.VoltMeasureSeqInfo.pSeqCmd = pSeqCmd;
        AppBATCfg.VoltMeasureSeqInfo.SeqLen = SeqLen;
        /* Write command to SRAM */
        AD5940_SEQCmdWrite(AppBATCfg.VoltMeasureSeqInfo.SeqRamAddr, pSeqCmd, SeqLen);
      }
      else
        return error; /* Error */
      return AD5940ERR_OK;
    }
    
    /* This function provide application initialize.   */
    AD5940Err AppBATInit(uint32_t *pBuffer, uint32_t BufferSize)
    {
      AD5940Err error = AD5940ERR_OK;
      SEQCfg_Type seq_cfg;
      FIFOCfg_Type fifo_cfg;
      
      if(AD5940_WakeUp(10) > 10)  /* Wakeup AFE by read register, read 10 times at most */
        return AD5940ERR_WAKEUP;  /* Wakeup Failed */
      
      /* Configure sequencer and stop it */
      seq_cfg.SeqMemSize = SEQMEMSIZE_2KB;  /* 2kB SRAM is used for sequencer, others for data FIFO */
      seq_cfg.SeqBreakEn = bFALSE;
      seq_cfg.SeqIgnoreEn = bFALSE;
      seq_cfg.SeqCntCRCClr = bTRUE;
      seq_cfg.SeqEnable = bFALSE;
      seq_cfg.SeqWrTimer = 0;
      AD5940_SEQCfg(&seq_cfg);
      
      /* Reconfigure FIFO */
      AD5940_FIFOCtrlS(FIFOSRC_DFT, bFALSE);									/* Disable FIFO firstly */
      fifo_cfg.FIFOEn = bTRUE;
      fifo_cfg.FIFOMode = FIFOMODE_FIFO;
      fifo_cfg.FIFOSize = FIFOSIZE_4KB;                       /* 4kB for FIFO, The reset 2kB for sequencer */
      fifo_cfg.FIFOSrc = FIFOSRC_DFT;
      fifo_cfg.FIFOThresh = AppBATCfg.FifoThresh;              /* DFT result. One pair for RCAL, another for Rz. One DFT result have real part and imaginary part */
      AD5940_FIFOCfg(&fifo_cfg);
      
      AD5940_INTCClrFlag(AFEINTSRC_ALLINT);
      
      /* Start sequence generator */
      /* Initialize sequencer generator */
      if((AppBATCfg.BATInited == bFALSE)||\
        (AppBATCfg.bParaChanged == bTRUE))
      {
        if(pBuffer == 0)  return AD5940ERR_PARA;
        if(BufferSize == 0) return AD5940ERR_PARA;   
        AD5940_SEQGenInit(pBuffer, BufferSize);
        /* Generate initialize sequence */
        error = AppBATSeqCfgGen(); /* Application initialization sequence using either MCU or sequencer */
        if(error != AD5940ERR_OK) return error;
        /* Generate measurement sequence */
        error = AppBATSeqMeasureGen();
        if(error != AD5940ERR_OK) return error;
        AppBATCfg.bParaChanged = bFALSE; /* Clear this flag as we already implemented the new configuration */
    		
    		 error = AppBATVoltSeqMeasureGen();
        if(error != AD5940ERR_OK) return error;
        AppBATCfg.bParaChanged = bFALSE; /* Clear this flag as we already implemented the new configuration */
    		
      }
      /* Initialization sequencer  */
      AppBATCfg.InitSeqInfo.WriteSRAM = bFALSE;
      AD5940_SEQInfoCfg(&AppBATCfg.InitSeqInfo);
      seq_cfg.SeqEnable = bTRUE;
      AD5940_SEQCfg(&seq_cfg);  /* Enable sequencer */
      AD5940_SEQMmrTrig(AppBATCfg.InitSeqInfo.SeqId);
      while(AD5940_INTCTestFlag(AFEINTC_1, AFEINTSRC_ENDSEQ) == bFALSE);
    
      /* Measurement sequence  */
      AppBATCfg.ImpedanceSeqInfo.WriteSRAM = bFALSE;
      AD5940_SEQInfoCfg(&AppBATCfg.ImpedanceSeqInfo);
    	/* Voltage Measurement Sequence  */
      AppBATCfg.VoltMeasureSeqInfo.WriteSRAM = bFALSE;
      AD5940_SEQInfoCfg(&AppBATCfg.VoltMeasureSeqInfo);
    	
      seq_cfg.SeqEnable = bTRUE;
      AD5940_SEQCfg(&seq_cfg);  /* Enable sequencer, and wait for trigger */
      AD5940_ClrMCUIntFlag();   /* Clear interrupt flag generated before */
      AD5940_AFEPwrBW(AppBATCfg.PwrMod, AFEBW_250KHZ);
      AD5940_WriteReg(REG_AFE_SWMUX, 1<<1);
      AppBATCfg.BATInited = bTRUE;  /* BAT application has been initialized. */
      return AD5940ERR_OK;
    }
    
    /* Modify registers when AFE wakeup */
    static AD5940Err AppBATRegModify(int32_t * const pData, uint32_t *pDataCount)
    {
      if(AppBATCfg.NumOfData > 0)
      {
        AppBATCfg.FifoDataCount += *pDataCount/4;
        if(AppBATCfg.FifoDataCount >= AppBATCfg.NumOfData)
        {
          AD5940_WUPTCtrl(bFALSE);
          return AD5940ERR_OK;
        }
      }
      if(AppBATCfg.StopRequired == bTRUE)
      {
        AD5940_WUPTCtrl(bFALSE);
        return AD5940ERR_OK;
      }
      return AD5940ERR_OK;
    }
    
    /* Depending on the data type, do appropriate data pre-process before return back to controller */
    static AD5940Err AppBATDataProcess(int32_t * const pData, uint32_t *pDataCount)
    {
      uint32_t DataCount = *pDataCount;
      
      *pDataCount = 0;
     // DataCount = (DataCount/4)*4;  /* We expect both Real and imaginary result.  */
      
      if(AppBATCfg.state == STATE_BATTERY)
      {
    	uint32_t DftResCount = DataCount/4;
      
      fImpCar_Type * const pOut = (fImpCar_Type*)pData;
      iImpCar_Type * pSrcData = (iImpCar_Type*)pData;
      
        /* Convert DFT result to int32_t type */
        for(uint32_t i=0; i<DataCount; i++)
        {
          pData[i] &= 0x3ffff;
          if(pData[i]&(1<<17)) /* Bit17 is sign bit */
          {
            pData[i] |= 0xfffc0000; /* Data is 18bit in two's complement, bit17 is the sign bit */
          }
        }
      for(uint32_t i=0; i<DftResCount; i++)
      {
        fImpCar_Type BatImp, BatVolt, RcalVolt;
        RcalVolt.Real = pSrcData->Real;
        RcalVolt.Image = pSrcData->Image;
        pSrcData ++;
        BatVolt.Real = pSrcData->Real;
        BatVolt.Image = pSrcData->Image;
        pSrcData ++;
        BatImp = AD5940_ComplexDivFloat(&BatVolt, &RcalVolt); //ratio measurement, Zbat = Vbat/Vrcal * Rcal;
        BatImp.Image *= AppBATCfg.RcalVal;
        BatImp.Real *= AppBATCfg.RcalVal;
        pOut[i] = BatImp;
      }
      *pDataCount = DftResCount;
    
    //  AppBATCfg.state = STATE_IDLE;
      }
    
    	else if(AppBATCfg.state == STATE_MEASVOLT)
      {
    	AppBATCfg.BatVolt = 0.0;
        for(int i=0; i<DataCount; i++)
    		{
          pData[i] &= 0xffff;
    			float temp, voltage = 0;
          voltage = AD5940_ADCCode2Volt(pData[i], ADCPGA_2, 1820) + 1110;
    			temp = ((V_DIVIDER_R1 + V_DIVIDER_R2)*voltage) /V_DIVIDER_R2;
          AppBATCfg.BatVolt += temp;
        }
    	AppBATCfg.BatVolt /= DataCount;
      //  AppBATCfg.state = STATE_IDLE;
        *pDataCount = 0;  /* Report no result to upper application */
      }
      return AD5940ERR_OK;
    }
    
    /**
    */
    AD5940Err AppBATISR(void *pBuff, uint32_t *pCount)
    {
      uint32_t FifoCnt;
      if(AppBATCfg.BATInited == bFALSE)
        return AD5940ERR_APPERROR;
      if(AD5940_WakeUp(10) > 10)  /* Wakeup AFE by read register, read 10 times at most */
        return AD5940ERR_WAKEUP;  /* Wakeup Failed */
      AD5940_SleepKeyCtrlS(SLPKEY_LOCK);  /* Don't enter hibernate */
      *pCount = 0;
      
      if(AD5940_INTCTestFlag(AFEINTC_1, AFEINTSRC_DFTRDY) == bTRUE)
      {
        FifoCnt = AD5940_FIFOGetCnt();
        AD5940_FIFORd((uint32_t *)pBuff, FifoCnt);
        AD5940_INTCClrFlag(AFEINTSRC_DFTRDY);
        AppBATRegModify(pBuff, &FifoCnt);   /* If there is need to do AFE re-configure, do it here when AFE is in active state */
        //AD5940_EnterSleepS();  /* Manually put AFE back to hibernate mode. */
        AD5940_SleepKeyCtrlS(SLPKEY_UNLOCK);  /* Allow AFE to enter hibernate mode */
        /* Process data */ 
        AppBATDataProcess((int32_t*)pBuff,&FifoCnt); 
        *pCount = FifoCnt;
        return 0;
      }
      
      return 0;
    }
    
    
    /**
    * @}
    */
    

    /*!
    *****************************************************************************
    @file:    BATImpedance.h
    @author: MLambe
    @brief:   BATImpedance.c header file.
    -----------------------------------------------------------------------------
    Copyright (c) 2017-2019 Analog Devices, Inc. All Rights Reserved.
    This software is proprietary to Analog Devices, Inc. and its licensors.
    By using this software you agree to the terms of the associated
    Analog Devices Software License Agreement.
    
    *****************************************************************************/
    
    #ifndef _BAT_IMPEDANCE_H_
    #define _BAT_IMPEDANCE_H_
    #include "ad5940.h"
    #include "stdio.h"
    #include "string.h"
    #include "math.h"
    
    #define PRECHARGE_WAIT_MS   400    //precharge time in ms.
    
    #define PRECHARGE_CH1       1
    #define PRECHARGE_CH2       2
    #define PRECHARGE_CH3       3
    
    #define PRECHARGE_RCAL      PRECHARGE_CH1
    #define PRECHARGE_BAT       PRECHARGE_CH2
    #define PRECHARGE_AMP       PRECHARGE_CH3
    
    #define DAC12BITVOLT_1LSB   (2200.0f/4095)  //mV
    #define DAC6BITVOLT_1LSB    (DAC12BITVOLT_1LSB*64)  //mV
    
    
    #define STATE_IDLE        			0   /**< Initial state. */
    #define STATE_BATTERY     	1   /**< Measure battery response voltage. */
    #define STATE_MEASVOLT		2	 /**< Measure battery Voltage. */
    #define STATE_RCAL	3
    
    #define V_DIVIDER_R1	1e6
    #define V_DIVIDER_R2	750e3
    
    typedef struct
    {
    /* Common configurations for all kinds of Application. */
      BoolFlag bParaChanged;        /* Indicate to generate sequence again. It's auto cleared by AppBATInit */
      uint32_t SeqStartAddr;        /* Initialaztion sequence start address in SRAM of AD5940  */
      uint32_t MaxSeqLen;           /* Limit the maximum sequence.   */
      uint32_t SeqStartAddrCal;     /* Measurement sequence start address in SRAM of AD5940 */
      uint32_t MaxSeqLenCal;
    	uint32_t SampleRate;
    /* Application related parameters */ 
    	uint32_t state;               /* 0: Init, 1: measure Rcal, 2: Measure Battery. */
      float SysClkFreq;             /* The real frequency of system clock */
      float WuptClkFreq;            /* The clock frequency of Wakeup Timer in Hz. Typically it's 32kHz. Leave it here in case we calibrate clock in software method */
      float AdcClkFreq;             /* The real frequency of ADC clock */
      uint32_t FifoThresh;           /* FIFO threshold. Should be N*4 */   
      int32_t NumOfData;            /* By default it's '-1'. If you want the engine stops after get NumofData, then set the value here. Otherwise, set it to '-1' which means never stop. */
      uint32_t PwrMod;              /* Control Chip power mode(LP/HP) */
      float ACVoltPP;               /* Final AC excitation voltage on pin AIN1 in mV peak to peak unit. */
      float DCVolt;                 /* The DC bias voltage on AIN1 pin. Unit is mV. */
      float RcalVal;                /* Rcal value in mOhm */
      float SinFreq;                /* Frequency of excitation signal */
      uint8_t ADCSinc3Osr;          /* SINC3 OSR selection. ADCSINC3OSR_2, ADCSINC3OSR_4 */
      uint8_t ADCSinc2Osr;          /* SINC2 OSR selection. ADCSINC2OSR_22...ADCSINC2OSR_1333 */
      uint32_t DftNum;              /* DFT number */
      uint32_t DftSrc;              /* DFT Source */
      BoolFlag HanWinEn;            /* Enable Hanning window */
    float BatVolt;
    /* Private variables for internal usage */
      float FreqofData;  
      BoolFlag BATInited;           /* If the program run firstly, generated sequence commands */
      SEQInfo_Type InitSeqInfo;
      SEQInfo_Type ImpedanceSeqInfo;
    	SEQInfo_Type VoltMeasureSeqInfo;
    	
    	
      BoolFlag StopRequired;        /* After FIFO is ready, stop the measurement sequence */
      uint32_t FifoDataCount;       /* Count how many times impedance have been measured */
    /* End */
    }AppBATCfg_Type;
    
    #define BATCTRL_MEASIMP          0
    #define BATCTRL_SHUTDOWN  1   /* Note: shutdown here means turn off everything and put AFE to hibernate mode. The word 'SHUT DOWN' is only used here. */
    #define BATCTRL_GETFREQ			2
    #define BATCTRL_MEASVOLT   3
    #define BATCTRL_MEASRCAL	4
    
    AD5940Err AppBATGetCfg(void *pCfg);
    AD5940Err AppBATInit(uint32_t *pBuffer, uint32_t BufferSize);
    AD5940Err AppBATISR(void *pBuff, uint32_t *pCount);
    AD5940Err AppBATCtrl(int32_t BatCtrl, void *pPara);
    void AppBATConnect(BoolFlag bConnect);
    
    
    #endif
    

    /*!
     *****************************************************************************
     @file:    UARTCmd.c
     @author:  $Author: nxu2 $
     @brief:   UART Command process
     @version: $Revision: 766 $
     @date:    $Date: 2017-08-21 14:09:35 +0100 (Mon, 21 Aug 2017) $
     -----------------------------------------------------------------------------
    
    Copyright (c) 2017-2019 Analog Devices, Inc. All Rights Reserved.
    
    This software is proprietary to Analog Devices, Inc. and its licensors.
    By using this software you agree to the terms of the associated
    Analog Devices Software License Agreement.
     
    *****************************************************************************/
    #include "stdint.h"
    #include "string.h"
    #include "stdio.h"
    #include <stdlib.h>
    
    #define LINEBUFF_SIZE 128
    #define CMDTABLE_SIZE 13
    
    uint32_t help(uint32_t para1, uint32_t para2);
    uint32_t say_hello(uint32_t para1, uint32_t para2);
    uint32_t batz_start(float para1, float para2);
    uint32_t batz_rst(uint32_t para1, uint32_t para2);
    uint32_t batz_set_rcal(float para1);
    uint32_t batz_set_dcvolt(float para1);
    uint32_t batz_set_acamplitude(float para1);
    uint32_t batz_connect(float para1);
    uint32_t batz_get_volt(uint32_t para1);
    uint32_t batz_disconnect(float para1);
    uint32_t batz_set_sinc_filter(float para1, float para2);
    uint32_t batz_set_dft(float para1, float para2);
    uint32_t batz_set_adc_sample_rate(float para1, float para2);
    
    struct __uartcmd_table
    {
      void *pObj;
      const char *cmd_name;
      const char *pDesc;
    }uart_cmd_table[CMDTABLE_SIZE]=
    {
      {(void*)help, "help", "print supported commands"},
      {(void*)help, "?", "print supported commands"},
      {(void*)batz_start, "batz_start", "Do 1 EIS measurement.  \"batz_start 10\" 10Hz "},
      {(void*)batz_rst, "batz_reset", "Reset hardware"},
    	{(void*)batz_set_rcal, "batz_set_rcal", "Set RFCAL value "},
    	{(void*)batz_set_dcvolt, "batz_set_dcvolt", "Set the common mode voltage "},
    	{(void*)batz_set_acamplitude, "batz_set_acamplitude", "Set amplitude of ac signal "},
    	{(void*)batz_disconnect, "batz_disconnect", "Disconnect battery from AD5941"},
    	{(void*)batz_connect, "batz_connect", "Connect battery to AD5941 signal"},
    	{(void*)batz_get_volt, "batz_get_volt", "Measure Battery Voltage"},
    	{(void*)batz_set_sinc_filter, "batz_set_sinc_filter", "Set Sinc filters OSR. Para1 = Sinc3 OSR, Para2 = Sinc3 OSR"},
    	{(void*)batz_set_dft, "batz_set_dft", "Set dft config. Para1 = DFT Number OSR, Para2 = DFT Source 0 for SINC£ 1 for SINC2 "},
    	{(void*)batz_set_adc_sample_rate, "batz_set_adc_sample_rate", "Set ADC Sample Rate."},
    };
    
    
    uint32_t help(uint32_t para1, uint32_t para2)
    {
      int i = 0;
      printf("\n*****help menu*****\nThe following are the supported commands:\n\n");
      for(;i<CMDTABLE_SIZE;i++)
      {
        if(uart_cmd_table[i].pObj)
          printf("%-8s --\t\t%s\n", uart_cmd_table[i].cmd_name, uart_cmd_table[i].pDesc);
      }
      printf("\n***table end***\n");
      return 0x87654321;
    }
    
    
    char line_buffer[LINEBUFF_SIZE];
    uint32_t line_buffer_index = 0;
    uint32_t token_count = 0;
    void *pObjFound = 0;
    float parameter1, parameter2;
    
    void UARTCmd_RemoveSpaces(void)
    {
      int i = 0;
      token_count = 0;
      char flag_found_token = 0;
      while(i<line_buffer_index)
      {
        if(line_buffer[i] == ' ') line_buffer[i] = '\0';
        else break;
        i++;
      }
      if(i == line_buffer_index) return;  /* All spaces... */
      while(i<line_buffer_index)
      {
        if(line_buffer[i] == ' ')
        {
          line_buffer[i] = '\0';
          flag_found_token = 0;
        }
        else
        { 
          if(flag_found_token == 0)
            token_count ++;
          flag_found_token = 1;
        }
        i++;
      }
    }
    
    void UARTCmd_MatchCommand(void)
    {
      char *pcmd;
      int i = 0;
      pObjFound = 0;
      while(i<line_buffer_index)
      {
        if(line_buffer[i] != '\0')
        {
          pcmd = &line_buffer[i];
          break;
        }
        i++;
      }
      for(i=0;i<CMDTABLE_SIZE;i++)
      {
        if(strcmp(uart_cmd_table[i].cmd_name, pcmd) == 0)
        {
          /* Found you! */
          pObjFound = uart_cmd_table[i].pObj;
          break;
        }
      }
    }
    
    /* Translate string 'p' to number, store results in 'Res', return error code */
    static uint32_t Str2Float(char *s, float *Res)
    {
      char *p;
       
      *Res = strtof( s, &p);
    
      return 0;
    }
    
    void UARTCmd_TranslateParas(void)
    {
      char *p = line_buffer;
      parameter1 = 0;
      parameter2 = 0;
      while(*p == '\0') p++;    /* goto command */
      while(*p != '\0') p++;    /* skip command. */
      while(*p == '\0') p++;    /* goto first parameter */
      if(Str2Float(p, &parameter1) != 0) return;
      if(token_count == 2) return;           /* Only one parameter */
      while(*p != '\0') p++;    /* skip first command. */
      while(*p == '\0') p++;    /* goto second parameter */
      Str2Float(p, &parameter2);
    }
    
    void UARTCmd_Process(char c)
    {
      if(line_buffer_index >= LINEBUFF_SIZE-1)
        line_buffer_index = 0;  /* Error: buffer overflow */
      if( (c == '\r') || (c == '\n'))
      {
        line_buffer[line_buffer_index] = '\0';
        /* Start to process command */
        if(line_buffer_index == 0) 
        {
          line_buffer_index = 0; /* Reset buffer */
          return;  /* No command inputs, return */
        }
        /* Step1, remove space */
        UARTCmd_RemoveSpaces();
        if(token_count == 0)
        {
          line_buffer_index = 0; /* Reset buffer */
          return; /* No valid input */
        }
        /* Step2, match commands */
        UARTCmd_MatchCommand();
        if(pObjFound == 0)
        {
          line_buffer_index = 0; /* Reset buffer */
          return;   /* Command not support */
        }
        if(token_count > 1)           /* There is parameters */
        {
          UARTCmd_TranslateParas();
        }
       // printf("FOund you!! %d , %d \n", parameter1, parameter2);
        /* Step3, call function */
        ((uint32_t (*)(float, float))(pObjFound))(parameter1, parameter2);
        line_buffer_index = 0;  /* Reset buffer */
      }
      else
      {
        line_buffer[line_buffer_index++] = c;
      }
    }
    

Children
  • Hello Akila, thank you for urgent response and sharing the program. I truly appreciate it and I'm still working on it. Aside from that we  want to print raw register data before DFT for low frequency measurement. The resulted measurement will be fed up to MATLAB for manual DFT measurement. Can you share to me the right variable? Thank you in advance.