i know this shit is SLOPPY rn but we finally have DATA even if it is in the form of a COMPLETE MALFUNTION wooo
This commit is contained in:
parent
6e1d6cc970
commit
b96e59e543
|
|
@ -14,6 +14,7 @@ pico_sdk_init()
|
|||
add_executable(EIS
|
||||
main.c
|
||||
ad5940.c
|
||||
Impedance.c
|
||||
)
|
||||
|
||||
target_compile_definitions(EIS PRIVATE CHIPSEL_594X)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,669 @@
|
|||
// File: Impedance.c
|
||||
#include "ad5940.h"
|
||||
#include <stdio.h>
|
||||
#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; i<DataCount; i++)
|
||||
{
|
||||
pData[i] &= 0x3ffff;
|
||||
if(pData[i]&(1L<<17))
|
||||
{
|
||||
pData[i] |= 0xfffc0000;
|
||||
}
|
||||
}
|
||||
|
||||
for(uint32_t i=0; i<ImpResCount; i++)
|
||||
{
|
||||
iImpCar_Type *pDftRcal, *pDftI, *pDftV;
|
||||
|
||||
pDftRcal = pSrcData++;
|
||||
pDftI = pSrcData++;
|
||||
pDftV = pSrcData++;
|
||||
|
||||
float MagI, PhaseI;
|
||||
float MagV, PhaseV;
|
||||
float ZMag, ZPhase;
|
||||
|
||||
// Calculate Magnitude and Phase for Current (I)
|
||||
MagI = sqrt((float)pDftI->Real*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;
|
||||
}
|
||||
|
|
@ -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,7 +64,6 @@ 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);
|
||||
|
|
@ -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 <stdio.h>
|
||||
#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; i<DataCount; i++)
|
||||
{
|
||||
pData[i] &= 0x3ffff;
|
||||
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++)
|
||||
{
|
||||
if(1)
|
||||
{
|
||||
fImpCar_Type DftRcal, DftRzRload, DftRload, temp1, temp2, res;
|
||||
fImpCar_Type DftConst1 = {1.0f, 0};
|
||||
/*
|
||||
The sign of DFT Image result is added '-1' by hardware. Fix it below.
|
||||
*/
|
||||
DftRzRload.Real = pSrcData->Real;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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 <stdio.h>
|
||||
#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
|
||||
|
|
@ -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 <stdio.h>
|
||||
#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; 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
// File: host/src/MainWindow.cpp
|
||||
#include "MainWindow.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QDebug>
|
||||
|
|
@ -10,7 +11,7 @@
|
|||
#include <QTimer>
|
||||
#include <cmath>
|
||||
|
||||
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 <freq>\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 <start> <end> <steps>
|
||||
// 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) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// File: host/src/MainWindow.h
|
||||
#pragma once
|
||||
|
||||
#include <QMainWindow>
|
||||
|
|
@ -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<double> sweepPoints;
|
||||
int currentSweepIndex;
|
||||
bool isSweeping;
|
||||
};
|
||||
389
main.c
389
main.c
|
|
@ -1,12 +1,18 @@
|
|||
// File: main.c
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#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
|
||||
|
|
@ -14,244 +20,253 @@
|
|||
#define PIN_RST 9
|
||||
#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);
|
||||
}
|
||||
|
||||
void configure_afe(void) {
|
||||
HSDACCfg_Type hsdac_cfg;
|
||||
HSTIACfg_Type hsrtia_cfg;
|
||||
HSLoopCfg_Type hsloop_cfg;
|
||||
void AD5940ImpedanceStructInit(void)
|
||||
{
|
||||
AppIMPCfg_Type *pImpedanceCfg;
|
||||
|
||||
// Reset AFE control
|
||||
AD5940_AFECtrlS(AFECTRL_ALL, bFALSE);
|
||||
AppIMPGetCfg(&pImpedanceCfg);
|
||||
|
||||
// Configure High Speed DAC
|
||||
hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_2;
|
||||
hsdac_cfg.HsDacGain = HSDACGAIN_1;
|
||||
hsdac_cfg.HsDacUpdateRate = 0x1B;
|
||||
AD5940_HSDacCfgS(&hsdac_cfg);
|
||||
pImpedanceCfg->SeqStartAddr = 0;
|
||||
pImpedanceCfg->MaxSeqLen = 512;
|
||||
|
||||
// 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->RcalVal = 10000.0;
|
||||
pImpedanceCfg->RtiaVal = 200.0;
|
||||
pImpedanceCfg->SinFreq = 1000.0;
|
||||
pImpedanceCfg->FifoThresh = 6;
|
||||
|
||||
// Configure High Speed Loop
|
||||
hsloop_cfg.HsDacCfg = hsdac_cfg;
|
||||
hsloop_cfg.HsTiaCfg = hsrtia_cfg;
|
||||
pImpedanceCfg->DacVoltPP = 600.0;
|
||||
pImpedanceCfg->ExcitBufGain = EXCITBUFGAIN_0P25;
|
||||
pImpedanceCfg->HsDacGain = HSDACGAIN_0P2;
|
||||
|
||||
hsloop_cfg.SWMatCfg.Dswitch = SWD_OPEN;
|
||||
hsloop_cfg.SWMatCfg.Pswitch = SWP_OPEN;
|
||||
hsloop_cfg.SWMatCfg.Nswitch = SWN_OPEN;
|
||||
hsloop_cfg.SWMatCfg.Tswitch = SWT_OPEN;
|
||||
pImpedanceCfg->DswitchSel = SWD_CE0;
|
||||
pImpedanceCfg->PswitchSel = SWP_CE0;
|
||||
pImpedanceCfg->NswitchSel = SWN_SE0;
|
||||
pImpedanceCfg->TswitchSel = SWT_TRTIA;
|
||||
|
||||
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;
|
||||
pImpedanceCfg->HstiaRtiaSel = HSTIARTIA_200;
|
||||
pImpedanceCfg->BiasVolt = 0.0;
|
||||
|
||||
AD5940_HSLoopCfgS(&hsloop_cfg);
|
||||
pImpedanceCfg->SweepCfg.SweepEn = bFALSE;
|
||||
pImpedanceCfg->SweepCfg.SweepStart = 100.0f;
|
||||
pImpedanceCfg->SweepCfg.SweepStop = 100000.0f;
|
||||
pImpedanceCfg->SweepCfg.SweepPoints = 50;
|
||||
pImpedanceCfg->SweepCfg.SweepLog = bTRUE;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
printf("END_SWEEP\n");
|
||||
}
|
||||
|
||||
void system_init(void) {
|
||||
setup_pins();
|
||||
|
||||
// Hardware Reset AD5940
|
||||
AD5940_RstClr();
|
||||
sleep_ms(10);
|
||||
AD5940_RstSet();
|
||||
sleep_ms(10);
|
||||
static int32_t AD5940PlatformCfg(void)
|
||||
{
|
||||
CLKCfg_Type clk_cfg;
|
||||
FIFOCfg_Type fifo_cfg;
|
||||
AGPIOCfg_Type gpio_cfg;
|
||||
|
||||
AD5940_HWReset();
|
||||
AD5940_Initialize();
|
||||
configure_afe();
|
||||
|
||||
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;i<DataCount;i++)
|
||||
{
|
||||
printf("DATA,%.2f,%.4f,%.4f,%.4f,%.4f\n",
|
||||
freq,
|
||||
pImp[i].Magnitude,
|
||||
pImp[i].Phase*180/MATH_PI,
|
||||
pImp[i].Magnitude,
|
||||
pImp[i].Phase
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Main Loop
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
char input_buffer[64];
|
||||
int input_pos = 0;
|
||||
|
||||
void process_command() {
|
||||
char cmd = input_buffer[0];
|
||||
AppIMPCfg_Type *pCfg;
|
||||
AppIMPGetCfg(&pCfg);
|
||||
|
||||
// CRITICAL: Stop any running measurement before reconfiguration
|
||||
AppIMPCtrl(IMPCTRL_STOPNOW, 0);
|
||||
|
||||
if (cmd == 'v') {
|
||||
uint32_t id = AD5940_ReadReg(REG_AFECON_CHIPID);
|
||||
printf("CHIP_ID:0x%04X\n", id);
|
||||
}
|
||||
else if (cmd == 'c') {
|
||||
pCfg->SweepCfg.SweepEn = bFALSE;
|
||||
pCfg->SinFreq = 1000.0f;
|
||||
if(AppIMPInit(AppBuff, APPBUFF_SIZE) == AD5940ERR_OK) {
|
||||
AppIMPCtrl(IMPCTRL_START, 0);
|
||||
} else {
|
||||
printf("ERROR: Init Failed\n");
|
||||
}
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
else if (cmd == 'z') {
|
||||
// Full System Reset
|
||||
watchdog_reboot(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
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 (gpio_get(PIN_INT) == 0) {
|
||||
uint32_t temp = APPBUFF_SIZE;
|
||||
AppIMPISR(AppBuff, &temp);
|
||||
if(temp > 0) {
|
||||
ImpedanceShowResult(AppBuff, temp);
|
||||
}
|
||||
if (c == 'z') {
|
||||
system_init();
|
||||
printf("RESET_DONE\n");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue