Post Go back to editing

Problem at reported Impedance data by CN0510: Invalid Impedance Values

Category: Software
Product Number: AD5941

Hi! I am working with CN0510 Board with NUCLEo-F411RE and I have Loaded my board with BATImpedance Project which is available on Github. I am currently using 50 m ohm Resistor with a Lead Acid battery to study the impedance spectrum of The battery but the problem is that I don't get valid impedance! could you please help me solve the problem?

on Sep 22, 2023 11:54 AM

Can you tell us a little more about your setup and configuration?  Can you share the link to the software you are using from Github?  You mentioned you are using the Nucleo board, but I believe the software that we provide for the CN0510 board was developed using the EVAL-ADICUP3029 development board.  Have you tried replicating the exact setup shown on the user guide (CN0510 User Guide [Analog Devices Wiki])? And can you get the desired results?

Have you tried removing the battery from the measurement and tested only with a known resistor to see if you can consistently read that value from the CN0510? 

 do you have any tips, tricks, questions, that would help troubleshoot this issue? 

  • sure !

    I'm using codes which are available on GitHub. this is the link:

    https://github.com/analogdevicesinc/ad5940-examples/tree/master/examples/AD5940_BATImpedance/NUCLEO-F411

    github.com/.../AD5940_BATImpedance

    According to the Link above, it is possible to connect CN0510 Board to the NUCLEO-F411RE Board. there is a written code for Nucleo-F411RE board.

    yes I replicated the setup mentioned in the Application Note of CN0510.

    I set the code(based on the setting in the application Note of CN0510) to generate Sweep Excitation signal in desired range, but when I load the code on the board and measure the Excitation signal on the oscilloscope I only have excitation signal in the first step of the sweep and after few seconds the excitation signal vanishes. after few moment results of impedance measurements come up on the serial monitor but they are irrelevant, I think this is considerable because there isn't any signal in the excitation sweep except for the first step, but my question is why I can see results of measurements at those frequency steps while they aren't stimulated? 

    No I can not remove the battery because it is powering the Darlington pair at the same time, I cannot get DC voltage from a passive resistor.

    The impedance of the battery which I am testing is in the range of the calibration Resistor placed on the CN0510 that is 50 mili-ohms.

    I have seen some identical issues on the following link but it hasn't been answered properly yet:

    ez.analog.com/.../eval-adicup3029-eval-ad5941batz-ad5940_batimpedance-problems

    Could it be a problem with the Keil compiler version I'm using?

    any clue or help is gratefully appreciated!

  • Hi   could you please help with this issue?

  • Hi,

    Could you please check with the below code:

    /*BATImpedance.c*/
    #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 = 
    {
      .state = STATE_IDLE,
      .bParaChanged = bFALSE,
      .SeqStartAddr = 0,
      .MaxSeqLen = 0,
      
      .SeqStartAddrCal = 0,
      .MaxSeqLenCal = 0,
    
      .SysClkFreq = 16000000.0,
      .WuptClkFreq = 32000.0,
      .AdcClkFreq = 16000000.0,
      .BatODR = 20.0, /* 20.0 Hz*/
      .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,
      .MeasSeqCycleCount = 0,
    	
    	.SweepCfg.SweepEn = bTRUE,
      .SweepCfg.SweepStart = 1000,
      .SweepCfg.SweepStop = 100000.0,
      .SweepCfg.SweepPoints = 101,
      .SweepCfg.SweepLog = bFALSE,
      .SweepCfg.SweepIndex = 0,
    };
    
    /**
       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;
    }
    
    
    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
    }
    
    AD5940Err AppBATCtrl(int32_t BatCtrl, void *pPara)
    {
      switch (BatCtrl)
      {
        case BATCTRL_START:
        {
          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_SWMUX, 1<<0); 				/* control ADG636 to measure battery */
    			AD5940_WriteReg(REG_AFE_SYNCEXTDEVICE, 0x0);
          PreCharge(PRECHARGE_BAT);
          PreCharge(PRECHARGE_AMP);
          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;
          /* Trigger sequence using MMR write */
    			AD5940_SEQMmrTrig(SEQID_0);
          AppBATCfg.FifoDataCount = 0;  /* restart */
          
          break;
        }
        case BATCTRL_STOPNOW:
        {
          if(AD5940_WakeUp(10) > 10)  /* Wakeup AFE by read register, read 10 times at most */
            return AD5940ERR_WAKEUP;  /* Wakeup Failed */
          /* Start Wupt right now */
          AD5940_WUPTCtrl(bFALSE);
          /* There is chance this operation will fail because sequencer could put AFE back 
            to hibernate mode just after waking up. Use STOPSYNC is better. */
          AD5940_WUPTCtrl(bFALSE);
          break;
        }
        case BATCTRL_STOPSYNC:
        {
          AppBATCfg.StopRequired = bTRUE;
          break;
        }
    		case BATCTRL_GETFREQ:
        if(pPara)
        {
          if(AppBATCfg.SweepCfg.SweepEn == bTRUE)
            *(float*)pPara = AppBATCfg.FreqofData;
          else
            *(float*)pPara = AppBATCfg.SinFreq;
        }
    		break;
        case BATCTRL_SHUTDOWN:
        {
          AppBATCtrl(BATCTRL_STOPNOW, 0);  /* Stop the measurement if it's running. */
          /* 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;
        case BATCTRL_MRCAL:
        if(AD5940_WakeUp(10) > 10)
            return AD5940ERR_WAKEUP;
        //Settle input RC filter.
        AD5940_WriteReg(REG_AFE_SWMUX, 0); //control ADG636 to measure rcal
    		AD5940_WriteReg(REG_AFE_SYNCEXTDEVICE, 0x4);
        PreCharge(PRECHARGE_RCAL);
        PreCharge(PRECHARGE_AMP);
        AD5940_FIFOCtrlS(FIFOSRC_DFT, bFALSE);
    		AD5940_FIFOThrshSet(2);
        AD5940_FIFOCtrlS(FIFOSRC_DFT, bTRUE); //enable FIFO
    		AppBATMeasureRCAL();
        break;
        default:
        break;
      }
      return AD5940ERR_OK;
    }
    
    /* 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;
    	if(AppBATCfg.SweepCfg.SweepEn == bTRUE)
      {
        AppBATCfg.FreqofData = AppBATCfg.SweepCfg.SweepStart;
        AppBATCfg.SweepCurrFreq = AppBATCfg.SweepCfg.SweepStart;
    		AD5940_SweepNext(&AppBATCfg.SweepCfg, &AppBATCfg.SweepNextFreq);
    		sin_freq = AppBATCfg.SweepCurrFreq;    
      }
      else
      {
        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_1P5;
      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, 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_1;
        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_DFT;
      clks_cal.DftSrc = AppBATCfg.DftSrc;
      clks_cal.DataCount = 1L<<(AppBATCfg.DftNum+2); /* 2^(DFTNUMBER+2) */
      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|AFECTRL_DFT, bTRUE);  /* Start ADC convert and DFT */
      AD5940_SEQGenFetchSeq(NULL, &AppBATCfg.SeqWaitAddr[0]); /* Record the start address of the next command. */
    
      AD5940_SEQGenInsert(SEQ_WAIT(WaitClks/2));
       AD5940_SEQGenInsert(SEQ_WAIT(WaitClks/2));  
      AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT/*|AFECTRL_WG*/|AFECTRL_ADCPWR|AFECTRL_SINC2NOTCH, bFALSE);  /* Stop ADC convert and DFT */
      //AD5940_EnterSleepS();/* Goto hibernate */
      /* Sequence end. */
      error = AD5940_SEQGenFetchSeq(&pSeqCmd, &SeqLen);
      AD5940_SEQGenCtrl(bFALSE); /* Stop sequencer generator */
    
      AppBATCfg.MeasSeqCycleCount = AD5940_SEQCycleTime();
      AppBATCfg.MaxODR = 1/(((AppBATCfg.MeasSeqCycleCount + 10) / 16.0)* 1E-6)  ;
      if(AppBATCfg.BatODR > AppBATCfg.MaxODR)
      {
        /* We have requested a sampling rate that cannot be achieved with the time it
           takes to acquire a sample.
        */
        AppBATCfg.BatODR = AppBATCfg.MaxODR;
      }
    
      if(error == AD5940ERR_OK)
      {
        AppBATCfg.MeasureSeqInfo.SeqId = SEQID_0;
        AppBATCfg.MeasureSeqInfo.SeqRamAddr = AppBATCfg.InitSeqInfo.SeqRamAddr + AppBATCfg.InitSeqInfo.SeqLen ;
        AppBATCfg.MeasureSeqInfo.pSeqCmd = pSeqCmd;
        AppBATCfg.MeasureSeqInfo.SeqLen = SeqLen;
        /* Write command to SRAM */
        AD5940_SEQCmdWrite(AppBATCfg.MeasureSeqInfo.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 */
      }
      /* 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);
      
    	AppBATCheckFreq(AppBATCfg.SweepCfg.SweepStart);
      /* Measurement sequence  */
      AppBATCfg.MeasureSeqInfo.WriteSRAM = bFALSE;
      AD5940_SEQInfoCfg(&AppBATCfg.MeasureSeqInfo);
      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;
    }
    
    /* Depending on frequency of Sin wave set optimum filter settings */
    AD5940Err AppBATCheckFreq(float freq)
    {
    	ADCFilterCfg_Type filter_cfg;
      DFTCfg_Type dft_cfg;
      HSDACCfg_Type hsdac_cfg;
      uint32_t WaitClks;
      ClksCalInfo_Type clks_cal;
      FreqParams_Type freq_params;
      uint32_t SeqCmdBuff[32];
      uint32_t SRAMAddr = 0;;
      /* Step 1: Check Frequency */
      freq_params = AD5940_GetFreqParameters(freq);
      
           if(freq < 0.51)
    	{
    	hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_2;
        hsdac_cfg.HsDacGain = HSDACGAIN_1;
        hsdac_cfg.HsDacUpdateRate = 0x1B;
        AD5940_HSDacCfgS(&hsdac_cfg);
        AD5940_HSRTIACfgS(HSTIARTIA_40K);
        
        /*Update ADC rate */
        filter_cfg.ADCRate = ADCRATE_800KHZ;
        AppBATCfg.AdcClkFreq = 16e6;
        
        /* Change clock to 16MHz oscillator */
        AD5940_HPModeEn(bFALSE);
    	}
            else if(freq < 5 )
    	{
    	hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_2;
        hsdac_cfg.HsDacGain = HSDACGAIN_1;
        hsdac_cfg.HsDacUpdateRate = 0x1B;
        AD5940_HSDacCfgS(&hsdac_cfg);
        AD5940_HSRTIACfgS(HSTIARTIA_40K);
        
        /*Update ADC rate */
        filter_cfg.ADCRate = ADCRATE_800KHZ;
        AppBATCfg.AdcClkFreq = 16e6;
        
        /* Change clock to 16MHz oscillator */
        AD5940_HPModeEn(bFALSE);
        
    	}else if(freq < 450)
    	{
        hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_2;
        hsdac_cfg.HsDacGain = HSDACGAIN_1;
        hsdac_cfg.HsDacUpdateRate = 0x1B;
        AD5940_HSDacCfgS(&hsdac_cfg);
        AD5940_HSRTIACfgS(HSTIARTIA_5K);
        
        /*Update ADC rate */
        filter_cfg.ADCRate = ADCRATE_800KHZ;
        AppBATCfg.AdcClkFreq = 16e6;
        
        /* Change clock to 16MHz oscillator */
        AD5940_HPModeEn(bFALSE);
    	}
           else if(freq<80000)
           {
    	hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_2;
        hsdac_cfg.HsDacGain = HSDACGAIN_1;
        hsdac_cfg.HsDacUpdateRate = 0x1B;
        AD5940_HSDacCfgS(&hsdac_cfg);
        AD5940_HSRTIACfgS(HSTIARTIA_5K);
        
        /*Update ADC rate */
        filter_cfg.ADCRate = ADCRATE_800KHZ;
        AppBATCfg.AdcClkFreq = 16e6;
        
        /* Change clock to 16MHz oscillator */
        AD5940_HPModeEn(bFALSE);
           }
            /* High power mode */
    	if(freq >= 80000)
    	{
    	hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_2;
        hsdac_cfg.HsDacGain = HSDACGAIN_1;
        hsdac_cfg.HsDacUpdateRate = 0x07;
        AD5940_HSDacCfgS(&hsdac_cfg);
        AD5940_HSRTIACfgS(HSTIARTIA_5K);
        
        /*Update ADC rate */
        filter_cfg.ADCRate = ADCRATE_1P6MHZ;
        AppBATCfg.AdcClkFreq = 32e6;
        
        /* Change clock to 32MHz oscillator */
        AD5940_HPModeEn(bTRUE);
    	}
      
      /* Step 2: Adjust ADCFILTERCON and DFTCON to set optimumn SINC3, SINC2 and DFTNUM settings  */
      filter_cfg.ADCAvgNum = ADCAVGNUM_16;  /* Don't care because it's disabled */ 
      filter_cfg.ADCSinc2Osr = freq_params.ADCSinc2Osr;
      filter_cfg.ADCSinc3Osr = freq_params.ADCSinc3Osr;
      filter_cfg.BpSinc3 = bFALSE;
      filter_cfg.BpNotch = bTRUE;
      filter_cfg.Sinc2NotchEnable = bTRUE;
      dft_cfg.DftNum = freq_params.DftNum;
      dft_cfg.DftSrc = freq_params.DftSrc;
      dft_cfg.HanWinEn = AppBATCfg.HanWinEn;
      AD5940_ADCFilterCfgS(&filter_cfg);
      AD5940_DFTCfgS(&dft_cfg);
      
      /* Step 3: Calculate clocks needed to get result to FIFO and update sequencer wait command */
      clks_cal.DataType = DATATYPE_DFT;
      clks_cal.DftSrc = freq_params.DftSrc;
      clks_cal.DataCount = 1L<<(freq_params.DftNum+2); /* 2^(DFTNUMBER+2) */
      clks_cal.ADCSinc2Osr = freq_params.ADCSinc2Osr;
      clks_cal.ADCSinc3Osr = freq_params.ADCSinc3Osr;
      clks_cal.ADCAvgNum = 0;
      clks_cal.RatioSys2AdcClk = AppBATCfg.SysClkFreq/AppBATCfg.AdcClkFreq;
      AD5940_ClksCalculate(&clks_cal, &WaitClks);		
    	
    	
    	  SRAMAddr = AppBATCfg.MeasureSeqInfo.SeqRamAddr + AppBATCfg.SeqWaitAddr[0];
    	   
               SeqCmdBuff[0] =SEQ_WAIT(WaitClks/2);
               SeqCmdBuff[1] =SEQ_WAIT(WaitClks/2);
          
    		AD5940_SEQCmdWrite(SRAMAddr, SeqCmdBuff, 2);
    		
      return AD5940ERR_OK;
    }

    /*AD5940Main.c*/
    #include "ad5940.h"
    #include <stdio.h>
    #include "string.h"
    #include "math.h"
    #include "BATImpedance.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)
    {
      fImpCar_Type *pImp = (fImpCar_Type*)pData;
    	float freq;
    	AppBATCtrl(BATCTRL_GETFREQ, &freq);
      /*Process data*/
      for(int i=0;i<DataCount;i++)
      {
        printf("Freq: %f (real, image) = ,%f , %f ,mOhm \n",freq, pImp[i].Real,pImp[i].Image);
      }
      return 0;
    }
    
    /* Initialize AD5940 basic blocks like clock */
    static int32_t AD5940PlatformCfg(void)
    {
      CLKCfg_Type clk_cfg;
      FIFOCfg_Type fifo_cfg;
      AGPIOCfg_Type gpio_cfg;
      /* Use hardware reset */
      AD5940_HWReset();
      /* Platform configuration */
      AD5940_Initialize();
      /* Step1. Configure clock */
      clk_cfg.ADCClkDiv = ADCCLKDIV_1;
      clk_cfg.ADCCLkSrc = ADCCLKSRC_HFOSC;
      clk_cfg.SysClkDiv = SYSCLKDIV_1;
      clk_cfg.SysClkSrc = SYSCLKSRC_HFOSC; //on battery board, there is a 32MHz crystal.
      clk_cfg.HfOSC32MHzMode = bFALSE;
      clk_cfg.HFOSCEn = bTRUE;
      clk_cfg.HFXTALEn = bFALSE;
      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;//AppBATCfg.FifoThresh;        /* 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_DATAFIFOTHRESH, 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;
      gpio_cfg.InputEnSet = AGPIO_Pin2;
      gpio_cfg.OutputEnSet = AGPIO_Pin0|AGPIO_Pin2;
      gpio_cfg.OutVal = 0;
      gpio_cfg.PullEnSet = 0;
      AD5940_AGPIOCfg(&gpio_cfg);
      AD5940_SleepKeyCtrlS(SLPKEY_UNLOCK);  /* Allow AFE to enter sleep mode. */
      return 0;
    }
    
    void AD5940BATStructInit(void)
    {
      AppBATCfg_Type *pBATCfg;
      AppBATGetCfg(&pBATCfg);
      pBATCfg->SeqStartAddr = 0;
      pBATCfg->MaxSeqLen = 512;
      pBATCfg->RcalVal = 50.0;  							/* Value of RCAL on EVAL-AD5941BATZ board is 50mOhm */
      pBATCfg->ACVoltPP = 300.0f;							/* Pk-pk amplitude is 300mV */
      pBATCfg->DCVolt = 1200.0f;							/* Offset voltage of 1.2V*/
      pBATCfg->DftNum = DFTNUM_8192;
      
      pBATCfg->FifoThresh = 2;      					/* 2 results in FIFO, real and imaginary part. */
    	
    	pBATCfg->SinFreq = 200;									/* Sin wave frequency. THis value has no effect if sweep is enabled */
    	
    	pBATCfg->SweepCfg.SweepEn = bTRUE;			/* Set to bTRUE to enable sweep function */
    	pBATCfg->SweepCfg.SweepStart = 1.0f;		/* Start sweep at 1Hz  */
    	pBATCfg->SweepCfg.SweepStop = 50000.0f;	/* Finish sweep at 1000Hz */
    	pBATCfg->SweepCfg.SweepPoints = 50;			/* 100 frequencies in the sweep */
    	pBATCfg->SweepCfg.SweepLog = bTRUE;			/* Set to bTRUE to use LOG scale. Set bFALSE to use linear scale */
    	
    }
    
    void AD5940_Main(void)
    {
      uint32_t temp;
      AD5940PlatformCfg();
      
      AD5940BATStructInit(); /* Configure your parameters in this function */
      
      AppBATInit(AppBuff, APPBUFF_SIZE);    /* Initialize BAT application. Provide a buffer, which is used to store sequencer commands */
      AppBATCtrl(BATCTRL_MRCAL, 0);     /* Measur RCAL each point in sweep */
    	AppBATCtrl(BATCTRL_START, 0); 
      while(1)
      {
        /* Check if interrupt flag which will be set when interrupt occurred. */
        if(AD5940_GetMCUIntFlag())
        {
    				AD5940_ClrMCUIntFlag(); 				/* Clear this flag */
    				temp = APPBUFF_SIZE;
    				AppBATISR(AppBuff, &temp); 			/* Deal with it and provide a buffer to store data we got */
    				AD5940_Delay10us(100000);
    				BATShowResult(AppBuff, temp);		/* Print measurement results over UART */		
    				AD5940_SEQMmrTrig(SEQID_0);  		/* Trigger next measurement ussing MMR write*/      
       }
      }
    }

    #ifndef _BAT_IMPEDANCE_H_
    #define _BAT_IMPEDANCE_H_
    #include "ad5940.h"
    #include "stdio.h"
    #include "string.h"
    #include "math.h"
    
    #define PRECHARGE_WAIT_MS   4000    //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
    /* 
      Note: this example will use SEQID_0 as measurement sequence, and use SEQID_1 as init sequence. 
      SEQID_3 is used for calibration.
    */
    
    #define STATE_IDLE        0   /**< Initial state. */
    #define STATE_RCAL        1   /**< Measure Rcal response voltage. */
    #define STATE_BATTERY     2   /**< Measure battery response voltage. */
    typedef struct
    {
    /* Common configurations for all kinds of Application. */
      uint32_t state;               /* 0: Init, 1: measure Rcal, 2: Measure Battery. */
      BoolFlag bParaChanged;        /* Indicate to generate sequence again. It's auto cleared by AppBATInit */
      BoolFlag bDoCal;              /* Need to do calibration. */
      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;
    /* Application related parameters */ 
      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 */   
      float BatODR;                 /* in Hz. ODR decides the period of WakeupTimer who will trigger sequencer periodically. DFT number and sample frequency decides the maxim ODR. */
      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 */
      uint32_t SeqWaitAddr[3];    
    /* Sweep Function Control */
      SoftSweepCfg_Type SweepCfg;
    /* Private variables for internal usage */
      float SweepCurrFreq;
      float SweepNextFreq;
      float FreqofData;  
      BoolFlag BATInited;           /* If the program run firstly, generated sequence commands */
      SEQInfo_Type InitSeqInfo;
      SEQInfo_Type MeasureSeqInfo;
      BoolFlag StopRequired;        /* After FIFO is ready, stop the measurement sequence */
      uint32_t FifoDataCount;       /* Count how many times impedance have been measured */
      uint32_t MeasSeqCycleCount;   /* How long the measurement sequence will take */
      float MaxODR;                 /* Max ODR for sampling in this config */
      fImpCar_Type RcalVolt;        /* The measured Rcal resistor(R1) response voltage. */
      float RcalVoltTable[100][2];    
    /* End */
    }AppBATCfg_Type;
    
    #define BATCTRL_START          0
    #define BATCTRL_STOPNOW        1
    #define BATCTRL_STOPSYNC       2
    #define BATCTRL_SHUTDOWN       4   /* Note: shutdown here means turn off everything and put AFE to hibernate mode. The word 'SHUT DOWN' is only used here. */
    #define BATCTRL_MRCAL          5   /* Measure RCAL response voltage */
    #define BATCTRL_GETFREQ				 6
    
    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);
    AD5940Err AppBATCheckFreq(float freq);
    AD5940Err AppBATMeasureRCAL(void);
    
    #endif