diff --git a/CMakeLists.txt b/CMakeLists.txt index 674e000..bcdd42b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ pico_sdk_init() add_executable(EIS main.c ad5940.c + Impedance.c ) target_compile_definitions(EIS PRIVATE CHIPSEL_594X) diff --git a/Impedance.c b/Impedance.c new file mode 100644 index 0000000..fd1b1fc --- /dev/null +++ b/Impedance.c @@ -0,0 +1,669 @@ +// File: Impedance.c +#include "ad5940.h" +#include +#include "string.h" +#include "math.h" +#include "Impedance.h" + +/* Default LPDAC resolution(2.5V internal reference). */ +#define DAC12BITVOLT_1LSB (2200.0f/4095) //mV +#define DAC6BITVOLT_1LSB (DAC12BITVOLT_1LSB*64) //mV + +AppIMPCfg_Type AppIMPCfg = +{ + .bParaChanged = bFALSE, + .SeqStartAddr = 0, + .MaxSeqLen = 0, + + .SeqStartAddrCal = 0, + .MaxSeqLenCal = 0, + + .ImpODR = 20.0, /* 20.0 Hz = 50ms period */ + .NumOfData = -1, + .SysClkFreq = 16000000.0, + .WuptClkFreq = 32000.0, + .AdcClkFreq = 16000000.0, + .RcalVal = 10000.0, + .RtiaVal = 200.0, + + .DswitchSel = SWD_CE0, + .PswitchSel = SWP_CE0, + .NswitchSel = SWN_SE0, + .TswitchSel = SWT_TRTIA, + + .PwrMod = AFEPWR_HP, + + .HstiaRtiaSel = HSTIARTIA_200, + .ExtRtia = 0, + .ExcitBufGain = EXCITBUFGAIN_0P25, + .HsDacGain = HSDACGAIN_0P2, + .HsDacUpdateRate = 7, + .DacVoltPP = 600.0, + .BiasVolt = -0.0f, + + .SinFreq = 1000.0, + + .DftNum = DFTNUM_16384, + .DftSrc = DFTSRC_SINC3, + .HanWinEn = bTRUE, + + .AdcPgaGain = ADCPGA_1P5, + .ADCSinc3Osr = ADCSINC3OSR_2, + .ADCSinc2Osr = ADCSINC2OSR_22, + + .ADCAvgNum = ADCAVGNUM_16, + + .SweepCfg.SweepEn = bTRUE, + .SweepCfg.SweepStart = 1000, + .SweepCfg.SweepStop = 100000.0, + .SweepCfg.SweepPoints = 101, + .SweepCfg.SweepLog = bFALSE, + .SweepCfg.SweepIndex = 0, + + .FifoThresh = 6, /* 3 measurements * 2 (Real/Imag) = 6 words */ + .IMPInited = bFALSE, + .StopRequired = bFALSE, +}; + +int32_t AppIMPGetCfg(void *pCfg) +{ + if(pCfg) + { + *(AppIMPCfg_Type**)pCfg = &AppIMPCfg; + return AD5940ERR_OK; + } + return AD5940ERR_PARA; +} + +int32_t AppIMPCtrl(uint32_t Command, void *pPara) +{ + switch (Command) + { + case IMPCTRL_START: + { + WUPTCfg_Type wupt_cfg; + if(AD5940_WakeUp(10) > 10) return AD5940ERR_WAKEUP; + if(AppIMPCfg.IMPInited == bFALSE) return AD5940ERR_APPERROR; + + wupt_cfg.WuptEn = bTRUE; + wupt_cfg.WuptEndSeq = WUPTENDSEQ_A; + wupt_cfg.WuptOrder[0] = SEQID_0; + wupt_cfg.SeqxSleepTime[SEQID_0] = 4; + + // Calculate Wakeup Time based on ODR + // 32kHz clock. For 20Hz: 32000/20 = 1600 ticks. + uint32_t wait_cycles = (uint32_t)(AppIMPCfg.WuptClkFreq/AppIMPCfg.ImpODR); + if(wait_cycles < 20) wait_cycles = 20; // Minimum safety guard + wupt_cfg.SeqxWakeupTime[SEQID_0] = wait_cycles - 4; + + AD5940_WUPTCfg(&wupt_cfg); + + AppIMPCfg.FifoDataCount = 0; + break; + } + case IMPCTRL_STOPNOW: + { + if(AD5940_WakeUp(10) > 10) return AD5940ERR_WAKEUP; + AD5940_WUPTCtrl(bFALSE); + AD5940_WUPTCtrl(bFALSE); + AD5940_SEQCtrlS(bFALSE); + break; + } + case IMPCTRL_STOPSYNC: + { + AppIMPCfg.StopRequired = bTRUE; + break; + } + case IMPCTRL_GETFREQ: + { + if(pPara == 0) return AD5940ERR_PARA; + if(AppIMPCfg.SweepCfg.SweepEn == bTRUE) + *(float*)pPara = AppIMPCfg.FreqofData; + else + *(float*)pPara = AppIMPCfg.SinFreq; + break; + } + case IMPCTRL_SHUTDOWN: + { + AppIMPCtrl(IMPCTRL_STOPNOW, 0); + 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(); + break; + } + default: + break; + } + return AD5940ERR_OK; +} + +float AppIMPGetCurrFreq(void) +{ + if(AppIMPCfg.SweepCfg.SweepEn == bTRUE) + return AppIMPCfg.FreqofData; + else + return AppIMPCfg.SinFreq; +} + +static AD5940Err AppIMPSeqCfgGen(void) +{ + AD5940Err error = AD5940ERR_OK; + const uint32_t *pSeqCmd; + uint32_t SeqLen; + AFERefCfg_Type aferef_cfg; + HSLoopCfg_Type HsLoopCfg; + DSPCfg_Type dsp_cfg; + float sin_freq; + + AD5940_SEQGenCtrl(bTRUE); + AD5940_AFECtrlS(AFECTRL_ALL, bFALSE); + + 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; + aferef_cfg.LpBandgapEn = bTRUE; + aferef_cfg.LpRefBufEn = bTRUE; + aferef_cfg.LpRefBoostEn = bFALSE; + AD5940_REFCfgS(&aferef_cfg); + + HsLoopCfg.HsDacCfg.ExcitBufGain = AppIMPCfg.ExcitBufGain; + HsLoopCfg.HsDacCfg.HsDacGain = AppIMPCfg.HsDacGain; + HsLoopCfg.HsDacCfg.HsDacUpdateRate = AppIMPCfg.HsDacUpdateRate; + + HsLoopCfg.HsTiaCfg.DiodeClose = bFALSE; + HsLoopCfg.HsTiaCfg.HstiaBias = HSTIABIAS_1P1; + HsLoopCfg.HsTiaCfg.HstiaCtia = 31; + HsLoopCfg.HsTiaCfg.HstiaDeRload = HSTIADERLOAD_OPEN; + HsLoopCfg.HsTiaCfg.HstiaDeRtia = HSTIADERTIA_OPEN; + HsLoopCfg.HsTiaCfg.HstiaRtiaSel = AppIMPCfg.HstiaRtiaSel; + HsLoopCfg.HsTiaCfg.ExtRtia = AppIMPCfg.ExtRtia; + + HsLoopCfg.SWMatCfg.Dswitch = AppIMPCfg.DswitchSel; + HsLoopCfg.SWMatCfg.Pswitch = AppIMPCfg.PswitchSel; + HsLoopCfg.SWMatCfg.Nswitch = AppIMPCfg.NswitchSel; + HsLoopCfg.SWMatCfg.Tswitch = SWT_TRTIA|AppIMPCfg.TswitchSel; + + HsLoopCfg.WgCfg.WgType = WGTYPE_SIN; + HsLoopCfg.WgCfg.GainCalEn = bTRUE; + HsLoopCfg.WgCfg.OffsetCalEn = bTRUE; + + if(AppIMPCfg.SweepCfg.SweepEn == bTRUE) + { + AppIMPCfg.FreqofData = AppIMPCfg.SweepCfg.SweepStart; + AppIMPCfg.SweepCurrFreq = AppIMPCfg.SweepCfg.SweepStart; + AD5940_SweepNext(&AppIMPCfg.SweepCfg, &AppIMPCfg.SweepNextFreq); + sin_freq = AppIMPCfg.SweepCurrFreq; + } + else + { + sin_freq = AppIMPCfg.SinFreq; + AppIMPCfg.FreqofData = sin_freq; + } + + HsLoopCfg.WgCfg.SinCfg.SinFreqWord = AD5940_WGFreqWordCal(sin_freq, AppIMPCfg.SysClkFreq); + HsLoopCfg.WgCfg.SinCfg.SinAmplitudeWord = (uint32_t)(AppIMPCfg.DacVoltPP/800.0f*2047 + 0.5f); + HsLoopCfg.WgCfg.SinCfg.SinOffsetWord = 0; + HsLoopCfg.WgCfg.SinCfg.SinPhaseWord = 0; + AD5940_HSLoopCfgS(&HsLoopCfg); + + dsp_cfg.ADCBaseCfg.ADCMuxN = ADCMUXN_HSTIA_N; + dsp_cfg.ADCBaseCfg.ADCMuxP = ADCMUXP_HSTIA_P; + dsp_cfg.ADCBaseCfg.ADCPga = AppIMPCfg.AdcPgaGain; + + memset(&dsp_cfg.ADCDigCompCfg, 0, sizeof(dsp_cfg.ADCDigCompCfg)); + + dsp_cfg.ADCFilterCfg.ADCAvgNum = AppIMPCfg.ADCAvgNum; + dsp_cfg.ADCFilterCfg.ADCRate = ADCRATE_800KHZ; + dsp_cfg.ADCFilterCfg.ADCSinc2Osr = AppIMPCfg.ADCSinc2Osr; + dsp_cfg.ADCFilterCfg.ADCSinc3Osr = AppIMPCfg.ADCSinc3Osr; + dsp_cfg.ADCFilterCfg.BpNotch = bTRUE; + dsp_cfg.ADCFilterCfg.BpSinc3 = bFALSE; + dsp_cfg.ADCFilterCfg.Sinc2NotchEnable = bTRUE; + dsp_cfg.DftCfg.DftNum = AppIMPCfg.DftNum; + dsp_cfg.DftCfg.DftSrc = AppIMPCfg.DftSrc; + dsp_cfg.DftCfg.HanWinEn = AppIMPCfg.HanWinEn; + + memset(&dsp_cfg.StatCfg, 0, sizeof(dsp_cfg.StatCfg)); + AD5940_DSPCfgS(&dsp_cfg); + + AD5940_AFECtrlS(AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\ + AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\ + AFECTRL_SINC2NOTCH, bTRUE); + + AD5940_SEQGenInsert(SEQ_STOP()); + + error = AD5940_SEQGenFetchSeq(&pSeqCmd, &SeqLen); + AD5940_SEQGenCtrl(bFALSE); + if(error == AD5940ERR_OK) + { + AppIMPCfg.InitSeqInfo.SeqId = SEQID_1; + AppIMPCfg.InitSeqInfo.SeqRamAddr = AppIMPCfg.SeqStartAddr; + AppIMPCfg.InitSeqInfo.pSeqCmd = pSeqCmd; + AppIMPCfg.InitSeqInfo.SeqLen = SeqLen; + AD5940_SEQCmdWrite(AppIMPCfg.InitSeqInfo.SeqRamAddr, pSeqCmd, SeqLen); + } + else + return error; + return AD5940ERR_OK; +} + +static AD5940Err AppIMPSeqMeasureGen(void) +{ + AD5940Err error = AD5940ERR_OK; + const uint32_t *pSeqCmd; + uint32_t SeqLen; + uint32_t WaitClks; + SWMatrixCfg_Type sw_cfg; + ClksCalInfo_Type clks_cal; + + clks_cal.DataType = DATATYPE_DFT; + clks_cal.DftSrc = AppIMPCfg.DftSrc; + clks_cal.DataCount = 1L<<(AppIMPCfg.DftNum+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); + + AD5940_SEQGenCtrl(bTRUE); + AD5940_SEQGpioCtrlS(AGPIO_Pin2); + AD5940_SEQGenInsert(SEQ_WAIT(16*250)); + + /* ----------------------------------------------------------------------- */ + /* Measurement 1: RCAL (Current) */ + /* ----------------------------------------------------------------------- */ + sw_cfg.Dswitch = SWD_RCAL0; + sw_cfg.Pswitch = SWP_RCAL0; + sw_cfg.Nswitch = SWN_RCAL1; + sw_cfg.Tswitch = SWT_RCAL1|SWT_TRTIA; + AD5940_SWMatrixCfgS(&sw_cfg); + + /* ADC Mux for Current (HSTIA) */ + AD5940_ADCMuxCfgS(ADCMUXP_HSTIA_P, ADCMUXN_HSTIA_N); + + AD5940_AFECtrlS(AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\ + AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\ + AFECTRL_SINC2NOTCH, bTRUE); + AD5940_AFECtrlS(AFECTRL_WG|AFECTRL_ADCPWR, bTRUE); + AD5940_SEQGenInsert(SEQ_WAIT(16*10)); // Settling + AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT, bTRUE); + + AD5940_SEQGenFetchSeq(NULL, &AppIMPCfg.SeqWaitAddr[0]); + AD5940_SEQGenInsert(SEQ_WAIT(WaitClks/2)); + AD5940_SEQGenInsert(SEQ_WAIT(WaitClks/2)); + + AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT|AFECTRL_WG, bFALSE); + + /* ----------------------------------------------------------------------- */ + /* Measurement 2: Sensor Current (I) */ + /* ----------------------------------------------------------------------- */ + sw_cfg.Dswitch = AppIMPCfg.DswitchSel; + sw_cfg.Pswitch = AppIMPCfg.PswitchSel; + sw_cfg.Nswitch = AppIMPCfg.NswitchSel; + sw_cfg.Tswitch = SWT_TRTIA|AppIMPCfg.TswitchSel; + AD5940_SWMatrixCfgS(&sw_cfg); + + /* ADC Mux for Current (HSTIA) */ + AD5940_ADCMuxCfgS(ADCMUXP_HSTIA_P, ADCMUXN_HSTIA_N); + + AD5940_AFECtrlS(AFECTRL_ADCPWR|AFECTRL_WG, bTRUE); + AD5940_SEQGenInsert(SEQ_WAIT(16*10)); + AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT, bTRUE); + + AD5940_SEQGenFetchSeq(NULL, &AppIMPCfg.SeqWaitAddr[1]); + AD5940_SEQGenInsert(SEQ_WAIT(WaitClks/2)); + AD5940_SEQGenInsert(SEQ_WAIT(WaitClks/2)); + + AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT|AFECTRL_WG, bFALSE); + + /* ----------------------------------------------------------------------- */ + /* Measurement 3: Sensor Voltage (V) */ + /* ----------------------------------------------------------------------- */ + /* Switches remain same (Force path active) */ + + /* ADC Mux for Voltage (AIN2/AIN3) */ + AD5940_ADCMuxCfgS(ADCMUXP_AIN2, ADCMUXN_AIN3); + + AD5940_AFECtrlS(AFECTRL_ADCPWR|AFECTRL_WG, bTRUE); + AD5940_SEQGenInsert(SEQ_WAIT(16*10)); + AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT, bTRUE); + + AD5940_SEQGenFetchSeq(NULL, &AppIMPCfg.SeqWaitAddr[2]); + AD5940_SEQGenInsert(SEQ_WAIT(WaitClks/2)); + AD5940_SEQGenInsert(SEQ_WAIT(WaitClks/2)); + + AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT|AFECTRL_WG|AFECTRL_ADCPWR, bFALSE); + AD5940_AFECtrlS(AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\ + AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\ + AFECTRL_SINC2NOTCH, bFALSE); + AD5940_SEQGpioCtrlS(0); + + AD5940_EnterSleepS(); + + error = AD5940_SEQGenFetchSeq(&pSeqCmd, &SeqLen); + AD5940_SEQGenCtrl(bFALSE); + + if(error == AD5940ERR_OK) + { + AppIMPCfg.MeasureSeqInfo.SeqId = SEQID_0; + AppIMPCfg.MeasureSeqInfo.SeqRamAddr = AppIMPCfg.InitSeqInfo.SeqRamAddr + AppIMPCfg.InitSeqInfo.SeqLen ; + AppIMPCfg.MeasureSeqInfo.pSeqCmd = pSeqCmd; + AppIMPCfg.MeasureSeqInfo.SeqLen = SeqLen; + AD5940_SEQCmdWrite(AppIMPCfg.MeasureSeqInfo.SeqRamAddr, pSeqCmd, SeqLen); + } + else + return error; + return AD5940ERR_OK; +} + +AD5940Err AppIMPCheckFreq(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; + + 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); + filter_cfg.ADCRate = ADCRATE_800KHZ; + AppIMPCfg.AdcClkFreq = 16e6; + 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); + filter_cfg.ADCRate = ADCRATE_800KHZ; + AppIMPCfg.AdcClkFreq = 16e6; + AD5940_HPModeEn(bFALSE); + } + else if(freq < 450) + { + hsdac_cfg.ExcitBufGain = AppIMPCfg.ExcitBufGain; + hsdac_cfg.HsDacGain = AppIMPCfg.HsDacGain; + hsdac_cfg.HsDacUpdateRate = 0x1B; + AD5940_HSDacCfgS(&hsdac_cfg); + AD5940_HSRTIACfgS(HSTIARTIA_5K); + filter_cfg.ADCRate = ADCRATE_800KHZ; + AppIMPCfg.AdcClkFreq = 16e6; + AD5940_HPModeEn(bFALSE); + } + else if(freq<80000) + { + hsdac_cfg.ExcitBufGain = AppIMPCfg.ExcitBufGain; + hsdac_cfg.HsDacGain = AppIMPCfg.HsDacGain; + hsdac_cfg.HsDacUpdateRate = 0x1B; + AD5940_HSDacCfgS(&hsdac_cfg); + AD5940_HSRTIACfgS(HSTIARTIA_5K); + filter_cfg.ADCRate = ADCRATE_800KHZ; + AppIMPCfg.AdcClkFreq = 16e6; + AD5940_HPModeEn(bFALSE); + } + if(freq >= 80000) + { + hsdac_cfg.ExcitBufGain = AppIMPCfg.ExcitBufGain; + hsdac_cfg.HsDacGain = AppIMPCfg.HsDacGain; + hsdac_cfg.HsDacUpdateRate = 0x07; + AD5940_HSDacCfgS(&hsdac_cfg); + AD5940_HSRTIACfgS(HSTIARTIA_5K); + filter_cfg.ADCRate = ADCRATE_1P6MHZ; + AppIMPCfg.AdcClkFreq = 32e6; + AD5940_HPModeEn(bTRUE); + } + + filter_cfg.ADCAvgNum = ADCAVGNUM_16; + 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 = AppIMPCfg.HanWinEn; + AD5940_ADCFilterCfgS(&filter_cfg); + AD5940_DFTCfgS(&dft_cfg); + + clks_cal.DataType = DATATYPE_DFT; + clks_cal.DftSrc = freq_params.DftSrc; + clks_cal.DataCount = 1L<<(freq_params.DftNum+2); + clks_cal.ADCSinc2Osr = freq_params.ADCSinc2Osr; + clks_cal.ADCSinc3Osr = freq_params.ADCSinc3Osr; + clks_cal.ADCAvgNum = 0; + clks_cal.RatioSys2AdcClk = AppIMPCfg.SysClkFreq/AppIMPCfg.AdcClkFreq; + AD5940_ClksCalculate(&clks_cal, &WaitClks); + + // Update Wait Times for all 3 measurements + for (int i = 0; i < 3; i++) { + SRAMAddr = AppIMPCfg.MeasureSeqInfo.SeqRamAddr + AppIMPCfg.SeqWaitAddr[i]; + SeqCmdBuff[0] = SEQ_WAIT(WaitClks/2); + SeqCmdBuff[1] = SEQ_WAIT(WaitClks/2); + AD5940_SEQCmdWrite(SRAMAddr, SeqCmdBuff, 2); + } + + return AD5940ERR_OK; +} + +int32_t AppIMPInit(uint32_t *pBuffer, uint32_t BufferSize) +{ + AD5940Err error = AD5940ERR_OK; + SEQCfg_Type seq_cfg; + FIFOCfg_Type fifo_cfg; + + if(AD5940_WakeUp(10) > 10) return AD5940ERR_WAKEUP; + + // CRITICAL: Stop WUPT and Sequencer before reconfiguration + AD5940_WUPTCtrl(bFALSE); + AD5940_SEQCtrlS(bFALSE); + + seq_cfg.SeqMemSize = SEQMEMSIZE_2KB; + seq_cfg.SeqBreakEn = bFALSE; + seq_cfg.SeqIgnoreEn = bTRUE; + seq_cfg.SeqCntCRCClr = bTRUE; + seq_cfg.SeqEnable = bFALSE; + seq_cfg.SeqWrTimer = 0; + AD5940_SEQCfg(&seq_cfg); + + AD5940_FIFOCtrlS(FIFOSRC_DFT, bFALSE); + fifo_cfg.FIFOEn = bTRUE; + fifo_cfg.FIFOMode = FIFOMODE_FIFO; + fifo_cfg.FIFOSize = FIFOSIZE_4KB; + fifo_cfg.FIFOSrc = FIFOSRC_DFT; + fifo_cfg.FIFOThresh = AppIMPCfg.FifoThresh; + AD5940_FIFOCfg(&fifo_cfg); + AD5940_INTCClrFlag(AFEINTSRC_ALLINT); + + if((AppIMPCfg.IMPInited == bFALSE)||(AppIMPCfg.bParaChanged == bTRUE)) + { + if(pBuffer == 0) return AD5940ERR_PARA; + if(BufferSize == 0) return AD5940ERR_PARA; + AD5940_SEQGenInit(pBuffer, BufferSize); + + error = AppIMPSeqCfgGen(); + if(error != AD5940ERR_OK) return error; + + error = AppIMPSeqMeasureGen(); + if(error != AD5940ERR_OK) return error; + + AppIMPCfg.bParaChanged = bFALSE; + } + + AppIMPCfg.InitSeqInfo.WriteSRAM = bFALSE; + AD5940_SEQInfoCfg(&AppIMPCfg.InitSeqInfo); + seq_cfg.SeqEnable = bTRUE; + AD5940_SEQCfg(&seq_cfg); + AD5940_SEQMmrTrig(AppIMPCfg.InitSeqInfo.SeqId); + + // Safety timeout for Init Sequence + int timeout = 100000; + while(AD5940_INTCTestFlag(AFEINTC_1, AFEINTSRC_ENDSEQ) == bFALSE) { + if(--timeout <= 0) { + return AD5940ERR_TIMEOUT; // Return error if init fails + } + } + AD5940_INTCClrFlag(AFEINTSRC_ALLINT); + + AppIMPCfg.MeasureSeqInfo.WriteSRAM = bFALSE; + AD5940_SEQInfoCfg(&AppIMPCfg.MeasureSeqInfo); + + AppIMPCheckFreq(AppIMPCfg.FreqofData); + + seq_cfg.SeqEnable = bTRUE; + AD5940_SEQCfg(&seq_cfg); + AD5940_ClrMCUIntFlag(); + + AppIMPCfg.IMPInited = bTRUE; + return AD5940ERR_OK; +} + +int32_t AppIMPRegModify(int32_t * const pData, uint32_t *pDataCount) +{ + if(AppIMPCfg.NumOfData > 0) + { + AppIMPCfg.FifoDataCount += *pDataCount/6; // 6 words per point + if(AppIMPCfg.FifoDataCount >= AppIMPCfg.NumOfData) + { + AD5940_WUPTCtrl(bFALSE); + return AD5940ERR_OK; + } + } + if(AppIMPCfg.StopRequired == bTRUE) + { + AD5940_WUPTCtrl(bFALSE); + return AD5940ERR_OK; + } + if(AppIMPCfg.SweepCfg.SweepEn) + { + AD5940_WGFreqCtrlS(AppIMPCfg.SweepNextFreq, AppIMPCfg.SysClkFreq); + AppIMPCheckFreq(AppIMPCfg.SweepNextFreq); + } + return AD5940ERR_OK; +} + +int32_t AppIMPDataProcess(int32_t * const pData, uint32_t *pDataCount) +{ + uint32_t DataCount = *pDataCount; + uint32_t ImpResCount = DataCount/6; // 3 measurements * 2 words + + fImpPol_Type * const pOut = (fImpPol_Type*)pData; + iImpCar_Type * pSrcData = (iImpCar_Type*)pData; + + *pDataCount = 0; + + for(uint32_t i=0; iReal*pDftI->Real + (float)pDftI->Image*pDftI->Image); + PhaseI = atan2(-pDftI->Image, pDftI->Real); + + // Calculate Magnitude and Phase for Voltage (V) + MagV = sqrt((float)pDftV->Real*pDftV->Real + (float)pDftV->Image*pDftV->Image); + PhaseV = atan2(-pDftV->Image, pDftV->Real); + + // Z = V / I * Rtia + if(MagI > 1e-9) // Avoid division by zero + ZMag = (MagV / MagI) * AppIMPCfg.RtiaVal; + else + ZMag = 0; + + ZPhase = PhaseV - PhaseI; + + // Normalize Phase to -PI to +PI + while(ZPhase > MATH_PI) ZPhase -= 2*MATH_PI; + while(ZPhase < -MATH_PI) ZPhase += 2*MATH_PI; + + pOut[i].Magnitude = ZMag; + pOut[i].Phase = ZPhase; + } + *pDataCount = ImpResCount; + AppIMPCfg.FreqofData = AppIMPCfg.SweepCurrFreq; + + if(AppIMPCfg.SweepCfg.SweepEn == bTRUE) + { + AppIMPCfg.FreqofData = AppIMPCfg.SweepCurrFreq; + AppIMPCfg.SweepCurrFreq = AppIMPCfg.SweepNextFreq; + AD5940_SweepNext(&AppIMPCfg.SweepCfg, &AppIMPCfg.SweepNextFreq); + } + + return 0; +} + +int32_t AppIMPISR(void *pBuff, uint32_t *pCount) +{ + uint32_t BuffCount; + uint32_t FifoCnt; + BuffCount = *pCount; + + *pCount = 0; + + if(AD5940_WakeUp(10) > 10) return AD5940ERR_WAKEUP; + AD5940_SleepKeyCtrlS(SLPKEY_LOCK); + + if(AD5940_INTCTestFlag(AFEINTC_0, AFEINTSRC_DATAFIFOTHRESH) == bTRUE) + { + FifoCnt = (AD5940_FIFOGetCnt()/6)*6; // Align to 6 words + + if (FifoCnt == 0) { + // Safety: If interrupt fired but no data, clear flag and exit + AD5940_INTCClrFlag(AFEINTSRC_DATAFIFOTHRESH); + AD5940_SleepKeyCtrlS(SLPKEY_UNLOCK); + return 0; + } + + if(FifoCnt > BuffCount) + { + FifoCnt = BuffCount; + } + AD5940_FIFORd((uint32_t *)pBuff, FifoCnt); + AD5940_INTCClrFlag(AFEINTSRC_DATAFIFOTHRESH); + AppIMPRegModify(pBuff, &FifoCnt); + AD5940_SleepKeyCtrlS(SLPKEY_UNLOCK); + AppIMPDataProcess((int32_t*)pBuff, &FifoCnt); + *pCount = FifoCnt; + return 0; + } + + return 0; +} \ No newline at end of file diff --git a/examples/AD5940_Impedance_Adjustable_with_frequency/Impedance.h b/Impedance.h similarity index 84% rename from examples/AD5940_Impedance_Adjustable_with_frequency/Impedance.h rename to Impedance.h index c24cdf5..0ec94bd 100644 --- a/examples/AD5940_Impedance_Adjustable_with_frequency/Impedance.h +++ b/Impedance.h @@ -1,17 +1,4 @@ -/*! - ***************************************************************************** - @file: Impedance.h - @author: Neo XU - @brief: 4-wire/2-wire impedance measurement 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. - -*****************************************************************************/ +// File: Impedance.h #ifndef _IMPEDANCESEQUENCES_H_ #define _IMPEDANCESEQUENCES_H_ #include "ad5940.h" @@ -26,7 +13,7 @@ typedef struct 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 SeqWaitAddr[2]; + uint32_t SeqWaitAddr[3]; /* Addresses of the Wait commands in the sequence, used to update delays for frequency changes */ uint32_t MaxSeqLenCal; /* Application related parameters */ float ImpODR; /* */ @@ -35,6 +22,7 @@ typedef struct float SysClkFreq; /* The real frequency of system clock */ float AdcClkFreq; /* The real frequency of ADC clock */ float RcalVal; /* Rcal value in Ohm */ + float RtiaVal; /* Rtia value in Ohm (used for 4-wire calculation) */ /* Switch Configuration */ uint32_t DswitchSel; uint32_t PswitchSel; @@ -42,6 +30,7 @@ typedef struct uint32_t TswitchSel; uint32_t PwrMod; /* Control Chip power mode(LP/HP) */ uint32_t HstiaRtiaSel; /* Use internal RTIA, select from RTIA_INT_200, RTIA_INT_1K, RTIA_INT_5K, RTIA_INT_10K, RTIA_INT_20K, RTIA_INT_40K, RTIA_INT_80K, RTIA_INT_160K */ + uint32_t ExtRtia; /* External RTIA switch control/value */ uint32_t ExcitBufGain; /* Select from EXCTBUFGAIN_2, EXCTBUFGAIN_0P25 */ uint32_t HsDacGain; /* Select from HSDACGAIN_1, HSDACGAIN_0P2 */ uint32_t HsDacUpdateRate; @@ -58,7 +47,6 @@ typedef struct /* Sweep Function Control */ SoftSweepCfg_Type SweepCfg; uint32_t FifoThresh; /* FIFO threshold. Should be N*4 */ -/* Private variables for internal usage */ /* Private variables for internal usage */ float SweepCurrFreq; float SweepNextFreq; @@ -76,10 +64,9 @@ typedef struct #define IMPCTRL_GETFREQ 3 /* Get Current frequency of returned data from ISR */ #define IMPCTRL_SHUTDOWN 4 /* Note: shutdown here means turn off everything and put AFE to hibernate mode. The word 'SHUT DOWN' is only used here. */ - int32_t AppIMPInit(uint32_t *pBuffer, uint32_t BufferSize); int32_t AppIMPGetCfg(void *pCfg); int32_t AppIMPISR(void *pBuff, uint32_t *pCount); int32_t AppIMPCtrl(uint32_t Command, void *pPara); -#endif +#endif \ No newline at end of file diff --git a/examples/AD5940_ECSns_EIS/Impedance.c b/examples/AD5940_ECSns_EIS/Impedance.c deleted file mode 100644 index 10323fe..0000000 --- a/examples/AD5940_ECSns_EIS/Impedance.c +++ /dev/null @@ -1,678 +0,0 @@ -/*! - ***************************************************************************** - @file: Impedance.c - @author: Neo Xu - @brief: Electrochemical impedance spectroscopy based on example AD5940_Impedance - ----------------------------------------------------------------------------- - -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 -#include "string.h" -#include "math.h" -#include "Impedance.h" - -/* Default LPDAC resolution(2.5V internal reference). */ -#define DAC12BITVOLT_1LSB (2200.0f/4095) //mV -#define DAC6BITVOLT_1LSB (DAC12BITVOLT_1LSB*64) //mV - -/* - 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 -*/ -AppIMPCfg_Type AppIMPCfg = -{ - .bParaChanged = bFALSE, - .SeqStartAddr = 0, - .MaxSeqLen = 0, - - .SeqStartAddrCal = 0, - .MaxSeqLenCal = 0, - - .ImpODR = 20.0, /* 20.0 Hz*/ - .NumOfData = -1, - .SysClkFreq = 16000000.0, - .WuptClkFreq = 32000.0, - .AdcClkFreq = 16000000.0, - .RcalVal = 10000.0, - - .DswitchSel = SWD_CE0, - .PswitchSel = SWP_CE0, - .NswitchSel = SWN_AIN1, - .TswitchSel = SWT_AIN1, - - .PwrMod = AFEPWR_LP, - - .LptiaRtiaSel = LPTIARTIA_4K, /* COnfigure RTIA */ - .LpTiaRf = LPTIARF_1M, /* Configure LPF resistor */ - .LpTiaRl = LPTIARLOAD_100R, - - .HstiaRtiaSel = HSTIARTIA_1K, - .ExcitBufGain = EXCITBUFGAIN_0P25, - .HsDacGain = HSDACGAIN_0P2, - .HsDacUpdateRate = 0x1B, - .DacVoltPP = 300.0, - .BiasVolt = -0.0f, - - .SinFreq = 100000.0, /* 1000Hz */ - - .DftNum = DFTNUM_16384, - .DftSrc = DFTSRC_SINC3, - .HanWinEn = bTRUE, - - .AdcPgaGain = ADCPGA_1, - .ADCSinc3Osr = ADCSINC3OSR_2, - .ADCSinc2Osr = ADCSINC2OSR_22, - - .ADCAvgNum = ADCAVGNUM_16, - - .SweepCfg.SweepEn = bTRUE, - .SweepCfg.SweepStart = 1000, - .SweepCfg.SweepStop = 100000.0, - .SweepCfg.SweepPoints = 101, - .SweepCfg.SweepLog = bFALSE, - .SweepCfg.SweepIndex = 0, - - .FifoThresh = 4, - .IMPInited = bFALSE, - .StopRequired = bFALSE, -}; - -/** - This function is provided for upper controllers that want to change - application parameters specially for user defined parameters. -*/ -int32_t AppIMPGetCfg(void *pCfg) -{ - if(pCfg) - { - *(AppIMPCfg_Type**)pCfg = &AppIMPCfg; - return AD5940ERR_OK; - } - return AD5940ERR_PARA; -} - -int32_t AppIMPCtrl(uint32_t Command, void *pPara) -{ - - switch (Command) - { - case IMPCTRL_START: - { - 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(AppIMPCfg.IMPInited == bFALSE) - return AD5940ERR_APPERROR; - /* Start it */ - wupt_cfg.WuptEn = bTRUE; - wupt_cfg.WuptEndSeq = WUPTENDSEQ_A; - wupt_cfg.WuptOrder[0] = SEQID_0; - wupt_cfg.SeqxSleepTime[SEQID_0] = 4; - wupt_cfg.SeqxWakeupTime[SEQID_0] = (uint32_t)(AppIMPCfg.WuptClkFreq/AppIMPCfg.ImpODR)-4; - AD5940_WUPTCfg(&wupt_cfg); - - AppIMPCfg.FifoDataCount = 0; /* restart */ - break; - } - case IMPCTRL_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); - AD5940_WUPTCtrl(bFALSE); - break; - } - case IMPCTRL_STOPSYNC: - { - AppIMPCfg.StopRequired = bTRUE; - break; - } - case IMPCTRL_GETFREQ: - { - if(pPara == 0) - return AD5940ERR_PARA; - if(AppIMPCfg.SweepCfg.SweepEn == bTRUE) - *(float*)pPara = AppIMPCfg.FreqofData; - else - *(float*)pPara = AppIMPCfg.SinFreq; - } - break; - case IMPCTRL_SHUTDOWN: - { - AppIMPCtrl(IMPCTRL_STOPNOW, 0); /* Stop the measurement if it's running. */ - /* Turn off LPloop related blocks which are not controlled automatically by hibernate operation */ - AFERefCfg_Type aferef_cfg; - LPLoopCfg_Type lploop_cfg; - memset(&aferef_cfg, 0, sizeof(aferef_cfg)); - AD5940_REFCfgS(&aferef_cfg); - memset(&lploop_cfg, 0, sizeof(lploop_cfg)); - AD5940_LPLoopCfgS(&lploop_cfg); - AD5940_EnterSleepS(); /* Enter Hibernate */ - } - break; - default: - break; - } - return AD5940ERR_OK; -} - -/* generated code snnipet */ -float AppIMPGetCurrFreq(void) -{ - if(AppIMPCfg.SweepCfg.SweepEn == bTRUE) - return AppIMPCfg.FreqofData; - else - return AppIMPCfg.SinFreq; -} - -/* Application initialization */ -static AD5940Err AppIMPSeqCfgGen(void) -{ - AD5940Err error = AD5940ERR_OK; - const uint32_t *pSeqCmd; - uint32_t SeqLen; - AFERefCfg_Type aferef_cfg; - HSLoopCfg_Type HsLoopCfg; - LPLoopCfg_Type lploop_cfg; - DSPCfg_Type dsp_cfg; - float sin_freq; - - /* Start sequence generator here */ - AD5940_SEQGenCtrl(bTRUE); - - AD5940_AFECtrlS(AFECTRL_ALL, bFALSE); /* Init all to disable state */ - - 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; - aferef_cfg.LpBandgapEn = bTRUE; - aferef_cfg.LpRefBufEn = bTRUE; - aferef_cfg.LpRefBoostEn = bFALSE; - AD5940_REFCfgS(&aferef_cfg); - - lploop_cfg.LpDacCfg.LpDacSrc = LPDACSRC_MMR; - lploop_cfg.LpDacCfg.LpDacSW = LPDACSW_VBIAS2LPPA|LPDACSW_VBIAS2PIN|LPDACSW_VZERO2LPTIA|LPDACSW_VZERO2PIN; - lploop_cfg.LpDacCfg.LpDacVzeroMux = LPDACVZERO_6BIT; - lploop_cfg.LpDacCfg.LpDacVbiasMux = LPDACVBIAS_12BIT; - lploop_cfg.LpDacCfg.LpDacRef = LPDACREF_2P5; - lploop_cfg.LpDacCfg.DataRst = bFALSE; - lploop_cfg.LpDacCfg.PowerEn = bTRUE; - lploop_cfg.LpDacCfg.DacData6Bit = (uint32_t)((AppIMPCfg.Vzero-200)/DAC6BITVOLT_1LSB); - lploop_cfg.LpDacCfg.DacData12Bit =(int32_t)((AppIMPCfg.BiasVolt)/DAC12BITVOLT_1LSB) + lploop_cfg.LpDacCfg.DacData6Bit*64; - if(lploop_cfg.LpDacCfg.DacData12Bit>lploop_cfg.LpDacCfg.DacData6Bit*64) - lploop_cfg.LpDacCfg.DacData12Bit--; - lploop_cfg.LpAmpCfg.LpAmpPwrMod = LPAMPPWR_NORM; - lploop_cfg.LpAmpCfg.LpPaPwrEn = bTRUE; - lploop_cfg.LpAmpCfg.LpTiaPwrEn = bTRUE; - lploop_cfg.LpAmpCfg.LpTiaRf = AppIMPCfg.LpTiaRf; - lploop_cfg.LpAmpCfg.LpTiaRload = AppIMPCfg.LpTiaRl; - lploop_cfg.LpAmpCfg.LpTiaRtia = AppIMPCfg.LptiaRtiaSel; - lploop_cfg.LpAmpCfg.LpTiaSW = LPTIASW(5)|LPTIASW(2)|LPTIASW(4)|LPTIASW(12)|LPTIASW(13); - - AD5940_LPLoopCfgS(&lploop_cfg); - - HsLoopCfg.HsDacCfg.ExcitBufGain = AppIMPCfg.ExcitBufGain; - HsLoopCfg.HsDacCfg.HsDacGain = AppIMPCfg.HsDacGain; - HsLoopCfg.HsDacCfg.HsDacUpdateRate = AppIMPCfg.HsDacUpdateRate; - - HsLoopCfg.HsTiaCfg.DiodeClose = bFALSE; - HsLoopCfg.HsTiaCfg.HstiaBias = HSTIABIAS_1P1; - HsLoopCfg.HsTiaCfg.HstiaCtia = 31; /* 31pF + 2pF */ - HsLoopCfg.HsTiaCfg.HstiaDeRload = HSTIADERLOAD_OPEN; - HsLoopCfg.HsTiaCfg.HstiaDeRtia = HSTIADERTIA_OPEN; - HsLoopCfg.HsTiaCfg.HstiaRtiaSel = AppIMPCfg.HstiaRtiaSel; - - HsLoopCfg.SWMatCfg.Dswitch = AppIMPCfg.DswitchSel; - HsLoopCfg.SWMatCfg.Pswitch = AppIMPCfg.PswitchSel; - HsLoopCfg.SWMatCfg.Nswitch = AppIMPCfg.NswitchSel; - HsLoopCfg.SWMatCfg.Tswitch = SWT_TRTIA|AppIMPCfg.TswitchSel; - - HsLoopCfg.WgCfg.WgType = WGTYPE_SIN; - HsLoopCfg.WgCfg.GainCalEn = bTRUE; - HsLoopCfg.WgCfg.OffsetCalEn = bTRUE; - if(AppIMPCfg.SweepCfg.SweepEn == bTRUE) - { - AppIMPCfg.FreqofData = AppIMPCfg.SweepCfg.SweepStart; - AppIMPCfg.SweepCurrFreq = AppIMPCfg.SweepCfg.SweepStart; - AD5940_SweepNext(&AppIMPCfg.SweepCfg, &AppIMPCfg.SweepNextFreq); - sin_freq = AppIMPCfg.SweepCurrFreq; - } - else - { - sin_freq = AppIMPCfg.SinFreq; - AppIMPCfg.FreqofData = sin_freq; - } - HsLoopCfg.WgCfg.SinCfg.SinFreqWord = AD5940_WGFreqWordCal(sin_freq, AppIMPCfg.SysClkFreq); - HsLoopCfg.WgCfg.SinCfg.SinAmplitudeWord = (uint32_t)(AppIMPCfg.DacVoltPP/800.0f*2047 + 0.5f); - HsLoopCfg.WgCfg.SinCfg.SinOffsetWord = 0; - HsLoopCfg.WgCfg.SinCfg.SinPhaseWord = 0; - AD5940_HSLoopCfgS(&HsLoopCfg); - - dsp_cfg.ADCBaseCfg.ADCMuxN = ADCMUXN_HSTIA_N; - dsp_cfg.ADCBaseCfg.ADCMuxP = ADCMUXP_HSTIA_P; - dsp_cfg.ADCBaseCfg.ADCPga = AppIMPCfg.AdcPgaGain; - - memset(&dsp_cfg.ADCDigCompCfg, 0, sizeof(dsp_cfg.ADCDigCompCfg)); - - dsp_cfg.ADCFilterCfg.ADCAvgNum = AppIMPCfg.ADCAvgNum; - dsp_cfg.ADCFilterCfg.ADCRate = ADCRATE_800KHZ; /* Tell filter block clock rate of ADC*/ - dsp_cfg.ADCFilterCfg.ADCSinc2Osr = AppIMPCfg.ADCSinc2Osr; - dsp_cfg.ADCFilterCfg.ADCSinc3Osr = AppIMPCfg.ADCSinc3Osr; - dsp_cfg.ADCFilterCfg.BpNotch = bTRUE; - dsp_cfg.ADCFilterCfg.BpSinc3 = bFALSE; - dsp_cfg.ADCFilterCfg.Sinc2NotchEnable = bTRUE; - dsp_cfg.DftCfg.DftNum = AppIMPCfg.DftNum; - dsp_cfg.DftCfg.DftSrc = AppIMPCfg.DftSrc; - dsp_cfg.DftCfg.HanWinEn = AppIMPCfg.HanWinEn; - - memset(&dsp_cfg.StatCfg, 0, sizeof(dsp_cfg.StatCfg)); - AD5940_DSPCfgS(&dsp_cfg); - - /* Enable all of them. They are automatically turned off during hibernate mode to save power */ - if(AppIMPCfg.BiasVolt == 0.0f) - AD5940_AFECtrlS(AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\ - AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\ - AFECTRL_SINC2NOTCH, bTRUE); - else - AD5940_AFECtrlS(AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\ - AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\ - AFECTRL_SINC2NOTCH|AFECTRL_DCBUFPWR, bTRUE); - /* Sequence end. */ - AD5940_SEQGenInsert(SEQ_STOP()); /* Add one extra 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) - { - AppIMPCfg.InitSeqInfo.SeqId = SEQID_1; - AppIMPCfg.InitSeqInfo.SeqRamAddr = AppIMPCfg.SeqStartAddr; - AppIMPCfg.InitSeqInfo.pSeqCmd = pSeqCmd; - AppIMPCfg.InitSeqInfo.SeqLen = SeqLen; - /* Write command to SRAM */ - AD5940_SEQCmdWrite(AppIMPCfg.InitSeqInfo.SeqRamAddr, pSeqCmd, SeqLen); - } - else - return error; /* Error */ - return AD5940ERR_OK; -} - - -static AD5940Err AppIMPSeqMeasureGen(void) -{ - AD5940Err error = AD5940ERR_OK; - const uint32_t *pSeqCmd; - uint32_t SeqLen; - - uint32_t WaitClks; - SWMatrixCfg_Type sw_cfg; - ClksCalInfo_Type clks_cal; - LPAmpCfg_Type LpAmpCfg; - - /* Calculate number of clocks to get data to FIFO */ - 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); - - /* Start Sequence Generator */ - AD5940_SEQGenCtrl(bTRUE); - AD5940_SEQGpioCtrlS(AGPIO_Pin2); /* Set GPIO1, clear others that under control */ - AD5940_SEQGenInsert(SEQ_WAIT(16*250)); /* @todo wait 250us? */ - - /* Disconnect SE0 from LPTIA*/ - LpAmpCfg.LpAmpPwrMod = LPAMPPWR_NORM; - LpAmpCfg.LpPaPwrEn = bTRUE; - LpAmpCfg.LpTiaPwrEn = bTRUE; - LpAmpCfg.LpTiaRf = AppIMPCfg.LpTiaRf; - LpAmpCfg.LpTiaRload = AppIMPCfg.LpTiaRl; - LpAmpCfg.LpTiaRtia = LPTIARTIA_OPEN; /* Disconnect Rtia to avoid RC filter discharge */ - LpAmpCfg.LpTiaSW = LPTIASW(7)|LPTIASW(8)|LPTIASW(12)|LPTIASW(13); - AD5940_LPAMPCfgS(&LpAmpCfg); - /* Sensor + Rload Measurement */ - sw_cfg.Dswitch = AppIMPCfg.DswitchSel; - sw_cfg.Pswitch = AppIMPCfg.PswitchSel; - sw_cfg.Nswitch = AppIMPCfg.NswitchSel; - sw_cfg.Tswitch = SWT_TRTIA|AppIMPCfg.TswitchSel; - AD5940_SWMatrixCfgS(&sw_cfg); - - AD5940_AFECtrlS(AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\ - AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\ - AFECTRL_SINC2NOTCH, bTRUE); - - - AD5940_AFECtrlS(AFECTRL_ADCPWR|AFECTRL_SINC2NOTCH, bTRUE); /* Enable Waveform generator */ - //delay for signal settling DFT_WAIT - AD5940_SEQGenInsert(SEQ_WAIT(16*10)); - AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT, bTRUE); /* Start ADC convert and DFT */ - AD5940_SEQGenInsert(SEQ_WAIT(WaitClks)); - //wait for first data ready - AD5940_AFECtrlS(AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\ - AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\ - AFECTRL_SINC2NOTCH|AFECTRL_DFT|AFECTRL_ADCCNV, bFALSE); - - /* RLOAD Measurement */ - sw_cfg.Dswitch = SWD_SE0; - sw_cfg.Pswitch = SWP_SE0; - sw_cfg.Nswitch = SWN_SE0LOAD; - sw_cfg.Tswitch = SWT_SE0LOAD|SWT_TRTIA; - AD5940_SWMatrixCfgS(&sw_cfg); - AD5940_AFECtrlS(AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\ - AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|AFECTRL_SINC2NOTCH, bTRUE); - AD5940_SEQGenInsert(SEQ_WAIT(16*10)); //delay for signal settling DFT_WAIT - AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT, bTRUE); /* Start ADC convert and DFT */ - AD5940_SEQGenInsert(SEQ_WAIT(WaitClks)); /* wait for first data ready */ - AD5940_AFECtrlS(AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\ - AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\ - AFECTRL_SINC2NOTCH|AFECTRL_ADCCNV, bFALSE); - - /* RCAL Measurement */ - sw_cfg.Dswitch = SWD_RCAL0; - sw_cfg.Pswitch = SWP_RCAL0; - sw_cfg.Nswitch = SWN_RCAL1; - sw_cfg.Tswitch = SWT_RCAL1|SWT_TRTIA; - AD5940_SWMatrixCfgS(&sw_cfg); - /* Reconnect LP loop */ - LpAmpCfg.LpTiaRtia = AppIMPCfg.LptiaRtiaSel; /* Disconnect Rtia to avoid RC filter discharge */ - LpAmpCfg.LpTiaSW = LPTIASW(5)|LPTIASW(2)|LPTIASW(4)|LPTIASW(12)|LPTIASW(13); - AD5940_LPAMPCfgS(&LpAmpCfg); - - AD5940_AFECtrlS(AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\ - AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|AFECTRL_SINC2NOTCH, bTRUE); - AD5940_SEQGenInsert(SEQ_WAIT(16*10)); //delay for signal settling DFT_WAIT - AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT/*|AFECTRL_SINC2NOTCH*/, bTRUE); /* Start ADC convert and DFT */ - AD5940_SEQGenInsert(SEQ_WAIT(WaitClks)); /* wait for first data ready */ - AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT|AFECTRL_WG|AFECTRL_ADCPWR, bFALSE); /* Stop ADC convert and DFT */ - AD5940_AFECtrlS(AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\ - AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\ - AFECTRL_SINC2NOTCH, bFALSE); - AD5940_SEQGpioCtrlS(0); /* Clr GPIO1 */ - - sw_cfg.Dswitch = SWD_OPEN; - sw_cfg.Pswitch = SWP_OPEN; - sw_cfg.Nswitch = SWN_OPEN; - sw_cfg.Tswitch = SWT_OPEN; - AD5940_SWMatrixCfgS(&sw_cfg); - - //AD5940_EnterSleepS();/* Goto hibernate */ - - /* Sequence end. */ - error = AD5940_SEQGenFetchSeq(&pSeqCmd, &SeqLen); - AD5940_SEQGenCtrl(bFALSE); /* Stop sequencer generator */ - - if(error == AD5940ERR_OK) - { - AppIMPCfg.MeasureSeqInfo.SeqId = SEQID_0; - AppIMPCfg.MeasureSeqInfo.SeqRamAddr = AppIMPCfg.InitSeqInfo.SeqRamAddr + AppIMPCfg.InitSeqInfo.SeqLen ; - AppIMPCfg.MeasureSeqInfo.pSeqCmd = pSeqCmd; - AppIMPCfg.MeasureSeqInfo.SeqLen = SeqLen; - /* Write command to SRAM */ - AD5940_SEQCmdWrite(AppIMPCfg.MeasureSeqInfo.SeqRamAddr, pSeqCmd, SeqLen); - } - else - return error; /* Error */ - return AD5940ERR_OK; -} - - -/* This function provide application initialize. It can also enable Wupt that will automatically trigger sequence. Or it can configure */ -int32_t AppIMPInit(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 = bTRUE; - 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 = AppIMPCfg.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((AppIMPCfg.IMPInited == bFALSE)||\ - (AppIMPCfg.bParaChanged == bTRUE)) - { - if(pBuffer == 0) return AD5940ERR_PARA; - if(BufferSize == 0) return AD5940ERR_PARA; - AD5940_SEQGenInit(pBuffer, BufferSize); - - /* Generate initialize sequence */ - error = AppIMPSeqCfgGen(); /* Application initialization sequence using either MCU or sequencer */ - if(error != AD5940ERR_OK) return error; - - /* Generate measurement sequence */ - error = AppIMPSeqMeasureGen(); - if(error != AD5940ERR_OK) return error; - - AppIMPCfg.bParaChanged = bFALSE; /* Clear this flag as we already implemented the new configuration */ - } - - /* Initialization sequencer */ - AppIMPCfg.InitSeqInfo.WriteSRAM = bFALSE; - AD5940_SEQInfoCfg(&AppIMPCfg.InitSeqInfo); - seq_cfg.SeqEnable = bTRUE; - AD5940_SEQCfg(&seq_cfg); /* Enable sequencer */ - AD5940_SEQMmrTrig(AppIMPCfg.InitSeqInfo.SeqId); - while(AD5940_INTCTestFlag(AFEINTC_1, AFEINTSRC_ENDSEQ) == bFALSE); - - /* Measurement sequence */ - AppIMPCfg.MeasureSeqInfo.WriteSRAM = bFALSE; - AD5940_SEQInfoCfg(&AppIMPCfg.MeasureSeqInfo); - - seq_cfg.SeqEnable = bTRUE; - AD5940_SEQCfg(&seq_cfg); /* Enable sequencer, and wait for trigger */ - AD5940_ClrMCUIntFlag(); /* Clear interrupt flag generated before */ - - AD5940_AFEPwrBW(AppIMPCfg.PwrMod, AFEBW_250KHZ); - - AD5940_WriteReg(REG_AFE_LPTIASW0, 0x3180); - AppIMPCfg.IMPInited = bTRUE; /* IMP application has been initialized. */ - return AD5940ERR_OK; -} - -/* Modify registers when AFE wakeup */ -int32_t AppIMPRegModify(int32_t * const pData, uint32_t *pDataCount) -{ - if(AppIMPCfg.NumOfData > 0) - { - AppIMPCfg.FifoDataCount += *pDataCount/4; - if(AppIMPCfg.FifoDataCount >= AppIMPCfg.NumOfData) - { - AD5940_WUPTCtrl(bFALSE); - return AD5940ERR_OK; - } - } - if(AppIMPCfg.StopRequired == bTRUE) - { - AD5940_WUPTCtrl(bFALSE); - return AD5940ERR_OK; - } - if(AppIMPCfg.SweepCfg.SweepEn) /* Need to set new frequency and set power mode */ - { - /* Check frequency and update FIlter settings */ - AD5940_WGFreqCtrlS(AppIMPCfg.SweepNextFreq, AppIMPCfg.SysClkFreq); - } - return AD5940ERR_OK; -} - -/* 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/6; - - fImpPol_Type * const pOut = (fImpPol_Type*)pData; - iImpCar_Type * pSrcData = (iImpCar_Type*)pData; - - *pDataCount = 0; - - DataCount = (DataCount/6)*6;/* We expect Rz+Rload, Rload and RCAL 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; iReal; - DftRzRload.Image = -pSrcData->Image; - pSrcData++; - DftRload.Real = pSrcData->Real; - DftRload.Image = -pSrcData->Image; - pSrcData++; - DftRcal.Real = pSrcData->Real; - DftRcal.Image = -pSrcData->Image; - pSrcData++; - /** - Rz = RloadRz - Rload - RloadRz = DftRcal/DftRzRload*RCAL; - Rload = DftRcal/DftRload*RCAL; - Rz = RloadRz - Rload = - (1/DftRzRload - 1/DftRload)*DftRcal*RCAL; - where RCAL is the RCAL resistor value in Ohm. - */ - //temp1 = 1/DftRzRload; - //temp2 = 1/DftRload; - temp1 = AD5940_ComplexDivFloat(&DftConst1, &DftRzRload); - temp2 = AD5940_ComplexDivFloat(&DftConst1, &DftRload); - res = AD5940_ComplexSubFloat(&temp1, &temp2); - res = AD5940_ComplexMulFloat(&res, &DftRcal); - pOut[i].Magnitude = AD5940_ComplexMag(&res)*AppIMPCfg.RcalVal; - pOut[i].Phase = AD5940_ComplexPhase(&res); - } - else - { - iImpCar_Type *pDftRcal, *pDftRzRload, *pDftRload; - - pDftRzRload = pSrcData++; - pDftRload = pSrcData++; - pDftRcal = pSrcData++; - - float RzRloadMag, RzRloadPhase; - float RloadMag, RloadPhase; - float RzMag,RzPhase; - float RcalMag, RcalPhase; - float RzReal, RzImage; - - RzReal = pDftRload->Real - pDftRzRload->Real; - RzImage = pDftRload->Image - pDftRzRload->Image; - - RzRloadMag = sqrt((float)pDftRzRload->Real*pDftRzRload->Real+(float)pDftRzRload->Image*pDftRzRload->Image); - RzRloadPhase = atan2(-pDftRzRload->Image,pDftRzRload->Real); - RcalMag = sqrt((float)pDftRcal->Real*pDftRcal->Real+(float)pDftRcal->Image*pDftRcal->Image); - RcalPhase = atan2(-pDftRcal->Image,pDftRcal->Real); - RzMag = sqrt((float)RzReal*RzReal+(float)RzImage*RzImage); - RzPhase = atan2(-RzImage,RzReal); - RloadMag = sqrt((float)pDftRload->Real*pDftRload->Real+(float)pDftRload->Image*pDftRload->Image); - RloadPhase = atan2(-pDftRload->Image,pDftRload->Real); - - RzMag = (AppIMPCfg.RcalVal*RcalMag*RzMag)/(RzRloadMag*RloadMag); - RzPhase = -(RcalPhase + RzPhase - RloadPhase - RzRloadPhase); - // RzPhase = (RcalPhase + RzPhase - RloadPhase - RzRloadPhase); - - - 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; -} - -/** - -*/ -int32_t AppIMPISR(void *pBuff, uint32_t *pCount) -{ - uint32_t BuffCount; - uint32_t FifoCnt; - BuffCount = *pCount; - - *pCount = 0; - - if(AD5940_WakeUp(10) > 10) /* Wakeup AFE by read register, read 10 times at most */ - return AD5940ERR_WAKEUP; /* Wakeup Failed */ - AD5940_SleepKeyCtrlS(SLPKEY_LOCK); /* Prohibit AFE to enter sleep mode. */ - - if(AD5940_INTCTestFlag(AFEINTC_0, AFEINTSRC_DATAFIFOTHRESH) == bTRUE) - { - /* Now there should be 4 data in FIFO */ - FifoCnt = (AD5940_FIFOGetCnt()/6)*6; - - if(FifoCnt > BuffCount) - { - ///@todo buffer is limited. - } - AD5940_FIFORd((uint32_t *)pBuff, FifoCnt); - AD5940_INTCClrFlag(AFEINTSRC_DATAFIFOTHRESH); - AppIMPRegModify(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. This operation only takes effect when register value is ACTIVE previously */ - AD5940_SleepKeyCtrlS(SLPKEY_UNLOCK); /* Allow AFE to enter sleep mode. */ - /* Process data */ - AppIMPDataProcess((int32_t*)pBuff,&FifoCnt); - *pCount = FifoCnt; - return 0; - } - - return 0; -} - - diff --git a/examples/AD5940_ECSns_EIS/Impedance.h b/examples/AD5940_ECSns_EIS/Impedance.h deleted file mode 100644 index e7d5425..0000000 --- a/examples/AD5940_ECSns_EIS/Impedance.h +++ /dev/null @@ -1,91 +0,0 @@ -/*! - ***************************************************************************** - @file: Impedance.h - @author: Neo Xu - @brief: Electrochemical impedance spectroscopy based on example AD5940_Impedance - ----------------------------------------------------------------------------- - -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 _IMPEDANCESEQUENCES_H_ -#define _IMPEDANCESEQUENCES_H_ -#include "AD5940.H" -#include -#include "string.h" -#include "math.h" - -typedef struct -{ -/* Common configurations for all kinds of Application. */ - BoolFlag bParaChanged; /* Indicate to generate sequence again. It's auto cleared by AppBIAInit */ - 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 ImpODR; /* */ - 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. */ - 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 SysClkFreq; /* The real frequency of system clock */ - float AdcClkFreq; /* The real frequency of ADC clock */ - float RcalVal; /* Rcal value in Ohm */ - /* Switch Configuration */ - uint32_t DswitchSel; - uint32_t PswitchSel; - uint32_t NswitchSel; - uint32_t TswitchSel; - uint32_t PwrMod; /* Control Chip power mode(LP/HP) */ - uint32_t HstiaRtiaSel; /* Use internal RTIA, select from RTIA_INT_200, RTIA_INT_1K, RTIA_INT_5K, RTIA_INT_10K, RTIA_INT_20K, RTIA_INT_40K, RTIA_INT_80K, RTIA_INT_160K */ - uint32_t ExcitBufGain; /* Select from EXCTBUFGAIN_2, EXCTBUFGAIN_0P25 */ - uint32_t HsDacGain; /* Select from HSDACGAIN_1, HSDACGAIN_0P2 */ - uint32_t HsDacUpdateRate; - float DacVoltPP; /* DAC output voltage in mV peak to peak. Maximum value is 600mVpp. Peak to peak voltage */ - float BiasVolt; /* The excitation signal is DC+AC. This parameter decides the DC value in mV unit. 0.0mV means no DC bias.*/ - float SinFreq; /* Frequency of excitation signal */ - uint32_t DftNum; /* DFT number */ - uint32_t DftSrc; /* DFT Source */ - BoolFlag HanWinEn; /* Enable Hanning window */ - uint32_t AdcPgaGain; /* PGA Gain select from GNPGA_1, GNPGA_1_5, GNPGA_2, GNPGA_4, GNPGA_9 !!! We must ensure signal is in range of +-1.5V which is limited by ADC input stage */ - uint8_t ADCSinc3Osr; - uint8_t ADCSinc2Osr; - uint8_t ADCAvgNum; - uint8_t ADC_Rate; - - uint32_t LptiaRtiaSel; /* Use internal RTIA, select from RTIA_INT_200, RTIA_INT_1K, RTIA_INT_5K, RTIA_INT_10K, RTIA_INT_20K, RTIA_INT_40K, RTIA_INT_80K, RTIA_INT_160K */ - uint32_t LpTiaRf; /* Rfilter select */ - uint32_t LpTiaRl; /* SE0 Rload select */ - float Vzero; /* Voltage on SE0 pin and Vzero, optimumly 1100mV*/ - float Vbias; /* Voltage on CE0 and PA */ - /* Sweep Function Control */ - SoftSweepCfg_Type SweepCfg; - uint32_t FifoThresh; /* FIFO threshold. Should be N*4 */ -/* Private variables for internal usage */ -/* Private variables for internal usage */ - float SweepCurrFreq; - float SweepNextFreq; - float FreqofData; /* The frequency of latest data sampled */ - BoolFlag IMPInited; /* 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 */ -}AppIMPCfg_Type; - -#define IMPCTRL_START 0 -#define IMPCTRL_STOPNOW 1 -#define IMPCTRL_STOPSYNC 2 -#define IMPCTRL_GETFREQ 3 /* Get Current frequency of returned data from ISR */ -#define IMPCTRL_SHUTDOWN 4 /* Note: shutdown here means turn off everything and put AFE to hibernate mode. The word 'SHUT DOWN' is only used here. */ - - -int32_t AppIMPInit(uint32_t *pBuffer, uint32_t BufferSize); -int32_t AppIMPGetCfg(void *pCfg); -int32_t AppIMPISR(void *pBuff, uint32_t *pCount); -int32_t AppIMPCtrl(uint32_t Command, void *pPara); - -#endif diff --git a/examples/AD5940_Impedance_Adjustable_with_frequency/Impedance.c b/examples/AD5940_Impedance_Adjustable_with_frequency/Impedance.c deleted file mode 100644 index 0a0ad3c..0000000 --- a/examples/AD5940_Impedance_Adjustable_with_frequency/Impedance.c +++ /dev/null @@ -1,740 +0,0 @@ -/*! - ***************************************************************************** - @file: Impedance.c - @author: Neo Xu - @brief: standard 4-wire or 2-wire 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 "ad5940.h" -#include -#include "string.h" -#include "math.h" -#include "Impedance.h" - -/* Default LPDAC resolution(2.5V internal reference). */ -#define DAC12BITVOLT_1LSB (2200.0f/4095) //mV -#define DAC6BITVOLT_1LSB (DAC12BITVOLT_1LSB*64) //mV - -/* - 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 -*/ -AppIMPCfg_Type AppIMPCfg = -{ - .bParaChanged = bFALSE, - .SeqStartAddr = 0, - .MaxSeqLen = 0, - - .SeqStartAddrCal = 0, - .MaxSeqLenCal = 0, - - .ImpODR = 0.0001, /* 20.0 Hz*/ - .NumOfData = -1, - .SysClkFreq = 16000000.0, - .WuptClkFreq = 32000.0, - .AdcClkFreq = 16000000.0, - .RcalVal = 10000.0, - - .DswitchSel = SWD_CE0, - .PswitchSel = SWP_CE0, - .NswitchSel = SWN_AIN1, - .TswitchSel = SWT_AIN1, - - .PwrMod = AFEPWR_HP, - - .HstiaRtiaSel = HSTIARTIA_5K, - .ExtRtia = 0, //set only when HstiaRtiaSel = HSTIARTIA_OPEN - .ExcitBufGain = EXCITBUFGAIN_0P25,//EXCITBUFGAIN_2, - .HsDacGain = HSDACGAIN_0P2,//HSDACGAIN_1, - .HsDacUpdateRate = 7, - .DacVoltPP = 800.0, - .BiasVolt = -0.0f, - - .SinFreq = 100000.0, /* 1000Hz */ - - .DftNum = DFTNUM_16384, - .DftSrc = DFTSRC_SINC3, - .HanWinEn = bTRUE, - - .AdcPgaGain = ADCPGA_4,//ADCPGA_1, - .ADCSinc3Osr = ADCSINC3OSR_2, - .ADCSinc2Osr = ADCSINC2OSR_22, - - .ADCAvgNum = ADCAVGNUM_16, - - .SweepCfg.SweepEn = bTRUE, - .SweepCfg.SweepStart = 1000, - .SweepCfg.SweepStop = 100000.0, - .SweepCfg.SweepPoints = 101, - .SweepCfg.SweepLog = bFALSE, - .SweepCfg.SweepIndex = 0, - - .FifoThresh = 4, - .IMPInited = bFALSE, - .StopRequired = bFALSE, -}; - -/** - This function is provided for upper controllers that want to change - application parameters specially for user defined parameters. -*/ -int32_t AppIMPGetCfg(void *pCfg) -{ - if(pCfg) - { - *(AppIMPCfg_Type**)pCfg = &AppIMPCfg; - return AD5940ERR_OK; - } - return AD5940ERR_PARA; -} - -int32_t AppIMPCtrl(uint32_t Command, void *pPara) -{ - - switch (Command) - { - case IMPCTRL_START: - { - 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(AppIMPCfg.IMPInited == bFALSE) - return AD5940ERR_APPERROR; - /* Start it */ - wupt_cfg.WuptEn = bTRUE; - wupt_cfg.WuptEndSeq = WUPTENDSEQ_A; - wupt_cfg.WuptOrder[0] = SEQID_0; - wupt_cfg.SeqxSleepTime[SEQID_0] = 4; - wupt_cfg.SeqxWakeupTime[SEQID_0] = (uint32_t)(AppIMPCfg.WuptClkFreq/AppIMPCfg.ImpODR)-4; - AD5940_WUPTCfg(&wupt_cfg); - - AppIMPCfg.FifoDataCount = 0; /* restart */ - break; - } - case IMPCTRL_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 IMPCTRL_STOPSYNC: - { - AppIMPCfg.StopRequired = bTRUE; - break; - } - case IMPCTRL_GETFREQ: - { - if(pPara == 0) - return AD5940ERR_PARA; - if(AppIMPCfg.SweepCfg.SweepEn == bTRUE) - *(float*)pPara = AppIMPCfg.FreqofData; - else - *(float*)pPara = AppIMPCfg.SinFreq; - } - break; - case IMPCTRL_SHUTDOWN: - { - AppIMPCtrl(IMPCTRL_STOPNOW, 0); /* Stop the measurement if it's running. */ - /* Turn off LPloop related blocks which are not controlled automatically by hibernate 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; -} - -/* generated code snnipet */ -float AppIMPGetCurrFreq(void) -{ - if(AppIMPCfg.SweepCfg.SweepEn == bTRUE) - return AppIMPCfg.FreqofData; - else - return AppIMPCfg.SinFreq; -} - -/* Application initialization */ -static AD5940Err AppIMPSeqCfgGen(void) -{ - AD5940Err error = AD5940ERR_OK; - const uint32_t *pSeqCmd; - uint32_t SeqLen; - AFERefCfg_Type aferef_cfg; - HSLoopCfg_Type HsLoopCfg; - DSPCfg_Type dsp_cfg; - float sin_freq; - - /* Start sequence generator here */ - AD5940_SEQGenCtrl(bTRUE); - - AD5940_AFECtrlS(AFECTRL_ALL, bFALSE); /* Init all to disable state */ - - 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 - turn off them to save power*/ - if(AppIMPCfg.BiasVolt != 0.0f) /* With bias voltage */ - { - aferef_cfg.LpBandgapEn = bTRUE; - aferef_cfg.LpRefBufEn = bTRUE; - } - else - { - aferef_cfg.LpBandgapEn = bFALSE; - aferef_cfg.LpRefBufEn = bFALSE; - } - aferef_cfg.LpRefBoostEn = bFALSE; - AD5940_REFCfgS(&aferef_cfg); - HsLoopCfg.HsDacCfg.ExcitBufGain = AppIMPCfg.ExcitBufGain; - HsLoopCfg.HsDacCfg.HsDacGain = AppIMPCfg.HsDacGain; - HsLoopCfg.HsDacCfg.HsDacUpdateRate = AppIMPCfg.HsDacUpdateRate; - - HsLoopCfg.HsTiaCfg.DiodeClose = bFALSE; - if(AppIMPCfg.BiasVolt != 0.0f) /* With bias voltage */ - HsLoopCfg.HsTiaCfg.HstiaBias = HSTIABIAS_VZERO0; - else - HsLoopCfg.HsTiaCfg.HstiaBias = HSTIABIAS_1P1; - HsLoopCfg.HsTiaCfg.HstiaCtia = 31; /* 31pF + 2pF */ - HsLoopCfg.HsTiaCfg.HstiaDeRload = HSTIADERLOAD_OPEN; - HsLoopCfg.HsTiaCfg.HstiaDeRtia = HSTIADERTIA_OPEN; - HsLoopCfg.HsTiaCfg.HstiaRtiaSel = AppIMPCfg.HstiaRtiaSel; - - HsLoopCfg.SWMatCfg.Dswitch = AppIMPCfg.DswitchSel; - HsLoopCfg.SWMatCfg.Pswitch = AppIMPCfg.PswitchSel; - HsLoopCfg.SWMatCfg.Nswitch = AppIMPCfg.NswitchSel; - HsLoopCfg.SWMatCfg.Tswitch = SWT_TRTIA|AppIMPCfg.TswitchSel; - - HsLoopCfg.WgCfg.WgType = WGTYPE_SIN; - HsLoopCfg.WgCfg.GainCalEn = bTRUE; - HsLoopCfg.WgCfg.OffsetCalEn = bTRUE; - if(AppIMPCfg.SweepCfg.SweepEn == bTRUE) - { - AppIMPCfg.FreqofData = AppIMPCfg.SweepCfg.SweepStart; - AppIMPCfg.SweepCurrFreq = AppIMPCfg.SweepCfg.SweepStart; - AD5940_SweepNext(&AppIMPCfg.SweepCfg, &AppIMPCfg.SweepNextFreq); - sin_freq = AppIMPCfg.SweepCurrFreq; - } - else - { - sin_freq = AppIMPCfg.SinFreq; - AppIMPCfg.FreqofData = sin_freq; - } - HsLoopCfg.WgCfg.SinCfg.SinFreqWord = AD5940_WGFreqWordCal(sin_freq, AppIMPCfg.SysClkFreq); - HsLoopCfg.WgCfg.SinCfg.SinAmplitudeWord = (uint32_t)(AppIMPCfg.DacVoltPP/800.0f*2047 + 0.5f); - HsLoopCfg.WgCfg.SinCfg.SinOffsetWord = 0; - HsLoopCfg.WgCfg.SinCfg.SinPhaseWord = 0; - AD5940_HSLoopCfgS(&HsLoopCfg); - if(AppIMPCfg.BiasVolt != 0.0f) /* With bias voltage */ - { - LPDACCfg_Type lpdac_cfg; - - lpdac_cfg.LpdacSel = LPDAC0; - lpdac_cfg.LpDacVbiasMux = LPDACVBIAS_12BIT; /* Use Vbias to tuning BiasVolt. */ - lpdac_cfg.LpDacVzeroMux = LPDACVZERO_6BIT; /* Vbias-Vzero = BiasVolt */ - lpdac_cfg.DacData6Bit = 0x40>>1; /* Set Vzero to middle scale. */ - if(AppIMPCfg.BiasVolt<-1100.0f) AppIMPCfg.BiasVolt = -1100.0f + DAC12BITVOLT_1LSB; - if(AppIMPCfg.BiasVolt> 1100.0f) AppIMPCfg.BiasVolt = 1100.0f - DAC12BITVOLT_1LSB; - lpdac_cfg.DacData12Bit = (uint32_t)((AppIMPCfg.BiasVolt + 1100.0f)/DAC12BITVOLT_1LSB); - lpdac_cfg.DataRst = bFALSE; /* Do not reset data register */ - lpdac_cfg.LpDacSW = LPDACSW_VBIAS2LPPA|LPDACSW_VBIAS2PIN|LPDACSW_VZERO2LPTIA|LPDACSW_VZERO2PIN|LPDACSW_VZERO2HSTIA; - lpdac_cfg.LpDacRef = LPDACREF_2P5; - lpdac_cfg.LpDacSrc = LPDACSRC_MMR; /* Use MMR data, we use LPDAC to generate bias voltage for LPTIA - the Vzero */ - lpdac_cfg.PowerEn = bTRUE; /* Power up LPDAC */ - AD5940_LPDACCfgS(&lpdac_cfg); - } - dsp_cfg.ADCBaseCfg.ADCMuxN = ADCMUXN_HSTIA_N; - dsp_cfg.ADCBaseCfg.ADCMuxP = ADCMUXP_HSTIA_P; - dsp_cfg.ADCBaseCfg.ADCPga = AppIMPCfg.AdcPgaGain; - - memset(&dsp_cfg.ADCDigCompCfg, 0, sizeof(dsp_cfg.ADCDigCompCfg)); - - dsp_cfg.ADCFilterCfg.ADCAvgNum = AppIMPCfg.ADCAvgNum; - dsp_cfg.ADCFilterCfg.ADCRate = ADCRATE_800KHZ; /* Tell filter block clock rate of ADC*/ - dsp_cfg.ADCFilterCfg.ADCSinc2Osr = AppIMPCfg.ADCSinc2Osr; - dsp_cfg.ADCFilterCfg.ADCSinc3Osr = AppIMPCfg.ADCSinc3Osr; - dsp_cfg.ADCFilterCfg.BpNotch = bTRUE; - dsp_cfg.ADCFilterCfg.BpSinc3 = bFALSE; - dsp_cfg.ADCFilterCfg.Sinc2NotchEnable = bTRUE; - dsp_cfg.DftCfg.DftNum = AppIMPCfg.DftNum; - dsp_cfg.DftCfg.DftSrc = AppIMPCfg.DftSrc; - dsp_cfg.DftCfg.HanWinEn = AppIMPCfg.HanWinEn; - - memset(&dsp_cfg.StatCfg, 0, sizeof(dsp_cfg.StatCfg)); - AD5940_DSPCfgS(&dsp_cfg); - - /* Enable all of them. They are automatically turned off during hibernate mode to save power */ - if(AppIMPCfg.BiasVolt == 0.0f) - AD5940_AFECtrlS(AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\ - AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\ - AFECTRL_SINC2NOTCH, bTRUE); - else - AD5940_AFECtrlS(AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\ - AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\ - AFECTRL_SINC2NOTCH|AFECTRL_DCBUFPWR, bTRUE); - /* Sequence end. */ - AD5940_SEQGenInsert(SEQ_STOP()); /* Add one extra 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) - { - AppIMPCfg.InitSeqInfo.SeqId = SEQID_1; - AppIMPCfg.InitSeqInfo.SeqRamAddr = AppIMPCfg.SeqStartAddr; - AppIMPCfg.InitSeqInfo.pSeqCmd = pSeqCmd; - AppIMPCfg.InitSeqInfo.SeqLen = SeqLen; - /* Write command to SRAM */ - AD5940_SEQCmdWrite(AppIMPCfg.InitSeqInfo.SeqRamAddr, pSeqCmd, SeqLen); - } - else - return error; /* Error */ - return AD5940ERR_OK; -} - - -static AD5940Err AppIMPSeqMeasureGen(void) -{ - AD5940Err error = AD5940ERR_OK; - const uint32_t *pSeqCmd; - uint32_t SeqLen; - - uint32_t WaitClks; - SWMatrixCfg_Type sw_cfg; - 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); - - AD5940_SEQGenCtrl(bTRUE); - AD5940_SEQGpioCtrlS(AGPIO_Pin2); /* Set GPIO1, clear others that under control */ - AD5940_SEQGenInsert(SEQ_WAIT(16*250)); /* @todo wait 250us? */ - sw_cfg.Dswitch = SWD_RCAL0; - sw_cfg.Pswitch = SWP_RCAL0; - sw_cfg.Nswitch = SWN_RCAL1; - sw_cfg.Tswitch = SWT_RCAL1|SWT_TRTIA; - AD5940_SWMatrixCfgS(&sw_cfg); - - AD5940_AFECtrlS(AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\ - AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\ - AFECTRL_SINC2NOTCH, bTRUE); - AD5940_AFECtrlS(AFECTRL_WG|AFECTRL_ADCPWR, bTRUE); /* Enable Waveform generator */ - //delay for signal settling DFT_WAIT - AD5940_SEQGenInsert(SEQ_WAIT(16*10)); - AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT, bTRUE); /* Start ADC convert and DFT */ - - AD5940_SEQGenFetchSeq(NULL, &AppIMPCfg.SeqWaitAddr[0]); /* Record the start address of the next command. */ - - AD5940_SEQGenInsert(SEQ_WAIT(WaitClks/2)); - AD5940_SEQGenInsert(SEQ_WAIT(WaitClks/2)); - - //wait for first data ready - AD5940_AFECtrlS(AFECTRL_ADCPWR|AFECTRL_ADCCNV|AFECTRL_DFT|AFECTRL_WG, bFALSE); /* Stop ADC convert and DFT */ - - /* Configure matrix for external Rz */ - sw_cfg.Dswitch = AppIMPCfg.DswitchSel; - sw_cfg.Pswitch = AppIMPCfg.PswitchSel; - sw_cfg.Nswitch = AppIMPCfg.NswitchSel; - sw_cfg.Tswitch = SWT_TRTIA|AppIMPCfg.TswitchSel; - AD5940_SWMatrixCfgS(&sw_cfg); - AD5940_AFECtrlS(AFECTRL_ADCPWR|AFECTRL_WG, bTRUE); /* Enable Waveform generator */ - AD5940_SEQGenInsert(SEQ_WAIT(16*10)); //delay for signal settling DFT_WAIT - AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT, bTRUE); /* Start ADC convert and DFT */ - - AD5940_SEQGenFetchSeq(NULL, &AppIMPCfg.SeqWaitAddr[1]); /* Record the start address of next command */ - - AD5940_SEQGenInsert(SEQ_WAIT(WaitClks/2)); - AD5940_SEQGenInsert(SEQ_WAIT(WaitClks/2)); - - AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT|AFECTRL_WG|AFECTRL_ADCPWR, bFALSE); /* Stop ADC convert and DFT */ - AD5940_AFECtrlS(AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\ - AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\ - AFECTRL_SINC2NOTCH, bFALSE); - AD5940_SEQGpioCtrlS(0); /* Clr GPIO1 */ - - AD5940_EnterSleepS();/* Goto hibernate */ - - /* Sequence end. */ - error = AD5940_SEQGenFetchSeq(&pSeqCmd, &SeqLen); - AD5940_SEQGenCtrl(bFALSE); /* Stop sequencer generator */ - - if(error == AD5940ERR_OK) - { - AppIMPCfg.MeasureSeqInfo.SeqId = SEQID_0; - AppIMPCfg.MeasureSeqInfo.SeqRamAddr = AppIMPCfg.InitSeqInfo.SeqRamAddr + AppIMPCfg.InitSeqInfo.SeqLen ; - AppIMPCfg.MeasureSeqInfo.pSeqCmd = pSeqCmd; - AppIMPCfg.MeasureSeqInfo.SeqLen = SeqLen; - /* Write command to SRAM */ - AD5940_SEQCmdWrite(AppIMPCfg.MeasureSeqInfo.SeqRamAddr, pSeqCmd, SeqLen); - } - else - return error; /* Error */ - return AD5940ERR_OK; -} - -/* Depending on frequency of Sin wave set optimum filter settings */ -AD5940Err AppIMPCheckFreq(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) - { - /* Update HSDAC update rate */ - hsdac_cfg.ExcitBufGain =EXCITBUFGAIN_2;// AppIMPCfg.ExcitBufGain; - hsdac_cfg.HsDacGain = HSDACGAIN_1;//AppIMPCfg.HsDacGain; - hsdac_cfg.HsDacUpdateRate = 0x1B; - AD5940_HSDacCfgS(&hsdac_cfg); - AD5940_HSRTIACfgS(HSTIARTIA_40K); //set as per load current range - - /*Update ADC rate */ - filter_cfg.ADCRate = ADCRATE_800KHZ; - AppIMPCfg.AdcClkFreq = 16e6; - - /* Change clock to 16MHz oscillator */ - AD5940_HPModeEn(bFALSE); - } - else if(freq < 5 ) - { - /* Update HSDAC update rate */ - hsdac_cfg.ExcitBufGain =EXCITBUFGAIN_2;// AppIMPCfg.ExcitBufGain; - hsdac_cfg.HsDacGain = HSDACGAIN_1;//AppIMPCfg.HsDacGain; - hsdac_cfg.HsDacUpdateRate = 0x1B; - AD5940_HSDacCfgS(&hsdac_cfg); - AD5940_HSRTIACfgS(HSTIARTIA_40K); //set as per load current range - - /*Update ADC rate */ - filter_cfg.ADCRate = ADCRATE_800KHZ; - AppIMPCfg.AdcClkFreq = 16e6; - - /* Change clock to 16MHz oscillator */ - AD5940_HPModeEn(bFALSE); - - }else if(freq < 450) - { - /* Update HSDAC update rate */ - hsdac_cfg.ExcitBufGain =AppIMPCfg.ExcitBufGain; - hsdac_cfg.HsDacGain = AppIMPCfg.HsDacGain; - - hsdac_cfg.HsDacUpdateRate = 0x1B; - AD5940_HSDacCfgS(&hsdac_cfg); - AD5940_HSRTIACfgS(HSTIARTIA_5K); //set as per load current range - - /*Update ADC rate */ - filter_cfg.ADCRate = ADCRATE_800KHZ; - AppIMPCfg.AdcClkFreq = 16e6; - - /* Change clock to 16MHz oscillator */ - AD5940_HPModeEn(bFALSE); - } - else if(freq<80000) - { - /* Update HSDAC update rate */ - hsdac_cfg.ExcitBufGain =AppIMPCfg.ExcitBufGain; - hsdac_cfg.HsDacGain = AppIMPCfg.HsDacGain; - hsdac_cfg.HsDacUpdateRate = 0x1B; - AD5940_HSDacCfgS(&hsdac_cfg); - AD5940_HSRTIACfgS(HSTIARTIA_5K); //set as per load current range - - /*Update ADC rate */ - filter_cfg.ADCRate = ADCRATE_800KHZ; - AppIMPCfg.AdcClkFreq = 16e6; - - /* Change clock to 16MHz oscillator */ - AD5940_HPModeEn(bFALSE); - } - /* High power mode */ - if(freq >= 80000) - { - /* Update HSDAC update rate */ - hsdac_cfg.ExcitBufGain =AppIMPCfg.ExcitBufGain; - hsdac_cfg.HsDacGain = AppIMPCfg.HsDacGain; - hsdac_cfg.HsDacUpdateRate = 0x07; - AD5940_HSDacCfgS(&hsdac_cfg); - AD5940_HSRTIACfgS(HSTIARTIA_5K); //set as per load current range - - /*Update ADC rate */ - filter_cfg.ADCRate = ADCRATE_1P6MHZ; - AppIMPCfg.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 = AppIMPCfg.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 = AppIMPCfg.SysClkFreq/AppIMPCfg.AdcClkFreq; - AD5940_ClksCalculate(&clks_cal, &WaitClks); - - - SRAMAddr = AppIMPCfg.MeasureSeqInfo.SeqRamAddr + AppIMPCfg.SeqWaitAddr[0]; - - SeqCmdBuff[0] =SEQ_WAIT(WaitClks/2); - SeqCmdBuff[1] =SEQ_WAIT(WaitClks/2); - - AD5940_SEQCmdWrite(SRAMAddr, SeqCmdBuff, 2); - - SRAMAddr = AppIMPCfg.MeasureSeqInfo.SeqRamAddr + AppIMPCfg.SeqWaitAddr[1]; - - SeqCmdBuff[0] =SEQ_WAIT(WaitClks/2); - SeqCmdBuff[1] =SEQ_WAIT(WaitClks/2); - - AD5940_SEQCmdWrite(SRAMAddr, SeqCmdBuff, 2); - - - return AD5940ERR_OK; -} - - -/* This function provide application initialize. It can also enable Wupt that will automatically trigger sequence. Or it can configure */ -int32_t AppIMPInit(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 = bTRUE; - 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 = AppIMPCfg.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((AppIMPCfg.IMPInited == bFALSE)||\ - (AppIMPCfg.bParaChanged == bTRUE)) - { - if(pBuffer == 0) return AD5940ERR_PARA; - if(BufferSize == 0) return AD5940ERR_PARA; - AD5940_SEQGenInit(pBuffer, BufferSize); - - /* Generate initialize sequence */ - error = AppIMPSeqCfgGen(); /* Application initialization sequence using either MCU or sequencer */ - if(error != AD5940ERR_OK) return error; - - /* Generate measurement sequence */ - error = AppIMPSeqMeasureGen(); - if(error != AD5940ERR_OK) return error; - - AppIMPCfg.bParaChanged = bFALSE; /* Clear this flag as we already implemented the new configuration */ - } - - /* Initialization sequencer */ - AppIMPCfg.InitSeqInfo.WriteSRAM = bFALSE; - AD5940_SEQInfoCfg(&AppIMPCfg.InitSeqInfo); - seq_cfg.SeqEnable = bTRUE; - AD5940_SEQCfg(&seq_cfg); /* Enable sequencer */ - AD5940_SEQMmrTrig(AppIMPCfg.InitSeqInfo.SeqId); - while(AD5940_INTCTestFlag(AFEINTC_1, AFEINTSRC_ENDSEQ) == bFALSE); - AD5940_INTCClrFlag(AFEINTSRC_ALLINT); - /* Measurement sequence */ - AppIMPCfg.MeasureSeqInfo.WriteSRAM = bFALSE; - AD5940_SEQInfoCfg(&AppIMPCfg.MeasureSeqInfo); - - AppIMPCheckFreq(AppIMPCfg.FreqofData); - - seq_cfg.SeqEnable = bTRUE; - AD5940_SEQCfg(&seq_cfg); /* Enable sequencer, and wait for trigger */ - AD5940_ClrMCUIntFlag(); /* Clear interrupt flag generated before */ - - //AD5940_AFEPwrBW(AppIMPCfg.PwrMod, AFEBW_250KHZ); - - AppIMPCfg.IMPInited = bTRUE; /* IMP application has been initialized. */ - return AD5940ERR_OK; -} - -/* Modify registers when AFE wakeup */ -int32_t AppIMPRegModify(int32_t * const pData, uint32_t *pDataCount) -{ - if(AppIMPCfg.NumOfData > 0) - { - AppIMPCfg.FifoDataCount += *pDataCount/4; - if(AppIMPCfg.FifoDataCount >= AppIMPCfg.NumOfData) - { - AD5940_WUPTCtrl(bFALSE); - return AD5940ERR_OK; - } - } - if(AppIMPCfg.StopRequired == bTRUE) - { - AD5940_WUPTCtrl(bFALSE); - return AD5940ERR_OK; - } - if(AppIMPCfg.SweepCfg.SweepEn) /* Need to set new frequency and set power mode */ - { - AD5940_WGFreqCtrlS(AppIMPCfg.SweepNextFreq, AppIMPCfg.SysClkFreq); - AppIMPCheckFreq(AppIMPCfg.SweepNextFreq); - } - return AD5940ERR_OK; -} - -/* 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; iReal*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; -} - -/** - -*/ -int32_t AppIMPISR(void *pBuff, uint32_t *pCount) -{ - uint32_t BuffCount; - uint32_t FifoCnt; - BuffCount = *pCount; - - *pCount = 0; - - if(AD5940_WakeUp(10) > 10) /* Wakeup AFE by read register, read 10 times at most */ - return AD5940ERR_WAKEUP; /* Wakeup Failed */ - AD5940_SleepKeyCtrlS(SLPKEY_LOCK); /* Prohibit AFE to enter sleep mode. */ - - if(AD5940_INTCTestFlag(AFEINTC_0, AFEINTSRC_DATAFIFOTHRESH) == bTRUE) - { - /* Now there should be 4 data in FIFO */ - FifoCnt = (AD5940_FIFOGetCnt()/4)*4; - - if(FifoCnt > BuffCount) - { - ///@todo buffer is limited. - } - AD5940_FIFORd((uint32_t *)pBuff, FifoCnt); - AD5940_INTCClrFlag(AFEINTSRC_DATAFIFOTHRESH); - AppIMPRegModify(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. This operation only takes effect when register value is ACTIVE previously */ - AD5940_SleepKeyCtrlS(SLPKEY_UNLOCK); /* Allow AFE to enter sleep mode. */ - /* Process data */ - AppIMPDataProcess((int32_t*)pBuff,&FifoCnt); - *pCount = FifoCnt; - return 0; - } - - return 0; -} - - diff --git a/host/src/MainWindow.cpp b/host/src/MainWindow.cpp index 3a6a1c6..b5edfda 100644 --- a/host/src/MainWindow.cpp +++ b/host/src/MainWindow.cpp @@ -1,3 +1,4 @@ +// File: host/src/MainWindow.cpp #include "MainWindow.h" #include #include @@ -10,7 +11,7 @@ #include #include -MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), currentSweepIndex(0), isSweeping(false) { +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { serial = new QSerialPort(this); connect(serial, &QSerialPort::readyRead, this, &MainWindow::handleSerialData); connect(serial, &QSerialPort::errorOccurred, this, &MainWindow::onPortError); @@ -18,7 +19,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), currentSweepIndex setupUi(); // Delayed refresh to allow the window to render before auto-scanning QTimer::singleShot(1000, this, &MainWindow::refreshPorts); - generateSweepPoints(); // Enable Swipe Gestures for Mobile Tab Switching grabGesture(Qt::SwipeGesture); @@ -103,10 +103,13 @@ void MainWindow::setupUi() { connect(calibrateBtn, &QPushButton::clicked, this, &MainWindow::runCalibration); connect(sweepBtn, &QPushButton::clicked, this, &MainWindow::startSweep); - connect(measureBtn, &QPushButton::clicked, [this]() { + // Measure Button Logic + connect(measureBtn, &QPushButton::clicked, [this, spinFreq]() { if (serial->isOpen()) { - logWidget->append(">> Requesting Measure (m)..."); - serial->write("m"); + double freq = spinFreq->value(); + logWidget->append(QString(">> Requesting Measure (m %1)...").arg(freq)); + // Send 'm \n' + serial->write(QString("m %1\n").arg(freq).toUtf8()); } }); @@ -149,7 +152,6 @@ void MainWindow::connectToPort() { checkIdBtn->setEnabled(false); calibrateBtn->setEnabled(false); sweepBtn->setEnabled(false); - isSweeping = false; return; } @@ -177,42 +179,33 @@ void MainWindow::onPortError(QSerialPort::SerialPortError error) { checkIdBtn->setEnabled(false); calibrateBtn->setEnabled(false); sweepBtn->setEnabled(false); - isSweeping = false; } } void MainWindow::checkDeviceId() { if (serial->isOpen()) { logWidget->append(">> Checking ID (v)..."); - serial->write("v"); + serial->write("v\n"); } } void MainWindow::runCalibration() { if (serial->isOpen()) { logWidget->append(">> Running Calibration (c)..."); - serial->write("c"); + serial->write("c\n"); } } void MainWindow::startSweep() { if (!serial->isOpen()) return; - isSweeping = true; - currentSweepIndex = 0; + finalGraph->clear(); rawGraph->clear(); - logWidget->append(">> Starting Ratio-metric Sweep..."); - sendNextSweepPoint(); -} - -void MainWindow::sendNextSweepPoint() { - if (!isSweeping || !serial->isOpen()) return; - if (currentSweepIndex >= sweepPoints.size()) { - isSweeping = false; - logWidget->append(">> Sweep Complete."); - return; - } - serial->write("m"); + + // Use Firmware Sweep Command: s + // Example: 100Hz to 200kHz, 50 steps + logWidget->append(">> Starting Firmware Sweep (s 100 200000 50)..."); + serial->write("s 100 200000 50\n"); } void MainWindow::handleSerialData() { @@ -232,6 +225,7 @@ void MainWindow::handleSerialData() { } void MainWindow::parseData(const QString &data) { + // Format: DATA,Freq,Mag,Phase,Real,Imag QStringList parts = data.split(','); if (parts.size() < 6) return; @@ -244,24 +238,6 @@ void MainWindow::parseData(const QString &data) { if (okF && okM && okP) finalGraph->addData(freq, mag, phase); if (okF && okR && okI) rawGraph->addData(freq, real, imag); - - if (isSweeping) { - currentSweepIndex++; - QTimer::singleShot(50, this, &MainWindow::sendNextSweepPoint); - } -} - -void MainWindow::generateSweepPoints() { - sweepPoints.clear(); - double startFreq = 100.0; - double endFreq = 200000.0; - int steps = 50; - double logStart = std::log10(startFreq); - double logEnd = std::log10(endFreq); - double logStep = (logEnd - logStart) / (steps - 1); - for (int i = 0; i < steps; ++i) { - sweepPoints.append(std::pow(10, logStart + i * logStep)); - } } bool MainWindow::event(QEvent *event) { diff --git a/host/src/MainWindow.h b/host/src/MainWindow.h index c60f60f..66a1ecf 100644 --- a/host/src/MainWindow.h +++ b/host/src/MainWindow.h @@ -1,3 +1,4 @@ +// File: host/src/MainWindow.h #pragma once #include @@ -35,13 +36,11 @@ private slots: void checkDeviceId(); void runCalibration(); void startSweep(); - void sendNextSweepPoint(); private: void setupUi(); void parseData(const QString &data); void handleSwipe(QSwipeGesture *gesture); - void generateSweepPoints(); QSerialPort *serial; @@ -58,9 +57,4 @@ private: QPushButton *checkIdBtn; QPushButton *calibrateBtn; QPushButton *sweepBtn; - - // Sweep Logic - QList sweepPoints; - int currentSweepIndex; - bool isSweeping; }; \ No newline at end of file diff --git a/main.c b/main.c index 784e310..1de3271 100644 --- a/main.c +++ b/main.c @@ -1,257 +1,272 @@ // File: main.c #include #include +#include +#include #include "pico/stdlib.h" #include "hardware/spi.h" #include "hardware/gpio.h" +#include "hardware/watchdog.h" #include "ad5940.h" +#include "Impedance.h" -// Pin Definitions +// --------------------------------------------------------------------------- +// Hardware Definitions +// --------------------------------------------------------------------------- #define PIN_MISO 0 #define PIN_CS 1 #define PIN_SCK 2 #define PIN_MOSI 3 #define PIN_RST 9 -#define PIN_INT 29 +#define PIN_INT 29 -#define RCAL_VALUE 100.0f +#define APPBUFF_SIZE 512 +uint32_t AppBuff[APPBUFF_SIZE]; // --------------------------------------------------------------------------- -// Platform Interface Implementation (Required by AD5940 Lib) +// Platform Interface Implementation // --------------------------------------------------------------------------- - -void AD5940_CsClr(void) { - gpio_put(PIN_CS, 0); -} - -void AD5940_CsSet(void) { - gpio_put(PIN_CS, 1); -} - -void AD5940_RstClr(void) { - gpio_put(PIN_RST, 0); -} - -void AD5940_RstSet(void) { - gpio_put(PIN_RST, 1); -} - -void AD5940_Delay10us(uint32_t time) { - sleep_us(time * 10); -} - +void AD5940_CsClr(void) { gpio_put(PIN_CS, 0); } +void AD5940_CsSet(void) { gpio_put(PIN_CS, 1); } +void AD5940_RstClr(void) { gpio_put(PIN_RST, 0); } +void AD5940_RstSet(void) { gpio_put(PIN_RST, 1); } +void AD5940_Delay10us(uint32_t time) { sleep_us(time * 10); } void AD5940_ReadWriteNBytes(unsigned char *pSendBuffer, unsigned char *pRecvBuff, unsigned long length) { spi_write_read_blocking(spi0, pSendBuffer, pRecvBuff, length); } +uint32_t AD5940_GetMCUIntFlag(void) { + return (gpio_get(PIN_INT) == 0); +} + +uint32_t AD5940_ClrMCUIntFlag(void) { + return 1; +} + +uint32_t AD5940_MCUResourceInit(void *pCfg) { + return 0; +} + +void AD5940_MCUGpioWrite(uint32_t data) { (void)data; } +uint32_t AD5940_MCUGpioRead(uint32_t pin) { (void)pin; return 0; } +void AD5940_MCUGpioCtrl(uint32_t pin, BoolFlag enable) { (void)pin; (void)enable; } + // --------------------------------------------------------------------------- // Application Logic // --------------------------------------------------------------------------- void setup_pins(void) { - // SPI0 at 1MHz - spi_init(spi0, 1000000); + // Increase SPI speed to 4MHz to prevent FIFO overflow during fast sweeps + spi_init(spi0, 4000000); gpio_set_function(PIN_MISO, GPIO_FUNC_SPI); gpio_set_function(PIN_SCK, GPIO_FUNC_SPI); gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI); - // CS gpio_init(PIN_CS); gpio_set_dir(PIN_CS, GPIO_OUT); gpio_put(PIN_CS, 1); - // RST gpio_init(PIN_RST); gpio_set_dir(PIN_RST, GPIO_OUT); gpio_put(PIN_RST, 1); - // INT gpio_init(PIN_INT); gpio_set_dir(PIN_INT, GPIO_IN); - gpio_pull_up(PIN_INT); + gpio_pull_up(PIN_INT); } -void configure_afe(void) { - HSDACCfg_Type hsdac_cfg; - HSTIACfg_Type hsrtia_cfg; - HSLoopCfg_Type hsloop_cfg; +void AD5940ImpedanceStructInit(void) +{ + AppIMPCfg_Type *pImpedanceCfg; + + AppIMPGetCfg(&pImpedanceCfg); + + pImpedanceCfg->SeqStartAddr = 0; + pImpedanceCfg->MaxSeqLen = 512; - // Reset AFE control - AD5940_AFECtrlS(AFECTRL_ALL, bFALSE); + pImpedanceCfg->RcalVal = 10000.0; + pImpedanceCfg->RtiaVal = 200.0; + pImpedanceCfg->SinFreq = 1000.0; + pImpedanceCfg->FifoThresh = 6; + + pImpedanceCfg->DacVoltPP = 600.0; + pImpedanceCfg->ExcitBufGain = EXCITBUFGAIN_0P25; + pImpedanceCfg->HsDacGain = HSDACGAIN_0P2; + + pImpedanceCfg->DswitchSel = SWD_CE0; + pImpedanceCfg->PswitchSel = SWP_CE0; + pImpedanceCfg->NswitchSel = SWN_SE0; + pImpedanceCfg->TswitchSel = SWT_TRTIA; - // Configure High Speed DAC - hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_2; - hsdac_cfg.HsDacGain = HSDACGAIN_1; - hsdac_cfg.HsDacUpdateRate = 0x1B; - AD5940_HSDacCfgS(&hsdac_cfg); + pImpedanceCfg->HstiaRtiaSel = HSTIARTIA_200; + pImpedanceCfg->BiasVolt = 0.0; - // Configure High Speed TIA - hsrtia_cfg.HstiaDeRtia = HSTIADERTIA_1K; - hsrtia_cfg.HstiaCtia = 31; // 31pF - hsrtia_cfg.HstiaRtiaSel = HSTIARTIA_1K; - hsrtia_cfg.HstiaBias = HSTIABIAS_1P1; - hsrtia_cfg.DiodeClose = bFALSE; - hsrtia_cfg.HstiaDeRload = HSTIADERLOAD_OPEN; - AD5940_HSTIACfgS(&hsrtia_cfg); + pImpedanceCfg->SweepCfg.SweepEn = bFALSE; + pImpedanceCfg->SweepCfg.SweepStart = 100.0f; + pImpedanceCfg->SweepCfg.SweepStop = 100000.0f; + pImpedanceCfg->SweepCfg.SweepPoints = 50; + pImpedanceCfg->SweepCfg.SweepLog = bTRUE; - // Configure High Speed Loop - hsloop_cfg.HsDacCfg = hsdac_cfg; - hsloop_cfg.HsTiaCfg = hsrtia_cfg; - - hsloop_cfg.SWMatCfg.Dswitch = SWD_OPEN; - hsloop_cfg.SWMatCfg.Pswitch = SWP_OPEN; - hsloop_cfg.SWMatCfg.Nswitch = SWN_OPEN; - hsloop_cfg.SWMatCfg.Tswitch = SWT_OPEN; - - hsloop_cfg.WgCfg.WgType = WGTYPE_SIN; - hsloop_cfg.WgCfg.GainCalEn = bFALSE; - hsloop_cfg.WgCfg.OffsetCalEn = bFALSE; - hsloop_cfg.WgCfg.SinCfg.SinFreqWord = AD5940_WGFreqWordCal(1000.0, 16000000.0); - hsloop_cfg.WgCfg.SinCfg.SinAmplitudeWord = 2047; - hsloop_cfg.WgCfg.SinCfg.SinOffsetWord = 0; - hsloop_cfg.WgCfg.SinCfg.SinPhaseWord = 0; - - AD5940_HSLoopCfgS(&hsloop_cfg); - - // Enable Power - AD5940_AFECtrlS(AFECTRL_ADCPWR | AFECTRL_HSTIAPWR | AFECTRL_HSDACPWR | AFECTRL_HPREFPWR, bTRUE); - - // Enable Interrupts - AD5940_WriteReg(REG_INTC_INTCSEL0, BITM_INTC_INTCSEL0_INTSEL14); + pImpedanceCfg->PwrMod = AFEPWR_LP; + pImpedanceCfg->ADCSinc3Osr = ADCSINC3OSR_4; + pImpedanceCfg->DftNum = DFTNUM_16384; + pImpedanceCfg->DftSrc = DFTSRC_SINC3; } -float perform_dft(void) { - iImpCar_Type dft_res; - fImpCar_Type f_res; - - AD5940_AFECtrlS(AFECTRL_ADCCNV | AFECTRL_DFT, bTRUE); - - // Wait for interrupt or timeout - uint32_t timeout = 50000; - while(gpio_get(PIN_INT) && timeout--) { - sleep_us(10); +static int32_t AD5940PlatformCfg(void) +{ + CLKCfg_Type clk_cfg; + FIFOCfg_Type fifo_cfg; + AGPIOCfg_Type gpio_cfg; + + AD5940_HWReset(); + AD5940_Initialize(); + + 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); + + fifo_cfg.FIFOEn = bFALSE; + fifo_cfg.FIFOMode = FIFOMODE_FIFO; + fifo_cfg.FIFOSize = FIFOSIZE_4KB; + fifo_cfg.FIFOSrc = FIFOSRC_DFT; + fifo_cfg.FIFOThresh = 6; + AD5940_FIFOCfg(&fifo_cfg); + fifo_cfg.FIFOEn = bTRUE; + AD5940_FIFOCfg(&fifo_cfg); + + AD5940_INTCCfg(AFEINTC_1, AFEINTSRC_ALLINT, bTRUE); + AD5940_INTCClrFlag(AFEINTSRC_ALLINT); + AD5940_INTCCfg(AFEINTC_0, AFEINTSRC_DATAFIFOTHRESH, bTRUE); + AD5940_INTCClrFlag(AFEINTSRC_ALLINT); + + gpio_cfg.FuncSet = GP0_INT; + gpio_cfg.InputEnSet = 0; + gpio_cfg.OutputEnSet = AGPIO_Pin0; + gpio_cfg.OutVal = 0; + gpio_cfg.PullEnSet = 0; + AD5940_AGPIOCfg(&gpio_cfg); + + AD5940_SleepKeyCtrlS(SLPKEY_UNLOCK); + return 0; +} + +void ImpedanceShowResult(uint32_t *pData, uint32_t DataCount) +{ + float freq; + fImpPol_Type *pImp = (fImpPol_Type*)pData; + AppIMPCtrl(IMPCTRL_GETFREQ, &freq); + + for(int i=0;iSweepCfg.SweepEn = bFALSE; + pCfg->SinFreq = 1000.0f; + if(AppIMPInit(AppBuff, APPBUFF_SIZE) == AD5940ERR_OK) { + AppIMPCtrl(IMPCTRL_START, 0); + } else { + printf("ERROR: Init Failed\n"); + } } - - dft_res.Real = (int32_t)AD5940_ReadReg(REG_AFE_DFTREAL); - dft_res.Image = (int32_t)AD5940_ReadReg(REG_AFE_DFTIMAG); - - AD5940_AFECtrlS(AFECTRL_ADCCNV | AFECTRL_DFT, bFALSE); - AD5940_WriteReg(REG_INTC_INTCFLAG0, BITM_INTC_INTCFLAG0_FLAG14); - - f_res.Real = (float)dft_res.Real; - f_res.Image = (float)dft_res.Image; - - return AD5940_ComplexMag(&f_res); -} - -void set_sw_matrix(uint32_t lp_sw, uint32_t hs_sw) { - AD5940_WriteReg(REG_AFE_LPTIASW0, lp_sw); - AD5940_WriteReg(REG_AFE_HSTIACON, hs_sw); -} - -void measure_at_freq(float freq) { - FreqParams_Type freq_params = AD5940_GetFreqParameters(freq); - - // 1. Update HSDAC Update Rate based on frequency - uint32_t hsdac_rate = 0x1B; - if(freq >= 80000.0f) { - hsdac_rate = 0x07; + else if (cmd == 'm') { + float freq = 1000.0f; + if (strlen(input_buffer) > 2) freq = atof(input_buffer + 2); + + pCfg->SweepCfg.SweepEn = bFALSE; + pCfg->SinFreq = freq; + + if(AppIMPInit(AppBuff, APPBUFF_SIZE) == AD5940ERR_OK) { + AppIMPCtrl(IMPCTRL_START, 0); + } else { + printf("ERROR: Init Failed\n"); + } } - - uint32_t hsdaccon = AD5940_ReadReg(REG_AFE_HSDACCON); - hsdaccon &= ~BITM_AFE_HSDACCON_RATE; - hsdaccon |= (hsdac_rate << BITP_AFE_HSDACCON_RATE); - AD5940_WriteReg(REG_AFE_HSDACCON, hsdaccon); - - // 2. Update Waveform Generator Frequency - uint32_t freq_word = AD5940_WGFreqWordCal(freq, 16000000.0f); - AD5940_WriteReg(REG_AFE_WGFCW, freq_word); - - // 3. Update Filter Settings - ADCFilterCfg_Type filter_cfg; - // Initialize struct to 0 to avoid garbage - filter_cfg.ADCSinc3Osr = freq_params.ADCSinc3Osr; - filter_cfg.ADCSinc2Osr = freq_params.ADCSinc2Osr; - filter_cfg.ADCAvgNum = ADCAVGNUM_16; - filter_cfg.ADCRate = ADCRATE_800KHZ; - filter_cfg.BpNotch = bTRUE; - filter_cfg.BpSinc3 = bFALSE; - filter_cfg.Sinc2NotchEnable = bTRUE; - filter_cfg.DFTClkEnable = bTRUE; - filter_cfg.WGClkEnable = bTRUE; - filter_cfg.Sinc3ClkEnable = bTRUE; - filter_cfg.Sinc2NotchClkEnable = bTRUE; - AD5940_ADCFilterCfgS(&filter_cfg); - - DFTCfg_Type dft_cfg; - dft_cfg.DftNum = freq_params.DftNum; - dft_cfg.DftSrc = freq_params.DftSrc; - dft_cfg.HanWinEn = bTRUE; - AD5940_DFTCfgS(&dft_cfg); - - // 4. Perform Measurement - // RCAL - set_sw_matrix(0, SWP_RCAL0 | SWN_RCAL1); - sleep_ms(5); - float mag_cal = perform_dft(); - - // Z - set_sw_matrix(0, SWP_CE0 | SWP_RE0 | SWN_SE0 | SWT_DE0); - sleep_ms(5); - float mag_z = perform_dft(); - - if (mag_z > 0.01f && mag_cal > 0.01f) { - float impedance = (mag_cal / mag_z) * RCAL_VALUE; - printf("DATA,%.2f,%.2f,0,0,0\n", freq, impedance); - } else { - printf("DATA,%.2f,0,0,0,0\n", freq); + else if (cmd == 's') { + float start = 100.0f, end = 100000.0f; + int steps = 50; + if (strlen(input_buffer) > 2) sscanf(input_buffer + 2, "%f %f %d", &start, &end, &steps); + + pCfg->SweepCfg.SweepEn = bTRUE; + pCfg->SweepCfg.SweepStart = start; + pCfg->SweepCfg.SweepStop = end; + pCfg->SweepCfg.SweepPoints = steps; + pCfg->SweepCfg.SweepLog = bTRUE; + + if(AppIMPInit(AppBuff, APPBUFF_SIZE) == AD5940ERR_OK) { + AppIMPCtrl(IMPCTRL_START, 0); + } else { + printf("ERROR: Init Failed\n"); + } } -} - -void run_sweep(float start_freq, float end_freq, int steps) { - float log_start = log10f(start_freq); - float log_end = log10f(end_freq); - float step_size = (steps > 1) ? (log_end - log_start) / (steps - 1) : 0; - - printf("START_SWEEP\n"); - - for (int i = 0; i < steps; ++i) { - float freq = powf(10.0f, log_start + (i * step_size)); - measure_at_freq(freq); + else if (cmd == 'z') { + // Full System Reset + watchdog_reboot(0, 0, 0); } - - printf("END_SWEEP\n"); -} - -void system_init(void) { - setup_pins(); - - // Hardware Reset AD5940 - AD5940_RstClr(); - sleep_ms(10); - AD5940_RstSet(); - sleep_ms(10); - - AD5940_Initialize(); - configure_afe(); } int main() { stdio_init_all(); sleep_ms(2000); - system_init(); - + setup_pins(); + AD5940PlatformCfg(); + AD5940ImpedanceStructInit(); + printf("SYSTEM_READY\n"); while (true) { - int c = getchar_timeout_us(100); - if (c == 'm') { - run_sweep(100.0f, 100000.0f, 50); + int c = getchar_timeout_us(0); + if (c != PICO_ERROR_TIMEOUT) { + if (c == '\n' || c == '\r') { + input_buffer[input_pos] = 0; + if (input_pos > 0) process_command(); + input_pos = 0; + } else if (input_pos < 63) { + input_buffer[input_pos++] = (char)c; + } } - if (c == 'z') { - system_init(); - printf("RESET_DONE\n"); + + if (gpio_get(PIN_INT) == 0) { + uint32_t temp = APPBUFF_SIZE; + AppIMPISR(AppBuff, &temp); + if(temp > 0) { + ImpedanceShowResult(AppBuff, temp); + } } } return 0;