commit
This commit is contained in:
parent
4266c4b672
commit
6adf55bc47
|
|
@ -12,6 +12,7 @@ build*
|
||||||
*.png
|
*.png
|
||||||
icons/
|
icons/
|
||||||
*.pdf
|
*.pdf
|
||||||
|
*.txt
|
||||||
examples/
|
examples/
|
||||||
|
|
||||||
build/
|
build/
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,495 @@
|
||||||
|
// Amperometric.c
|
||||||
|
/*!
|
||||||
|
*****************************************************************************
|
||||||
|
@file: Amperometric.c
|
||||||
|
@author: $Author: mlambe $
|
||||||
|
@brief: Amperometric measurement.
|
||||||
|
@version: $Revision: 766 $
|
||||||
|
@date: $Date: 2018-03-21 14:09:35 +0100 (Wed, 21 Mar 2018) $
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
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 "Amperometric.h"
|
||||||
|
|
||||||
|
#define AD5940ERR_STOP 10
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
AppAMPCfg_Type AppAMPCfg =
|
||||||
|
{
|
||||||
|
.bParaChanged = bFALSE,
|
||||||
|
.SeqStartAddr = 0,
|
||||||
|
.MaxSeqLen = 0,
|
||||||
|
|
||||||
|
.SeqStartAddrCal = 0,
|
||||||
|
.MaxSeqLenCal = 0,
|
||||||
|
.FifoThresh = 5, /* Number of points for FIFO */
|
||||||
|
|
||||||
|
.SysClkFreq = 16000000.0,
|
||||||
|
.WuptClkFreq = 32000.0,
|
||||||
|
.AdcClkFreq = 16000000.0,
|
||||||
|
.AmpODR = 1.0, /* Sample time in seconds. I.e. every 5 seconds make a measurement */
|
||||||
|
.NumOfData = -1,
|
||||||
|
.RcalVal = 100.0, /* RCAL = 100 Ohms */
|
||||||
|
.PwrMod = AFEPWR_LP,
|
||||||
|
.AMPInited = bFALSE,
|
||||||
|
.StopRequired = bFALSE,
|
||||||
|
|
||||||
|
/* LPTIA Configure */
|
||||||
|
.ExtRtia = bFALSE, /* Set to true if using external RTIA */
|
||||||
|
.LptiaRtiaSel = LPTIARTIA_4K, /* COnfigure RTIA */
|
||||||
|
.LpTiaRf = LPTIARF_1M, /* Configure LPF resistor */
|
||||||
|
.LpTiaRl = LPTIARLOAD_100R,
|
||||||
|
.ReDoRtiaCal = bTRUE,
|
||||||
|
.RtiaCalValue = 0,
|
||||||
|
.ExtRtiaVal = 0,
|
||||||
|
|
||||||
|
/*LPDAC Configure */
|
||||||
|
.Vzero = 1100, /* Sets voltage on SE0 and LPTIA */
|
||||||
|
.SensorBias = 500, /* Sets voltage between RE0 and SE0 */
|
||||||
|
|
||||||
|
/* ADC Configure*/
|
||||||
|
.ADCPgaGain = ADCPGA_1P5,
|
||||||
|
.ADCSinc3Osr = ADCSINC3OSR_4,
|
||||||
|
.ADCSinc2Osr = ADCSINC2OSR_22,
|
||||||
|
.DataFifoSrc = FIFOSRC_SINC2NOTCH,
|
||||||
|
.ADCRefVolt = 1.8162, /* Measure voltage on ADCRefVolt pin and enter here*/
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function is provided for upper controllers that want to change
|
||||||
|
application parameters specially for user defined parameters.
|
||||||
|
*/
|
||||||
|
AD5940Err AppAMPGetCfg(void *pCfg)
|
||||||
|
{
|
||||||
|
if(pCfg){
|
||||||
|
*(AppAMPCfg_Type**)pCfg = &AppAMPCfg;
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
return AD5940ERR_PARA;
|
||||||
|
}
|
||||||
|
|
||||||
|
AD5940Err AppAMPCtrl(int32_t AmpCtrl, void *pPara)
|
||||||
|
{
|
||||||
|
switch (AmpCtrl)
|
||||||
|
{
|
||||||
|
case AMPCTRL_START:
|
||||||
|
{
|
||||||
|
WUPTCfg_Type wupt_cfg;
|
||||||
|
|
||||||
|
AD5940_ReadReg(REG_AFE_ADCDAT); /* Any SPI Operation can wakeup AFE */
|
||||||
|
if(AppAMPCfg.AMPInited == 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-1;
|
||||||
|
wupt_cfg.SeqxWakeupTime[SEQID_0] = (uint32_t)(AppAMPCfg.WuptClkFreq*AppAMPCfg.AmpODR)-4-1;
|
||||||
|
AD5940_WUPTCfg(&wupt_cfg);
|
||||||
|
|
||||||
|
AppAMPCfg.FifoDataCount = 0; /* restart */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AMPCTRL_STOPNOW:
|
||||||
|
{
|
||||||
|
AD5940_ReadReg(REG_AFE_ADCDAT); /* Any SPI Operation can wakeup AFE */
|
||||||
|
/* 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 AMPCTRL_STOPSYNC:
|
||||||
|
{
|
||||||
|
AppAMPCfg.StopRequired = bTRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AMPCTRL_SHUTDOWN:
|
||||||
|
{
|
||||||
|
AppAMPCtrl(AMPCTRL_STOPNOW, 0); /* Stop the measurement if it's running. */
|
||||||
|
/* Turn off LPloop related blocks which are not controlled automatically by sleep operation */
|
||||||
|
AFERefCfg_Type aferef_cfg;
|
||||||
|
LPLoopCfg_Type lp_loop;
|
||||||
|
memset(&aferef_cfg, 0, sizeof(aferef_cfg));
|
||||||
|
AD5940_REFCfgS(&aferef_cfg);
|
||||||
|
memset(&lp_loop, 0, sizeof(lp_loop));
|
||||||
|
AD5940_LPLoopCfgS(&lp_loop);
|
||||||
|
AD5940_EnterSleepS(); /* Enter Hibernate */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate init sequence */
|
||||||
|
static AD5940Err AppAMPSeqCfgGen(void)
|
||||||
|
{
|
||||||
|
AD5940Err error = AD5940ERR_OK;
|
||||||
|
uint32_t const *pSeqCmd;
|
||||||
|
uint32_t SeqLen;
|
||||||
|
|
||||||
|
AFERefCfg_Type aferef_cfg;
|
||||||
|
LPLoopCfg_Type lp_loop;
|
||||||
|
DSPCfg_Type dsp_cfg;
|
||||||
|
SWMatrixCfg_Type sw_cfg;
|
||||||
|
/* 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 = bTRUE;
|
||||||
|
aferef_cfg.Lp1V8BuffEn = bTRUE;
|
||||||
|
/* LP reference control - turn off them to save power*/
|
||||||
|
aferef_cfg.LpBandgapEn = bTRUE;
|
||||||
|
aferef_cfg.LpRefBufEn = bTRUE;
|
||||||
|
aferef_cfg.LpRefBoostEn = bFALSE;
|
||||||
|
AD5940_REFCfgS(&aferef_cfg);
|
||||||
|
|
||||||
|
lp_loop.LpDacCfg.LpdacSel = LPDAC0;
|
||||||
|
lp_loop.LpDacCfg.LpDacSrc = LPDACSRC_MMR;
|
||||||
|
lp_loop.LpDacCfg.LpDacSW = LPDACSW_VBIAS2LPPA|LPDACSW_VBIAS2PIN|LPDACSW_VZERO2LPTIA|LPDACSW_VZERO2PIN;
|
||||||
|
lp_loop.LpDacCfg.LpDacVzeroMux = LPDACVZERO_6BIT;
|
||||||
|
lp_loop.LpDacCfg.LpDacVbiasMux = LPDACVBIAS_12BIT;
|
||||||
|
lp_loop.LpDacCfg.LpDacRef = LPDACREF_2P5;
|
||||||
|
lp_loop.LpDacCfg.DataRst = bFALSE;
|
||||||
|
lp_loop.LpDacCfg.PowerEn = bTRUE;
|
||||||
|
lp_loop.LpDacCfg.DacData6Bit = (uint32_t)((AppAMPCfg.Vzero-200)/DAC6BITVOLT_1LSB);
|
||||||
|
lp_loop.LpDacCfg.DacData12Bit =(int32_t)((AppAMPCfg.SensorBias)/DAC12BITVOLT_1LSB) + lp_loop.LpDacCfg.DacData6Bit*64;
|
||||||
|
if(lp_loop.LpDacCfg.DacData12Bit>lp_loop.LpDacCfg.DacData6Bit*64)
|
||||||
|
lp_loop.LpDacCfg.DacData12Bit--;
|
||||||
|
lp_loop.LpAmpCfg.LpAmpSel = LPAMP0;
|
||||||
|
lp_loop.LpAmpCfg.LpAmpPwrMod = LPAMPPWR_NORM;
|
||||||
|
lp_loop.LpAmpCfg.LpPaPwrEn = bTRUE;
|
||||||
|
lp_loop.LpAmpCfg.LpTiaPwrEn = bTRUE;
|
||||||
|
lp_loop.LpAmpCfg.LpTiaRf = AppAMPCfg.LpTiaRf;
|
||||||
|
lp_loop.LpAmpCfg.LpTiaRload = AppAMPCfg.LpTiaRl;
|
||||||
|
if(AppAMPCfg.ExtRtia == bTRUE)
|
||||||
|
{
|
||||||
|
lp_loop.LpAmpCfg.LpTiaRtia = LPTIARTIA_OPEN;
|
||||||
|
lp_loop.LpAmpCfg.LpTiaSW = LPTIASW(9)|LPTIASW(2)|LPTIASW(4)|LPTIASW(5)|LPTIASW(12)|LPTIASW(13);
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
lp_loop.LpAmpCfg.LpTiaRtia = AppAMPCfg.LptiaRtiaSel;
|
||||||
|
lp_loop.LpAmpCfg.LpTiaSW = LPTIASW(5)|LPTIASW(2)|LPTIASW(4)|LPTIASW(12)|LPTIASW(13);
|
||||||
|
}
|
||||||
|
AD5940_LPLoopCfgS(&lp_loop);
|
||||||
|
|
||||||
|
|
||||||
|
dsp_cfg.ADCBaseCfg.ADCMuxN = ADCMUXN_VZERO0;
|
||||||
|
dsp_cfg.ADCBaseCfg.ADCMuxP = ADCMUXP_AIN4;
|
||||||
|
dsp_cfg.ADCBaseCfg.ADCPga = AppAMPCfg.ADCPgaGain;
|
||||||
|
|
||||||
|
memset(&dsp_cfg.ADCDigCompCfg, 0, sizeof(dsp_cfg.ADCDigCompCfg));
|
||||||
|
memset(&dsp_cfg.DftCfg, 0, sizeof(dsp_cfg.DftCfg));
|
||||||
|
dsp_cfg.ADCFilterCfg.ADCAvgNum = ADCAVGNUM_16; /* Don't care because it's disabled */
|
||||||
|
dsp_cfg.ADCFilterCfg.ADCRate = ADCRATE_800KHZ; /* Tell filter block clock rate of ADC*/
|
||||||
|
dsp_cfg.ADCFilterCfg.ADCSinc2Osr = AppAMPCfg.ADCSinc2Osr;
|
||||||
|
dsp_cfg.ADCFilterCfg.ADCSinc3Osr = AppAMPCfg.ADCSinc3Osr;
|
||||||
|
dsp_cfg.ADCFilterCfg.BpSinc3 = bFALSE;
|
||||||
|
dsp_cfg.ADCFilterCfg.BpNotch = bFALSE;
|
||||||
|
dsp_cfg.ADCFilterCfg.Sinc2NotchEnable = bTRUE;
|
||||||
|
|
||||||
|
memset(&dsp_cfg.StatCfg, 0, sizeof(dsp_cfg.StatCfg)); /* Don't care about Statistic */
|
||||||
|
AD5940_DSPCfgS(&dsp_cfg);
|
||||||
|
|
||||||
|
sw_cfg.Dswitch = 0;
|
||||||
|
sw_cfg.Pswitch = 0;
|
||||||
|
sw_cfg.Nswitch = 0;
|
||||||
|
sw_cfg.Tswitch = 0;
|
||||||
|
AD5940_SWMatrixCfgS(&sw_cfg);
|
||||||
|
|
||||||
|
/* Enable all of them. They are automatically turned off during hibernate mode to save power */
|
||||||
|
AD5940_AFECtrlS(AFECTRL_HPREFPWR|AFECTRL_SINC2NOTCH, bTRUE);
|
||||||
|
AD5940_AFECtrlS(AFECTRL_SINC2NOTCH, bFALSE);
|
||||||
|
AD5940_SEQGpioCtrlS(0/*AGPIO_Pin6|AGPIO_Pin5|AGPIO_Pin1*/); //GP6->endSeq, GP5 -> AD8233=OFF, GP1->RLD=OFF .
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
AppAMPCfg.InitSeqInfo.SeqId = SEQID_1;
|
||||||
|
AppAMPCfg.InitSeqInfo.SeqRamAddr = AppAMPCfg.SeqStartAddr;
|
||||||
|
AppAMPCfg.InitSeqInfo.pSeqCmd = pSeqCmd;
|
||||||
|
AppAMPCfg.InitSeqInfo.SeqLen = SeqLen;
|
||||||
|
/* Write command to SRAM */
|
||||||
|
AD5940_SEQCmdWrite(AppAMPCfg.InitSeqInfo.SeqRamAddr, pSeqCmd, SeqLen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return error; /* Error */
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AD5940Err AppAMPSeqMeasureGen(void)
|
||||||
|
{
|
||||||
|
AD5940Err error = AD5940ERR_OK;
|
||||||
|
uint32_t const *pSeqCmd;
|
||||||
|
uint32_t SeqLen;
|
||||||
|
|
||||||
|
uint32_t WaitClks;
|
||||||
|
ClksCalInfo_Type clks_cal;
|
||||||
|
|
||||||
|
clks_cal.DataType = DATATYPE_SINC2;
|
||||||
|
clks_cal.DataCount = 1;
|
||||||
|
clks_cal.ADCSinc2Osr = AppAMPCfg.ADCSinc2Osr;
|
||||||
|
clks_cal.ADCSinc3Osr = AppAMPCfg.ADCSinc3Osr;
|
||||||
|
clks_cal.ADCAvgNum = 0;
|
||||||
|
clks_cal.RatioSys2AdcClk = AppAMPCfg.SysClkFreq/AppAMPCfg.AdcClkFreq;
|
||||||
|
AD5940_ClksCalculate(&clks_cal, &WaitClks);
|
||||||
|
WaitClks += 15;
|
||||||
|
AD5940_SEQGenCtrl(bTRUE);
|
||||||
|
AD5940_SEQGpioCtrlS(AGPIO_Pin2);
|
||||||
|
AD5940_AFECtrlS(AFECTRL_ADCPWR|AFECTRL_SINC2NOTCH, bTRUE);
|
||||||
|
AD5940_SEQGenInsert(SEQ_WAIT(16*250)); /* wait 250us */
|
||||||
|
AD5940_AFECtrlS(AFECTRL_ADCCNV, bTRUE); /* Start ADC convert*/
|
||||||
|
AD5940_SEQGenInsert(SEQ_WAIT(WaitClks)); /* wait for first data ready */
|
||||||
|
AD5940_AFECtrlS(AFECTRL_ADCPWR|AFECTRL_ADCCNV|AFECTRL_SINC2NOTCH, bFALSE); /* Stop ADC */
|
||||||
|
AD5940_SEQGpioCtrlS(0);
|
||||||
|
AD5940_EnterSleepS();/* Goto hibernate */
|
||||||
|
/* Sequence end. */
|
||||||
|
error = AD5940_SEQGenFetchSeq(&pSeqCmd, &SeqLen);
|
||||||
|
AD5940_SEQGenCtrl(bFALSE); /* Stop sequencer generator */
|
||||||
|
|
||||||
|
if(error == AD5940ERR_OK)
|
||||||
|
{
|
||||||
|
AppAMPCfg.MeasureSeqInfo.SeqId = SEQID_0;
|
||||||
|
AppAMPCfg.MeasureSeqInfo.SeqRamAddr = AppAMPCfg.InitSeqInfo.SeqRamAddr + AppAMPCfg.InitSeqInfo.SeqLen ;
|
||||||
|
AppAMPCfg.MeasureSeqInfo.pSeqCmd = pSeqCmd;
|
||||||
|
AppAMPCfg.MeasureSeqInfo.SeqLen = SeqLen;
|
||||||
|
/* Write command to SRAM */
|
||||||
|
AD5940_SEQCmdWrite(AppAMPCfg.MeasureSeqInfo.SeqRamAddr, pSeqCmd, SeqLen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return error; /* Error */
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
static AD5940Err AppAMPRtiaCal(void)
|
||||||
|
{
|
||||||
|
fImpPol_Type RtiaCalValue; /* Calibration result */
|
||||||
|
LPRTIACal_Type lprtia_cal;
|
||||||
|
AD5940_StructInit(&lprtia_cal, sizeof(lprtia_cal));
|
||||||
|
|
||||||
|
lprtia_cal.bPolarResult = bTRUE; /* Magnitude + Phase */
|
||||||
|
lprtia_cal.AdcClkFreq = AppAMPCfg.AdcClkFreq;
|
||||||
|
lprtia_cal.SysClkFreq = AppAMPCfg.SysClkFreq;
|
||||||
|
lprtia_cal.ADCSinc3Osr = ADCSINC3OSR_4;
|
||||||
|
lprtia_cal.ADCSinc2Osr = ADCSINC2OSR_22; /* Use SINC2 data as DFT data source */
|
||||||
|
lprtia_cal.DftCfg.DftNum = DFTNUM_2048; /* Maximum DFT number */
|
||||||
|
lprtia_cal.DftCfg.DftSrc = DFTSRC_SINC2NOTCH; /* For frequency under 12Hz, need to optimize DFT source. Use SINC3 data as DFT source */
|
||||||
|
lprtia_cal.DftCfg.HanWinEn = bTRUE;
|
||||||
|
lprtia_cal.fFreq = AppAMPCfg.AdcClkFreq/4/22/2048*3; /* Sample 3 period of signal, 13.317Hz here. Do not use DC method, because it needs ADC/PGA calibrated firstly(but it's faster) */
|
||||||
|
lprtia_cal.fRcal = AppAMPCfg.RcalVal;
|
||||||
|
lprtia_cal.LpTiaRtia = AppAMPCfg.LptiaRtiaSel;
|
||||||
|
lprtia_cal.LpAmpPwrMod = LPAMPPWR_NORM;
|
||||||
|
lprtia_cal.bWithCtia = bFALSE;
|
||||||
|
AD5940_LPRtiaCal(&lprtia_cal, &RtiaCalValue);
|
||||||
|
AppAMPCfg.RtiaCalValue = RtiaCalValue;
|
||||||
|
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
/* This function provide application initialize. */
|
||||||
|
AD5940Err AppAMPInit(uint32_t *pBuffer, uint32_t BufferSize)
|
||||||
|
{
|
||||||
|
AD5940Err error = AD5940ERR_OK;
|
||||||
|
SEQCfg_Type seq_cfg;
|
||||||
|
FIFOCfg_Type fifo_cfg;
|
||||||
|
|
||||||
|
if(AD5940_WakeUp(10) > 10) /* Wakeup AFE by read register, read 10 times at most */
|
||||||
|
return AD5940ERR_WAKEUP; /* Wakeup Failed */
|
||||||
|
|
||||||
|
/* Configure sequencer and stop it */
|
||||||
|
seq_cfg.SeqMemSize = SEQMEMSIZE_2KB; /* 2kB SRAM is used for sequencer, others for data FIFO */
|
||||||
|
seq_cfg.SeqBreakEn = bFALSE;
|
||||||
|
seq_cfg.SeqIgnoreEn = bFALSE;
|
||||||
|
seq_cfg.SeqCntCRCClr = bTRUE;
|
||||||
|
seq_cfg.SeqEnable = bFALSE;
|
||||||
|
seq_cfg.SeqWrTimer = 0;
|
||||||
|
AD5940_SEQCfg(&seq_cfg);
|
||||||
|
|
||||||
|
/* Do RTIA calibration */
|
||||||
|
if(((AppAMPCfg.ReDoRtiaCal == bTRUE) || \
|
||||||
|
AppAMPCfg.AMPInited == bFALSE) && AppAMPCfg.ExtRtia == bFALSE) /* Do calibration on the first initializaion */
|
||||||
|
{
|
||||||
|
AppAMPRtiaCal();
|
||||||
|
AppAMPCfg.ReDoRtiaCal = bFALSE;
|
||||||
|
}else
|
||||||
|
AppAMPCfg.RtiaCalValue.Magnitude = AppAMPCfg.ExtRtiaVal;
|
||||||
|
|
||||||
|
/* Reconfigure FIFO */
|
||||||
|
AD5940_FIFOCtrlS(DFTSRC_SINC3, 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 = AppAMPCfg.DataFifoSrc;
|
||||||
|
fifo_cfg.FIFOThresh = AppAMPCfg.FifoThresh;
|
||||||
|
AD5940_FIFOCfg(&fifo_cfg);
|
||||||
|
|
||||||
|
AD5940_INTCClrFlag(AFEINTSRC_ALLINT);
|
||||||
|
|
||||||
|
/* Start sequence generator */
|
||||||
|
/* Initialize sequencer generator */
|
||||||
|
if((AppAMPCfg.AMPInited == bFALSE)||\
|
||||||
|
(AppAMPCfg.bParaChanged == bTRUE))
|
||||||
|
{
|
||||||
|
if(pBuffer == 0) return AD5940ERR_PARA;
|
||||||
|
if(BufferSize == 0) return AD5940ERR_PARA;
|
||||||
|
AD5940_SEQGenInit(pBuffer, BufferSize);
|
||||||
|
|
||||||
|
/* Generate initialize sequence */
|
||||||
|
error = AppAMPSeqCfgGen(); /* Application initialization sequence using either MCU or sequencer */
|
||||||
|
if(error != AD5940ERR_OK) return error;
|
||||||
|
|
||||||
|
/* Generate measurement sequence */
|
||||||
|
error = AppAMPSeqMeasureGen();
|
||||||
|
if(error != AD5940ERR_OK) return error;
|
||||||
|
|
||||||
|
AppAMPCfg.bParaChanged = bFALSE; /* Clear this flag as we already implemented the new configuration */
|
||||||
|
}
|
||||||
|
/* Initialization sequencer */
|
||||||
|
AppAMPCfg.InitSeqInfo.WriteSRAM = bFALSE;
|
||||||
|
AD5940_SEQInfoCfg(&AppAMPCfg.InitSeqInfo);
|
||||||
|
seq_cfg.SeqEnable = bTRUE;
|
||||||
|
AD5940_SEQCfg(&seq_cfg); /* Enable sequencer */
|
||||||
|
AD5940_SEQMmrTrig(AppAMPCfg.InitSeqInfo.SeqId);
|
||||||
|
while(AD5940_INTCTestFlag(AFEINTC_1, AFEINTSRC_ENDSEQ) == bFALSE);
|
||||||
|
|
||||||
|
/* Measurement sequence */
|
||||||
|
AppAMPCfg.MeasureSeqInfo.WriteSRAM = bFALSE;
|
||||||
|
AD5940_SEQInfoCfg(&AppAMPCfg.MeasureSeqInfo);
|
||||||
|
|
||||||
|
// seq_cfg.SeqEnable = bTRUE;
|
||||||
|
// AD5940_SEQCfg(&seq_cfg); /* Enable sequencer, and wait for trigger */
|
||||||
|
AD5940_SEQCtrlS(bTRUE); /* Enable sequencer, and wait for trigger. It's disabled in initialization sequence */
|
||||||
|
AD5940_ClrMCUIntFlag(); /* Clear interrupt flag generated before */
|
||||||
|
|
||||||
|
AD5940_AFEPwrBW(AppAMPCfg.PwrMod, AFEBW_250KHZ);
|
||||||
|
AppAMPCfg.AMPInited = bTRUE; /* AMP application has been initialized. */
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modify registers when AFE wakeup */
|
||||||
|
static AD5940Err AppAMPRegModify(int32_t * const pData, uint32_t *pDataCount)
|
||||||
|
{
|
||||||
|
if(AppAMPCfg.NumOfData > 0)
|
||||||
|
{
|
||||||
|
AppAMPCfg.FifoDataCount += *pDataCount/4;
|
||||||
|
if(AppAMPCfg.FifoDataCount >= AppAMPCfg.NumOfData)
|
||||||
|
{
|
||||||
|
AD5940_WUPTCtrl(bFALSE);
|
||||||
|
return AD5940ERR_STOP; // Return STOP code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(AppAMPCfg.StopRequired == bTRUE)
|
||||||
|
{
|
||||||
|
AD5940_WUPTCtrl(bFALSE);
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Depending on the data type, do appropriate data pre-process before return back to controller */
|
||||||
|
static AD5940Err AppAMPDataProcess(int32_t * const pData, uint32_t *pDataCount)
|
||||||
|
{
|
||||||
|
uint32_t i, datacount;
|
||||||
|
datacount = *pDataCount;
|
||||||
|
float *pOut = (float *)pData;
|
||||||
|
for(i=0;i<datacount;i++)
|
||||||
|
{
|
||||||
|
pData[i] &= 0xffff;
|
||||||
|
pOut[i] = AppAMPCalcCurrent(pData[i]);
|
||||||
|
}
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
*/
|
||||||
|
AD5940Err AppAMPISR(void *pBuff, uint32_t *pCount)
|
||||||
|
{
|
||||||
|
uint32_t FifoCnt;
|
||||||
|
if(AD5940_WakeUp(10) > 10) /* Wakeup AFE by read register, read 10 times at most */
|
||||||
|
return AD5940ERR_WAKEUP; /* Wakeup Failed */
|
||||||
|
AD5940_SleepKeyCtrlS(SLPKEY_LOCK);
|
||||||
|
|
||||||
|
*pCount = 0;
|
||||||
|
if(AD5940_INTCTestFlag(AFEINTC_0, AFEINTSRC_DATAFIFOTHRESH) == bTRUE)
|
||||||
|
{
|
||||||
|
FifoCnt = AD5940_FIFOGetCnt();
|
||||||
|
AD5940_FIFORd((uint32_t *)pBuff, FifoCnt);
|
||||||
|
AD5940_INTCClrFlag(AFEINTSRC_DATAFIFOTHRESH);
|
||||||
|
|
||||||
|
AD5940Err status = AppAMPRegModify(pBuff, &FifoCnt); /* If there is need to do AFE re-configure, do it here when AFE is in active state */
|
||||||
|
AD5940_SleepKeyCtrlS(SLPKEY_UNLOCK);
|
||||||
|
//AD5940_EnterSleepS(); /* Manually put AFE back to hibernate mode. This operation only takes effect when register value is ACTIVE previously */
|
||||||
|
|
||||||
|
/* Process data */
|
||||||
|
AppAMPDataProcess((int32_t*)pBuff,&FifoCnt);
|
||||||
|
*pCount = FifoCnt;
|
||||||
|
|
||||||
|
if (status == AD5940ERR_STOP) return AD5940ERR_STOP;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate voltage */
|
||||||
|
float AppAMPCalcVoltage(uint32_t ADCcode)
|
||||||
|
{
|
||||||
|
float kFactor = 1.835/1.82;
|
||||||
|
float fVolt = 0.0;
|
||||||
|
int32_t tmp = 0;
|
||||||
|
tmp = ADCcode - 32768;
|
||||||
|
switch(AppAMPCfg.ADCPgaGain)
|
||||||
|
{
|
||||||
|
case ADCPGA_1:
|
||||||
|
fVolt = ((float)(tmp)/32768)*(AppAMPCfg.ADCRefVolt/1)*kFactor;
|
||||||
|
break;
|
||||||
|
case ADCPGA_1P5:
|
||||||
|
fVolt = ((float)(tmp)/32768)*(AppAMPCfg.ADCRefVolt/1.5f)*kFactor;
|
||||||
|
break;
|
||||||
|
case ADCPGA_2:
|
||||||
|
fVolt = ((float)(tmp)/32768)*(AppAMPCfg.ADCRefVolt/2)*kFactor;
|
||||||
|
break;
|
||||||
|
case ADCPGA_4:
|
||||||
|
fVolt = ((float)(tmp)/32768)*(AppAMPCfg.ADCRefVolt/4)*kFactor;
|
||||||
|
break;
|
||||||
|
case ADCPGA_9:
|
||||||
|
fVolt = ((float)(tmp)/32768)*(AppAMPCfg.ADCRefVolt/9)*kFactor;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return fVolt;
|
||||||
|
}
|
||||||
|
/* Calculate current in uA */
|
||||||
|
float AppAMPCalcCurrent(uint32_t ADCcode)
|
||||||
|
{
|
||||||
|
float fCurrent, fVoltage = 0.0;
|
||||||
|
fVoltage = AppAMPCalcVoltage(ADCcode);
|
||||||
|
fCurrent = fVoltage/AppAMPCfg.RtiaCalValue.Magnitude;
|
||||||
|
|
||||||
|
return -fCurrent*1000000;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
// File: Amperometric.h
|
||||||
|
/*!
|
||||||
|
*****************************************************************************
|
||||||
|
@file: Amperometric.h
|
||||||
|
@author: $Author: mlambe $
|
||||||
|
@brief: Amperometric measurement header file.
|
||||||
|
@version: $Revision: 766 $
|
||||||
|
@date: $Date: 2018-03-21 14:09:35 +0100 (Wed, 21 Mar 2018) $
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
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 _AMPEROMETRIC_H_
|
||||||
|
#define _AMPEROMETRIC_H_
|
||||||
|
#include "ad5940.h"
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "math.h"
|
||||||
|
|
||||||
|
#define DAC12BITVOLT_1LSB (2200.0f/4095) //mV
|
||||||
|
#define DAC6BITVOLT_1LSB (DAC12BITVOLT_1LSB*64) //mV
|
||||||
|
/*
|
||||||
|
Note: this example will use SEQID_0 as measurement sequence, and use SEQID_1 as init sequence.
|
||||||
|
SEQID_3 is used for calibration.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* Common configurations for all kinds of Application. */
|
||||||
|
BoolFlag bParaChanged; /* Indicate to generate sequence again. It's auto cleared by AppAMPInit */
|
||||||
|
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 */
|
||||||
|
BoolFlag ReDoRtiaCal; /* Set this flag to bTRUE when there is need to do calibration. */
|
||||||
|
float SysClkFreq; /* The real frequency of system clock */
|
||||||
|
float WuptClkFreq; /* The clock frequency of Wakeup Timer in Hz. Typically it's 32kHz. Leave it here in case we calibrate clock in software method */
|
||||||
|
float AdcClkFreq; /* The real frequency of ADC clock */
|
||||||
|
uint32_t FifoThresh; /* FIFO threshold. Should be N*4 */
|
||||||
|
float AmpODR; /* in Hz. ODR decides the period of WakeupTimer who will trigger sequencer periodically.*/
|
||||||
|
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 RcalVal; /* Rcal value in Ohm */
|
||||||
|
float ADCRefVolt; /* Measured 1.82 V reference*/
|
||||||
|
uint32_t PwrMod; /* Control Chip power mode(LP/HP) */
|
||||||
|
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; /* SINC3 OSR selection. ADCSINC3OSR_2, ADCSINC3OSR_4 */
|
||||||
|
uint8_t ADCSinc2Osr; /* SINC2 OSR selection. ADCSINC2OSR_22...ADCSINC2OSR_1333 */
|
||||||
|
uint32_t DataFifoSrc; /* DataFIFO source. FIFOSRC_SINC3, FIFOSRC_DFT, FIFOSRC_SINC2NOTCH, FIFOSRC_VAR, FIFOSRC_MEAN*/
|
||||||
|
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 */
|
||||||
|
fImpPol_Type RtiaCalValue; /* Calibrated Rtia value */
|
||||||
|
float Vzero; /* Voltage on SE0 pin and Vzero, optimumly 1100mV*/
|
||||||
|
float SensorBias; /* Sensor bias voltage = VRE0 - VSE0 */
|
||||||
|
BoolFlag ExtRtia; /* Use internal or external Rtia */
|
||||||
|
float ExtRtiaVal; /* External Rtia value if using one */
|
||||||
|
BoolFlag AMPInited; /* 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 */
|
||||||
|
/* End */
|
||||||
|
}AppAMPCfg_Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* int32_t type Impedance result in Cartesian coordinate
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
float Current;
|
||||||
|
float Voltage;
|
||||||
|
}fAmpRes_Type;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define AMPCTRL_START 0
|
||||||
|
#define AMPCTRL_STOPNOW 1
|
||||||
|
#define AMPCTRL_STOPSYNC 2
|
||||||
|
#define AMPCTRL_SHUTDOWN 4 /* Note: shutdown here means turn off everything and put AFE to hibernate mode. The word 'SHUT DOWN' is only used here. */
|
||||||
|
|
||||||
|
AD5940Err AppAMPGetCfg(void *pCfg);
|
||||||
|
AD5940Err AppAMPInit(uint32_t *pBuffer, uint32_t BufferSize);
|
||||||
|
AD5940Err AppAMPISR(void *pBuff, uint32_t *pCount);
|
||||||
|
AD5940Err AppAMPCtrl(int32_t AmpCtrl, void *pPara);
|
||||||
|
float AppAMPCalcVoltage(uint32_t ADCcode);
|
||||||
|
float AppAMPCalcCurrent(uint32_t ADCcode);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -15,6 +15,8 @@ add_executable(EIS
|
||||||
main.c
|
main.c
|
||||||
ad5940.c
|
ad5940.c
|
||||||
Impedance.c
|
Impedance.c
|
||||||
|
Amperometric.c
|
||||||
|
RampTest.c
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_definitions(EIS PRIVATE CHIPSEL_594X)
|
target_compile_definitions(EIS PRIVATE CHIPSEL_594X)
|
||||||
|
|
|
||||||
11
Impedance.c
11
Impedance.c
|
|
@ -1,10 +1,12 @@
|
||||||
// File: Impedance.c
|
// Impedance.c
|
||||||
#include "ad5940.h"
|
#include "ad5940.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
#include "Impedance.h"
|
#include "Impedance.h"
|
||||||
|
|
||||||
|
#define AD5940ERR_STOP 10
|
||||||
|
|
||||||
/* Default LPDAC resolution (2.5V internal reference) */
|
/* Default LPDAC resolution (2.5V internal reference) */
|
||||||
#define DAC12BITVOLT_1LSB (2200.0f/4095) // mV
|
#define DAC12BITVOLT_1LSB (2200.0f/4095) // mV
|
||||||
#define DAC6BITVOLT_1LSB (DAC12BITVOLT_1LSB*64) // mV
|
#define DAC6BITVOLT_1LSB (DAC12BITVOLT_1LSB*64) // mV
|
||||||
|
|
@ -622,7 +624,7 @@ int32_t AppIMPRegModify(int32_t * const pData, uint32_t *pDataCount)
|
||||||
{
|
{
|
||||||
AD5940_WUPTCtrl(bFALSE);
|
AD5940_WUPTCtrl(bFALSE);
|
||||||
AD5940_SEQCtrlS(bFALSE);
|
AD5940_SEQCtrlS(bFALSE);
|
||||||
return AD5940ERR_OK;
|
return AD5940ERR_STOP; // Return STOP code
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(AppIMPCfg.StopRequired == bTRUE)
|
if(AppIMPCfg.StopRequired == bTRUE)
|
||||||
|
|
@ -752,7 +754,8 @@ int32_t AppIMPISR(void *pBuff, uint32_t *pCount)
|
||||||
{
|
{
|
||||||
AD5940_SEQCtrlS(bFALSE);
|
AD5940_SEQCtrlS(bFALSE);
|
||||||
|
|
||||||
if (AppIMPRegModify(pBuff, &FifoCnt) == AD5940ERR_OK)
|
int32_t status = AppIMPRegModify(pBuff, &FifoCnt);
|
||||||
|
if (status == AD5940ERR_OK)
|
||||||
{
|
{
|
||||||
if(AppIMPCfg.FifoDataCount < AppIMPCfg.NumOfData || AppIMPCfg.NumOfData == -1)
|
if(AppIMPCfg.FifoDataCount < AppIMPCfg.NumOfData || AppIMPCfg.NumOfData == -1)
|
||||||
{
|
{
|
||||||
|
|
@ -780,6 +783,8 @@ int32_t AppIMPISR(void *pBuff, uint32_t *pCount)
|
||||||
} else {
|
} else {
|
||||||
*pCount = FifoCnt;
|
*pCount = FifoCnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status == AD5940ERR_STOP) return AD5940ERR_STOP;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,583 @@
|
||||||
|
// RampTest.c
|
||||||
|
#include "ad5940.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "string.h"
|
||||||
|
#include "math.h"
|
||||||
|
#include "RampTest.h"
|
||||||
|
|
||||||
|
#define AD5940ERR_STOP 10
|
||||||
|
|
||||||
|
AppRAMPCfg_Type AppRAMPCfg =
|
||||||
|
{
|
||||||
|
.bParaChanged = bFALSE,
|
||||||
|
.SeqStartAddr = 0,
|
||||||
|
.MaxSeqLen = 0,
|
||||||
|
.SeqStartAddrCal = 0,
|
||||||
|
.MaxSeqLenCal = 0,
|
||||||
|
|
||||||
|
.LFOSCClkFreq = 32000.0,
|
||||||
|
.SysClkFreq = 16000000.0,
|
||||||
|
.AdcClkFreq = 16000000.0,
|
||||||
|
.RcalVal = 10000.0,
|
||||||
|
.ADCRefVolt = 1820.0f,
|
||||||
|
.bTestFinished = bFALSE,
|
||||||
|
|
||||||
|
.RampStartVolt = -500.0f,
|
||||||
|
.RampPeakVolt = +500.0f,
|
||||||
|
.VzeroStart = 1100.0f,
|
||||||
|
.VzeroPeak = 1100.0f,
|
||||||
|
.StepNumber = 100,
|
||||||
|
.RampDuration = 10000,
|
||||||
|
|
||||||
|
.SampleDelay = 1.0f,
|
||||||
|
.LPTIARtiaSel = LPTIARTIA_4K,
|
||||||
|
.LpTiaRf = LPTIARF_20K, /* Default LPF */
|
||||||
|
.ExternalRtiaValue = 20000.0f,
|
||||||
|
.AdcPgaGain = ADCPGA_1P5,
|
||||||
|
.ADCSinc3Osr = ADCSINC3OSR_2,
|
||||||
|
.FifoThresh = 4,
|
||||||
|
|
||||||
|
.RAMPInited = bFALSE,
|
||||||
|
.StopRequired = bFALSE,
|
||||||
|
.RampState = RAMP_STATE0,
|
||||||
|
.bFirstDACSeq = bTRUE,
|
||||||
|
.bRampOneDir = bFALSE,
|
||||||
|
};
|
||||||
|
|
||||||
|
AD5940Err AppRAMPGetCfg(void *pCfg)
|
||||||
|
{
|
||||||
|
if(pCfg)
|
||||||
|
{
|
||||||
|
*(AppRAMPCfg_Type **)pCfg = &AppRAMPCfg;
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
return AD5940ERR_PARA;
|
||||||
|
}
|
||||||
|
|
||||||
|
AD5940Err AppRAMPCtrl(uint32_t Command, void *pPara)
|
||||||
|
{
|
||||||
|
switch (Command)
|
||||||
|
{
|
||||||
|
case APPCTRL_START:
|
||||||
|
{
|
||||||
|
WUPTCfg_Type wupt_cfg;
|
||||||
|
|
||||||
|
if(AD5940_WakeUp(10) > 10) return AD5940ERR_WAKEUP;
|
||||||
|
if(AppRAMPCfg.RAMPInited == bFALSE) return AD5940ERR_APPERROR;
|
||||||
|
if(AppRAMPCfg.RampState == RAMP_STOP) return AD5940ERR_APPERROR;
|
||||||
|
|
||||||
|
wupt_cfg.WuptEn = bTRUE;
|
||||||
|
wupt_cfg.WuptEndSeq = WUPTENDSEQ_D;
|
||||||
|
wupt_cfg.WuptOrder[0] = SEQID_0;
|
||||||
|
wupt_cfg.WuptOrder[1] = SEQID_2;
|
||||||
|
wupt_cfg.WuptOrder[2] = SEQID_1;
|
||||||
|
wupt_cfg.WuptOrder[3] = SEQID_2;
|
||||||
|
wupt_cfg.SeqxSleepTime[SEQID_2] = 4;
|
||||||
|
wupt_cfg.SeqxWakeupTime[SEQID_2] = (uint32_t)(AppRAMPCfg.LFOSCClkFreq * AppRAMPCfg.SampleDelay / 1000.0f) - 4 - 2;
|
||||||
|
wupt_cfg.SeqxSleepTime[SEQID_0] = 4;
|
||||||
|
wupt_cfg.SeqxWakeupTime[SEQID_0] = (uint32_t)(AppRAMPCfg.LFOSCClkFreq * (AppRAMPCfg.RampDuration / AppRAMPCfg.StepNumber - AppRAMPCfg.SampleDelay) / 1000.0f) - 4 - 2;
|
||||||
|
wupt_cfg.SeqxSleepTime[SEQID_1] = wupt_cfg.SeqxSleepTime[SEQID_0];
|
||||||
|
wupt_cfg.SeqxWakeupTime[SEQID_1] = wupt_cfg.SeqxWakeupTime[SEQID_0];
|
||||||
|
AD5940_WUPTCfg(&wupt_cfg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case APPCTRL_STOPNOW:
|
||||||
|
{
|
||||||
|
if(AD5940_WakeUp(10) > 10) return AD5940ERR_WAKEUP;
|
||||||
|
AD5940_WUPTCtrl(bFALSE);
|
||||||
|
AD5940_WUPTCtrl(bFALSE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case APPCTRL_STOPSYNC:
|
||||||
|
{
|
||||||
|
AppRAMPCfg.StopRequired = bTRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case APPCTRL_SHUTDOWN:
|
||||||
|
{
|
||||||
|
AppRAMPCtrl(APPCTRL_STOPNOW, 0);
|
||||||
|
AD5940_ShutDownS();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AD5940Err AppRAMPSeqInitGen(void)
|
||||||
|
{
|
||||||
|
AD5940Err error = AD5940ERR_OK;
|
||||||
|
const uint32_t *pSeqCmd;
|
||||||
|
uint32_t SeqLen;
|
||||||
|
AFERefCfg_Type aferef_cfg;
|
||||||
|
LPLoopCfg_Type lploop_cfg;
|
||||||
|
DSPCfg_Type dsp_cfg;
|
||||||
|
|
||||||
|
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 = bTRUE;
|
||||||
|
aferef_cfg.Lp1V8BuffEn = bTRUE;
|
||||||
|
aferef_cfg.LpBandgapEn = bTRUE;
|
||||||
|
aferef_cfg.LpRefBufEn = bTRUE;
|
||||||
|
aferef_cfg.LpRefBoostEn = bFALSE;
|
||||||
|
AD5940_REFCfgS(&aferef_cfg);
|
||||||
|
|
||||||
|
lploop_cfg.LpAmpCfg.LpAmpSel = LPAMP0;
|
||||||
|
lploop_cfg.LpAmpCfg.LpAmpPwrMod = LPAMPPWR_NORM;
|
||||||
|
lploop_cfg.LpAmpCfg.LpPaPwrEn = bTRUE;
|
||||||
|
lploop_cfg.LpAmpCfg.LpTiaPwrEn = bTRUE;
|
||||||
|
lploop_cfg.LpAmpCfg.LpTiaRf = AppRAMPCfg.LpTiaRf; // Use Configured LPF
|
||||||
|
lploop_cfg.LpAmpCfg.LpTiaRload = LPTIARLOAD_10R;
|
||||||
|
lploop_cfg.LpAmpCfg.LpTiaRtia = AppRAMPCfg.LPTIARtiaSel;
|
||||||
|
|
||||||
|
lploop_cfg.LpAmpCfg.LpTiaSW = LPTIASW(5)|LPTIASW(2)|LPTIASW(4)|LPTIASW(12)|LPTIASW(13);
|
||||||
|
|
||||||
|
lploop_cfg.LpDacCfg.LpdacSel = LPDAC0;
|
||||||
|
lploop_cfg.LpDacCfg.DacData12Bit = 0x800;
|
||||||
|
lploop_cfg.LpDacCfg.DacData6Bit = 0;
|
||||||
|
lploop_cfg.LpDacCfg.DataRst = bFALSE;
|
||||||
|
lploop_cfg.LpDacCfg.LpDacSW = LPDACSW_VBIAS2LPPA|LPDACSW_VBIAS2PIN|LPDACSW_VZERO2LPTIA|LPDACSW_VZERO2PIN;
|
||||||
|
lploop_cfg.LpDacCfg.LpDacRef = LPDACREF_2P5;
|
||||||
|
lploop_cfg.LpDacCfg.LpDacSrc = LPDACSRC_MMR;
|
||||||
|
lploop_cfg.LpDacCfg.LpDacVbiasMux = LPDACVBIAS_12BIT;
|
||||||
|
lploop_cfg.LpDacCfg.LpDacVzeroMux = LPDACVZERO_6BIT;
|
||||||
|
lploop_cfg.LpDacCfg.PowerEn = bTRUE;
|
||||||
|
AD5940_LPLoopCfgS(&lploop_cfg);
|
||||||
|
|
||||||
|
AD5940_StructInit(&dsp_cfg, sizeof(dsp_cfg));
|
||||||
|
dsp_cfg.ADCBaseCfg.ADCMuxN = ADCMUXN_LPTIA0_N;
|
||||||
|
dsp_cfg.ADCBaseCfg.ADCMuxP = ADCMUXP_LPTIA0_P;
|
||||||
|
dsp_cfg.ADCBaseCfg.ADCPga = AppRAMPCfg.AdcPgaGain;
|
||||||
|
|
||||||
|
dsp_cfg.ADCFilterCfg.ADCSinc3Osr = AppRAMPCfg.ADCSinc3Osr;
|
||||||
|
dsp_cfg.ADCFilterCfg.ADCRate = ADCRATE_800KHZ;
|
||||||
|
dsp_cfg.ADCFilterCfg.BpSinc3 = bFALSE;
|
||||||
|
dsp_cfg.ADCFilterCfg.Sinc2NotchEnable = bTRUE;
|
||||||
|
dsp_cfg.ADCFilterCfg.BpNotch = bTRUE;
|
||||||
|
dsp_cfg.ADCFilterCfg.ADCSinc2Osr = ADCSINC2OSR_1067;
|
||||||
|
dsp_cfg.ADCFilterCfg.ADCAvgNum = ADCAVGNUM_2;
|
||||||
|
AD5940_DSPCfgS(&dsp_cfg);
|
||||||
|
|
||||||
|
AD5940_SEQGenInsert(SEQ_STOP());
|
||||||
|
|
||||||
|
AD5940_SEQGenCtrl(bFALSE);
|
||||||
|
error = AD5940_SEQGenFetchSeq(&pSeqCmd, &SeqLen);
|
||||||
|
if(error == AD5940ERR_OK)
|
||||||
|
{
|
||||||
|
AD5940_StructInit(&AppRAMPCfg.InitSeqInfo, sizeof(AppRAMPCfg.InitSeqInfo));
|
||||||
|
if(SeqLen >= AppRAMPCfg.MaxSeqLen) return AD5940ERR_SEQLEN;
|
||||||
|
|
||||||
|
AppRAMPCfg.InitSeqInfo.SeqId = SEQID_3;
|
||||||
|
AppRAMPCfg.InitSeqInfo.SeqRamAddr = AppRAMPCfg.SeqStartAddr;
|
||||||
|
AppRAMPCfg.InitSeqInfo.pSeqCmd = pSeqCmd;
|
||||||
|
AppRAMPCfg.InitSeqInfo.SeqLen = SeqLen;
|
||||||
|
AppRAMPCfg.InitSeqInfo.WriteSRAM = bTRUE;
|
||||||
|
AD5940_SEQInfoCfg(&AppRAMPCfg.InitSeqInfo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return error;
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AD5940Err AppRAMPSeqADCCtrlGen(void)
|
||||||
|
{
|
||||||
|
AD5940Err error = AD5940ERR_OK;
|
||||||
|
const uint32_t *pSeqCmd;
|
||||||
|
uint32_t SeqLen;
|
||||||
|
uint32_t WaitClks;
|
||||||
|
ClksCalInfo_Type clks_cal;
|
||||||
|
|
||||||
|
clks_cal.DataCount = 1;
|
||||||
|
clks_cal.DataType = DATATYPE_SINC3;
|
||||||
|
clks_cal.ADCSinc3Osr = AppRAMPCfg.ADCSinc3Osr;
|
||||||
|
clks_cal.ADCSinc2Osr = ADCSINC2OSR_1067;
|
||||||
|
clks_cal.ADCAvgNum = ADCAVGNUM_2;
|
||||||
|
clks_cal.RatioSys2AdcClk = AppRAMPCfg.SysClkFreq / AppRAMPCfg.AdcClkFreq;
|
||||||
|
AD5940_ClksCalculate(&clks_cal, &WaitClks);
|
||||||
|
|
||||||
|
AD5940_SEQGenCtrl(bTRUE);
|
||||||
|
AD5940_SEQGpioCtrlS(AGPIO_Pin2);
|
||||||
|
AD5940_AFECtrlS(AFECTRL_ADCPWR, bTRUE);
|
||||||
|
AD5940_SEQGenInsert(SEQ_WAIT(16 * 250));
|
||||||
|
AD5940_AFECtrlS(AFECTRL_ADCCNV, bTRUE);
|
||||||
|
AD5940_SEQGenInsert(SEQ_WAIT(WaitClks));
|
||||||
|
AD5940_AFECtrlS(AFECTRL_ADCPWR | AFECTRL_ADCCNV, bFALSE);
|
||||||
|
AD5940_SEQGpioCtrlS(0);
|
||||||
|
AD5940_EnterSleepS();
|
||||||
|
|
||||||
|
error = AD5940_SEQGenFetchSeq(&pSeqCmd, &SeqLen);
|
||||||
|
AD5940_SEQGenCtrl(bFALSE);
|
||||||
|
|
||||||
|
if(error == AD5940ERR_OK)
|
||||||
|
{
|
||||||
|
AD5940_StructInit(&AppRAMPCfg.ADCSeqInfo, sizeof(AppRAMPCfg.ADCSeqInfo));
|
||||||
|
if((SeqLen + AppRAMPCfg.InitSeqInfo.SeqLen) >= AppRAMPCfg.MaxSeqLen)
|
||||||
|
return AD5940ERR_SEQLEN;
|
||||||
|
AppRAMPCfg.ADCSeqInfo.SeqId = SEQID_2;
|
||||||
|
AppRAMPCfg.ADCSeqInfo.SeqRamAddr = AppRAMPCfg.InitSeqInfo.SeqRamAddr + AppRAMPCfg.InitSeqInfo.SeqLen ;
|
||||||
|
AppRAMPCfg.ADCSeqInfo.pSeqCmd = pSeqCmd;
|
||||||
|
AppRAMPCfg.ADCSeqInfo.SeqLen = SeqLen;
|
||||||
|
AppRAMPCfg.ADCSeqInfo.WriteSRAM = bTRUE;
|
||||||
|
AD5940_SEQInfoCfg(&AppRAMPCfg.ADCSeqInfo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return error;
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AD5940Err RampDacRegUpdate(uint32_t *pDACData)
|
||||||
|
{
|
||||||
|
uint32_t VbiasCode, VzeroCode;
|
||||||
|
|
||||||
|
if (AppRAMPCfg.bRampOneDir)
|
||||||
|
{
|
||||||
|
switch(AppRAMPCfg.RampState)
|
||||||
|
{
|
||||||
|
case RAMP_STATE0:
|
||||||
|
AppRAMPCfg.CurrVzeroCode = (uint32_t)((AppRAMPCfg.VzeroStart - 200.0f) / DAC6BITVOLT_1LSB);
|
||||||
|
AppRAMPCfg.RampState = RAMP_STATE1;
|
||||||
|
break;
|
||||||
|
case RAMP_STATE1:
|
||||||
|
if(AppRAMPCfg.CurrStepPos >= AppRAMPCfg.StepNumber / 2)
|
||||||
|
{
|
||||||
|
AppRAMPCfg.RampState = RAMP_STATE4;
|
||||||
|
AppRAMPCfg.CurrVzeroCode = (uint32_t)((AppRAMPCfg.VzeroPeak - 200.0f) / DAC6BITVOLT_1LSB);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RAMP_STATE4:
|
||||||
|
if(AppRAMPCfg.CurrStepPos >= AppRAMPCfg.StepNumber)
|
||||||
|
AppRAMPCfg.RampState = RAMP_STOP;
|
||||||
|
break;
|
||||||
|
case RAMP_STOP:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch(AppRAMPCfg.RampState)
|
||||||
|
{
|
||||||
|
case RAMP_STATE0:
|
||||||
|
AppRAMPCfg.CurrVzeroCode = (uint32_t)((AppRAMPCfg.VzeroStart - 200.0f) / DAC6BITVOLT_1LSB);
|
||||||
|
AppRAMPCfg.RampState = RAMP_STATE1;
|
||||||
|
break;
|
||||||
|
case RAMP_STATE1:
|
||||||
|
if(AppRAMPCfg.CurrStepPos >= AppRAMPCfg.StepNumber / 4)
|
||||||
|
{
|
||||||
|
AppRAMPCfg.RampState = RAMP_STATE2;
|
||||||
|
AppRAMPCfg.CurrVzeroCode = (uint32_t)((AppRAMPCfg.VzeroPeak - 200.0f) / DAC6BITVOLT_1LSB);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RAMP_STATE2:
|
||||||
|
if(AppRAMPCfg.CurrStepPos >= (AppRAMPCfg.StepNumber * 2) / 4)
|
||||||
|
{
|
||||||
|
AppRAMPCfg.RampState = RAMP_STATE3;
|
||||||
|
AppRAMPCfg.bDACCodeInc = AppRAMPCfg.bDACCodeInc ? bFALSE : bTRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RAMP_STATE3:
|
||||||
|
if(AppRAMPCfg.CurrStepPos >= (AppRAMPCfg.StepNumber * 3) / 4)
|
||||||
|
{
|
||||||
|
AppRAMPCfg.RampState = RAMP_STATE4;
|
||||||
|
AppRAMPCfg.CurrVzeroCode = (uint32_t)((AppRAMPCfg.VzeroStart - 200.0f) / DAC6BITVOLT_1LSB);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RAMP_STATE4:
|
||||||
|
if(AppRAMPCfg.CurrStepPos >= AppRAMPCfg.StepNumber)
|
||||||
|
AppRAMPCfg.RampState = RAMP_STOP;
|
||||||
|
break;
|
||||||
|
case RAMP_STOP:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AppRAMPCfg.CurrStepPos ++;
|
||||||
|
if(AppRAMPCfg.bDACCodeInc)
|
||||||
|
AppRAMPCfg.CurrRampCode += AppRAMPCfg.DACCodePerStep;
|
||||||
|
else
|
||||||
|
AppRAMPCfg.CurrRampCode -= AppRAMPCfg.DACCodePerStep;
|
||||||
|
VzeroCode = AppRAMPCfg.CurrVzeroCode;
|
||||||
|
VbiasCode = (uint32_t)(VzeroCode * 64 + AppRAMPCfg.CurrRampCode);
|
||||||
|
if(VbiasCode < (VzeroCode * 64))
|
||||||
|
VbiasCode --;
|
||||||
|
|
||||||
|
if(VbiasCode > 4095) VbiasCode = 4095;
|
||||||
|
if(VzeroCode > 63) VzeroCode = 63;
|
||||||
|
*pDACData = (VzeroCode << 12) | VbiasCode;
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AD5940Err AppRAMPSeqDACCtrlGen(void)
|
||||||
|
{
|
||||||
|
#define SEQLEN_ONESTEP 4L
|
||||||
|
#define CURRBLK_BLK0 0
|
||||||
|
#define CURRBLK_BLK1 1
|
||||||
|
AD5940Err error = AD5940ERR_OK;
|
||||||
|
uint32_t BlockStartSRAMAddr;
|
||||||
|
uint32_t DACData, SRAMAddr;
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t StepsThisBlock;
|
||||||
|
BoolFlag bIsFinalBlk;
|
||||||
|
uint32_t SeqCmdBuff[SEQLEN_ONESTEP];
|
||||||
|
|
||||||
|
static BoolFlag bCmdForSeq0 = bTRUE;
|
||||||
|
static uint32_t DACSeqBlk0Addr, DACSeqBlk1Addr;
|
||||||
|
static uint32_t StepsRemainning, StepsPerBlock, DACSeqCurrBlk;
|
||||||
|
|
||||||
|
if(AppRAMPCfg.bFirstDACSeq == bTRUE)
|
||||||
|
{
|
||||||
|
int32_t DACSeqLenMax;
|
||||||
|
StepsRemainning = AppRAMPCfg.StepNumber;
|
||||||
|
DACSeqLenMax = (int32_t)AppRAMPCfg.MaxSeqLen - (int32_t)AppRAMPCfg.InitSeqInfo.SeqLen - (int32_t)AppRAMPCfg.ADCSeqInfo.SeqLen;
|
||||||
|
if(DACSeqLenMax < SEQLEN_ONESTEP * 4) return AD5940ERR_SEQLEN;
|
||||||
|
DACSeqLenMax -= SEQLEN_ONESTEP * 2;
|
||||||
|
StepsPerBlock = DACSeqLenMax / SEQLEN_ONESTEP / 2;
|
||||||
|
DACSeqBlk0Addr = AppRAMPCfg.ADCSeqInfo.SeqRamAddr + AppRAMPCfg.ADCSeqInfo.SeqLen;
|
||||||
|
DACSeqBlk1Addr = DACSeqBlk0Addr + StepsPerBlock * SEQLEN_ONESTEP;
|
||||||
|
DACSeqCurrBlk = CURRBLK_BLK0;
|
||||||
|
|
||||||
|
if (AppRAMPCfg.bRampOneDir)
|
||||||
|
{
|
||||||
|
AppRAMPCfg.DACCodePerStep = ((AppRAMPCfg.RampPeakVolt - AppRAMPCfg.RampStartVolt) / AppRAMPCfg.StepNumber) / DAC12BITVOLT_1LSB;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AppRAMPCfg.DACCodePerStep = ((AppRAMPCfg.RampPeakVolt - AppRAMPCfg.RampStartVolt) / AppRAMPCfg.StepNumber * 2) / DAC12BITVOLT_1LSB;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(AppRAMPCfg.DACCodePerStep > 0)
|
||||||
|
AppRAMPCfg.bDACCodeInc = bTRUE;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AppRAMPCfg.DACCodePerStep = -AppRAMPCfg.DACCodePerStep;
|
||||||
|
AppRAMPCfg.bDACCodeInc = bFALSE;
|
||||||
|
}
|
||||||
|
AppRAMPCfg.CurrRampCode = AppRAMPCfg.RampStartVolt / DAC12BITVOLT_1LSB;
|
||||||
|
|
||||||
|
AppRAMPCfg.RampState = RAMP_STATE0;
|
||||||
|
AppRAMPCfg.CurrStepPos = 0;
|
||||||
|
|
||||||
|
bCmdForSeq0 = bTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(StepsRemainning == 0) return AD5940ERR_OK;
|
||||||
|
bIsFinalBlk = StepsRemainning <= StepsPerBlock ? bTRUE : bFALSE;
|
||||||
|
if(bIsFinalBlk)
|
||||||
|
StepsThisBlock = StepsRemainning;
|
||||||
|
else
|
||||||
|
StepsThisBlock = StepsPerBlock;
|
||||||
|
StepsRemainning -= StepsThisBlock;
|
||||||
|
|
||||||
|
BlockStartSRAMAddr = (DACSeqCurrBlk == CURRBLK_BLK0) ? DACSeqBlk0Addr : DACSeqBlk1Addr;
|
||||||
|
SRAMAddr = BlockStartSRAMAddr;
|
||||||
|
|
||||||
|
for(i = 0; i < StepsThisBlock - 1; i++)
|
||||||
|
{
|
||||||
|
uint32_t CurrAddr = SRAMAddr;
|
||||||
|
SRAMAddr += SEQLEN_ONESTEP;
|
||||||
|
RampDacRegUpdate(&DACData);
|
||||||
|
SeqCmdBuff[0] = SEQ_WR(REG_AFE_LPDACDAT0, DACData);
|
||||||
|
SeqCmdBuff[1] = SEQ_WAIT(10);
|
||||||
|
SeqCmdBuff[2] = SEQ_WR(bCmdForSeq0 ? REG_AFE_SEQ1INFO : REG_AFE_SEQ0INFO, (SRAMAddr << BITP_AFE_SEQ1INFO_ADDR) | (SEQLEN_ONESTEP << BITP_AFE_SEQ1INFO_LEN));
|
||||||
|
SeqCmdBuff[3] = SEQ_SLP();
|
||||||
|
AD5940_SEQCmdWrite(CurrAddr, SeqCmdBuff, SEQLEN_ONESTEP);
|
||||||
|
bCmdForSeq0 = bCmdForSeq0 ? bFALSE : bTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bIsFinalBlk)
|
||||||
|
{
|
||||||
|
uint32_t CurrAddr = SRAMAddr;
|
||||||
|
SRAMAddr += SEQLEN_ONESTEP;
|
||||||
|
RampDacRegUpdate(&DACData);
|
||||||
|
SeqCmdBuff[0] = SEQ_WR(REG_AFE_LPDACDAT0, DACData);
|
||||||
|
SeqCmdBuff[1] = SEQ_WAIT(10);
|
||||||
|
SeqCmdBuff[2] = SEQ_WR(bCmdForSeq0 ? REG_AFE_SEQ1INFO : REG_AFE_SEQ0INFO, (SRAMAddr << BITP_AFE_SEQ1INFO_ADDR) | (SEQLEN_ONESTEP << BITP_AFE_SEQ1INFO_LEN));
|
||||||
|
SeqCmdBuff[3] = SEQ_SLP();
|
||||||
|
AD5940_SEQCmdWrite(CurrAddr, SeqCmdBuff, SEQLEN_ONESTEP);
|
||||||
|
CurrAddr += SEQLEN_ONESTEP;
|
||||||
|
|
||||||
|
SeqCmdBuff[0] = SEQ_NOP();
|
||||||
|
SeqCmdBuff[1] = SEQ_NOP();
|
||||||
|
SeqCmdBuff[2] = SEQ_NOP();
|
||||||
|
SeqCmdBuff[3] = SEQ_STOP();
|
||||||
|
AD5940_SEQCmdWrite(CurrAddr, SeqCmdBuff, SEQLEN_ONESTEP);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32_t CurrAddr = SRAMAddr;
|
||||||
|
SRAMAddr = (DACSeqCurrBlk == CURRBLK_BLK0) ? DACSeqBlk1Addr : DACSeqBlk0Addr;
|
||||||
|
RampDacRegUpdate(&DACData);
|
||||||
|
SeqCmdBuff[0] = SEQ_WR(REG_AFE_LPDACDAT0, DACData);
|
||||||
|
SeqCmdBuff[1] = SEQ_WAIT(10);
|
||||||
|
SeqCmdBuff[2] = SEQ_WR(bCmdForSeq0 ? REG_AFE_SEQ1INFO : REG_AFE_SEQ0INFO, (SRAMAddr << BITP_AFE_SEQ1INFO_ADDR) | (SEQLEN_ONESTEP << BITP_AFE_SEQ1INFO_LEN));
|
||||||
|
SeqCmdBuff[3] = SEQ_INT0();
|
||||||
|
AD5940_SEQCmdWrite(CurrAddr, SeqCmdBuff, SEQLEN_ONESTEP);
|
||||||
|
bCmdForSeq0 = bCmdForSeq0 ? bFALSE : bTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DACSeqCurrBlk = (DACSeqCurrBlk == CURRBLK_BLK0) ? CURRBLK_BLK1 : CURRBLK_BLK0;
|
||||||
|
if(AppRAMPCfg.bFirstDACSeq)
|
||||||
|
{
|
||||||
|
AppRAMPCfg.bFirstDACSeq = bFALSE;
|
||||||
|
if(bIsFinalBlk == bFALSE)
|
||||||
|
{
|
||||||
|
error = AppRAMPSeqDACCtrlGen();
|
||||||
|
if(error != AD5940ERR_OK) return error;
|
||||||
|
}
|
||||||
|
AppRAMPCfg.DACSeqInfo.SeqId = SEQID_0;
|
||||||
|
AppRAMPCfg.DACSeqInfo.SeqLen = SEQLEN_ONESTEP;
|
||||||
|
AppRAMPCfg.DACSeqInfo.SeqRamAddr = BlockStartSRAMAddr;
|
||||||
|
AppRAMPCfg.DACSeqInfo.WriteSRAM = bFALSE;
|
||||||
|
AD5940_SEQInfoCfg(&AppRAMPCfg.DACSeqInfo);
|
||||||
|
}
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
AD5940Err AppRAMPInit(uint32_t *pBuffer, uint32_t BufferSize)
|
||||||
|
{
|
||||||
|
AD5940Err error = AD5940ERR_OK;
|
||||||
|
FIFOCfg_Type fifo_cfg;
|
||||||
|
SEQCfg_Type seq_cfg;
|
||||||
|
|
||||||
|
if(AD5940_WakeUp(10) > 10) return AD5940ERR_WAKEUP;
|
||||||
|
|
||||||
|
seq_cfg.SeqMemSize = SEQMEMSIZE_4KB;
|
||||||
|
seq_cfg.SeqBreakEn = bFALSE;
|
||||||
|
seq_cfg.SeqIgnoreEn = bFALSE;
|
||||||
|
seq_cfg.SeqCntCRCClr = bTRUE;
|
||||||
|
seq_cfg.SeqEnable = bFALSE;
|
||||||
|
seq_cfg.SeqWrTimer = 0;
|
||||||
|
AD5940_SEQCfg(&seq_cfg);
|
||||||
|
|
||||||
|
if((AppRAMPCfg.RAMPInited == bFALSE) || (AppRAMPCfg.bParaChanged == bTRUE))
|
||||||
|
{
|
||||||
|
if(pBuffer == 0) return AD5940ERR_PARA;
|
||||||
|
if(BufferSize == 0) return AD5940ERR_PARA;
|
||||||
|
|
||||||
|
AppRAMPCfg.RAMPInited = bFALSE;
|
||||||
|
AD5940_SEQGenInit(pBuffer, BufferSize);
|
||||||
|
|
||||||
|
error = AppRAMPSeqInitGen();
|
||||||
|
if(error != AD5940ERR_OK) return error;
|
||||||
|
error = AppRAMPSeqADCCtrlGen();
|
||||||
|
if(error != AD5940ERR_OK) return error;
|
||||||
|
AppRAMPCfg.bParaChanged = bFALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
AD5940_FIFOCtrlS(FIFOSRC_SINC3, bFALSE);
|
||||||
|
fifo_cfg.FIFOEn = bTRUE;
|
||||||
|
fifo_cfg.FIFOSrc = FIFOSRC_SINC3;
|
||||||
|
fifo_cfg.FIFOThresh = AppRAMPCfg.FifoThresh;
|
||||||
|
fifo_cfg.FIFOMode = FIFOMODE_FIFO;
|
||||||
|
fifo_cfg.FIFOSize = FIFOSIZE_2KB;
|
||||||
|
AD5940_FIFOCfg(&fifo_cfg);
|
||||||
|
|
||||||
|
AD5940_INTCClrFlag(AFEINTSRC_ALLINT);
|
||||||
|
|
||||||
|
AppRAMPCfg.bFirstDACSeq = bTRUE;
|
||||||
|
error = AppRAMPSeqDACCtrlGen();
|
||||||
|
if(error != AD5940ERR_OK) return error;
|
||||||
|
|
||||||
|
AppRAMPCfg.InitSeqInfo.WriteSRAM = bFALSE;
|
||||||
|
AD5940_SEQInfoCfg(&AppRAMPCfg.InitSeqInfo);
|
||||||
|
|
||||||
|
AD5940_SEQCtrlS(bTRUE);
|
||||||
|
AD5940_SEQMmrTrig(AppRAMPCfg.InitSeqInfo.SeqId);
|
||||||
|
while(AD5940_INTCTestFlag(AFEINTC_1, AFEINTSRC_ENDSEQ) == bFALSE);
|
||||||
|
AD5940_INTCClrFlag(AFEINTSRC_ENDSEQ);
|
||||||
|
|
||||||
|
AppRAMPCfg.ADCSeqInfo.WriteSRAM = bFALSE;
|
||||||
|
AD5940_SEQInfoCfg(&AppRAMPCfg.ADCSeqInfo);
|
||||||
|
|
||||||
|
AppRAMPCfg.DACSeqInfo.WriteSRAM = bFALSE;
|
||||||
|
AD5940_SEQInfoCfg(&AppRAMPCfg.DACSeqInfo);
|
||||||
|
|
||||||
|
AD5940_SEQCtrlS(bFALSE);
|
||||||
|
AD5940_WriteReg(REG_AFE_SEQCNT, 0);
|
||||||
|
AD5940_SEQCtrlS(bTRUE);
|
||||||
|
AD5940_ClrMCUIntFlag();
|
||||||
|
|
||||||
|
AD5940_AFEPwrBW(AFEPWR_LP, AFEBW_250KHZ);
|
||||||
|
|
||||||
|
AppRAMPCfg.RAMPInited = bTRUE;
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t AppRAMPRegModify(int32_t *const pData, uint32_t *pDataCount)
|
||||||
|
{
|
||||||
|
if(AppRAMPCfg.StopRequired == bTRUE)
|
||||||
|
{
|
||||||
|
AD5940_WUPTCtrl(bFALSE);
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
return AD5940ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t AppRAMPDataProcess(int32_t *const pData, uint32_t *pDataCount)
|
||||||
|
{
|
||||||
|
uint32_t i, datacount;
|
||||||
|
datacount = *pDataCount;
|
||||||
|
float *pOut = (float *)pData;
|
||||||
|
float temp;
|
||||||
|
for(i = 0; i < datacount; i++)
|
||||||
|
{
|
||||||
|
pData[i] &= 0xffff;
|
||||||
|
temp = -AD5940_ADCCode2Volt(pData[i], AppRAMPCfg.AdcPgaGain, AppRAMPCfg.ADCRefVolt);
|
||||||
|
pOut[i] = temp / AppRAMPCfg.RtiaValue.Magnitude * 1e3f; /* Result unit is uA. */
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AD5940Err AppRAMPISR(void *pBuff, uint32_t *pCount)
|
||||||
|
{
|
||||||
|
uint32_t BuffCount;
|
||||||
|
uint32_t FifoCnt;
|
||||||
|
BuffCount = *pCount;
|
||||||
|
uint32_t IntFlag;
|
||||||
|
|
||||||
|
if(AD5940_WakeUp(10) > 10) return AD5940ERR_WAKEUP;
|
||||||
|
AD5940_SleepKeyCtrlS(SLPKEY_LOCK);
|
||||||
|
*pCount = 0;
|
||||||
|
IntFlag = AD5940_INTCGetFlag(AFEINTC_0);
|
||||||
|
|
||||||
|
if(IntFlag & AFEINTSRC_CUSTOMINT0)
|
||||||
|
{
|
||||||
|
AD5940Err error;
|
||||||
|
AD5940_INTCClrFlag(AFEINTSRC_CUSTOMINT0);
|
||||||
|
error = AppRAMPSeqDACCtrlGen();
|
||||||
|
if(error != AD5940ERR_OK) return error;
|
||||||
|
AD5940_SleepKeyCtrlS(SLPKEY_UNLOCK);
|
||||||
|
}
|
||||||
|
if(IntFlag & AFEINTSRC_DATAFIFOTHRESH)
|
||||||
|
{
|
||||||
|
FifoCnt = AD5940_FIFOGetCnt();
|
||||||
|
AD5940_FIFORd((uint32_t *)pBuff, FifoCnt);
|
||||||
|
AD5940_INTCClrFlag(AFEINTSRC_DATAFIFOTHRESH);
|
||||||
|
AppRAMPRegModify((int32_t*)pBuff, &FifoCnt);
|
||||||
|
AD5940_SleepKeyCtrlS(SLPKEY_UNLOCK);
|
||||||
|
AppRAMPDataProcess((int32_t *)pBuff, &FifoCnt);
|
||||||
|
*pCount = FifoCnt;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(IntFlag & AFEINTSRC_ENDSEQ)
|
||||||
|
{
|
||||||
|
FifoCnt = AD5940_FIFOGetCnt();
|
||||||
|
AD5940_INTCClrFlag(AFEINTSRC_ENDSEQ);
|
||||||
|
AD5940_FIFORd((uint32_t *)pBuff, FifoCnt);
|
||||||
|
AppRAMPDataProcess((int32_t *)pBuff, &FifoCnt);
|
||||||
|
*pCount = FifoCnt;
|
||||||
|
AppRAMPCtrl(APPCTRL_STOPNOW, 0);
|
||||||
|
|
||||||
|
// Signal that we are done
|
||||||
|
return AD5940ERR_STOP;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
// RampTest.h
|
||||||
|
#ifndef _RAMPTEST_H_
|
||||||
|
#define _RAMPTEST_H_
|
||||||
|
#include "ad5940.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "string.h"
|
||||||
|
#include "math.h"
|
||||||
|
|
||||||
|
#define ALIGIN_VOLT2LSB 0
|
||||||
|
#define DAC12BITVOLT_1LSB (2200.0f/4095) //mV
|
||||||
|
#define DAC6BITVOLT_1LSB (DAC12BITVOLT_1LSB*64) //mV
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
BoolFlag bParaChanged;
|
||||||
|
uint32_t SeqStartAddr;
|
||||||
|
uint32_t MaxSeqLen;
|
||||||
|
uint32_t SeqStartAddrCal;
|
||||||
|
uint32_t MaxSeqLenCal;
|
||||||
|
float LFOSCClkFreq;
|
||||||
|
float SysClkFreq;
|
||||||
|
float AdcClkFreq;
|
||||||
|
float RcalVal;
|
||||||
|
float ADCRefVolt;
|
||||||
|
BoolFlag bTestFinished;
|
||||||
|
float RampStartVolt;
|
||||||
|
float RampPeakVolt;
|
||||||
|
float VzeroStart;
|
||||||
|
float VzeroPeak;
|
||||||
|
uint32_t StepNumber;
|
||||||
|
uint32_t RampDuration;
|
||||||
|
float SampleDelay;
|
||||||
|
uint32_t LPTIARtiaSel;
|
||||||
|
uint32_t LPTIARloadSel;
|
||||||
|
uint32_t LpTiaRf; /* Added LPF Resistor Configuration */
|
||||||
|
float ExternalRtiaValue;
|
||||||
|
uint32_t AdcPgaGain;
|
||||||
|
uint8_t ADCSinc3Osr;
|
||||||
|
uint32_t FifoThresh;
|
||||||
|
BoolFlag RAMPInited;
|
||||||
|
fImpPol_Type RtiaValue;
|
||||||
|
SEQInfo_Type InitSeqInfo;
|
||||||
|
SEQInfo_Type ADCSeqInfo;
|
||||||
|
BoolFlag bFirstDACSeq;
|
||||||
|
SEQInfo_Type DACSeqInfo;
|
||||||
|
uint32_t CurrStepPos;
|
||||||
|
float DACCodePerStep;
|
||||||
|
float CurrRampCode;
|
||||||
|
uint32_t CurrVzeroCode;
|
||||||
|
BoolFlag bDACCodeInc;
|
||||||
|
BoolFlag StopRequired;
|
||||||
|
enum _RampState{RAMP_STATE0 = 0, RAMP_STATE1, RAMP_STATE2, RAMP_STATE3, RAMP_STATE4, RAMP_STOP} RampState;
|
||||||
|
BoolFlag bRampOneDir;
|
||||||
|
}AppRAMPCfg_Type;
|
||||||
|
|
||||||
|
#define APPCTRL_START 0
|
||||||
|
#define APPCTRL_STOPNOW 1
|
||||||
|
#define APPCTRL_STOPSYNC 2
|
||||||
|
#define APPCTRL_SHUTDOWN 3
|
||||||
|
|
||||||
|
AD5940Err AppRAMPInit(uint32_t *pBuffer, uint32_t BufferSize);
|
||||||
|
AD5940Err AppRAMPGetCfg(void *pCfg);
|
||||||
|
AD5940Err AppRAMPISR(void *pBuff, uint32_t *pCount);
|
||||||
|
AD5940Err AppRAMPCtrl(uint32_t Command, void *pPara);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// File: host/src/GraphWidget.cpp
|
// host/src/GraphWidget.cpp
|
||||||
#include "GraphWidget.h"
|
#include "GraphWidget.h"
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
@ -7,159 +7,322 @@ GraphWidget::GraphWidget(QWidget *parent) : QWidget(parent) {
|
||||||
layout = new QVBoxLayout(this);
|
layout = new QVBoxLayout(this);
|
||||||
plot = new QCustomPlot(this);
|
plot = new QCustomPlot(this);
|
||||||
|
|
||||||
// Setup Layout
|
|
||||||
layout->addWidget(plot);
|
layout->addWidget(plot);
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
// Setup Graphs
|
plot->setBackground(QBrush(QColor(25, 25, 25)));
|
||||||
graph1 = plot->addGraph();
|
|
||||||
graph2 = plot->addGraph(plot->xAxis, plot->yAxis2);
|
|
||||||
graph3 = plot->addGraph(plot->xAxis, plot->yAxis2); // Hilbert Trace
|
|
||||||
|
|
||||||
// Style Graph 1 (Real - Blue)
|
auto styleAxis = [](QCPAxis *axis) {
|
||||||
QPen pen1(Qt::blue);
|
axis->setBasePen(QPen(Qt::white));
|
||||||
|
axis->setTickPen(QPen(Qt::white));
|
||||||
|
axis->setSubTickPen(QPen(Qt::white));
|
||||||
|
axis->setTickLabelColor(Qt::white);
|
||||||
|
axis->setLabelColor(Qt::white);
|
||||||
|
axis->grid()->setPen(QPen(QColor(60, 60, 60), 0, Qt::DotLine));
|
||||||
|
axis->grid()->setSubGridVisible(true);
|
||||||
|
axis->grid()->setSubGridPen(QPen(QColor(40, 40, 40), 0, Qt::DotLine));
|
||||||
|
};
|
||||||
|
|
||||||
|
styleAxis(plot->xAxis);
|
||||||
|
styleAxis(plot->yAxis);
|
||||||
|
styleAxis(plot->yAxis2);
|
||||||
|
|
||||||
|
// --- Setup Graphs ---
|
||||||
|
|
||||||
|
// 1. Real / Raw Nyquist (Cyan)
|
||||||
|
graphReal = plot->addGraph();
|
||||||
|
QPen pen1(QColor(0, 255, 255));
|
||||||
pen1.setWidth(2);
|
pen1.setWidth(2);
|
||||||
graph1->setPen(pen1);
|
graphReal->setPen(pen1);
|
||||||
graph1->setLineStyle(QCPGraph::lsLine);
|
graphReal->setLineStyle(QCPGraph::lsLine);
|
||||||
graph1->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, 3));
|
graphReal->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, QColor(0, 255, 255), 3));
|
||||||
graph1->setName("Real");
|
|
||||||
|
|
||||||
// Style Graph 2 (Imaginary - Red)
|
// 2. Imaginary (Magenta)
|
||||||
QPen pen2(Qt::red);
|
graphImag = plot->addGraph(plot->xAxis, plot->yAxis2);
|
||||||
|
QPen pen2(QColor(255, 0, 255));
|
||||||
pen2.setWidth(2);
|
pen2.setWidth(2);
|
||||||
graph2->setPen(pen2);
|
graphImag->setPen(pen2);
|
||||||
graph2->setLineStyle(QCPGraph::lsLine);
|
graphImag->setLineStyle(QCPGraph::lsLine);
|
||||||
graph2->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssTriangle, 3));
|
graphImag->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssTriangle, QColor(255, 0, 255), 3));
|
||||||
graph2->setName("Imaginary");
|
|
||||||
|
|
||||||
// Style Graph 3 (Hilbert - Green Dashed)
|
// 3. Hilbert (Green Dashed)
|
||||||
|
graphHilbert = plot->addGraph(plot->xAxis, plot->yAxis2);
|
||||||
QPen pen3(Qt::green);
|
QPen pen3(Qt::green);
|
||||||
pen3.setWidth(2);
|
pen3.setWidth(2);
|
||||||
pen3.setStyle(Qt::DashLine);
|
pen3.setStyle(Qt::DashLine);
|
||||||
graph3->setPen(pen3);
|
graphHilbert->setPen(pen3);
|
||||||
graph3->setLineStyle(QCPGraph::lsLine);
|
|
||||||
graph3->setName("Hilbert (Analytic)");
|
// 4. Corrected Nyquist (Orange)
|
||||||
|
graphNyquistCorr = plot->addGraph(plot->xAxis, plot->yAxis);
|
||||||
|
QPen pen4(QColor(255, 165, 0));
|
||||||
|
pen4.setWidth(2);
|
||||||
|
graphNyquistCorr->setPen(pen4);
|
||||||
|
graphNyquistCorr->setLineStyle(QCPGraph::lsLine);
|
||||||
|
graphNyquistCorr->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCross, 4));
|
||||||
|
graphNyquistCorr->setName("De-embedded (True Cell)");
|
||||||
|
|
||||||
|
// 5. Amperometric Graph (Lime)
|
||||||
|
graphAmp = plot->addGraph();
|
||||||
|
QPen pen5(QColor(50, 255, 50));
|
||||||
|
pen5.setWidth(2);
|
||||||
|
graphAmp->setPen(pen5);
|
||||||
|
graphAmp->setLineStyle(QCPGraph::lsLine);
|
||||||
|
graphAmp->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, 3));
|
||||||
|
graphAmp->setName("Current");
|
||||||
|
|
||||||
|
// 6. Extrapolated Point (Gold Star)
|
||||||
|
graphExtrapolated = plot->addGraph(plot->xAxis, plot->yAxis);
|
||||||
|
graphExtrapolated->setLineStyle(QCPGraph::lsNone);
|
||||||
|
graphExtrapolated->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssStar, QColor(255, 215, 0), 12));
|
||||||
|
QPen pen6(QColor(255, 215, 0));
|
||||||
|
pen6.setWidth(3);
|
||||||
|
graphExtrapolated->setPen(pen6);
|
||||||
|
graphExtrapolated->setName("Rs (Extrapolated)");
|
||||||
|
|
||||||
|
// 7. LSV Blank (Gray)
|
||||||
|
graphLSVBlank = plot->addGraph();
|
||||||
|
QPen penBlank(QColor(150, 150, 150));
|
||||||
|
penBlank.setWidth(2);
|
||||||
|
penBlank.setStyle(Qt::DashLine);
|
||||||
|
graphLSVBlank->setPen(penBlank);
|
||||||
|
graphLSVBlank->setName("Blank (Tap Water)");
|
||||||
|
|
||||||
|
// 8. LSV Sample (Yellow)
|
||||||
|
graphLSVSample = plot->addGraph();
|
||||||
|
QPen penSample(Qt::yellow);
|
||||||
|
penSample.setWidth(2);
|
||||||
|
graphLSVSample->setPen(penSample);
|
||||||
|
graphLSVSample->setName("Sample (Bleach)");
|
||||||
|
|
||||||
|
// 9. LSV Diff (Cyan)
|
||||||
|
graphLSVDiff = plot->addGraph();
|
||||||
|
QPen penDiff(Qt::cyan);
|
||||||
|
penDiff.setWidth(3);
|
||||||
|
graphLSVDiff->setPen(penDiff);
|
||||||
|
graphLSVDiff->setName("Diff (Chlorine)");
|
||||||
|
|
||||||
|
graphNyquistRaw = graphReal;
|
||||||
|
|
||||||
// Enable Right Axis
|
|
||||||
plot->yAxis2->setVisible(true);
|
plot->yAxis2->setVisible(true);
|
||||||
plot->yAxis2->setTickLabels(true);
|
plot->yAxis2->setTickLabels(true);
|
||||||
|
|
||||||
// Link Axes for Zooming
|
|
||||||
connect(plot->yAxis, SIGNAL(rangeChanged(QCPRange)), plot->yAxis2, SLOT(setRange(QCPRange)));
|
connect(plot->yAxis, SIGNAL(rangeChanged(QCPRange)), plot->yAxis2, SLOT(setRange(QCPRange)));
|
||||||
connect(plot->yAxis2, SIGNAL(rangeChanged(QCPRange)), plot->yAxis, SLOT(setRange(QCPRange)));
|
connect(plot->yAxis2, SIGNAL(rangeChanged(QCPRange)), plot->yAxis, SLOT(setRange(QCPRange)));
|
||||||
|
|
||||||
// Interactions
|
|
||||||
plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
|
plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
|
||||||
|
|
||||||
// Legend
|
|
||||||
plot->legend->setVisible(true);
|
plot->legend->setVisible(true);
|
||||||
QFont legendFont = font();
|
QFont legendFont = font();
|
||||||
legendFont.setPointSize(9);
|
legendFont.setPointSize(9);
|
||||||
plot->legend->setFont(legendFont);
|
plot->legend->setFont(legendFont);
|
||||||
plot->legend->setBrush(QBrush(QColor(255, 255, 255, 230)));
|
plot->legend->setBrush(QBrush(QColor(40, 40, 40, 200)));
|
||||||
|
plot->legend->setBorderPen(QPen(Qt::white));
|
||||||
|
plot->legend->setTextColor(Qt::white);
|
||||||
|
|
||||||
// Default Mode
|
|
||||||
configureRawPlot();
|
configureRawPlot();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphWidget::configureRawPlot() {
|
void GraphWidget::configureRawPlot() {
|
||||||
clear();
|
// Only clear if explicitly requested, but here we just set visibility
|
||||||
|
|
||||||
// X Axis: Frequency (Log)
|
|
||||||
plot->xAxis->setLabel("Frequency (Hz)");
|
plot->xAxis->setLabel("Frequency (Hz)");
|
||||||
plot->xAxis->setScaleType(QCPAxis::stLogarithmic);
|
plot->xAxis->setScaleType(QCPAxis::stLogarithmic);
|
||||||
QSharedPointer<QCPAxisTickerLog> logTicker(new QCPAxisTickerLog);
|
QSharedPointer<QCPAxisTickerLog> logTicker(new QCPAxisTickerLog);
|
||||||
plot->xAxis->setTicker(logTicker);
|
plot->xAxis->setTicker(logTicker);
|
||||||
plot->xAxis->setNumberFormat("eb");
|
plot->xAxis->setNumberFormat("eb");
|
||||||
|
|
||||||
// Y Axis 1: Real (Linear)
|
|
||||||
plot->yAxis->setLabel("Real (Ohms)");
|
plot->yAxis->setLabel("Real (Ohms)");
|
||||||
plot->yAxis->setScaleType(QCPAxis::stLinear);
|
plot->yAxis->setScaleType(QCPAxis::stLinear);
|
||||||
QSharedPointer<QCPAxisTicker> linTicker(new QCPAxisTicker);
|
QSharedPointer<QCPAxisTicker> linTicker(new QCPAxisTicker);
|
||||||
plot->yAxis->setTicker(linTicker);
|
plot->yAxis->setTicker(linTicker);
|
||||||
plot->yAxis->setNumberFormat("f");
|
plot->yAxis->setNumberFormat("f");
|
||||||
|
|
||||||
// Y Axis 2: Imaginary (Linear)
|
|
||||||
plot->yAxis2->setLabel("Imaginary (Ohms)");
|
plot->yAxis2->setLabel("Imaginary (Ohms)");
|
||||||
plot->yAxis2->setScaleType(QCPAxis::stLinear);
|
plot->yAxis2->setScaleType(QCPAxis::stLinear);
|
||||||
plot->yAxis2->setTicker(linTicker);
|
plot->yAxis2->setTicker(linTicker);
|
||||||
plot->yAxis2->setNumberFormat("f");
|
plot->yAxis2->setNumberFormat("f");
|
||||||
plot->yAxis2->setVisible(true);
|
plot->yAxis2->setVisible(true);
|
||||||
|
|
||||||
graph1->setName("Real");
|
graphReal->setName("Real");
|
||||||
graph2->setName("Imaginary");
|
graphImag->setName("Imaginary");
|
||||||
graph2->setVisible(true);
|
graphHilbert->setName("Hilbert");
|
||||||
graph3->setVisible(true);
|
|
||||||
|
graphReal->setVisible(true);
|
||||||
|
graphImag->setVisible(true);
|
||||||
|
graphHilbert->setVisible(true);
|
||||||
|
graphNyquistCorr->setVisible(false);
|
||||||
|
graphAmp->setVisible(false);
|
||||||
|
graphExtrapolated->setVisible(false);
|
||||||
|
|
||||||
|
graphLSVBlank->setVisible(false);
|
||||||
|
graphLSVSample->setVisible(false);
|
||||||
|
graphLSVDiff->setVisible(false);
|
||||||
|
|
||||||
plot->replot();
|
plot->replot();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphWidget::configureNyquistPlot() {
|
void GraphWidget::configureNyquistPlot() {
|
||||||
clear();
|
|
||||||
|
|
||||||
// X Axis: Real (Z')
|
|
||||||
plot->xAxis->setLabel("Real (Z')");
|
plot->xAxis->setLabel("Real (Z')");
|
||||||
plot->xAxis->setScaleType(QCPAxis::stLinear);
|
plot->xAxis->setScaleType(QCPAxis::stLinear);
|
||||||
QSharedPointer<QCPAxisTicker> linTicker(new QCPAxisTicker);
|
QSharedPointer<QCPAxisTicker> linTicker(new QCPAxisTicker);
|
||||||
plot->xAxis->setTicker(linTicker);
|
plot->xAxis->setTicker(linTicker);
|
||||||
plot->xAxis->setNumberFormat("f");
|
plot->xAxis->setNumberFormat("f");
|
||||||
|
|
||||||
// Y Axis 1: -Imaginary (-Z'')
|
|
||||||
plot->yAxis->setLabel("-Imaginary (-Z'')");
|
plot->yAxis->setLabel("-Imaginary (-Z'')");
|
||||||
plot->yAxis->setScaleType(QCPAxis::stLinear);
|
plot->yAxis->setScaleType(QCPAxis::stLinear);
|
||||||
plot->yAxis->setTicker(linTicker);
|
plot->yAxis->setTicker(linTicker);
|
||||||
plot->yAxis->setNumberFormat("f");
|
plot->yAxis->setNumberFormat("f");
|
||||||
|
|
||||||
// Disable Secondary Axis for Nyquist
|
|
||||||
plot->yAxis2->setVisible(false);
|
plot->yAxis2->setVisible(false);
|
||||||
graph2->setVisible(false);
|
|
||||||
graph3->setVisible(false);
|
|
||||||
|
|
||||||
graph1->setName("Nyquist");
|
graphReal->setName("Measured (Raw)");
|
||||||
graph1->setLineStyle(QCPGraph::lsLine);
|
graphReal->setLineStyle(QCPGraph::lsLine);
|
||||||
graph1->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, 4));
|
graphReal->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, 4));
|
||||||
|
|
||||||
|
graphReal->setVisible(true);
|
||||||
|
graphImag->setVisible(false);
|
||||||
|
graphHilbert->setVisible(false);
|
||||||
|
graphNyquistCorr->setVisible(true);
|
||||||
|
graphAmp->setVisible(false);
|
||||||
|
graphExtrapolated->setVisible(true);
|
||||||
|
|
||||||
|
graphLSVBlank->setVisible(false);
|
||||||
|
graphLSVSample->setVisible(false);
|
||||||
|
graphLSVDiff->setVisible(false);
|
||||||
|
|
||||||
plot->replot();
|
plot->replot();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphWidget::addData(double x, double val1, double val2) {
|
void GraphWidget::configureAmperometricPlot() {
|
||||||
// Mode Detection based on Axis Labels (Simple state check)
|
plot->xAxis->setLabel("Sample Index");
|
||||||
bool isNyquist = (plot->xAxis->label() == "Real (Z')");
|
plot->xAxis->setScaleType(QCPAxis::stLinear);
|
||||||
|
QSharedPointer<QCPAxisTicker> linTicker(new QCPAxisTicker);
|
||||||
|
plot->xAxis->setTicker(linTicker);
|
||||||
|
plot->xAxis->setNumberFormat("f");
|
||||||
|
|
||||||
if (isNyquist) {
|
plot->yAxis->setLabel("Current (uA)");
|
||||||
// For Nyquist: x = Real, val1 = Imaginary
|
plot->yAxis->setScaleType(QCPAxis::stLinear);
|
||||||
// We plot Real vs -Imaginary
|
plot->yAxis->setTicker(linTicker);
|
||||||
graph1->addData(x, -val1);
|
plot->yAxis->setNumberFormat("f");
|
||||||
} else {
|
|
||||||
// Raw Plot: x = Freq, val1 = Real, val2 = Imag
|
|
||||||
if (plot->xAxis->scaleType() == QCPAxis::stLogarithmic && x <= 0) return;
|
|
||||||
|
|
||||||
graph1->addData(x, val1);
|
plot->yAxis2->setVisible(false);
|
||||||
graph2->addData(x, val2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auto-scale
|
graphAmp->setName("Current");
|
||||||
graph1->rescaleAxes(false);
|
graphAmp->setVisible(true);
|
||||||
if (!isNyquist) {
|
|
||||||
graph2->rescaleAxes(false);
|
graphReal->setVisible(false);
|
||||||
graph3->rescaleAxes(false);
|
graphImag->setVisible(false);
|
||||||
}
|
graphHilbert->setVisible(false);
|
||||||
|
graphNyquistCorr->setVisible(false);
|
||||||
|
graphExtrapolated->setVisible(false);
|
||||||
|
|
||||||
|
graphLSVBlank->setVisible(false);
|
||||||
|
graphLSVSample->setVisible(false);
|
||||||
|
graphLSVDiff->setVisible(false);
|
||||||
|
|
||||||
plot->replot();
|
plot->replot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GraphWidget::configureLSVPlot() {
|
||||||
|
plot->xAxis->setLabel("Voltage (mV)");
|
||||||
|
plot->xAxis->setScaleType(QCPAxis::stLinear);
|
||||||
|
QSharedPointer<QCPAxisTicker> linTicker(new QCPAxisTicker);
|
||||||
|
plot->xAxis->setTicker(linTicker);
|
||||||
|
plot->xAxis->setNumberFormat("f");
|
||||||
|
|
||||||
|
plot->yAxis->setLabel("Current (uA)");
|
||||||
|
plot->yAxis->setScaleType(QCPAxis::stLinear);
|
||||||
|
plot->yAxis->setTicker(linTicker);
|
||||||
|
plot->yAxis->setNumberFormat("f");
|
||||||
|
|
||||||
|
plot->yAxis2->setVisible(false);
|
||||||
|
|
||||||
|
graphLSVBlank->setVisible(true);
|
||||||
|
graphLSVSample->setVisible(true);
|
||||||
|
graphLSVDiff->setVisible(true);
|
||||||
|
|
||||||
|
graphReal->setVisible(false);
|
||||||
|
graphImag->setVisible(false);
|
||||||
|
graphHilbert->setVisible(false);
|
||||||
|
graphNyquistCorr->setVisible(false);
|
||||||
|
graphExtrapolated->setVisible(false);
|
||||||
|
graphAmp->setVisible(false);
|
||||||
|
|
||||||
|
plot->replot();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphWidget::addBodeData(double freq, double val1, double val2) {
|
||||||
|
if (plot->xAxis->scaleType() == QCPAxis::stLogarithmic && freq <= 0) return;
|
||||||
|
graphReal->addData(freq, val1);
|
||||||
|
graphImag->addData(freq, val2);
|
||||||
|
graphReal->rescaleAxes(false);
|
||||||
|
graphImag->rescaleAxes(false);
|
||||||
|
graphHilbert->rescaleAxes(false);
|
||||||
|
plot->replot();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphWidget::addNyquistData(double r_meas, double i_meas, double r_corr, double i_corr, bool showCorr) {
|
||||||
|
graphNyquistRaw->addData(r_meas, -i_meas);
|
||||||
|
if (showCorr) {
|
||||||
|
graphNyquistCorr->addData(r_corr, -i_corr);
|
||||||
|
}
|
||||||
|
graphNyquistRaw->rescaleAxes(false);
|
||||||
|
if (showCorr) {
|
||||||
|
graphNyquistCorr->rescaleAxes(true);
|
||||||
|
}
|
||||||
|
plot->replot();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphWidget::addAmperometricData(double index, double current) {
|
||||||
|
graphAmp->addData(index, current);
|
||||||
|
graphAmp->rescaleAxes(false);
|
||||||
|
plot->replot();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphWidget::addLSVData(double voltage, double current, LSVTrace traceType) {
|
||||||
|
QCPGraph* target = nullptr;
|
||||||
|
switch(traceType) {
|
||||||
|
case LSV_BLANK: target = graphLSVBlank; break;
|
||||||
|
case LSV_SAMPLE: target = graphLSVSample; break;
|
||||||
|
case LSV_DIFF: target = graphLSVDiff; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target) {
|
||||||
|
target->addData(voltage, current);
|
||||||
|
target->rescaleAxes(false); // Rescale to fit new data
|
||||||
|
plot->replot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GraphWidget::addHilbertData(const QVector<double>& freq, const QVector<double>& hilbertImag) {
|
void GraphWidget::addHilbertData(const QVector<double>& freq, const QVector<double>& hilbertImag) {
|
||||||
// Only valid for Raw Plot
|
|
||||||
if (plot->xAxis->label() != "Frequency (Hz)") return;
|
if (plot->xAxis->label() != "Frequency (Hz)") return;
|
||||||
|
graphHilbert->setData(freq, hilbertImag);
|
||||||
|
graphHilbert->rescaleAxes(false);
|
||||||
|
plot->replot();
|
||||||
|
}
|
||||||
|
|
||||||
graph3->setData(freq, hilbertImag);
|
void GraphWidget::setExtrapolatedPoint(double real, double imag) {
|
||||||
graph3->rescaleAxes(false);
|
graphExtrapolated->data()->clear();
|
||||||
|
graphExtrapolated->addData(real, -imag);
|
||||||
plot->replot();
|
plot->replot();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphWidget::clear() {
|
void GraphWidget::clear() {
|
||||||
graph1->data()->clear();
|
graphReal->data()->clear();
|
||||||
graph2->data()->clear();
|
graphImag->data()->clear();
|
||||||
graph3->data()->clear();
|
graphHilbert->data()->clear();
|
||||||
|
graphNyquistCorr->data()->clear();
|
||||||
|
graphAmp->data()->clear();
|
||||||
|
graphExtrapolated->data()->clear();
|
||||||
|
|
||||||
|
// Note: We deliberately do NOT clear LSV data in generic clear()
|
||||||
|
// to allow Blank scans to persist across tab changes or mode switches
|
||||||
|
// until explicitly cleared.
|
||||||
|
plot->replot();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphWidget::clearLSV(LSVTrace traceType) {
|
||||||
|
if (traceType == LSV_BLANK) graphLSVBlank->data()->clear();
|
||||||
|
if (traceType == LSV_SAMPLE) graphLSVSample->data()->clear();
|
||||||
|
if (traceType == LSV_DIFF) graphLSVDiff->data()->clear();
|
||||||
plot->replot();
|
plot->replot();
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// File: host/src/GraphWidget.h
|
// host/src/GraphWidget.h
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
@ -12,18 +12,46 @@ public:
|
||||||
explicit GraphWidget(QWidget *parent = nullptr);
|
explicit GraphWidget(QWidget *parent = nullptr);
|
||||||
|
|
||||||
// Data Handling
|
// Data Handling
|
||||||
void addData(double freq, double val1, double val2);
|
void addBodeData(double freq, double val1, double val2);
|
||||||
|
void addNyquistData(double r_meas, double i_meas, double r_corr, double i_corr, bool showCorr);
|
||||||
|
void addAmperometricData(double index, double current);
|
||||||
|
|
||||||
|
// Updated LSV Data handler
|
||||||
|
enum LSVTrace { LSV_BLANK, LSV_SAMPLE, LSV_DIFF };
|
||||||
|
void addLSVData(double voltage, double current, LSVTrace traceType);
|
||||||
|
|
||||||
void addHilbertData(const QVector<double>& freq, const QVector<double>& hilbertImag);
|
void addHilbertData(const QVector<double>& freq, const QVector<double>& hilbertImag);
|
||||||
|
|
||||||
|
void setExtrapolatedPoint(double real, double imag);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
void clearLSV(LSVTrace traceType); // Clear specific LSV trace
|
||||||
|
|
||||||
// View Configurations
|
// View Configurations
|
||||||
void configureRawPlot();
|
void configureRawPlot();
|
||||||
void configureNyquistPlot();
|
void configureNyquistPlot();
|
||||||
|
void configureAmperometricPlot();
|
||||||
|
void configureLSVPlot();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVBoxLayout *layout;
|
QVBoxLayout *layout;
|
||||||
QCustomPlot *plot;
|
QCustomPlot *plot;
|
||||||
QCPGraph *graph1; // Real
|
|
||||||
QCPGraph *graph2; // Imaginary
|
// Bode Graphs
|
||||||
QCPGraph *graph3; // Hilbert (Analytic Imaginary)
|
QCPGraph *graphReal;
|
||||||
|
QCPGraph *graphImag;
|
||||||
|
QCPGraph *graphHilbert;
|
||||||
|
|
||||||
|
// Nyquist Graphs
|
||||||
|
QCPGraph *graphNyquistRaw;
|
||||||
|
QCPGraph *graphNyquistCorr;
|
||||||
|
QCPGraph *graphExtrapolated;
|
||||||
|
|
||||||
|
// Amperometric Graph
|
||||||
|
QCPGraph *graphAmp;
|
||||||
|
|
||||||
|
// LSV Graphs
|
||||||
|
QCPGraph *graphLSVBlank; // The "Tap Water" baseline
|
||||||
|
QCPGraph *graphLSVSample; // The "Bleach" spike
|
||||||
|
QCPGraph *graphLSVDiff; // The calculated difference (Chlorine only)
|
||||||
};
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,4 +1,4 @@
|
||||||
// File: host/src/MainWindow.h
|
// host/src/MainWindow.h
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
|
@ -14,6 +14,8 @@
|
||||||
#include <QGestureEvent>
|
#include <QGestureEvent>
|
||||||
#include <QSwipeGesture>
|
#include <QSwipeGesture>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QSettings>
|
||||||
#include "GraphWidget.h"
|
#include "GraphWidget.h"
|
||||||
|
|
||||||
class MainWindow : public QMainWindow {
|
class MainWindow : public QMainWindow {
|
||||||
|
|
@ -31,29 +33,49 @@ private slots:
|
||||||
void connectToPort();
|
void connectToPort();
|
||||||
void refreshPorts();
|
void refreshPorts();
|
||||||
void onPortError(QSerialPort::SerialPortError error);
|
void onPortError(QSerialPort::SerialPortError error);
|
||||||
|
void onBlinkTimer();
|
||||||
|
|
||||||
// Action Slots
|
// Action Slots
|
||||||
void checkDeviceId();
|
void checkDeviceId();
|
||||||
void runCalibration();
|
void runCalibration();
|
||||||
void startSweep();
|
void startSweep();
|
||||||
void toggleMeasurement();
|
void toggleMeasurement();
|
||||||
|
void toggleAmperometry();
|
||||||
|
|
||||||
|
// LSV Slots
|
||||||
|
void startLSVBlank();
|
||||||
|
void startLSVSample();
|
||||||
|
void stopLSV();
|
||||||
|
|
||||||
|
void calibrateCellConstant();
|
||||||
|
void onLPFChanged(int index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupUi();
|
void setupUi();
|
||||||
|
void loadSettings();
|
||||||
|
void saveSettings();
|
||||||
void parseData(const QString &data);
|
void parseData(const QString &data);
|
||||||
void handleSwipe(QSwipeGesture *gesture);
|
void handleSwipe(QSwipeGesture *gesture);
|
||||||
void computeHilbert();
|
void computeHilbert();
|
||||||
|
void performCircleFit();
|
||||||
|
void calculateLSVDiff();
|
||||||
|
void setButtonBlinking(QPushButton *btn, bool blinking);
|
||||||
|
|
||||||
QSerialPort *serial;
|
QSerialPort *serial;
|
||||||
|
QSettings *settings;
|
||||||
|
QTimer *blinkTimer;
|
||||||
|
QPushButton *activeButton = nullptr;
|
||||||
|
bool blinkState = false;
|
||||||
|
|
||||||
// Views
|
// Views
|
||||||
GraphWidget *rawGraph; // Raw Data (Freq vs Real/Imag)
|
GraphWidget *rawGraph;
|
||||||
GraphWidget *nyquistGraph; // Nyquist (Real vs -Imag)
|
GraphWidget *nyquistGraph;
|
||||||
QTextEdit *logWidget; // Serial Log
|
GraphWidget *ampGraph;
|
||||||
|
GraphWidget *lsvGraph;
|
||||||
|
QTextEdit *logWidget;
|
||||||
|
|
||||||
// Layout
|
// Layout
|
||||||
QTabWidget *tabWidget;
|
QTabWidget *tabWidget;
|
||||||
QToolBar *toolbar;
|
|
||||||
QComboBox *portSelector;
|
QComboBox *portSelector;
|
||||||
QPushButton *connectBtn;
|
QPushButton *connectBtn;
|
||||||
QPushButton *checkIdBtn;
|
QPushButton *checkIdBtn;
|
||||||
|
|
@ -62,14 +84,52 @@ private:
|
||||||
QPushButton *measureBtn;
|
QPushButton *measureBtn;
|
||||||
QDoubleSpinBox *spinFreq;
|
QDoubleSpinBox *spinFreq;
|
||||||
|
|
||||||
// EIS
|
// EIS Configuration
|
||||||
QDoubleSpinBox *spinSweepStart;
|
QDoubleSpinBox *spinSweepStart;
|
||||||
QDoubleSpinBox *spinSweepStop;
|
QDoubleSpinBox *spinSweepStop;
|
||||||
QSpinBox *spinSweepPPD;
|
QSpinBox *spinSweepPPD;
|
||||||
|
QComboBox *comboRange;
|
||||||
|
|
||||||
bool isMeasuring = false;
|
// Shunt / De-embedding Configuration
|
||||||
|
QCheckBox *checkShunt;
|
||||||
|
QDoubleSpinBox *spinShuntRes;
|
||||||
|
|
||||||
// Data Accumulation for Hilbert
|
// Amperometry Configuration
|
||||||
|
QDoubleSpinBox *spinAmpBias;
|
||||||
|
QPushButton *ampBtn;
|
||||||
|
QComboBox *comboLPF; // New LPF Dropdown
|
||||||
|
|
||||||
|
// LSV Configuration
|
||||||
|
QDoubleSpinBox *spinLsvStart;
|
||||||
|
QDoubleSpinBox *spinLsvStop;
|
||||||
|
QSpinBox *spinLsvSteps;
|
||||||
|
QSpinBox *spinLsvDuration;
|
||||||
|
QPushButton *lsvBlankBtn;
|
||||||
|
QPushButton *lsvSampleBtn;
|
||||||
|
|
||||||
|
// Conductivity Calibration
|
||||||
|
QDoubleSpinBox *spinCondStd;
|
||||||
|
QPushButton *btnCalCond;
|
||||||
|
QLabel *lblResultRs;
|
||||||
|
QLabel *lblResultCond;
|
||||||
|
|
||||||
|
double cellConstant = 1.0;
|
||||||
|
|
||||||
|
bool isMeasuringImp = false;
|
||||||
|
bool isMeasuringAmp = false;
|
||||||
|
bool isSweeping = false;
|
||||||
|
|
||||||
|
// LSV State
|
||||||
|
enum LSVState { LSV_IDLE, LSV_RUNNING_BLANK, LSV_RUNNING_SAMPLE };
|
||||||
|
LSVState lsvState = LSV_IDLE;
|
||||||
|
|
||||||
|
// Data Accumulation
|
||||||
QVector<double> sweepFreqs;
|
QVector<double> sweepFreqs;
|
||||||
QVector<double> sweepReals;
|
QVector<double> sweepReals;
|
||||||
|
QVector<double> sweepImags;
|
||||||
|
|
||||||
|
// LSV Data Storage for Diff Calculation
|
||||||
|
struct LSVPoint { double voltage; double current; };
|
||||||
|
QVector<LSVPoint> lsvBlankData;
|
||||||
|
QVector<LSVPoint> lsvSampleData;
|
||||||
};
|
};
|
||||||
|
|
@ -1,23 +1,67 @@
|
||||||
// File: host/src/main.cpp
|
// host/src/main.cpp
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QStyleFactory>
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
// High DPI Scaling
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||||
|
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
QApplication::setApplicationName("EIS Configurator");
|
QApplication::setApplicationName("EIS Configurator");
|
||||||
QApplication::setApplicationVersion("1.0");
|
QApplication::setApplicationVersion("1.0");
|
||||||
|
|
||||||
// Dark Theme
|
// --- Apply Dark Fusion Theme ---
|
||||||
QPalette p = app.palette();
|
app.setStyle(QStyleFactory::create("Fusion"));
|
||||||
p.setColor(QPalette::Window, QColor(30, 30, 30));
|
|
||||||
|
QPalette p;
|
||||||
|
p.setColor(QPalette::Window, QColor(53, 53, 53));
|
||||||
p.setColor(QPalette::WindowText, Qt::white);
|
p.setColor(QPalette::WindowText, Qt::white);
|
||||||
p.setColor(QPalette::Base, QColor(15, 15, 15));
|
p.setColor(QPalette::Base, QColor(25, 25, 25));
|
||||||
p.setColor(QPalette::AlternateBase, QColor(45, 45, 45));
|
p.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
|
||||||
|
p.setColor(QPalette::ToolTipBase, Qt::white);
|
||||||
|
p.setColor(QPalette::ToolTipText, Qt::white);
|
||||||
p.setColor(QPalette::Text, Qt::white);
|
p.setColor(QPalette::Text, Qt::white);
|
||||||
p.setColor(QPalette::Button, QColor(45, 45, 45));
|
p.setColor(QPalette::Button, QColor(53, 53, 53));
|
||||||
p.setColor(QPalette::ButtonText, Qt::white);
|
p.setColor(QPalette::ButtonText, Qt::white);
|
||||||
|
p.setColor(QPalette::BrightText, Qt::red);
|
||||||
|
p.setColor(QPalette::Link, QColor(42, 130, 218));
|
||||||
|
p.setColor(QPalette::Highlight, QColor(42, 130, 218));
|
||||||
|
p.setColor(QPalette::HighlightedText, Qt::black);
|
||||||
app.setPalette(p);
|
app.setPalette(p);
|
||||||
|
|
||||||
|
// --- Global Stylesheet for Modern Look ---
|
||||||
|
app.setStyleSheet(
|
||||||
|
"QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }"
|
||||||
|
"QGroupBox { border: 1px solid #555; border-radius: 5px; margin-top: 10px; font-weight: bold; }"
|
||||||
|
"QGroupBox::title { subcontrol-origin: margin; left: 10px; padding: 0 3px; }"
|
||||||
|
"QSpinBox, QDoubleSpinBox, QComboBox, QLineEdit { "
|
||||||
|
" background: #333; color: #FFF; border: 1px solid #555; padding: 4px; border-radius: 4px; "
|
||||||
|
" selection-background-color: #2A82DA; "
|
||||||
|
"}"
|
||||||
|
"QSpinBox::up-button, QDoubleSpinBox::up-button, QSpinBox::down-button, QDoubleSpinBox::down-button { "
|
||||||
|
" background: #444; width: 16px; border-radius: 2px;"
|
||||||
|
"}"
|
||||||
|
"QPushButton { "
|
||||||
|
" background-color: #444; border: 1px solid #555; border-radius: 4px; padding: 5px 15px; color: white; font-weight: bold;"
|
||||||
|
"}"
|
||||||
|
"QPushButton:hover { background-color: #555; }"
|
||||||
|
"QPushButton:pressed { background-color: #2A82DA; }"
|
||||||
|
"QPushButton:disabled { background-color: #333; color: #777; border: 1px solid #444; }"
|
||||||
|
"QTabWidget::pane { border: 1px solid #444; }"
|
||||||
|
"QTabBar::tab { background: #333; color: #AAA; padding: 8px 20px; border-top-left-radius: 4px; border-top-right-radius: 4px; }"
|
||||||
|
"QTabBar::tab:selected { background: #535353; color: #FFF; border-bottom: 2px solid #2A82DA; }"
|
||||||
|
"QScrollBar:vertical { background: #333; width: 12px; }"
|
||||||
|
"QScrollBar::handle:vertical { background: #555; min-height: 20px; border-radius: 6px; }"
|
||||||
|
"QLabel { color: #EEE; }"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Set default font size
|
||||||
|
QFont font = app.font();
|
||||||
|
font.setPointSize(12);
|
||||||
|
app.setFont(font);
|
||||||
|
|
||||||
MainWindow w;
|
MainWindow w;
|
||||||
w.show();
|
w.show();
|
||||||
|
|
||||||
|
|
|
||||||
357
main.c
357
main.c
|
|
@ -9,6 +9,15 @@
|
||||||
#include "hardware/watchdog.h"
|
#include "hardware/watchdog.h"
|
||||||
#include "ad5940.h"
|
#include "ad5940.h"
|
||||||
#include "Impedance.h"
|
#include "Impedance.h"
|
||||||
|
#include "Amperometric.h"
|
||||||
|
#include "RampTest.h"
|
||||||
|
|
||||||
|
#define AD5940ERR_STOP 10
|
||||||
|
|
||||||
|
// Fix for missing definition in some SDK versions
|
||||||
|
#ifndef LPTIARF_BYPASS
|
||||||
|
#define LPTIARF_BYPASS 0x2000
|
||||||
|
#endif
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Hardware Definitions
|
// Hardware Definitions
|
||||||
|
|
@ -23,6 +32,72 @@
|
||||||
#define APPBUFF_SIZE 512
|
#define APPBUFF_SIZE 512
|
||||||
uint32_t AppBuff[APPBUFF_SIZE];
|
uint32_t AppBuff[APPBUFF_SIZE];
|
||||||
|
|
||||||
|
// Application State
|
||||||
|
typedef enum {
|
||||||
|
MODE_IDLE,
|
||||||
|
MODE_IMPEDANCE,
|
||||||
|
MODE_AMPEROMETRIC,
|
||||||
|
MODE_RAMP
|
||||||
|
} AppMode;
|
||||||
|
|
||||||
|
AppMode CurrentMode = MODE_IDLE;
|
||||||
|
float LFOSCFreq = 32000.0; // Default, updated by calibration
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Range / RTIA Management
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Nominal values for the 8 supported ranges
|
||||||
|
float RtiaCalibrationTable[8] = {200.0, 1000.0, 5000.0, 10000.0, 20000.0, 40000.0, 80000.0, 160000.0};
|
||||||
|
uint32_t CurrentRtiaIndex = 0; // Default to 200 Ohm (Index 0)
|
||||||
|
uint32_t ConfigRtiaVal = 200; // Default Value
|
||||||
|
uint32_t CurrentLpTiaRf = LPTIARF_20K; // Default LPF
|
||||||
|
|
||||||
|
// Map integer value to HSTIA Enum (Impedance)
|
||||||
|
uint32_t GetHSTIARtia(uint32_t val) {
|
||||||
|
switch(val) {
|
||||||
|
case 200: return HSTIARTIA_200;
|
||||||
|
case 1000: return HSTIARTIA_1K;
|
||||||
|
case 5000: return HSTIARTIA_5K;
|
||||||
|
case 10000: return HSTIARTIA_10K;
|
||||||
|
case 20000: return HSTIARTIA_20K;
|
||||||
|
case 40000: return HSTIARTIA_40K;
|
||||||
|
case 80000: return HSTIARTIA_80K;
|
||||||
|
case 160000: return HSTIARTIA_160K;
|
||||||
|
default: return HSTIARTIA_200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map integer value to LPTIA Enum (Amperometric/Ramp)
|
||||||
|
uint32_t GetLPTIARtia(uint32_t val) {
|
||||||
|
switch(val) {
|
||||||
|
case 200: return LPTIARTIA_200R;
|
||||||
|
case 1000: return LPTIARTIA_1K;
|
||||||
|
case 5000: return LPTIARTIA_4K;
|
||||||
|
case 10000: return LPTIARTIA_10K;
|
||||||
|
case 20000: return LPTIARTIA_20K;
|
||||||
|
case 40000: return LPTIARTIA_40K;
|
||||||
|
case 80000: return LPTIARTIA_85K;
|
||||||
|
case 160000: return LPTIARTIA_160K;
|
||||||
|
default: return LPTIARTIA_1K;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to find index for calibration table
|
||||||
|
int GetRtiaIndex(uint32_t val) {
|
||||||
|
switch(val) {
|
||||||
|
case 200: return 0;
|
||||||
|
case 1000: return 1;
|
||||||
|
case 5000: return 2;
|
||||||
|
case 10000: return 3;
|
||||||
|
case 20000: return 4;
|
||||||
|
case 40000: return 5;
|
||||||
|
case 80000: return 6;
|
||||||
|
case 160000: return 7;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Platform Interface Implementation
|
// Platform Interface Implementation
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
@ -77,41 +152,80 @@ void setup_pins(void) {
|
||||||
void AD5940ImpedanceStructInit(void)
|
void AD5940ImpedanceStructInit(void)
|
||||||
{
|
{
|
||||||
AppIMPCfg_Type *pImpedanceCfg;
|
AppIMPCfg_Type *pImpedanceCfg;
|
||||||
|
|
||||||
AppIMPGetCfg(&pImpedanceCfg);
|
AppIMPGetCfg(&pImpedanceCfg);
|
||||||
|
|
||||||
pImpedanceCfg->SeqStartAddr = 0;
|
pImpedanceCfg->SeqStartAddr = 0;
|
||||||
pImpedanceCfg->MaxSeqLen = 512;
|
pImpedanceCfg->MaxSeqLen = 512;
|
||||||
|
|
||||||
pImpedanceCfg->RcalVal = 100.0;
|
pImpedanceCfg->RcalVal = 100.0;
|
||||||
pImpedanceCfg->RtiaVal = 200.0;
|
pImpedanceCfg->RtiaVal = RtiaCalibrationTable[CurrentRtiaIndex];
|
||||||
pImpedanceCfg->SinFreq = 1000.0;
|
pImpedanceCfg->SinFreq = 1000.0;
|
||||||
pImpedanceCfg->FifoThresh = 6;
|
pImpedanceCfg->FifoThresh = 6;
|
||||||
|
|
||||||
pImpedanceCfg->DacVoltPP = 600.0;
|
pImpedanceCfg->DacVoltPP = 600.0;
|
||||||
pImpedanceCfg->ExcitBufGain = EXCITBUFGAIN_0P25;
|
pImpedanceCfg->ExcitBufGain = EXCITBUFGAIN_0P25;
|
||||||
pImpedanceCfg->HsDacGain = HSDACGAIN_0P2;
|
pImpedanceCfg->HsDacGain = HSDACGAIN_0P2;
|
||||||
|
|
||||||
pImpedanceCfg->DswitchSel = SWD_CE0;
|
pImpedanceCfg->DswitchSel = SWD_CE0;
|
||||||
pImpedanceCfg->PswitchSel = SWP_CE0;
|
pImpedanceCfg->PswitchSel = SWP_CE0;
|
||||||
pImpedanceCfg->NswitchSel = SWN_SE0;
|
pImpedanceCfg->NswitchSel = SWN_SE0;
|
||||||
pImpedanceCfg->TswitchSel = SWT_SE0LOAD;
|
pImpedanceCfg->TswitchSel = SWT_SE0LOAD;
|
||||||
|
pImpedanceCfg->HstiaRtiaSel = GetHSTIARtia(ConfigRtiaVal);
|
||||||
pImpedanceCfg->HstiaRtiaSel = HSTIARTIA_200;
|
|
||||||
pImpedanceCfg->BiasVolt = 0.0;
|
pImpedanceCfg->BiasVolt = 0.0;
|
||||||
|
|
||||||
pImpedanceCfg->SweepCfg.SweepEn = bFALSE;
|
pImpedanceCfg->SweepCfg.SweepEn = bFALSE;
|
||||||
pImpedanceCfg->SweepCfg.SweepStart = 100.0f;
|
pImpedanceCfg->SweepCfg.SweepStart = 100.0f;
|
||||||
pImpedanceCfg->SweepCfg.SweepStop = 100000.0f;
|
pImpedanceCfg->SweepCfg.SweepStop = 100000.0f;
|
||||||
pImpedanceCfg->SweepCfg.SweepPoints = 50;
|
pImpedanceCfg->SweepCfg.SweepPoints = 50;
|
||||||
pImpedanceCfg->SweepCfg.SweepLog = bTRUE;
|
pImpedanceCfg->SweepCfg.SweepLog = bTRUE;
|
||||||
|
|
||||||
pImpedanceCfg->PwrMod = AFEPWR_LP;
|
pImpedanceCfg->PwrMod = AFEPWR_LP;
|
||||||
pImpedanceCfg->ADCSinc3Osr = ADCSINC3OSR_4;
|
pImpedanceCfg->ADCSinc3Osr = ADCSINC3OSR_4;
|
||||||
pImpedanceCfg->DftNum = DFTNUM_16384;
|
pImpedanceCfg->DftNum = DFTNUM_16384;
|
||||||
pImpedanceCfg->DftSrc = DFTSRC_SINC3;
|
pImpedanceCfg->DftSrc = DFTSRC_SINC3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AD5940AMPStructInit(void)
|
||||||
|
{
|
||||||
|
AppAMPCfg_Type *pAMPCfg;
|
||||||
|
AppAMPGetCfg(&pAMPCfg);
|
||||||
|
pAMPCfg->WuptClkFreq = LFOSCFreq;
|
||||||
|
pAMPCfg->SeqStartAddr = 0;
|
||||||
|
pAMPCfg->MaxSeqLen = 512;
|
||||||
|
pAMPCfg->RcalVal = 100.0;
|
||||||
|
pAMPCfg->NumOfData = -1;
|
||||||
|
pAMPCfg->AmpODR = 1.0;
|
||||||
|
pAMPCfg->FifoThresh = 4;
|
||||||
|
pAMPCfg->SensorBias = 0;
|
||||||
|
pAMPCfg->LptiaRtiaSel = GetLPTIARtia(ConfigRtiaVal);
|
||||||
|
pAMPCfg->LpTiaRl = LPTIARLOAD_10R;
|
||||||
|
pAMPCfg->LpTiaRf = CurrentLpTiaRf; // Use configured LPF
|
||||||
|
pAMPCfg->Vzero = 1100;
|
||||||
|
pAMPCfg->ADCRefVolt = 1.82;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AD5940RampStructInit(void)
|
||||||
|
{
|
||||||
|
AppRAMPCfg_Type *pRampCfg;
|
||||||
|
AppRAMPGetCfg(&pRampCfg);
|
||||||
|
|
||||||
|
pRampCfg->SeqStartAddr = 0;
|
||||||
|
pRampCfg->MaxSeqLen = 1024;
|
||||||
|
pRampCfg->RcalVal = 100.0;
|
||||||
|
pRampCfg->ADCRefVolt = 1820.0f;
|
||||||
|
pRampCfg->FifoThresh = 4;
|
||||||
|
pRampCfg->SysClkFreq = 16000000.0f;
|
||||||
|
pRampCfg->LFOSCClkFreq = LFOSCFreq;
|
||||||
|
|
||||||
|
pRampCfg->RampStartVolt = -500.0f;
|
||||||
|
pRampCfg->RampPeakVolt = +500.0f;
|
||||||
|
pRampCfg->VzeroStart = 1100.0f;
|
||||||
|
pRampCfg->VzeroPeak = 1100.0f;
|
||||||
|
pRampCfg->StepNumber = 100;
|
||||||
|
pRampCfg->RampDuration = 10000;
|
||||||
|
pRampCfg->SampleDelay = 1.0f;
|
||||||
|
|
||||||
|
pRampCfg->LPTIARtiaSel = GetLPTIARtia(ConfigRtiaVal);
|
||||||
|
pRampCfg->LPTIARloadSel = LPTIARLOAD_10R;
|
||||||
|
pRampCfg->LpTiaRf = CurrentLpTiaRf; // Use configured LPF
|
||||||
|
pRampCfg->AdcPgaGain = ADCPGA_1P5;
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t AD5940PlatformCfg(void)
|
static int32_t AD5940PlatformCfg(void)
|
||||||
{
|
{
|
||||||
CLKCfg_Type clk_cfg;
|
CLKCfg_Type clk_cfg;
|
||||||
|
|
@ -121,7 +235,6 @@ static int32_t AD5940PlatformCfg(void)
|
||||||
AD5940_HWReset();
|
AD5940_HWReset();
|
||||||
AD5940_Initialize();
|
AD5940_Initialize();
|
||||||
|
|
||||||
// Use HFOSC (16MHz) for stability across all frequencies
|
|
||||||
clk_cfg.ADCClkDiv = ADCCLKDIV_1;
|
clk_cfg.ADCClkDiv = ADCCLKDIV_1;
|
||||||
clk_cfg.ADCCLkSrc = ADCCLKSRC_HFOSC;
|
clk_cfg.ADCCLkSrc = ADCCLKSRC_HFOSC;
|
||||||
clk_cfg.SysClkDiv = SYSCLKDIV_1;
|
clk_cfg.SysClkDiv = SYSCLKDIV_1;
|
||||||
|
|
@ -144,7 +257,7 @@ static int32_t AD5940PlatformCfg(void)
|
||||||
|
|
||||||
AD5940_INTCCfg(AFEINTC_1, AFEINTSRC_ALLINT, bTRUE);
|
AD5940_INTCCfg(AFEINTC_1, AFEINTSRC_ALLINT, bTRUE);
|
||||||
AD5940_INTCClrFlag(AFEINTSRC_ALLINT);
|
AD5940_INTCClrFlag(AFEINTSRC_ALLINT);
|
||||||
AD5940_INTCCfg(AFEINTC_0, AFEINTSRC_DATAFIFOTHRESH, bTRUE);
|
AD5940_INTCCfg(AFEINTC_0, AFEINTSRC_DATAFIFOTHRESH|AFEINTSRC_CUSTOMINT0, bTRUE);
|
||||||
AD5940_INTCClrFlag(AFEINTSRC_ALLINT);
|
AD5940_INTCClrFlag(AFEINTSRC_ALLINT);
|
||||||
|
|
||||||
gpio_cfg.FuncSet = GP0_INT;
|
gpio_cfg.FuncSet = GP0_INT;
|
||||||
|
|
@ -168,17 +281,28 @@ void ImpedanceShowResult(uint32_t *pData, uint32_t DataCount)
|
||||||
{
|
{
|
||||||
float mag = pImp[i].Magnitude;
|
float mag = pImp[i].Magnitude;
|
||||||
float phase = pImp[i].Phase;
|
float phase = pImp[i].Phase;
|
||||||
|
|
||||||
float real = mag * cosf(phase);
|
float real = mag * cosf(phase);
|
||||||
float imag = mag * sinf(phase);
|
float imag = mag * sinf(phase);
|
||||||
|
|
||||||
printf("DATA,%.2f,%.4f,%.4f,%.4f,%.4f\n",
|
printf("DATA,%.2f,%.4f,%.4f,%.4f,%.4f\n", freq, mag, phase * 180.0f / MATH_PI, real, imag);
|
||||||
freq,
|
}
|
||||||
mag,
|
}
|
||||||
phase * 180.0f / MATH_PI,
|
|
||||||
real,
|
void AmperometricShowResult(float *pData, uint32_t DataCount)
|
||||||
imag
|
{
|
||||||
);
|
static int index = 0;
|
||||||
|
for(int i=0;i<DataCount;i++)
|
||||||
|
{
|
||||||
|
printf("AMP,%d,%.4f\n", index++, pData[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RampShowResult(float *pData, uint32_t DataCount)
|
||||||
|
{
|
||||||
|
static int index = 0;
|
||||||
|
for(int i=0;i<DataCount;i++)
|
||||||
|
{
|
||||||
|
printf("RAMP,%d,%.4f\n", index++, pData[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,22 +312,37 @@ void ImpedanceShowResult(uint32_t *pData, uint32_t DataCount)
|
||||||
|
|
||||||
void Routine_CalibrateLFO(void) {
|
void Routine_CalibrateLFO(void) {
|
||||||
printf(">> Calibrating LFOSC...\n");
|
printf(">> Calibrating LFOSC...\n");
|
||||||
AppIMPCleanup();
|
if (CurrentMode == MODE_IMPEDANCE) AppIMPCleanup();
|
||||||
AppIMPCalibrateLFO();
|
else if (CurrentMode == MODE_AMPEROMETRIC) AppAMPCtrl(AMPCTRL_SHUTDOWN, 0);
|
||||||
printf(">> LFOSC Calibrated.\n");
|
else if (CurrentMode == MODE_RAMP) AppRAMPCtrl(APPCTRL_SHUTDOWN, 0);
|
||||||
|
|
||||||
|
LFOSCMeasure_Type cal_cfg;
|
||||||
|
cal_cfg.CalDuration = 1000.0;
|
||||||
|
cal_cfg.CalSeqAddr = 0;
|
||||||
|
cal_cfg.SystemClkFreq = 16000000.0;
|
||||||
|
|
||||||
|
if(AD5940_LFOSCMeasure(&cal_cfg, &LFOSCFreq) == AD5940ERR_OK) {
|
||||||
|
printf(">> LFOSC Calibrated: %.2f Hz\n", LFOSCFreq);
|
||||||
|
} else {
|
||||||
|
printf(">> LFOSC Calibration Failed.\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Routine_Measure(float freq) {
|
void Routine_Measure(float freq) {
|
||||||
|
if (CurrentMode == MODE_AMPEROMETRIC) AppAMPCtrl(AMPCTRL_SHUTDOWN, 0);
|
||||||
|
else if (CurrentMode == MODE_RAMP) AppRAMPCtrl(APPCTRL_SHUTDOWN, 0);
|
||||||
|
CurrentMode = MODE_IMPEDANCE;
|
||||||
|
|
||||||
AppIMPCfg_Type *pCfg;
|
AppIMPCfg_Type *pCfg;
|
||||||
AppIMPGetCfg(&pCfg);
|
AppIMPGetCfg(&pCfg);
|
||||||
|
|
||||||
AppIMPCleanup();
|
AppIMPCleanup();
|
||||||
AppIMPCalibrateLFO();
|
pCfg->WuptClkFreq = LFOSCFreq;
|
||||||
|
pCfg->HstiaRtiaSel = GetHSTIARtia(ConfigRtiaVal);
|
||||||
|
pCfg->RtiaVal = RtiaCalibrationTable[CurrentRtiaIndex];
|
||||||
pCfg->SweepCfg.SweepEn = bFALSE;
|
pCfg->SweepCfg.SweepEn = bFALSE;
|
||||||
pCfg->SinFreq = freq;
|
pCfg->SinFreq = freq;
|
||||||
pCfg->NumOfData = -1;
|
pCfg->NumOfData = -1;
|
||||||
pCfg->RealDataCount = -1; // Disable filtering
|
pCfg->RealDataCount = -1;
|
||||||
pCfg->bParaChanged = bTRUE;
|
pCfg->bParaChanged = bTRUE;
|
||||||
|
|
||||||
if(AppIMPInit(AppBuff, APPBUFF_SIZE) == AD5940ERR_OK) {
|
if(AppIMPInit(AppBuff, APPBUFF_SIZE) == AD5940ERR_OK) {
|
||||||
|
|
@ -214,23 +353,22 @@ void Routine_Measure(float freq) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Routine_Sweep(float start, float end, int steps) {
|
void Routine_Sweep(float start, float end, int steps) {
|
||||||
|
if (CurrentMode == MODE_AMPEROMETRIC) AppAMPCtrl(AMPCTRL_SHUTDOWN, 0);
|
||||||
|
else if (CurrentMode == MODE_RAMP) AppRAMPCtrl(APPCTRL_SHUTDOWN, 0);
|
||||||
|
CurrentMode = MODE_IMPEDANCE;
|
||||||
|
|
||||||
AppIMPCfg_Type *pCfg;
|
AppIMPCfg_Type *pCfg;
|
||||||
AppIMPGetCfg(&pCfg);
|
AppIMPGetCfg(&pCfg);
|
||||||
|
|
||||||
AppIMPCleanup();
|
AppIMPCleanup();
|
||||||
AppIMPCalibrateLFO();
|
pCfg->WuptClkFreq = LFOSCFreq;
|
||||||
|
pCfg->HstiaRtiaSel = GetHSTIARtia(ConfigRtiaVal);
|
||||||
|
pCfg->RtiaVal = RtiaCalibrationTable[CurrentRtiaIndex];
|
||||||
pCfg->SweepCfg.SweepEn = bTRUE;
|
pCfg->SweepCfg.SweepEn = bTRUE;
|
||||||
pCfg->SweepCfg.SweepStart = start;
|
pCfg->SweepCfg.SweepStart = start;
|
||||||
pCfg->SweepCfg.SweepStop = end;
|
pCfg->SweepCfg.SweepStop = end;
|
||||||
|
|
||||||
// DUMMY POINT STRATEGY:
|
|
||||||
// Request steps + 1 from the engine, but tell the ISR to only report 'steps'.
|
|
||||||
// The artifact will happen on the +1 point, which is discarded.
|
|
||||||
pCfg->SweepCfg.SweepPoints = steps + 1;
|
pCfg->SweepCfg.SweepPoints = steps + 1;
|
||||||
pCfg->NumOfData = steps + 1;
|
pCfg->NumOfData = steps + 1;
|
||||||
pCfg->RealDataCount = steps; // Stop reporting after this count
|
pCfg->RealDataCount = steps;
|
||||||
|
|
||||||
pCfg->SweepCfg.SweepLog = bTRUE;
|
pCfg->SweepCfg.SweepLog = bTRUE;
|
||||||
pCfg->bParaChanged = bTRUE;
|
pCfg->bParaChanged = bTRUE;
|
||||||
|
|
||||||
|
|
@ -241,13 +379,69 @@ void Routine_Sweep(float start, float end, int steps) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Routine_Amperometric(float bias_mv) {
|
||||||
|
if (CurrentMode == MODE_IMPEDANCE) AppIMPCleanup();
|
||||||
|
else if (CurrentMode == MODE_RAMP) AppRAMPCtrl(APPCTRL_SHUTDOWN, 0);
|
||||||
|
CurrentMode = MODE_AMPEROMETRIC;
|
||||||
|
|
||||||
|
printf(">> Starting Amperometry (Bias: %.1f mV, Range: %d)...\n", bias_mv, ConfigRtiaVal);
|
||||||
|
|
||||||
|
AppAMPCfg_Type *pCfg;
|
||||||
|
AppAMPGetCfg(&pCfg);
|
||||||
|
AD5940AMPStructInit();
|
||||||
|
pCfg->SensorBias = bias_mv;
|
||||||
|
pCfg->WuptClkFreq = LFOSCFreq;
|
||||||
|
pCfg->LptiaRtiaSel = GetLPTIARtia(ConfigRtiaVal);
|
||||||
|
pCfg->ReDoRtiaCal = bTRUE;
|
||||||
|
|
||||||
|
if(AppAMPInit(AppBuff, APPBUFF_SIZE) == AD5940ERR_OK) {
|
||||||
|
AppAMPCtrl(AMPCTRL_START, 0);
|
||||||
|
} else {
|
||||||
|
printf("ERROR: AMP Init Failed\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Routine_LSV(float start_mv, float end_mv, int steps, int duration_ms) {
|
||||||
|
if (CurrentMode == MODE_IMPEDANCE) AppIMPCleanup();
|
||||||
|
else if (CurrentMode == MODE_AMPEROMETRIC) AppAMPCtrl(AMPCTRL_SHUTDOWN, 0);
|
||||||
|
CurrentMode = MODE_RAMP;
|
||||||
|
|
||||||
|
printf(">> Starting LSV (%.1f to %.1f mV, %d steps, %d ms)...\n", start_mv, end_mv, steps, duration_ms);
|
||||||
|
|
||||||
|
AppRAMPCfg_Type *pCfg;
|
||||||
|
AppRAMPGetCfg(&pCfg);
|
||||||
|
AD5940RampStructInit();
|
||||||
|
|
||||||
|
pCfg->RampStartVolt = start_mv;
|
||||||
|
pCfg->RampPeakVolt = end_mv;
|
||||||
|
pCfg->StepNumber = steps;
|
||||||
|
pCfg->RampDuration = duration_ms;
|
||||||
|
pCfg->LFOSCClkFreq = LFOSCFreq;
|
||||||
|
pCfg->LPTIARtiaSel = GetLPTIARtia(ConfigRtiaVal);
|
||||||
|
|
||||||
|
// Use global calibration value
|
||||||
|
pCfg->RtiaValue.Magnitude = RtiaCalibrationTable[CurrentRtiaIndex];
|
||||||
|
pCfg->RtiaValue.Phase = 0;
|
||||||
|
|
||||||
|
pCfg->bRampOneDir = bTRUE; // Linear Sweep (not Cyclic)
|
||||||
|
pCfg->bParaChanged = bTRUE;
|
||||||
|
|
||||||
|
if(AppRAMPInit(AppBuff, APPBUFF_SIZE) == AD5940ERR_OK) {
|
||||||
|
AppRAMPCtrl(APPCTRL_START, 0);
|
||||||
|
} else {
|
||||||
|
printf("ERROR: RAMP Init Failed\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Routine_CalibrateSystem(void) {
|
void Routine_CalibrateSystem(void) {
|
||||||
|
if (CurrentMode == MODE_AMPEROMETRIC) AppAMPCtrl(AMPCTRL_SHUTDOWN, 0);
|
||||||
|
else if (CurrentMode == MODE_RAMP) AppRAMPCtrl(APPCTRL_SHUTDOWN, 0);
|
||||||
|
CurrentMode = MODE_IMPEDANCE;
|
||||||
|
|
||||||
AppIMPCfg_Type *pCfg;
|
AppIMPCfg_Type *pCfg;
|
||||||
AppIMPGetCfg(&pCfg);
|
AppIMPGetCfg(&pCfg);
|
||||||
|
|
||||||
AppIMPCleanup();
|
AppIMPCleanup();
|
||||||
|
|
||||||
// 1. ADC Calibration
|
|
||||||
ADCPGACal_Type adcpga_cal;
|
ADCPGACal_Type adcpga_cal;
|
||||||
adcpga_cal.AdcClkFreq = 16000000.0;
|
adcpga_cal.AdcClkFreq = 16000000.0;
|
||||||
adcpga_cal.SysClkFreq = 16000000.0;
|
adcpga_cal.SysClkFreq = 16000000.0;
|
||||||
|
|
@ -261,18 +455,15 @@ void Routine_CalibrateSystem(void) {
|
||||||
printf(">> Calibrating ADC Offset...\n");
|
printf(">> Calibrating ADC Offset...\n");
|
||||||
AD5940_ADCPGACal(&adcpga_cal);
|
AD5940_ADCPGACal(&adcpga_cal);
|
||||||
|
|
||||||
// 2. HSDAC Configuration
|
|
||||||
HSDACCfg_Type hsdac_cfg;
|
HSDACCfg_Type hsdac_cfg;
|
||||||
hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_0P25;
|
hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_0P25;
|
||||||
hsdac_cfg.HsDacGain = HSDACGAIN_0P2;
|
hsdac_cfg.HsDacGain = HSDACGAIN_0P2;
|
||||||
hsdac_cfg.HsDacUpdateRate = 7;
|
hsdac_cfg.HsDacUpdateRate = 7;
|
||||||
AD5940_HSDacCfgS(&hsdac_cfg);
|
AD5940_HSDacCfgS(&hsdac_cfg);
|
||||||
|
|
||||||
// 3. RTIA Calibration
|
|
||||||
HSRTIACal_Type hsrtia_cal;
|
HSRTIACal_Type hsrtia_cal;
|
||||||
fImpPol_Type Res;
|
fImpPol_Type Res;
|
||||||
memset(&hsrtia_cal, 0, sizeof(hsrtia_cal));
|
memset(&hsrtia_cal, 0, sizeof(hsrtia_cal));
|
||||||
|
|
||||||
hsrtia_cal.fFreq = 1000.0f;
|
hsrtia_cal.fFreq = 1000.0f;
|
||||||
hsrtia_cal.AdcClkFreq = 16000000.0;
|
hsrtia_cal.AdcClkFreq = 16000000.0;
|
||||||
hsrtia_cal.SysClkFreq = 16000000.0;
|
hsrtia_cal.SysClkFreq = 16000000.0;
|
||||||
|
|
@ -283,15 +474,16 @@ void Routine_CalibrateSystem(void) {
|
||||||
hsrtia_cal.HsTiaCfg.DiodeClose = bFALSE;
|
hsrtia_cal.HsTiaCfg.DiodeClose = bFALSE;
|
||||||
hsrtia_cal.HsTiaCfg.HstiaBias = HSTIABIAS_1P1;
|
hsrtia_cal.HsTiaCfg.HstiaBias = HSTIABIAS_1P1;
|
||||||
hsrtia_cal.HsTiaCfg.HstiaCtia = 31;
|
hsrtia_cal.HsTiaCfg.HstiaCtia = 31;
|
||||||
hsrtia_cal.HsTiaCfg.HstiaRtiaSel = HSTIARTIA_200;
|
hsrtia_cal.HsTiaCfg.HstiaRtiaSel = GetHSTIARtia(ConfigRtiaVal);
|
||||||
hsrtia_cal.HsTiaCfg.HstiaDeRtia = HSTIADERTIA_OPEN;
|
hsrtia_cal.HsTiaCfg.HstiaDeRtia = HSTIADERTIA_OPEN;
|
||||||
hsrtia_cal.HsTiaCfg.HstiaDeRload = HSTIADERLOAD_OPEN;
|
hsrtia_cal.HsTiaCfg.HstiaDeRload = HSTIADERLOAD_OPEN;
|
||||||
hsrtia_cal.DftCfg.DftNum = DFTNUM_16384;
|
hsrtia_cal.DftCfg.DftNum = DFTNUM_16384;
|
||||||
hsrtia_cal.DftCfg.DftSrc = DFTSRC_SINC3;
|
hsrtia_cal.DftCfg.DftSrc = DFTSRC_SINC3;
|
||||||
|
|
||||||
printf(">> Calibrating HSTIARTIA_200...\n");
|
printf(">> Calibrating RTIA %d Ohm...\n", ConfigRtiaVal);
|
||||||
if (AD5940_HSRtiaCal(&hsrtia_cal, &Res) == AD5940ERR_OK) {
|
if (AD5940_HSRtiaCal(&hsrtia_cal, &Res) == AD5940ERR_OK) {
|
||||||
printf("Calibrated Rtia: Mag = %f Ohm, Phase = %f\n", Res.Magnitude, Res.Phase);
|
printf("Calibrated Rtia: Mag = %f Ohm, Phase = %f\n", Res.Magnitude, Res.Phase);
|
||||||
|
RtiaCalibrationTable[CurrentRtiaIndex] = Res.Magnitude;
|
||||||
pCfg->RtiaVal = Res.Magnitude;
|
pCfg->RtiaVal = Res.Magnitude;
|
||||||
} else {
|
} else {
|
||||||
printf("Calibration Failed\n");
|
printf("Calibration Failed\n");
|
||||||
|
|
@ -307,14 +499,38 @@ int input_pos = 0;
|
||||||
|
|
||||||
void process_command() {
|
void process_command() {
|
||||||
char cmd = input_buffer[0];
|
char cmd = input_buffer[0];
|
||||||
|
|
||||||
sleep_ms(10);
|
sleep_ms(10);
|
||||||
|
|
||||||
if (cmd == 'v') {
|
if (cmd == 'v') {
|
||||||
uint32_t id = AD5940_ReadReg(REG_AFECON_CHIPID);
|
uint32_t id = AD5940_ReadReg(REG_AFECON_CHIPID);
|
||||||
printf("CHIP_ID:0x%04X\n", id);
|
printf("CHIP_ID:0x%04X\n", id);
|
||||||
}
|
}
|
||||||
|
else if (cmd == 'r') {
|
||||||
|
if (strlen(input_buffer) > 2) {
|
||||||
|
uint32_t val = atoi(input_buffer + 2);
|
||||||
|
ConfigRtiaVal = val;
|
||||||
|
CurrentRtiaIndex = GetRtiaIndex(val);
|
||||||
|
printf("RANGE_SET:%d\n", ConfigRtiaVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cmd == 'f') {
|
||||||
|
if (strlen(input_buffer) > 2) {
|
||||||
|
int idx = atoi(input_buffer + 2);
|
||||||
|
switch(idx) {
|
||||||
|
case 0: CurrentLpTiaRf = LPTIARF_BYPASS; break;
|
||||||
|
case 1: CurrentLpTiaRf = LPTIARF_20K; break;
|
||||||
|
case 2: CurrentLpTiaRf = LPTIARF_100K; break;
|
||||||
|
case 3: CurrentLpTiaRf = LPTIARF_200K; break;
|
||||||
|
case 4: CurrentLpTiaRf = LPTIARF_400K; break;
|
||||||
|
case 5: CurrentLpTiaRf = LPTIARF_600K; break;
|
||||||
|
case 6: CurrentLpTiaRf = LPTIARF_1M; break;
|
||||||
|
default: CurrentLpTiaRf = LPTIARF_20K; break;
|
||||||
|
}
|
||||||
|
printf("LPF_SET:%d\n", idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (cmd == 'c') {
|
else if (cmd == 'c') {
|
||||||
|
Routine_CalibrateLFO();
|
||||||
Routine_CalibrateSystem();
|
Routine_CalibrateSystem();
|
||||||
}
|
}
|
||||||
else if (cmd == 'm') {
|
else if (cmd == 'm') {
|
||||||
|
|
@ -328,8 +544,23 @@ void process_command() {
|
||||||
if (strlen(input_buffer) > 2) sscanf(input_buffer + 2, "%f %f %d", &start, &end, &steps);
|
if (strlen(input_buffer) > 2) sscanf(input_buffer + 2, "%f %f %d", &start, &end, &steps);
|
||||||
Routine_Sweep(start, end, steps);
|
Routine_Sweep(start, end, steps);
|
||||||
}
|
}
|
||||||
|
else if (cmd == 'a') {
|
||||||
|
float bias = 0.0f;
|
||||||
|
if (strlen(input_buffer) > 2) bias = atof(input_buffer + 2);
|
||||||
|
Routine_Amperometric(bias);
|
||||||
|
}
|
||||||
|
else if (cmd == 'l') {
|
||||||
|
// l <start> <end> <steps> <duration>
|
||||||
|
float start = -500.0f, end = 500.0f;
|
||||||
|
int steps = 100, duration = 10000;
|
||||||
|
if (strlen(input_buffer) > 2) sscanf(input_buffer + 2, "%f %f %d %d", &start, &end, &steps, &duration);
|
||||||
|
Routine_LSV(start, end, steps, duration);
|
||||||
|
}
|
||||||
else if (cmd == 'x') {
|
else if (cmd == 'x') {
|
||||||
AppIMPCleanup();
|
if (CurrentMode == MODE_IMPEDANCE) AppIMPCleanup();
|
||||||
|
else if (CurrentMode == MODE_AMPEROMETRIC) AppAMPCtrl(AMPCTRL_SHUTDOWN, 0);
|
||||||
|
else if (CurrentMode == MODE_RAMP) AppRAMPCtrl(APPCTRL_SHUTDOWN, 0);
|
||||||
|
CurrentMode = MODE_IDLE;
|
||||||
printf("STOPPED\n");
|
printf("STOPPED\n");
|
||||||
}
|
}
|
||||||
else if (cmd == 'z') {
|
else if (cmd == 'z') {
|
||||||
|
|
@ -344,6 +575,10 @@ int main() {
|
||||||
setup_pins();
|
setup_pins();
|
||||||
AD5940PlatformCfg();
|
AD5940PlatformCfg();
|
||||||
AD5940ImpedanceStructInit();
|
AD5940ImpedanceStructInit();
|
||||||
|
AD5940AMPStructInit();
|
||||||
|
AD5940RampStructInit();
|
||||||
|
|
||||||
|
Routine_CalibrateLFO();
|
||||||
|
|
||||||
printf("SYSTEM_READY\n");
|
printf("SYSTEM_READY\n");
|
||||||
|
|
||||||
|
|
@ -361,15 +596,47 @@ int main() {
|
||||||
|
|
||||||
if (gpio_get(PIN_INT) == 0) {
|
if (gpio_get(PIN_INT) == 0) {
|
||||||
uint32_t temp = APPBUFF_SIZE;
|
uint32_t temp = APPBUFF_SIZE;
|
||||||
int32_t status = AppIMPISR(AppBuff, &temp);
|
int32_t status = 0;
|
||||||
|
|
||||||
|
if (CurrentMode == MODE_IMPEDANCE) {
|
||||||
|
status = AppIMPISR(AppBuff, &temp);
|
||||||
if (status == AD5940ERR_FIFO) {
|
if (status == AD5940ERR_FIFO) {
|
||||||
printf("ERROR: FIFO Overflow/Underflow. Stopping.\n");
|
printf("ERROR: FIFO Overflow/Underflow. Stopping.\n");
|
||||||
AppIMPCleanup();
|
AppIMPCleanup();
|
||||||
|
CurrentMode = MODE_IDLE;
|
||||||
} else if(temp > 0) {
|
} else if(temp > 0) {
|
||||||
ImpedanceShowResult(AppBuff, temp);
|
ImpedanceShowResult(AppBuff, temp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (CurrentMode == MODE_AMPEROMETRIC) {
|
||||||
|
status = AppAMPISR(AppBuff, &temp);
|
||||||
|
if (status == AD5940ERR_FIFO) {
|
||||||
|
printf("ERROR: FIFO Overflow/Underflow. Stopping.\n");
|
||||||
|
AppAMPCtrl(AMPCTRL_SHUTDOWN, 0);
|
||||||
|
CurrentMode = MODE_IDLE;
|
||||||
|
} else if(temp > 0) {
|
||||||
|
AmperometricShowResult((float*)AppBuff, temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (CurrentMode == MODE_RAMP) {
|
||||||
|
status = AppRAMPISR(AppBuff, &temp);
|
||||||
|
if (status == AD5940ERR_FIFO) {
|
||||||
|
printf("ERROR: FIFO Overflow/Underflow. Stopping.\n");
|
||||||
|
AppRAMPCtrl(APPCTRL_SHUTDOWN, 0);
|
||||||
|
CurrentMode = MODE_IDLE;
|
||||||
|
} else if(temp > 0) {
|
||||||
|
RampShowResult((float*)AppBuff, temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == AD5940ERR_STOP) {
|
||||||
|
printf("STOPPED\n");
|
||||||
|
if (CurrentMode == MODE_IMPEDANCE) AppIMPCleanup();
|
||||||
|
else if (CurrentMode == MODE_AMPEROMETRIC) AppAMPCtrl(AMPCTRL_SHUTDOWN, 0);
|
||||||
|
else if (CurrentMode == MODE_RAMP) AppRAMPCtrl(APPCTRL_SHUTDOWN, 0);
|
||||||
|
CurrentMode = MODE_IDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue