Post Go back to editing

is there way to use ad5940 without interrupt or GPIO interrupt pin?

Category: Software
Product Number: ad5940

Hi i want to use AD5940 with our Hardware problem is we have limited IO pins for AD5940 , so we decided to use SPI pins and Chip select for AD5940 ICs, so we are not gonna use external reset from MCU and Interrupt GPIO. i looked at example code and the code is mainly for interrupt controller. so basically looking to use ad5940 without interrupt controller or with interrupt controller but no external GPIO pins. what are the option available and also is there sample code ?

  • Hi,

    We will look into this, I'll contact the product owner and get back to you.

  • Hi,

    One way is :

    Instead of creating sequences and letting GPIO interrupts or timer to run the sequences, you may directly call the functions(initialization and measurement and ISR functions) in AD5940Main.c

    *****************************************************************************
    @file:    AD5940Main.c
    *****************************************************************************/
    
    #include "ad5940.h"
    #include "AD5940.h"
    #include <stdio.h>
    #include "string.h"
    #include "math.h"
    #include "Amperometric.h"
    #include "Impedance.h"
    #include "ADuCM3029.h"
    
    #define APPBUFF_SIZE_IMPEDANCE 512
    uint32_t AppBuffImpedance[APPBUFF_SIZE_IMPEDANCE];
    
     uint64_t counter = 0;
    
    /* Initialize AD5940 basic blocks like clock */
    static int32_t AD5940PlatformCfg(void)
    {
      CLKCfg_Type clk_cfg;
      FIFOCfg_Type fifo_cfg;
      SEQCfg_Type seq_cfg;
      LFOSCMeasure_Type LfoscMeasure;
      /* Use hardware reset */
      AD5940_HWReset();
      AD5940_Initialize();
      /* Platform configuration */
      /* Step1. Configure clock */
      clk_cfg.ADCClkDiv = ADCCLKDIV_1;
      clk_cfg.ADCCLkSrc = ADCCLKSRC_HFOSC;
      clk_cfg.SysClkDiv = SYSCLKDIV_1;
      clk_cfg.SysClkSrc = SYSCLKSRC_HFOSC;
      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;      
      AD5940_FIFOCfg(&fifo_cfg);                             /* Disable to reset FIFO. */
      fifo_cfg.FIFOEn = bTRUE;  
      AD5940_FIFOCfg(&fifo_cfg);                             /* Enable FIFO here */
      /* Configure sequencer and stop it */
      seq_cfg.SeqMemSize = SEQMEMSIZE_2KB;
      seq_cfg.SeqBreakEn = bFALSE;
      seq_cfg.SeqIgnoreEn = bFALSE;
      seq_cfg.SeqCntCRCClr = bTRUE;
      seq_cfg.SeqEnable = bFALSE;
      seq_cfg.SeqWrTimer = 0;
      AD5940_SEQCfg(&seq_cfg);
      
      
      //AD5940_SleepKeyCtrlS(SLPKEY_UNLOCK);  /* Allow AFE to enter sleep mode. */
      /* 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 AD5940AMPStructInit(void)
    {
      AppAMPCfg_Type *pAMPCfg;
      
      AppAMPGetCfg(&pAMPCfg);
      pAMPCfg->WuptClkFreq = LFOSCFreq;
      /* Configure general parameters */
      pAMPCfg->SeqStartAddr = 0;
      pAMPCfg->MaxSeqLen = 512;     /* @todo add checker in function */  
      pAMPCfg->RcalVal = 10000.0;
      pAMPCfg->NumOfData = -1;      /* Never stop until you stop it manually by AppAMPCtrl() function */	
      
      
      /* Configure measurement parameters */
      pAMPCfg->AmpODR = 0.1;          	/* Time between samples in seconds */
      pAMPCfg->FifoThresh = 1;      		/* Number of measurements before alerting host microcontroller */
      
      pAMPCfg->SensorBias = 0.0f;   			/* Sensor bias voltage between reference and sense electrodes*/ 
      pAMPCfg->LptiaRtiaSel = LPTIARTIA_1K;
      pAMPCfg->LpTiaRl = LPTIARLOAD_100R; 
      pAMPCfg->Vzero = 1100;        		/* Vzero voltage. Voltage on Sense electrode. Unit is mV*/
      
      pAMPCfg->ADCRefVolt = 1.82;		/* Measure voltage on Vref_1V8 pin */
    
    }
    
    void AD5940ImpedanceStructInit(void)
    {
      AppIMPCfg_Type *pImpedanceCfg;
      
      AppIMPGetCfg(&pImpedanceCfg);
      /* Step1: configure initialization sequence Info */
      pImpedanceCfg->SeqStartAddr = 0;
      pImpedanceCfg->MaxSeqLen = 512; /* @todo add checker in function */
      
      pImpedanceCfg->RcalVal = 10000.0;
      pImpedanceCfg->SinFreq = 6000.0;
      pImpedanceCfg->FifoThresh = 2;
      
      pImpedanceCfg->DacVoltPP = 100.0;	/* Maximum value is 600mV*/
      pImpedanceCfg->ExcitBufGain = EXCITBUFGAIN_2;
      pImpedanceCfg->HsDacGain = HSDACGAIN_1;
      
      /* Set switch matrix to onboard(EVAL-AD5940ELECZ) dummy sensor. */
      /* Note the RCAL0 resistor is 10kOhm. */
      pImpedanceCfg->DswitchSel = SWD_CE0;
      pImpedanceCfg->PswitchSel = SWP_RE0;
      pImpedanceCfg->NswitchSel = SWN_SE0;
      pImpedanceCfg->TswitchSel = SWT_SE0LOAD;
      /* The dummy sensor is as low as 5kOhm. We need to make sure RTIA is small enough that HSTIA won't be saturated. */
      pImpedanceCfg->HstiaRtiaSel = HSTIARTIA_40K;	/* #RFMOD increased from HSTIARTIA_5K to HSTIARTIA_40K */
      pImpedanceCfg->BiasVolt = 150.0; /* Bias Voltage in mV*/ /* #RFMOD initialized to zero bias */
    	pImpedanceCfg->DacVoltPP = 40.0;
      pImpedanceCfg->Vzero = 1100; /* Set voltage on SE0 pin. Unit is mV */
      
      /* Configure the sweep function. */
      pImpedanceCfg->SweepCfg.SweepEn = bTRUE;
      pImpedanceCfg->SweepCfg.SweepStart = 100.0f;	/* Start from 1kHz */
      pImpedanceCfg->SweepCfg.SweepStop = 100e3f;		/* Stop at 100kHz */
      pImpedanceCfg->SweepCfg.SweepPoints = 201;		/* Points is 101 */
      pImpedanceCfg->SweepCfg.SweepLog = bFALSE;
      pImpedanceCfg->SweepCfg.SweepCustom = bTRUE; /* Default Sweep */
      /* Configure Power Mode. Use HP mode if frequency is higher than 80kHz. */
      pImpedanceCfg->PwrMod = AFEPWR_HP;
      /* Configure filters if necessary */
      pImpedanceCfg->ADCSinc3Osr = ADCSINC3OSR_2;		/* Sample rate is 800kSPS/2 = 400kSPS */ /*#RFMOD changed from ADCSINC3OSR_4 to ADCSINC3OSR_2*/
    	pImpedanceCfg->AdcPgaGain = ADCPGA_1P5; /*#RFMOD same as default. Just re-initialized here.*/
      //pImpedanceCfg->DftNum = DFTNUM_16384;
    	pImpedanceCfg->DftNum = DFTNUM_4096;
      pImpedanceCfg->DftSrc = DFTSRC_SINC3;
      
     }
    
     int32_t ImpedanceShowResult(uint32_t *pData, uint32_t DataCount, uint64_t Counter)
    {
      float freq;
      int index=0;
      fImpPol_Type *pImp = (fImpPol_Type*)pData;
      AppIMPCtrl(IMPCTRL_GETFREQ, &freq);
    	
    	{
    		//printf("\n-------------------------- CURRENT STATE --------------------------------\n");
    		//  printf("%d,%d,%s,%f,",Counter,(int)rawtime,ctime(&rawtime),freq);
    		printf("%lld,%f,",Counter,freq);
    		/*Process data*/
    		for(int i=0;i<DataCount;i++)
    		{
    			printf("%f,%f,%d,%d,%d,1\n",pImp[i].Magnitude,pImp[i].Phase*180/MATH_PI,pImp[i].Real,pImp[i].Image,i+1);
    		}
    		//printf("\n-------------------------------------------------------------------------\n");
      }
      return 0;
    }
    
    static AD5940Err AppIMPMeasureGen(void)
    {
      AD5940Err error = AD5940ERR_OK;
    
      uint32_t WaitClks;
      ClksCalInfo_Type clks_cal;
    
      clks_cal.DataType = DATATYPE_DFT;
      clks_cal.DftSrc = AppIMPCfg.DftSrc;
      clks_cal.DataCount = 1L<<(AppIMPCfg.DftNum+2); /* 2^(DFTNUMBER+2) */
      clks_cal.ADCSinc2Osr = AppIMPCfg.ADCSinc2Osr;
      clks_cal.ADCSinc3Osr = AppIMPCfg.ADCSinc3Osr;
      clks_cal.ADCAvgNum = AppIMPCfg.ADCAvgNum;
      clks_cal.RatioSys2AdcClk = AppIMPCfg.SysClkFreq/AppIMPCfg.AdcClkFreq;
      AD5940_ClksCalculate(&clks_cal, &WaitClks);	
      
      /* Measure Impedance */
      AD5940_WriteReg(REG_AFE_SWCON, (0x5<<BITP_AFE_SWCON_DMUXCON)|(5<<BITP_AFE_SWCON_PMUXCON)\
        |(0x9<<BITP_AFE_SWCON_NMUXCON)|(0x5<<BITP_AFE_SWCON_TMUXCON)|\
          BITM_AFE_SWCON_T9CON);
      
      AD5940_AFECtrlS(AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\
        AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\
          AFECTRL_SINC2NOTCH|AFECTRL_DCBUFPWR, bTRUE);
      AD5940_AFECtrlS(AFECTRL_ADCPWR|AFECTRL_SINC2NOTCH, bTRUE);  /* Enable Waveform generator */
    
    	/* Delay for ADC power up */
    	AD5940_Delay10us(16*250*100000);
      AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_ADCPWR|AFECTRL_DFT, bTRUE);  /* Start ADC convert and DFT */
      /* Wait for ADC and DFT to finish converting samples */
      AD5940_Delay10us(WaitClks* (AppIMPCfg.AdcClkFreq/AppIMPCfg.SysClkFreq)*100000);
      AD5940_AFECtrlS(AFECTRL_ADCPWR|AFECTRL_ADCCNV|AFECTRL_DFT|AFECTRL_SINC2NOTCH/*|AFECTRL_WG*/, bFALSE);  /* Stop ADC convert and DFT */
      return AD5940ERR_OK;
    }
    
     void AD5940_Main(void)
    {
    
    AD5940PlatformCfg();
    AD5940ImpedanceStructInit();
    AppIMPMeasureGen();
    AD5940_ClrMCUIntFlag(); /* Clear this flag */
    ImpedanceShowResult(AppBuffImpedance, temp,++counter);
    
    } // GPIOs, Timers and sequences are not used anywhere

  • Hi John, 

    did you make it work or are you still working on this? I have the same problem. I would appreciate it if you could contact me. 

    Regards 

    Toni

  • Hi,

    You will have to add 

    AppIMPDataProcess((int32_t*)pBuff,&FifoCnt); 

    function inside AD5940_Main() before 

    ImpedanceShowResult(AppBuffImpedance, temp,++counter); function.

    /* Depending on the data type, do appropriate data pre-process before return back to controller */
    int32_t AppIMPDataProcess(int32_t * const pData, uint32_t *pDataCount)
    {
      uint32_t DataCount = *pDataCount;
      uint32_t ImpResCount = DataCount/4;
    
      fImpPol_Type * const pOut = (fImpPol_Type*)pData;
      iImpCar_Type * pSrcData = (iImpCar_Type*)pData;
    
      *pDataCount = 0;
    
      DataCount = (DataCount/4)*4;/* We expect RCAL data together with Rz data. One DFT result has two data in FIFO, real part and imaginary part.  */
    
      /* Convert DFT result to int32_t type */
      for(uint32_t i=0; i<DataCount; i++)
      {
        pData[i] &= 0x3ffff; /* @todo option to check ECC */
        if(pData[i]&(1L<<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<ImpResCount; i++)
      {
        iImpCar_Type *pDftRcal, *pDftRz;
    
        pDftRcal = pSrcData++;
        pDftRz = pSrcData++;
        float RzMag,RzPhase;
        float RcalMag, RcalPhase;
        
        RcalMag = sqrt((float)pDftRcal->Real*pDftRcal->Real+(float)pDftRcal->Image*pDftRcal->Image);
        RcalPhase = atan2(-pDftRcal->Image,pDftRcal->Real);
        RzMag = sqrt((float)pDftRz->Real*pDftRz->Real+(float)pDftRz->Image*pDftRz->Image);
        RzPhase = atan2(-pDftRz->Image,pDftRz->Real);
    
        RzMag = RcalMag/RzMag*AppIMPCfg.RcalVal;
        RzPhase = RcalPhase - RzPhase;
        //printf("V:%d,%d,I:%d,%d ",pDftRcal->Real,pDftRcal->Image, pDftRz->Real, pDftRz->Image);
        
        pOut[i].Magnitude = RzMag;
        pOut[i].Phase = RzPhase;
      }
      *pDataCount = ImpResCount; 
      AppIMPCfg.FreqofData = AppIMPCfg.SweepCurrFreq;
      /* Calculate next frequency point */
      if(AppIMPCfg.SweepCfg.SweepEn == bTRUE)
      {
        AppIMPCfg.FreqofData = AppIMPCfg.SweepCurrFreq;
        AppIMPCfg.SweepCurrFreq = AppIMPCfg.SweepNextFreq;
        AD5940_SweepNext(&AppIMPCfg.SweepCfg, &AppIMPCfg.SweepNextFreq);
      }
    
      return 0;
    }

    Output data is stored in pOut[].

  • Hi,

    How do I set waveform parameters in this, like amplitude & frequency in this example? Also, don't I need to configure AFE, HS Loop, DSP block as in other examples?