Hi everyone, I have trouble with ADG2128. My objective is 4-wire BIA measuring in 'EVAL-CN0565-ARDZ' using Arduino Wemos D1. Specifically, after configuring AD5940 depending on this code:
(https://github.com/analogdevicesinc/ad5940examples/blob/master/examples/AD5940_BIA/BodyImpedance.c)
It worked, there was a sine waveform at CE0 (capacitor C1). But I tried many ways to configure ADG2128 but it didn't work. At first, it cannot communicate to ADG2128 (I2C). I reconfigured AD5940's GPIO, and then it can. But up to now, there has been no signal or waveform at CN0565's pins (in the picture). I don't know why. My full Arduino code version in below.
Someone can help me
:'(. Thank you very much. I'm really grateful for that.
#include <SPI.h>
#include <Wire.h>
#include "ad5941.h"
#include <ADG2128.h>
#define SEQUENCE_GENERATOR
#define APPBUFF_SIZE 128
#define CS_PIN 15 // Chân CS tùy chỉnh
uint32_t AppBuff[APPBUFF_SIZE];
#define ADG2128_MUX_SIZE 24
// ADG2128 Pin Mapping
struct adg2128_pinmap {
uint8_t chip_addr; // I2C address
uint8_t selector; // Mux config (X input)
};
struct adg2128_pinmap board_map[ADG2128_MUX_SIZE] = {
{0x71, 0x80}, // Electrode 0, I2C addr = 0x71, X0
{0x71, 0x88}, // Electrode 1, I2C addr = 0x71, X1
{0x71, 0x90}, // Electrode 2, I2C addr = 0x71, X2
{0x71, 0x98}, // Electrode 3, I2C addr = 0x71, X3
{0x71, 0xA0}, // Electrode 4, I2C addr = 0x71, X4
{0x71, 0xA8}, // Electrode 5, I2C addr = 0x71, X5
{0x71, 0xC0}, // Electrode 6, I2C addr = 0x71, X6
{0x71, 0xC8}, // Electrode 7, I2C addr = 0x71, X7
{0x71, 0xD0}, //Electrode x, I2C addr = 0x71, Mux Config (X8 to Yn)
{0x71, 0xD8}, //Electrode x, I2C addr = 0x71, Mux Config (X9 to Yn)
{0x71, 0xE0}, //Electrode x, I2C addr = 0x71, Mux Config (X10 to Yn)
{0x71, 0xE8}, //Electrode x, I2C addr = 0x71, Mux Config (X11 to Yn)
{0x70, 0x80}, // Electrode 8, I2C addr = 0x70, X0
{0x70, 0x88}, // Electrode 9, I2C addr = 0x70, X1
{0x70, 0x90}, // Electrode 10, I2C addr = 0x70, X2
{0x70, 0x98}, // Electrode 11, I2C addr = 0x70, X3
{0x70, 0xA0}, // Electrode 12, I2C addr = 0x70, X4
{0x70, 0xA8}, // Electrode 13, I2C addr = 0x70, X5
{0x70, 0xC0}, // Electrode 14, I2C addr = 0x70, X6
{0x70, 0xC8}, // Electrode 15, I2C addr = 0x70, X7
{0x70, 0xD0}, //Electrode x, I2C addr = 0x70, Mux Config (X8 to Yn)
{0x70, 0xD8}, //Electrode x, I2C addr = 0x70, Mux Config (X9 to Yn)
{0x70, 0xE0}, //Electrode x, I2C addr = 0x70, Mux Config (X10 to Yn)
{0x70, 0xE8}, //Electrode x, I2C addr = 0x70, Mux Config (X11 to Yn)
};
// Electrode Combo Structure (4 electrodes for Y0-Y3)
struct electrode_combo {
uint16_t y0;
uint16_t y1;
uint16_t y2;
uint16_t y3;
};
void setMuxSwitch(struct electrode_combo sw, uint16_t nElCount) {
uint8_t i2c_addr;
uint8_t muxData[2] = {0, 0x00}; // Latch bit 0x00 (immediate update)
uint16_t *Y = (uint16_t *)&sw; // Access sw as array
uint16_t curr_el;
uint8_t i;
// Compute electrode factor
uint16_t el_factor = (uint16_t)ADG2128_MUX_SIZE / nElCount;
if (el_factor != 0 && ((el_factor & (el_factor - 1)) == 0)) {
// Configure switches for Y0-Y3
for (i = 0; i < 4; i++) {
if ((*(Y + i)) < ADG2128_MUX_SIZE) {
curr_el = (*(Y + i)) * el_factor;
i2c_addr = board_map[curr_el].chip_addr;
muxData[0] = board_map[curr_el].selector + (i << 1); // Adjust Y output
Wire.beginTransmission(i2c_addr);
Wire.write(muxData[0]);
Wire.write(muxData[1]);
int error = Wire.endTransmission();
if (error == 0) {
Serial.print("ADG2128 0x"); Serial.print(i2c_addr, HEX);
Serial.print(": Electrode "); Serial.print(curr_el);
Serial.print(" to Y"); Serial.println(i);
} else {
Serial.print("I2C Error for 0x"); Serial.print(i2c_addr, HEX);
Serial.print(": "); Serial.println(error);
}
}
}
delayMicroseconds(1); // Replace no_os_udelay
}
}
typedef struct
{
uint32_t RegAddr :8; /**< 8bit address is enough for sequencer */
uint32_t RegValue :24; /**< Reg data is limited to 24bit by sequencer */
}SEQGenRegInfo_Type;
/**
* Sequencer generator data base.
*/
struct
{
BoolFlag EngineStart; /**< Flag to mark start of the generator */
uint32_t BufferSize; /**< Total buffer size */
uint32_t *pSeqBuff; /**< The buffer for sequence generator(both sequences and RegInfo) */
uint32_t SeqLen; /**< Generated sequence length till now */
SEQGenRegInfo_Type *pRegInfo; /**< Pointer to buffer where stores register info */
uint32_t RegCount; /**< The count of register info available in buffer *pRegInfo. */
AD5940Err LastError; /**< The last error message. */
}SeqGenDB; /* Data base of Seq Generator */
void AD5940_CsClr(void)
{
digitalWrite(CS_PIN, LOW);
}
void AD5940_CsSet(void)
{
digitalWrite(CS_PIN, HIGH);
}
void AD5940_ReadWriteNBytes(unsigned char *pSendBuffer, unsigned char *pRecvBuff, unsigned long length)
{
SPI.beginTransaction(SPISettings(160000, MSBFIRST, SPI_MODE0));
for (int i = 0; i < length; i++)
{
pRecvBuff[i] = SPI.transfer(pSendBuffer[i]);
delay(1);
}
SPI.endTransaction();
}
static unsigned char AD5940_ReadWrite8B(unsigned char data)
{
uint8_t tx[1], rx[1];
tx[0] = data;
AD5940_ReadWriteNBytes(tx,rx,1);
return rx[0];
}
/**
@brief Using SPI to transmit two bytes and return the received bytes.
@param data: The 16-bit data SPI will transmit.
@return received data.
**/
static uint16_t AD5940_ReadWrite16B(uint16_t data)
{
uint8_t SendBuffer[2];
uint8_t RecvBuffer[2];
SendBuffer[0] = data>>8;
SendBuffer[1] = data&0xff;
AD5940_ReadWriteNBytes(SendBuffer,RecvBuffer,2);
return (((uint16_t)RecvBuffer[0])<<8)|RecvBuffer[1];
}
/**
* @brief Using SPI to transmit four bytes and return the received bytes.
* @param data: The 32-bit data SPI will transmit.
* @return received data.
**/
static uint32_t AD5940_ReadWrite32B(uint32_t data)
{
uint8_t SendBuffer[4];
uint8_t RecvBuffer[4];
SendBuffer[0] = (data>>24)&0xff;
SendBuffer[1] = (data>>16)&0xff;
SendBuffer[2] = (data>> 8)&0xff;
SendBuffer[3] = (data )&0xff;
AD5940_ReadWriteNBytes(SendBuffer,RecvBuffer,4);
return (((uint32_t)RecvBuffer[0])<<24)|(((uint32_t)RecvBuffer[1])<<16)|(((uint32_t)RecvBuffer[2])<<8)|RecvBuffer[3];
}
static void AD5940_SPIWriteReg(uint16_t RegAddr, uint32_t RegData)
{
/* Set register address */
AD5940_CsClr();
AD5940_ReadWrite8B(SPICMD_SETADDR);
AD5940_ReadWrite16B(RegAddr);
AD5940_CsSet();
/* Add delay here to meet the SPI timing. */
AD5940_CsClr();
AD5940_ReadWrite8B(SPICMD_WRITEREG);
if(((RegAddr>=0x1000)&&(RegAddr<=0x3014)))
AD5940_ReadWrite32B(RegData);
else
AD5940_ReadWrite16B(RegData);
AD5940_CsSet();
}
static uint32_t AD5940_SPIReadReg(uint16_t RegAddr)
{
uint32_t Data = 0;
/* Set register address that we want to read */
AD5940_CsClr();
AD5940_ReadWrite8B(SPICMD_SETADDR);
AD5940_ReadWrite16B(RegAddr);
AD5940_CsSet();
/* Read it */
AD5940_CsClr();
AD5940_ReadWrite8B(SPICMD_READREG);
AD5940_ReadWrite8B(0); //Dummy read
/* The real data is coming */
if((RegAddr>=0x1000)&&(RegAddr<=0x3014))
Data = AD5940_ReadWrite32B(0);
else
Data = AD5940_ReadWrite16B(0);
AD5940_CsSet();
return Data;
}
static AD5940Err AD5940_SEQGenSearchReg(uint32_t RegAddr, uint32_t *pIndex)
{
uint32_t i;
RegAddr = (RegAddr>>2)&0xff;
for(i=0;i<SeqGenDB.SeqLen;i++)
{
if(RegAddr == SeqGenDB.pRegInfo[i].RegAddr)
{
*pIndex = i;
return AD5940ERR_OK;
}
}
return AD5940ERR_SEQREG;
}
void AD5940_SEQGenInsert(uint32_t CmdWord)
{
uint32_t temp;
temp = SeqGenDB.RegCount + SeqGenDB.SeqLen;
/* Generate Sequence command */
if(temp < SeqGenDB.BufferSize)
{
SeqGenDB.pSeqBuff[SeqGenDB.SeqLen] = CmdWord;
SeqGenDB.SeqLen ++;
}
else /* There is no buffer */
SeqGenDB.LastError = AD5940ERR_BUFF;
}
static void AD5940_SEQRegInfoInsert(uint16_t RegAddr, uint32_t RegData)
{
uint32_t temp;
temp = SeqGenDB.RegCount + SeqGenDB.SeqLen;
if(temp < SeqGenDB.BufferSize)
{
SeqGenDB.pRegInfo --; /* Move back */
SeqGenDB.pRegInfo[0].RegAddr = (RegAddr>>2)&0xff;
SeqGenDB.pRegInfo[0].RegValue = RegData&0x00ffffff;
SeqGenDB.RegCount ++;
}
else /* There is no more buffer */
{
SeqGenDB.LastError = AD5940ERR_BUFF;
}
}
static void AD5940_SEQWriteReg(uint16_t RegAddr, uint32_t RegData)
{
uint32_t RegIndex;
if(RegAddr > 0x21ff)
{
SeqGenDB.LastError = AD5940ERR_ADDROR; /* address out of range */
return;
}
if(AD5940_SEQGenSearchReg(RegAddr, &RegIndex) == AD5940ERR_OK)
{
/* Store register value */
SeqGenDB.pRegInfo[RegIndex].RegValue = RegData;
/* Generate Sequence command */
AD5940_SEQGenInsert(SEQ_WR(RegAddr, RegData));
}
else
{
AD5940_SEQRegInfoInsert(RegAddr, RegData);
/* Generate Sequence command */
AD5940_SEQGenInsert(SEQ_WR(RegAddr, RegData));
}
}
static AD5940Err AD5940_SEQGenGetRegDefault(uint32_t RegAddr, uint32_t *pRegData)
{
*pRegData = AD5940_SPIReadReg(RegAddr);
return AD5940ERR_OK;
}
static uint32_t AD5940_SEQReadReg(uint16_t RegAddr)
{
uint32_t RegIndex, RegData;
if(AD5940_SEQGenSearchReg(RegAddr, &RegIndex) != AD5940ERR_OK)
{
/* There is no record in data-base, read the default value. */
AD5940_SEQGenGetRegDefault(RegAddr, &RegData);
AD5940_SEQRegInfoInsert(RegAddr, RegData);
}
else
{
/* return the current register value stored in data-base */
RegData = SeqGenDB.pRegInfo[RegIndex].RegValue;
}
return RegData;
}
void AD5940_WriteReg(uint16_t RegAddr, uint32_t RegData)
{
#ifdef SEQUENCE_GENERATOR
if(SeqGenDB.EngineStart == bTRUE)
AD5940_SEQWriteReg(RegAddr, RegData);
else
#endif
AD5940_SPIWriteReg(RegAddr, RegData);
}
uint32_t AD5940_ReadReg(uint16_t RegAddr)
{
#ifdef SEQUENCE_GENERATOR
if(SeqGenDB.EngineStart == bTRUE)
return AD5940_SEQReadReg(RegAddr);
else
#endif
return AD5940_SPIReadReg(RegAddr);
}
uint32_t AD5940_WakeUp(int32_t TryCount)
{
uint32_t count = 0;
while(1)
{
count++;
if(AD5940_ReadReg(REG_AFECON_ADIID) == AD5940_ADIID)
break; /* Succeed */
if(TryCount<=0)
continue; /* Always try to wakeup AFE */
if(count > TryCount)
break; /* Failed */
}
return count;
}
void AD5940_WUPTCfg(WUPTCfg_Type *pWuptCfg)
{
uint32_t tempreg;
//check parameters
/* Sleep and Wakeup time */
AD5940_WriteReg(REG_WUPTMR_SEQ0WUPL, (pWuptCfg->SeqxWakeupTime[0] & 0xFFFF));
AD5940_WriteReg(REG_WUPTMR_SEQ0WUPH, (pWuptCfg->SeqxWakeupTime[0] & 0xF0000)>>16);
AD5940_WriteReg(REG_WUPTMR_SEQ0SLEEPL, (pWuptCfg->SeqxSleepTime[0] & 0xFFFF));
AD5940_WriteReg(REG_WUPTMR_SEQ0SLEEPH, (pWuptCfg->SeqxSleepTime[0] & 0xF0000)>>16);
AD5940_WriteReg(REG_WUPTMR_SEQ1WUPL, (pWuptCfg->SeqxWakeupTime[1] & 0xFFFF));
AD5940_WriteReg(REG_WUPTMR_SEQ1WUPH, (pWuptCfg->SeqxWakeupTime[1] & 0xF0000)>>16);
AD5940_WriteReg(REG_WUPTMR_SEQ1SLEEPL, (pWuptCfg->SeqxSleepTime[1] & 0xFFFF));
AD5940_WriteReg(REG_WUPTMR_SEQ1SLEEPH, (pWuptCfg->SeqxSleepTime[1] & 0xF0000)>>16);
AD5940_WriteReg(REG_WUPTMR_SEQ2WUPL, (pWuptCfg->SeqxWakeupTime[2] & 0xFFFF));
AD5940_WriteReg(REG_WUPTMR_SEQ2WUPH, (pWuptCfg->SeqxWakeupTime[2] & 0xF0000)>>16);
AD5940_WriteReg(REG_WUPTMR_SEQ2SLEEPL, (pWuptCfg->SeqxSleepTime[2] & 0xFFFF));
AD5940_WriteReg(REG_WUPTMR_SEQ2SLEEPH, (pWuptCfg->SeqxSleepTime[2] & 0xF0000)>>16);
AD5940_WriteReg(REG_WUPTMR_SEQ3WUPL, (pWuptCfg->SeqxWakeupTime[3] & 0xFFFF));
AD5940_WriteReg(REG_WUPTMR_SEQ3WUPH, (pWuptCfg->SeqxWakeupTime[3] & 0xF0000)>>16);
AD5940_WriteReg(REG_WUPTMR_SEQ3SLEEPL, (pWuptCfg->SeqxSleepTime[3] & 0xFFFF));
AD5940_WriteReg(REG_WUPTMR_SEQ3SLEEPH, (pWuptCfg->SeqxSleepTime[3] & 0xF0000)>>16);
/* TMRCON register */
//if(pWuptCfg->WakeupEn == bTRUE) /* enable use Wupt to wakeup AFE */
/* We always allow Wupt to wakeup AFE automatically. */
AD5940_WriteReg(REG_ALLON_TMRCON, BITM_ALLON_TMRCON_TMRINTEN);
/* Wupt order */
tempreg = 0;
tempreg |= (pWuptCfg->WuptOrder[0]&0x03) << BITP_WUPTMR_SEQORDER_SEQA;
tempreg |= (pWuptCfg->WuptOrder[1]&0x03) << BITP_WUPTMR_SEQORDER_SEQB;
tempreg |= (pWuptCfg->WuptOrder[2]&0x03) << BITP_WUPTMR_SEQORDER_SEQC;
tempreg |= (pWuptCfg->WuptOrder[3]&0x03) << BITP_WUPTMR_SEQORDER_SEQD;
tempreg |= (pWuptCfg->WuptOrder[4]&0x03) << BITP_WUPTMR_SEQORDER_SEQE;
tempreg |= (pWuptCfg->WuptOrder[5]&0x03) << BITP_WUPTMR_SEQORDER_SEQF;
tempreg |= (pWuptCfg->WuptOrder[6]&0x03) << BITP_WUPTMR_SEQORDER_SEQG;
tempreg |= (pWuptCfg->WuptOrder[7]&0x03) << BITP_WUPTMR_SEQORDER_SEQH;
AD5940_WriteReg(REG_WUPTMR_SEQORDER, tempreg);
tempreg = 0;
if(pWuptCfg->WuptEn == bTRUE)
tempreg |= BITM_WUPTMR_CON_EN;
/* We always allow Wupt to trigger sequencer */
tempreg |= pWuptCfg->WuptEndSeq << BITP_WUPTMR_CON_ENDSEQ;
//tempreg |= 1L<<4;
AD5940_WriteReg(REG_WUPTMR_CON, tempreg);
}
void AD5940_WUPTCtrl(BoolFlag Enable)
{
uint16_t tempreg;
tempreg = AD5940_ReadReg(REG_WUPTMR_CON);
tempreg &= ~BITM_WUPTMR_CON_EN;
if(Enable == bTRUE)
tempreg |= BITM_WUPTMR_CON_EN;
AD5940_WriteReg(REG_WUPTMR_CON, tempreg);
}
void AD5940_REFCfgS(AFERefCfg_Type *pBufCfg)
{
uint32_t tempreg;
/* HP Reference(bandgap) */
tempreg = AD5940_ReadReg(REG_AFE_AFECON);
tempreg &= ~BITM_AFE_AFECON_HPREFDIS;
if(pBufCfg->HpBandgapEn == bFALSE)
tempreg |= BITM_AFE_AFECON_HPREFDIS;
AD5940_WriteReg(REG_AFE_AFECON, tempreg);
/* Reference buffer configure */
tempreg = AD5940_ReadReg(REG_AFE_BUFSENCON);
if(pBufCfg->Hp1V8BuffEn == bTRUE)
tempreg |= BITM_AFE_BUFSENCON_V1P8HPADCEN;
if(pBufCfg->Hp1V1BuffEn == bTRUE)
tempreg |= BITM_AFE_BUFSENCON_V1P1HPADCEN;
if(pBufCfg->Lp1V8BuffEn == bTRUE)
tempreg |= BITM_AFE_BUFSENCON_V1P8LPADCEN;
if(pBufCfg->Lp1V1BuffEn == bTRUE)
tempreg |= BITM_AFE_BUFSENCON_V1P1LPADCEN;
if(pBufCfg->Hp1V8ThemBuff == bTRUE)
tempreg |= BITM_AFE_BUFSENCON_V1P8THERMSTEN;
if(pBufCfg->Hp1V8Ilimit == bTRUE)
tempreg |= BITM_AFE_BUFSENCON_V1P8HPADCILIMITEN;
if(pBufCfg->Disc1V8Cap == bTRUE)
tempreg |= BITM_AFE_BUFSENCON_V1P8HPADCCHGDIS;
if(pBufCfg->Disc1V1Cap == bTRUE)
tempreg |= BITM_AFE_BUFSENCON_V1P1LPADCCHGDIS;
AD5940_WriteReg(REG_AFE_BUFSENCON, tempreg);
/* LPREFBUFCON */
tempreg = 0;
if(pBufCfg->LpRefBufEn == bFALSE)
tempreg |= BITM_AFE_LPREFBUFCON_LPBUF2P5DIS;
if(pBufCfg->LpBandgapEn == bFALSE)
tempreg |= BITM_AFE_LPREFBUFCON_LPREFDIS;
if(pBufCfg->LpRefBoostEn == bTRUE)
tempreg |= BITM_AFE_LPREFBUFCON_BOOSTCURRENT;
AD5940_WriteReg(REG_AFE_LPREFBUFCON, tempreg);
}
void AD5940_LPDAC0WriteS(uint16_t Data12Bit, uint8_t Data6Bit)
{
/* Check parameter */
Data6Bit &= 0x3f;
Data12Bit &= 0xfff;
AD5940_WriteReg(REG_AFE_LPDACDAT0, ((uint32_t)Data6Bit<<12)|Data12Bit);
}
void AD5940_LPDAC1WriteS(uint16_t Data12Bit, uint8_t Data6Bit)
{
/* Check parameter */
Data6Bit &= 0x3f;
Data12Bit &= 0xfff;
AD5940_WriteReg(REG_AFE_LPDACDAT1, ((uint32_t)Data6Bit<<12)|Data12Bit);
}
void AD5940_LPDACCfgS(LPDACCfg_Type *pLpDacCfg)
{
uint32_t tempreg;
tempreg = 0;
tempreg = (pLpDacCfg->LpDacSrc)<<BITP_AFE_LPDACCON0_WAVETYPE;
tempreg |= (pLpDacCfg->LpDacVzeroMux)<<BITP_AFE_LPDACCON0_VZEROMUX;
tempreg |= (pLpDacCfg->LpDacVbiasMux)<<BITP_AFE_LPDACCON0_VBIASMUX;
tempreg |= (pLpDacCfg->LpDacRef)<<BITP_AFE_LPDACCON0_REFSEL;
if(pLpDacCfg->DataRst == bFALSE)
tempreg |= BITM_AFE_LPDACCON0_RSTEN;
if(pLpDacCfg->PowerEn == bFALSE)
tempreg |= BITM_AFE_LPDACCON0_PWDEN;
if(pLpDacCfg->LpdacSel == LPDAC0)
{
AD5940_WriteReg(REG_AFE_LPDACCON0, tempreg);
AD5940_LPDAC0WriteS(pLpDacCfg->DacData12Bit, pLpDacCfg->DacData6Bit);
AD5940_WriteReg(REG_AFE_LPDACSW0, pLpDacCfg->LpDacSW|BITM_AFE_LPDACSW0_LPMODEDIS); /* Overwrite LPDACSW settings. On Si1, this register is not accessible. */
}
else
{
AD5940_WriteReg(REG_AFE_LPDACCON1, tempreg);
AD5940_LPDAC1WriteS(pLpDacCfg->DacData12Bit, pLpDacCfg->DacData6Bit);
AD5940_WriteReg(REG_AFE_LPDACSW1, pLpDacCfg->LpDacSW|BITM_AFE_LPDACSW0_LPMODEDIS); /* Overwrite LPDACSW settings. On Si1, this register is not accessible. */
}
}
void AD5940_LPAMPCfgS(LPAmpCfg_Type *pLpAmpCfg)
{
//check parameters
uint32_t tempreg;
tempreg = 0;
if(pLpAmpCfg->LpPaPwrEn == bFALSE)
tempreg |= BITM_AFE_LPTIACON0_PAPDEN;
if(pLpAmpCfg->LpTiaPwrEn == bFALSE)
tempreg |= BITM_AFE_LPTIACON0_TIAPDEN;
if(pLpAmpCfg->LpAmpPwrMod == LPAMPPWR_HALF)
tempreg |= BITM_AFE_LPTIACON0_HALFPWR;
else
{
tempreg |= pLpAmpCfg->LpAmpPwrMod<<BITP_AFE_LPTIACON0_IBOOST;
}
tempreg |= pLpAmpCfg->LpTiaRtia<<BITP_AFE_LPTIACON0_TIAGAIN;
tempreg |= pLpAmpCfg->LpTiaRload<<BITP_AFE_LPTIACON0_TIARL;
tempreg |= pLpAmpCfg->LpTiaRf<<BITP_AFE_LPTIACON0_TIARF;
if(pLpAmpCfg->LpAmpSel == LPAMP0)
{
AD5940_WriteReg(REG_AFE_LPTIACON0, tempreg);
AD5940_WriteReg(REG_AFE_LPTIASW0, pLpAmpCfg->LpTiaSW);
}
else
{
AD5940_WriteReg(REG_AFE_LPTIACON1, tempreg);
AD5940_WriteReg(REG_AFE_LPTIASW1, pLpAmpCfg->LpTiaSW);
}
}
void AD5940_LPLoopCfgS(LPLoopCfg_Type *pLpLoopCfg)
{
AD5940_LPDACCfgS(&pLpLoopCfg->LpDacCfg);
AD5940_LPAMPCfgS(&pLpLoopCfg->LpAmpCfg);
}
void AD5940_EnterSleepS(void)
{
AD5940_WriteReg(REG_AFE_SEQTRGSLP, 0);
AD5940_WriteReg(REG_AFE_SEQTRGSLP, 1);
}
void AD5940_SEQGenCtrl(BoolFlag bFlag)
{
if(bFlag == bFALSE) /* Disable sequence generator */
{
SeqGenDB.EngineStart = bFALSE;
}
else
{
SeqGenDB.SeqLen = 0;
SeqGenDB.LastError = AD5940ERR_OK; /* Clear error message */
SeqGenDB.EngineStart = bTRUE;
}
}
void AD5940_SweepNext(SoftSweepCfg_Type *pSweepCfg, float *pNextFreq)
{
float frequency;
if(pSweepCfg->SweepLog)/* Log step */
{
if(pSweepCfg->SweepStart<pSweepCfg->SweepStop) /* Normal */
{
if(++pSweepCfg->SweepIndex == pSweepCfg->SweepPoints)
pSweepCfg->SweepIndex = 0;
frequency = pSweepCfg->SweepStart*pow(10,pSweepCfg->SweepIndex*log10(pSweepCfg->SweepStop/pSweepCfg->SweepStart)/(pSweepCfg->SweepPoints-1));
}
else
{
pSweepCfg->SweepIndex --;
if(pSweepCfg->SweepIndex >= pSweepCfg->SweepPoints)
pSweepCfg->SweepIndex = pSweepCfg->SweepPoints-1;
frequency = pSweepCfg->SweepStop*pow(10,pSweepCfg->SweepIndex*
(log10(pSweepCfg->SweepStart/pSweepCfg->SweepStop)/(pSweepCfg->SweepPoints-1)));
}
}
else/* Linear step */
{
if(pSweepCfg->SweepStart<pSweepCfg->SweepStop) /* Normal */
{
if(++pSweepCfg->SweepIndex == pSweepCfg->SweepPoints)
pSweepCfg->SweepIndex = 0;
frequency = pSweepCfg->SweepStart + pSweepCfg->SweepIndex*(double)(pSweepCfg->SweepStop-pSweepCfg->SweepStart)/(pSweepCfg->SweepPoints-1);
}
else
{
pSweepCfg->SweepIndex --;
if(pSweepCfg->SweepIndex >= pSweepCfg->SweepPoints)
pSweepCfg->SweepIndex = pSweepCfg->SweepPoints-1;
frequency = pSweepCfg->SweepStop + pSweepCfg->SweepIndex*(double)(pSweepCfg->SweepStart - pSweepCfg->SweepStop)/(pSweepCfg->SweepPoints-1);
}
}
*pNextFreq = frequency;
}
uint32_t AD5940_WGFreqWordCal(float SinFreqHz, float WGClock)
{
uint32_t temp;
uint32_t __BITWIDTH_WGFCW = 30;
if(WGClock == 0) return 0;
temp = (uint32_t)(SinFreqHz*(1LL<<__BITWIDTH_WGFCW)/WGClock + 0.5f);
if(temp > ((__BITWIDTH_WGFCW == 26)?0xfffff:0xffffff))
temp = (__BITWIDTH_WGFCW == 26)?0xfffff:0xffffff;
return temp;
}
void AD5940_HSDacCfgS(HSDACCfg_Type *pHsDacCfg)
{
uint32_t tempreg;
//Check parameters
tempreg = 0;
if(pHsDacCfg->ExcitBufGain == EXCITBUFGAIN_0P25)
tempreg |= BITM_AFE_HSDACCON_INAMPGNMDE; /* Enable attenuator */
if(pHsDacCfg->HsDacGain == HSDACGAIN_0P2)
tempreg |= BITM_AFE_HSDACCON_ATTENEN; /* Enable attenuator */
tempreg |= (pHsDacCfg->HsDacUpdateRate&0xff)<<BITP_AFE_HSDACCON_RATE;
AD5940_WriteReg(REG_AFE_HSDACCON, tempreg);
}
void AD5940_SetDExRTIA(uint32_t DExPin, uint32_t DeRtia, uint32_t DeRload)
{
uint32_t tempreg;
/* deal with HSTIA DE RTIA */
if(DeRtia >= HSTIADERTIA_OPEN)
tempreg = 0x1f << 3; /* bit field HPTIRES03CON[7:3] */
else if(DeRtia >= HSTIADERTIA_1K)
{
tempreg = (DeRtia - 3 + 11) << 3;
}
else /* DERTIA 50/100/200Ohm */
{
const uint8_t DeRtiaTable[3][5] =
{
//Rload 0 10 30 50 100
{0x00, 0x01, 0x02, 0x03, 0x06}, /* RTIA 50Ohm */
{0x03, 0x04, 0x05, 0x06, 0x07}, /* RTIA 100Ohm */
{0x07, 0x07, 0x09, 0x09, 0x0a}, /* RTIA 200Ohm */
};
if(DeRload < HSTIADERLOAD_OPEN)
tempreg = (uint32_t)(DeRtiaTable[DeRtia][DeRload])<<3;
else
tempreg = (0x1f)<<3; /* Set it to HSTIADERTIA_OPEN. This setting is illegal */
}
/* deal with HSTIA Rload */
tempreg |= DeRload;
if(DExPin) //DE1
AD5940_WriteReg(REG_AFE_DE1RESCON, tempreg);
else //DE0
AD5940_WriteReg(REG_AFE_DE0RESCON, tempreg);
}
AD5940Err AD5940_HSTIACfgS(HSTIACfg_Type *pHsTiaCfg)
{
uint32_t tempreg;
//Check parameters
if(pHsTiaCfg == NULL) return AD5940ERR_NULLP;
/* Available parameter is 1k, 5k,...,160k, short, OPEN */
if(pHsTiaCfg->HstiaDeRtia < HSTIADERTIA_1K)
return AD5940ERR_PARA;
if(pHsTiaCfg->HstiaDeRtia > HSTIADERTIA_OPEN)
return AD5940ERR_PARA; /* Parameter is invalid */
if(pHsTiaCfg->HstiaDeRload > HSTIADERLOAD_OPEN)
return AD5940ERR_PARA; /* Available parameter is OPEN, 0R,..., 100R */
tempreg = 0;
tempreg |= pHsTiaCfg->HstiaBias;
AD5940_WriteReg(REG_AFE_HSTIACON, tempreg);
/* HSRTIACON */
/* Calculate CTIA value */
tempreg = pHsTiaCfg->HstiaCtia << BITP_AFE_HSRTIACON_CTIACON;
tempreg |= pHsTiaCfg->HstiaRtiaSel;
if(pHsTiaCfg->DiodeClose == bTRUE)
tempreg |= BITM_AFE_HSRTIACON_TIASW6CON; /* Close switch 6 */
AD5940_WriteReg(REG_AFE_HSRTIACON, tempreg);
/* DExRESCON */
AD5940_SetDExRTIA(0, pHsTiaCfg->HstiaDeRtia, pHsTiaCfg->HstiaDeRload);
return AD5940ERR_OK;
}
void AD5940_SWMatrixCfgS(SWMatrixCfg_Type *pSwMatrix)
{
AD5940_WriteReg(REG_AFE_DSWFULLCON, pSwMatrix->Dswitch);
AD5940_WriteReg(REG_AFE_PSWFULLCON, pSwMatrix->Pswitch);
AD5940_WriteReg(REG_AFE_NSWFULLCON, pSwMatrix->Nswitch);
AD5940_WriteReg(REG_AFE_TSWFULLCON, pSwMatrix->Tswitch);
AD5940_WriteReg(REG_AFE_SWCON, BITM_AFE_SWCON_SWSOURCESEL); /* Update switch configuration */
}
void AD5940_WGCfgS(WGCfg_Type *pWGInit)
{
//Check parameters
uint32_t tempreg;
if(pWGInit->WgType == WGTYPE_SIN)
{
/* Configure Sine wave Generator */
AD5940_WriteReg(REG_AFE_WGFCW, pWGInit->SinCfg.SinFreqWord);
AD5940_WriteReg(REG_AFE_WGAMPLITUDE, pWGInit->SinCfg.SinAmplitudeWord);
AD5940_WriteReg(REG_AFE_WGOFFSET, pWGInit->SinCfg.SinOffsetWord);
AD5940_WriteReg(REG_AFE_WGPHASE, pWGInit->SinCfg.SinPhaseWord);
}
else if(pWGInit->WgType == WGTYPE_TRAPZ)
{
/* Configure Trapezoid Generator */
AD5940_WriteReg(REG_AFE_WGDCLEVEL1, pWGInit->TrapzCfg.WGTrapzDCLevel1);
AD5940_WriteReg(REG_AFE_WGDCLEVEL2, pWGInit->TrapzCfg.WGTrapzDCLevel2);
AD5940_WriteReg(REG_AFE_WGDELAY1, pWGInit->TrapzCfg.WGTrapzDelay1);
AD5940_WriteReg(REG_AFE_WGDELAY2, pWGInit->TrapzCfg.WGTrapzDelay2);
AD5940_WriteReg(REG_AFE_WGSLOPE1, pWGInit->TrapzCfg.WGTrapzSlope1);
AD5940_WriteReg(REG_AFE_WGSLOPE2, pWGInit->TrapzCfg.WGTrapzSlope2);
}
else
{
/* Write DAC data. It's only have effect when WgType set to WGTYPE_MMR */
AD5940_WriteReg(REG_AFE_HSDACDAT, pWGInit->WgCode);
}
tempreg = 0;
if(pWGInit->GainCalEn == bTRUE)
tempreg |= BITM_AFE_WGCON_DACGAINCAL;
if(pWGInit->OffsetCalEn == bTRUE)
tempreg |= BITM_AFE_WGCON_DACOFFSETCAL;
tempreg |= (pWGInit->WgType) << BITP_AFE_WGCON_TYPESEL;
AD5940_WriteReg(REG_AFE_WGCON, tempreg);
}
void AD5940_HSLoopCfgS(HSLoopCfg_Type *pHsLoopCfg)
{
AD5940_HSDacCfgS(&pHsLoopCfg->HsDacCfg);
AD5940_HSTIACfgS(&pHsLoopCfg->HsTiaCfg);
AD5940_SWMatrixCfgS(&pHsLoopCfg->SWMatCfg);
AD5940_WGCfgS(&pHsLoopCfg->WgCfg);
}
void AD5940_ADCBaseCfgS(ADCBaseCfg_Type *pADCInit)
{
uint32_t tempreg = 0;
tempreg = pADCInit->ADCMuxP;
tempreg |= (uint32_t)(pADCInit->ADCMuxN)<<BITP_AFE_ADCCON_MUXSELN;
//if(pADCInit->OffCancEnable == bTRUE)
// tempreg |= BITM_AFE_ADCCON_GNOFSELPGA;
tempreg |= (uint32_t)(pADCInit->ADCPga)<<BITP_AFE_ADCCON_GNPGA;
AD5940_WriteReg(REG_AFE_ADCCON, tempreg);
}
void AD5940_AFECtrlS(uint32_t AfeCtrlSet, BoolFlag State)
{
/* Check parameters */
uint32_t tempreg;
tempreg = AD5940_ReadReg(REG_AFE_AFECON);
if (State == bTRUE) {
/* Clear bits to enable HPREF and ALDOLimit*/
if (AfeCtrlSet & AFECTRL_HPREFPWR) {
tempreg &= ~BITM_AFE_AFECON_HPREFDIS;
AfeCtrlSet &= ~AFECTRL_HPREFPWR;
}
if(AfeCtrlSet & AFECTRL_ALDOLIMIT)
{
tempreg &= ~BITM_AFE_AFECON_ALDOILIMITEN;
AfeCtrlSet &= ~AFECTRL_ALDOLIMIT;
}
tempreg |= AfeCtrlSet;
}
else
{
/* Set bits to Disable HPREF and ALDOLimit*/
if(AfeCtrlSet & AFECTRL_HPREFPWR)
{
tempreg |= BITM_AFE_AFECON_HPREFDIS;
AfeCtrlSet &= ~AFECTRL_HPREFPWR;
}
if(AfeCtrlSet & AFECTRL_ALDOLIMIT)
{
tempreg |= BITM_AFE_AFECON_ALDOILIMITEN;
AfeCtrlSet &= ~AFECTRL_ALDOLIMIT;
}
tempreg &= ~AfeCtrlSet;
}
AD5940_WriteReg(REG_AFE_AFECON, tempreg);
}
void AD5940_ADCFilterCfgS(ADCFilterCfg_Type *pFiltCfg)
{
uint32_t tempreg;
//PARA_CHECK(IS_ADCSINC3OSR(pFiltCfg->ADCSinc3Osr));
//PARA_CHECK(IS_ADCSINC2OSR(pFiltCfg->ADCSinc2Osr));
//PARA_CHECK(IS_ADCAVGNUM(pFiltCfg->ADCAvgNum));
//PARA_CHECK(IS_ADCRATE(pFiltCfg->ADCRate));
tempreg = AD5940_ReadReg(REG_AFE_ADCFILTERCON);
tempreg &= BITM_AFE_ADCFILTERCON_AVRGEN; /* Keep this bit setting. */
tempreg |= pFiltCfg->ADCRate;
if(pFiltCfg->BpNotch == bTRUE)
tempreg |= BITM_AFE_ADCFILTERCON_LPFBYPEN;
if(pFiltCfg->BpSinc3 == bTRUE)
tempreg |= BITM_AFE_ADCFILTERCON_SINC3BYP;
tempreg |= (uint32_t)(pFiltCfg->ADCSinc2Osr)<<BITP_AFE_ADCFILTERCON_SINC2OSR;
tempreg |= (uint32_t)(pFiltCfg->ADCSinc3Osr)<<BITP_AFE_ADCFILTERCON_SINC3OSR;
tempreg |= (uint32_t)(pFiltCfg->ADCAvgNum)<<BITP_AFE_ADCFILTERCON_AVRGNUM;
AD5940_WriteReg(REG_AFE_ADCFILTERCON, tempreg);
if(pFiltCfg->Sinc2NotchEnable)
{
AD5940_AFECtrlS(AFECTRL_SINC2NOTCH,bTRUE);
}
}
void AD5940_ADCDigCompCfgS(ADCDigComp_Type *pCompCfg)
{
//PARA_CHECK((AfeResultSel));
AD5940_WriteReg(REG_AFE_ADCMIN, pCompCfg->ADCMin);
AD5940_WriteReg(REG_AFE_ADCMINSM, pCompCfg->ADCMinHys);
AD5940_WriteReg(REG_AFE_ADCMAX, pCompCfg->ADCMax);
AD5940_WriteReg(REG_AFE_ADCMAXSMEN, pCompCfg->ADCMaxHys);
}
void AD5940_DFTCfgS(DFTCfg_Type *pDftCfg)
{
uint32_t reg_dftcon, reg_adcfilter;
reg_dftcon = 0;
/* Deal with DFTSRC_AVG. Once average function is enabled, it's automatically set as DFT source */
reg_adcfilter = AD5940_ReadReg(REG_AFE_ADCFILTERCON);
if(pDftCfg->DftSrc == DFTSRC_AVG)
{
reg_adcfilter |= BITM_AFE_ADCFILTERCON_AVRGEN;
AD5940_WriteReg(REG_AFE_ADCFILTERCON, reg_adcfilter);
}
else
{
/* Disable Average function and set correct DFT source */
reg_adcfilter &= ~BITM_AFE_ADCFILTERCON_AVRGEN;
AD5940_WriteReg(REG_AFE_ADCFILTERCON, reg_adcfilter);
/* Set new DFT source */
reg_dftcon |= (pDftCfg->DftSrc) << BITP_AFE_DFTCON_DFTINSEL;
}
/* Set DFT number */
reg_dftcon |= (pDftCfg->DftNum) << BITP_AFE_DFTCON_DFTNUM;
if(pDftCfg->HanWinEn == bTRUE)
reg_dftcon |= BITM_AFE_DFTCON_HANNINGEN;
AD5940_WriteReg(REG_AFE_DFTCON, reg_dftcon);
}
void AD5940_StatisticCfgS(StatCfg_Type *pStatCfg)
{
uint32_t tempreg;
//check parameters
tempreg = 0;
if(pStatCfg->StatEnable == bTRUE)
tempreg |= BITM_AFE_STATSCON_STATSEN;
tempreg |= (pStatCfg->StatSample) << BITP_AFE_STATSCON_SAMPLENUM;
tempreg |= (pStatCfg->StatDev) << BITP_AFE_STATSCON_STDDEV;
AD5940_WriteReg(REG_AFE_STATSCON, tempreg);
}
void AD5940_DSPCfgS(DSPCfg_Type *pDSPCfg)
{
AD5940_ADCBaseCfgS(&pDSPCfg->ADCBaseCfg);
AD5940_ADCFilterCfgS(&pDSPCfg->ADCFilterCfg);
AD5940_ADCDigCompCfgS(&pDSPCfg->ADCDigCompCfg);
AD5940_DFTCfgS(&pDSPCfg->DftCfg);
AD5940_StatisticCfgS(&pDSPCfg->StatCfg);
}
void AD5940_SEQGpioCtrlS(uint32_t Gpio)
{
AD5940_WriteReg(REG_AFE_SYNCEXTDEVICE, Gpio);
}
AD5940Err AD5940_SEQGenFetchSeq(const uint32_t **ppSeqCmd, uint32_t *pSeqLen)
{
AD5940Err lasterror;
if(ppSeqCmd)
*ppSeqCmd = SeqGenDB.pSeqBuff;
if(pSeqLen)
*pSeqLen = SeqGenDB.SeqLen;
//SeqGenDB.SeqLen = 0; /* Start a new sequence */
lasterror = SeqGenDB.LastError;
//SeqGenDB.LastError = AD5940ERR_OK; /* Clear error message */
return lasterror;
}
void AD5940_SEQCmdWrite(uint32_t StartAddr, const uint32_t *pCommand, uint32_t CmdCnt)
{
while(CmdCnt--)
{
AD5940_WriteReg(REG_AFE_CMDFIFOWADDR, StartAddr++);
AD5940_WriteReg(REG_AFE_CMDFIFOWRITE, *pCommand++);
}
}
uint32_t AD5940_INTCGetCfg(uint32_t AfeIntcSel)
{
uint32_t tempreg;
if(AfeIntcSel == AFEINTC_0)
tempreg = AD5940_ReadReg(REG_INTC_INTCSEL0);
else
tempreg = AD5940_ReadReg(REG_INTC_INTCSEL1);
return tempreg;
}
void AD5940_INTCCfg(uint32_t AfeIntcSel, uint32_t AFEIntSrc, BoolFlag State)
{
uint32_t tempreg;
uint32_t regaddr = REG_INTC_INTCSEL0;
if(AfeIntcSel == AFEINTC_1)
regaddr = REG_INTC_INTCSEL1;
tempreg = AD5940_ReadReg(regaddr);
if(State == bTRUE)
tempreg |= AFEIntSrc; /* Enable this interrupt */
else
tempreg &= ~(AFEIntSrc); /* Disable this interrupt */
AD5940_WriteReg(regaddr,tempreg);
}
void AD5940_StructInit(void *pStruct, uint32_t StructSize)
{
memset(pStruct, 0, StructSize);
}
BoolFlag AD5940_INTCTestFlag(uint32_t AfeIntcSel, uint32_t AfeIntSrcSel)
{
uint32_t tempreg;
uint32_t regaddr = (AfeIntcSel == AFEINTC_0)? REG_INTC_INTCFLAG0: REG_INTC_INTCFLAG1;
tempreg = AD5940_ReadReg(regaddr);
if(tempreg & AfeIntSrcSel)
return bTRUE;
else
return bFALSE;
}
void AD5940_INTCClrFlag(uint32_t AfeIntSrcSel)
{
AD5940_WriteReg(REG_INTC_INTCCLR,AfeIntSrcSel);
}
uint32_t AD5940_ReadAfeResult(uint32_t AfeResultSel)
{
uint32_t rd = 0;
//PARA_CHECK((AfeResultSel));
switch (AfeResultSel)
{
case AFERESULT_SINC3:
rd = AD5940_ReadReg(REG_AFE_ADCDAT);
break;
case AFERESULT_SINC2:
rd = AD5940_ReadReg(REG_AFE_SINC2DAT);
break;
case AFERESULT_TEMPSENSOR:
rd = AD5940_ReadReg(REG_AFE_TEMPSENSDAT);
break;
case AFERESULT_DFTREAL:
rd = AD5940_ReadReg(REG_AFE_DFTREAL);
break;
case AFERESULT_DFTIMAGE:
rd = AD5940_ReadReg(REG_AFE_DFTIMAG);
break;
case AFERESULT_STATSMEAN:
rd = AD5940_ReadReg(REG_AFE_STATSMEAN);
break;
case AFERESULT_STATSVAR:
rd = AD5940_ReadReg(REG_AFE_STATSVAR);
break;
}
return rd;
}
void AD5940_ADCMuxCfgS(uint32_t ADCMuxP, uint32_t ADCMuxN)
{
uint32_t tempreg;
//PARA_CHECK(IS_ADCMUXP(ADCMuxP));
//PARA_CHECK(IS_ADCMUXN(ADCMuxN));
tempreg = AD5940_ReadReg(REG_AFE_ADCCON);
tempreg &= ~(BITM_AFE_ADCCON_MUXSELN|BITM_AFE_ADCCON_MUXSELP);
tempreg |= ADCMuxP<<BITP_AFE_ADCCON_MUXSELP;
tempreg |= ADCMuxN<<BITP_AFE_ADCCON_MUXSELN;
AD5940_WriteReg(REG_AFE_ADCCON, tempreg);
}
fImpCar_Type AD5940_ComplexDivInt(iImpCar_Type *a, iImpCar_Type *b)
{
fImpCar_Type res;
float temp;
temp = (float)b->Real*b->Real + (float)b->Image*b->Image;
res.Real = (float)a->Real*b->Real + (float)a->Image*b->Image;
res.Real /= temp;
res.Image = (float)a->Image*b->Real - (float)a->Real*b->Image;
res.Image /= temp;
return res;
}
float AD5940_ComplexMag(fImpCar_Type *a)
{
return sqrt(a->Real*a->Real + a->Image*a->Image);
}
float AD5940_ComplexPhase(fImpCar_Type *a)
{
return atan2(a->Image, a->Real);
}
AD5940Err AD5940_HSRtiaCal(HSRTIACal_Type *pCalCfg, void *pResult)
{
/***** CALIBRATION METHOD ******
1) Measure the complex voltage V_Rcal across the calibration DUT (Rcal).
2) Measure the complex voltage V_Rtia across Rtia [HSTIA_P (output) - HSTIA_N].
3) Note Rtia carries the same current as Rcal; I_Rtia = I_exc = I_Rcal
4) Implement the equation: Rtia = V_Rtia / I_Rtia
--> Rtia = (V_Rtia / V_Rcal) * Rcal
*******************************/
AFERefCfg_Type aferef_cfg;
HSLoopCfg_Type hs_loop;
DSPCfg_Type dsp_cfg;
uint32_t INTCCfg;
BoolFlag bADCClk32MHzMode = bFALSE;
uint32_t ExcitBuffGain = EXCITBUFGAIN_2;
uint32_t HsDacGain = HSDACGAIN_1;
float ExcitVolt; /* Excitation voltage, unit is mV */
uint32_t RtiaVal;
uint32_t const HpRtiaTable[]={200,1000,5000,10000,20000,40000,80000,160000,0};
uint32_t const HSTIADERLOADTable[]={0,10,30,50,100,999999999999};
uint32_t const HSTIADERTIATable[] = {50,100,200,1000,5000,10000,20000,40000,80000,160000,0,999999999999999};
uint32_t WgAmpWord;
iImpCar_Type DftRcalVolt, DftRtiaVolt;
if(pCalCfg == NULL) return AD5940ERR_NULLP;
if(pCalCfg->fRcal == 0)
return AD5940ERR_PARA;
//if(pCalCfg->HsTiaCfg.HstiaRtiaSel > HSTIARTIA_160K)
// return AD5940ERR_PARA;
//if(pCalCfg->HsTiaCfg.HstiaRtiaSel == HSTIARTIA_OPEN)
// return AD5940ERR_PARA; /* Do not support calibrating DE0-RTIA */
if(pResult == NULL)
return AD5940ERR_NULLP;
if(pCalCfg->AdcClkFreq > (32000000*0.8))
bADCClk32MHzMode = bTRUE;
/* Calculate the excitation voltage we should use based on RCAL/Rtia */
if(pCalCfg->HsTiaCfg.HstiaRtiaSel == HSTIARTIA_OPEN)
{
if(pCalCfg->HsTiaCfg.HstiaDeRtia == HSTIADERTIA_TODE)
{
RtiaVal = pCalCfg->HsTiaCfg.ExtRtia;
}
else
{
RtiaVal = pCalCfg->HsTiaCfg.ExtRtia + HSTIADERLOADTable[pCalCfg->HsTiaCfg.HstiaDeRload] + HSTIADERTIATable[pCalCfg->HsTiaCfg.HstiaDeRtia];
}
}
else
RtiaVal = HpRtiaTable[pCalCfg->HsTiaCfg.HstiaRtiaSel];
/*
DAC output voltage calculation
Note: RCAL value should be similar to RTIA so the accuracy is best.
HSTIA output voltage should be limited to 0.2V to AVDD-0.2V, with 1.1V bias. We use 80% of this range for safe.
Because the bias voltage is fixed to 1.1V, so for AC signal maximum amplitude is 1.1V-0.2V = 0.9Vp. That's 1.8Vpp.
Formula is: ExcitVolt(in mVpp) = (1800mVpp*80% / RTIA) * RCAL
ADC input range is +-1.5V which is enough for calibration.
*/
ExcitVolt = 1800*0.8*pCalCfg->fRcal/RtiaVal;
if(ExcitVolt <= 800*0.05) /* Voltage is so small that we can enable the attenuator of DAC(1/5) and Excitation buffer(1/4). 800mVpp is the DAC output voltage */
{
ExcitBuffGain = EXCITBUFGAIN_0P25;
HsDacGain = HSDACGAIN_0P2;
/* Excitation buffer voltage full range is 800mVpp*0.05 = 40mVpp */
WgAmpWord = ((uint32_t)(ExcitVolt/40*2047*2)+1)>>1; /* Assign value with rounding (0.5 LSB error) */
}
else if(ExcitVolt <= 800*0.25) /* Enable Excitation buffer attenuator */
{
ExcitBuffGain = EXCITBUFGAIN_0P25;
HsDacGain = HSDACGAIN_1;
/* Excitation buffer voltage full range is 800mVpp*0.25 = 200mVpp */
WgAmpWord = ((uint32_t)(ExcitVolt/200*2047*2)+1)>>1; /* Assign value with rounding (0.5 LSB error) */
}
else if(ExcitVolt <= 800*0.4) /* Enable DAC attenuator */
{
ExcitBuffGain = EXCITBUFGAIN_2;
HsDacGain = HSDACGAIN_0P2;
/* Excitation buffer voltage full range is 800mVpp*0.4 = 320mV */
WgAmpWord = ((uint32_t)(ExcitVolt/320*2047*2)+1)>>1; /* Assign value with rounding (0.5 LSB error) */
}
else /* No attenuator is needed. This is the best condition which means RTIA is close to RCAL */
{
ExcitBuffGain = EXCITBUFGAIN_2;
HsDacGain = HSDACGAIN_1;
/* Excitation buffer voltage full range is 800mVpp*2=1600mVpp */
WgAmpWord = ((uint32_t)(ExcitVolt/1600*2047*2)+1)>>1; /* Assign value with rounding (0.5 LSB error) */
}
if(WgAmpWord > 0x7ff)
WgAmpWord = 0x7ff;
/*INTC configuration */
INTCCfg = AD5940_INTCGetCfg(AFEINTC_1);
AD5940_INTCCfg(AFEINTC_1, AFEINTSRC_DFTRDY, bTRUE); /* Enable SINC2 Interrupt in INTC1 */
AD5940_AFECtrlS(AFECTRL_ALL, bFALSE); /* Init all to disable state */
/* Configure reference system */
aferef_cfg.HpBandgapEn = bTRUE;
aferef_cfg.Hp1V1BuffEn = bTRUE;
aferef_cfg.Hp1V8BuffEn = bTRUE;
aferef_cfg.Disc1V1Cap = bFALSE;
aferef_cfg.Disc1V8Cap = bFALSE;
aferef_cfg.Hp1V8ThemBuff = bFALSE;
aferef_cfg.Hp1V8Ilimit = bFALSE;
aferef_cfg.Lp1V1BuffEn = bFALSE;
aferef_cfg.Lp1V8BuffEn = bFALSE;
aferef_cfg.LpBandgapEn = bFALSE;
aferef_cfg.LpRefBufEn = bFALSE;
aferef_cfg.LpRefBoostEn = bFALSE;
AD5940_REFCfgS(&aferef_cfg);
/* Configure HP Loop */
hs_loop.HsDacCfg.ExcitBufGain = ExcitBuffGain;
hs_loop.HsDacCfg.HsDacGain = HsDacGain;
hs_loop.HsDacCfg.HsDacUpdateRate = 7; /* Set it to highest update rate */
memcpy(&hs_loop.HsTiaCfg, &pCalCfg->HsTiaCfg, sizeof(pCalCfg->HsTiaCfg));
hs_loop.SWMatCfg.Dswitch = SWD_RCAL0;
hs_loop.SWMatCfg.Pswitch = SWP_RCAL0;
hs_loop.SWMatCfg.Nswitch = SWN_RCAL1;
hs_loop.SWMatCfg.Tswitch = SWT_RCAL1 | SWT_TRTIA; // SWT_RCAL1|SWT_TRTIA|SWT_AIN1;
hs_loop.WgCfg.WgType = WGTYPE_SIN;
hs_loop.WgCfg.GainCalEn = bFALSE; //bTRUE;
hs_loop.WgCfg.OffsetCalEn = bFALSE; // bTRUE;
hs_loop.WgCfg.SinCfg.SinFreqWord = AD5940_WGFreqWordCal(pCalCfg->fFreq, pCalCfg->SysClkFreq);
hs_loop.WgCfg.SinCfg.SinAmplitudeWord = WgAmpWord;
hs_loop.WgCfg.SinCfg.SinOffsetWord = 0;
hs_loop.WgCfg.SinCfg.SinPhaseWord = 0;
AD5940_HSLoopCfgS(&hs_loop);
/* Configure DSP */
dsp_cfg.ADCBaseCfg.ADCMuxN = ADCMUXN_N_NODE;
dsp_cfg.ADCBaseCfg.ADCMuxP = ADCMUXP_P_NODE;
dsp_cfg.ADCBaseCfg.ADCPga = ADCPGA_1P5;
AD5940_StructInit(&dsp_cfg.ADCDigCompCfg, sizeof(dsp_cfg.ADCDigCompCfg));
dsp_cfg.ADCFilterCfg.ADCAvgNum = ADCAVGNUM_16; /* Don't care because it's disabled */
dsp_cfg.ADCFilterCfg.ADCRate = bADCClk32MHzMode?ADCRATE_1P6MHZ:ADCRATE_800KHZ;
dsp_cfg.ADCFilterCfg.ADCSinc2Osr = pCalCfg->ADCSinc2Osr;
dsp_cfg.ADCFilterCfg.ADCSinc3Osr = pCalCfg->ADCSinc3Osr;
dsp_cfg.ADCFilterCfg.BpNotch = bTRUE;
dsp_cfg.ADCFilterCfg.BpSinc3 = bFALSE;
dsp_cfg.ADCFilterCfg.Sinc2NotchEnable = bTRUE;
memcpy(&dsp_cfg.DftCfg, &pCalCfg->DftCfg, sizeof(pCalCfg->DftCfg));
memset(&dsp_cfg.StatCfg, 0, sizeof(dsp_cfg.StatCfg));
AD5940_DSPCfgS(&dsp_cfg);
/* Enable all of them. They are automatically turned off during hibernate mode to save power */
AD5940_AFECtrlS(AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\
/*AFECTRL_WG|*/AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\
AFECTRL_SINC2NOTCH, bTRUE);
/***** MEASURE VOLTAGE ACROSS RCAL *****/
AD5940_AFECtrlS(AFECTRL_WG|AFECTRL_ADCPWR, bTRUE); /* Enable Waveform generator, ADC power */
//wait for sometime.
delayMicroseconds(250);
AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT, bTRUE); /* Start ADC convert and DFT */
/* Wait until DFT ready */
Serial.println(AD5940_ReadReg(REG_AFE_AFECON), HEX);
while(AD5940_INTCTestFlag(AFEINTC_1, AFEINTSRC_DFTRDY) == bFALSE);
AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT|AFECTRL_ADCPWR, bFALSE); /* Stop ADC convert and DFT */ //|AFECTRL_WG
AD5940_INTCClrFlag(AFEINTSRC_DFTRDY);
DftRcalVolt.Real = AD5940_ReadAfeResult(AFERESULT_DFTREAL);
DftRcalVolt.Image = AD5940_ReadAfeResult(AFERESULT_DFTIMAGE);
/***** MEASURE VOLTAGE ACROSS RTIA *****/
AD5940_ADCMuxCfgS(ADCMUXP_HSTIA_P, ADCMUXN_HSTIA_N);
AD5940_AFECtrlS(AFECTRL_WG|AFECTRL_ADCPWR, bTRUE); /* Enable Waveform generator, ADC power */
//wait for sometime.
delayMicroseconds(250);
AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT, bTRUE); /* Start ADC convert and DFT */
/* Wait until DFT ready */
while(AD5940_INTCTestFlag(AFEINTC_1, AFEINTSRC_DFTRDY) == bFALSE);
AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT|AFECTRL_ADCPWR, bFALSE); /* Stop ADC convert and DFT */ //|AFECTRL_WG
AD5940_INTCClrFlag(AFEINTSRC_DFTRDY);
DftRtiaVolt.Real = AD5940_ReadAfeResult(AFERESULT_DFTREAL);
DftRtiaVolt.Image = AD5940_ReadAfeResult(AFERESULT_DFTIMAGE);
if(DftRcalVolt.Real&(1L<<17))
DftRcalVolt.Real |= 0xfffc0000;
if(DftRcalVolt.Image&(1L<<17))
DftRcalVolt.Image |= 0xfffc0000;
if(DftRtiaVolt.Real&(1L<<17))
DftRtiaVolt.Real |= 0xfffc0000;
if(DftRtiaVolt.Image&(1L<<17))
DftRtiaVolt.Image |= 0xfffc0000;
/*
ADC MUX is set to HSTIA_P and HSTIA_N.
While the current flow through RCAL and then into RTIA, the current direction should be from HSTIA_N to HSTIA_P if we
measure the voltage across RCAL by MUXSELP_P_NODE and MUXSELN_N_NODE.
So here, we add a negative sign to results
*/
DftRtiaVolt.Image = -DftRtiaVolt.Image;
DftRtiaVolt.Real = -DftRtiaVolt.Real; /* Current is measured by MUX HSTIA_P-HSTIA_N. It should be */
/*
The impedance engine inside of AD594x give us Real part and Imaginary part of DFT. Due to technology used, the Imaginary
part in register is the opposite number. So we add a negative sign on the Imaginary part of results.
*/
DftRtiaVolt.Image = -DftRtiaVolt.Image;
DftRcalVolt.Image = -DftRcalVolt.Image;
/***** Implement RTIA = (V_Rtia / V_Rcal) * Rcal ******/
fImpCar_Type temp;
temp = AD5940_ComplexDivInt(&DftRtiaVolt, &DftRcalVolt);
temp.Real *= pCalCfg->fRcal;
temp.Image *= pCalCfg->fRcal;
if(pCalCfg->bPolarResult == bFALSE)
{
*(fImpCar_Type*)pResult = temp;
}
else
{
((fImpPol_Type*)pResult)->Magnitude = AD5940_ComplexMag(&temp);
((fImpPol_Type*)pResult)->Phase = AD5940_ComplexPhase(&temp);
}
/* Restore INTC1 DFT configure */
if(INTCCfg&AFEINTSRC_DFTRDY);
else
AD5940_INTCCfg(AFEINTC_1, AFEINTSRC_DFTRDY, bFALSE); /* Disable DFT Interrupt */
return AD5940ERR_OK;
}
static int32_t _is_value_in_table(uint8_t value, const uint8_t *table, uint8_t len, uint8_t *index)
{
for(int i=0; i<len; i++)
{
if(value == table[i])
{
*index = i;
return bTRUE;
}
}
return bFALSE;
}
BoolFlag AD5940_Notch50HzAvailable(ADCFilterCfg_Type *pFilterInfo, uint8_t *dl)
{
if((pFilterInfo->ADCRate == ADCRATE_800KHZ && pFilterInfo->ADCSinc3Osr == ADCSINC3OSR_2)||\
(pFilterInfo->ADCRate == ADCRATE_1P6MHZ && pFilterInfo->ADCSinc3Osr != ADCSINC3OSR_2))
{
//this combination suits for filter:
//SINC3 OSR2, for 800kSPS
//and SINC3 OSR4 and OSR5 for 1.6MSPS,
const uint8_t available_sinc2_osr[] = {ADCSINC2OSR_533, ADCSINC2OSR_667,ADCSINC2OSR_800, ADCSINC2OSR_889, ADCSINC2OSR_1333};
const uint8_t dl_50Hz[] = {15,12,10,9,6};
uint8_t index;
if(_is_value_in_table(pFilterInfo->ADCSinc2Osr, available_sinc2_osr, sizeof(available_sinc2_osr), &index))
{
*dl = dl_50Hz[index];
return bTRUE;
}
}
else if(pFilterInfo->ADCRate == ADCRATE_1P6MHZ && pFilterInfo->ADCSinc3Osr == ADCSINC3OSR_2)
{
//this combination suits for filter:
//SINC3 OSR2 for 1.6MSPS
const uint8_t available_sinc2_osr[] = {ADCSINC2OSR_889, ADCSINC2OSR_1067, ADCSINC2OSR_1333};
const uint8_t dl_50Hz[] = {18,15,12};
uint8_t index;
if(_is_value_in_table(pFilterInfo->ADCSinc2Osr, available_sinc2_osr, sizeof(available_sinc2_osr), &index))
{
*dl = dl_50Hz[index];
return bTRUE;
}
}
else if(pFilterInfo->ADCRate == ADCRATE_800KHZ && pFilterInfo->ADCSinc3Osr != ADCSINC3OSR_2)
{
//this combination suits for filter:
//SINC3 OSR4 and OSR5 for 800kSPS,
const uint8_t available_sinc2_osr[] = {ADCSINC2OSR_178, ADCSINC2OSR_267, ADCSINC2OSR_533, ADCSINC2OSR_640,\
ADCSINC2OSR_800, ADCSINC2OSR_1067};
const uint8_t dl_50Hz[] = {18,12,6,5,4,3};
uint8_t index;
if(_is_value_in_table(pFilterInfo->ADCSinc2Osr, available_sinc2_osr, sizeof(available_sinc2_osr), &index))
{
*dl = dl_50Hz[index];
return bTRUE;
}
}
*dl = 0;
return bFALSE;
}
BoolFlag AD5940_Notch60HzAvailable(ADCFilterCfg_Type *pFilterInfo, uint8_t *dl)
{
if((pFilterInfo->ADCRate == ADCRATE_800KHZ && pFilterInfo->ADCSinc3Osr == ADCSINC3OSR_2)||\
(pFilterInfo->ADCRate == ADCRATE_1P6MHZ && pFilterInfo->ADCSinc3Osr != ADCSINC3OSR_2))
{
//this combination suits for filter:
//SINC3 OSR2, for 800kSPS
//and SINC3 OSR4 and OSR5 for 1.6MSPS,
const uint8_t available_sinc2_osr[] = {ADCSINC2OSR_667, ADCSINC2OSR_1333};
const uint8_t dl_60Hz[] = {10,5};
uint8_t index;
if(_is_value_in_table(pFilterInfo->ADCSinc2Osr, available_sinc2_osr, sizeof(available_sinc2_osr), &index))
{
*dl = dl_60Hz[index];
return bTRUE;
}
}
else if(pFilterInfo->ADCRate == ADCRATE_1P6MHZ && pFilterInfo->ADCSinc3Osr == ADCSINC3OSR_2)
{
//this combination suits for filter:
//SINC3 OSR2 for 1.6MSPS
const uint8_t available_sinc2_osr[] = {ADCSINC2OSR_889, ADCSINC2OSR_1333};
const uint8_t dl_60Hz[] = {15,10};
uint8_t index;
if(_is_value_in_table(pFilterInfo->ADCSinc2Osr, available_sinc2_osr, sizeof(available_sinc2_osr), &index))
{
*dl = dl_60Hz[index];
return bTRUE;
}
}
else if(pFilterInfo->ADCRate == ADCRATE_800KHZ && pFilterInfo->ADCSinc3Osr != ADCSINC3OSR_2)
{
//this combination suits for filter:
//SINC3 OSR4 and OSR5 for 800kSPS,
const uint8_t available_sinc2_osr[] = {ADCSINC2OSR_178, ADCSINC2OSR_267, ADCSINC2OSR_533, ADCSINC2OSR_667,\
ADCSINC2OSR_889, ADCSINC2OSR_1333};
const uint8_t dl_60Hz[] = {15,10,5,4,3,2};
uint8_t index;
if(_is_value_in_table(pFilterInfo->ADCSinc2Osr, available_sinc2_osr, sizeof(available_sinc2_osr), &index))
{
*dl = dl_60Hz[index];
return bTRUE;
}
}
*dl = 0;
return bFALSE;
}
void AD5940_ClksCalculate(ClksCalInfo_Type *pFilterInfo, uint32_t *pClocks)
{
uint32_t temp = 0;
const uint32_t sinc2osr_table[] = {22,44,89,178,267,533,640,667,800,889,1067,1333,0};
const uint32_t sinc3osr_table[] = {5,4,2,0};
*pClocks = 0;
if(pFilterInfo == NULL) return;
if(pClocks == NULL) return;
if(pFilterInfo->ADCSinc2Osr > ADCSINC2OSR_1333) return;
if(pFilterInfo->ADCSinc3Osr > 2) return; /* 0: OSR5, 1:OSR4, 2:OSR2 */
if(pFilterInfo->ADCAvgNum > ADCAVGNUM_16) return; /* Average number index:0,1,2,3 */
switch(pFilterInfo->DataType)
{
case DATATYPE_ADCRAW:
temp = (uint32_t)(20*pFilterInfo->DataCount*pFilterInfo->RatioSys2AdcClk);
break;
case DATATYPE_SINC3:
temp = (uint32_t)(((pFilterInfo->DataCount+2)*sinc3osr_table[pFilterInfo->ADCSinc3Osr]+1)*20*pFilterInfo->RatioSys2AdcClk + 0.5f);
break;
case DATATYPE_SINC2:
temp = (pFilterInfo->DataCount+1)*sinc2osr_table[pFilterInfo->ADCSinc2Osr] + 1;
pFilterInfo->DataType = DATATYPE_SINC3;
pFilterInfo->DataCount = temp;
AD5940_ClksCalculate(pFilterInfo, &temp);
pFilterInfo->DataType = DATATYPE_SINC2;
temp += 15; /* Need extra 15 clocks for FIFO etc. Just to be safe. */
break;
case DATATYPE_NOTCH:
{
ADCFilterCfg_Type filter;
filter.ADCRate = pFilterInfo->ADCRate;
filter.ADCSinc3Osr = pFilterInfo->ADCSinc3Osr;
filter.ADCSinc2Osr = pFilterInfo->ADCSinc2Osr;
uint8_t dl=0, dl_50, dl_60;
if(AD5940_Notch50HzAvailable(&filter, &dl_50)){
dl += dl_50 - 1;
}
if(AD5940_Notch60HzAvailable(&filter, &dl_60)){
dl += dl_60 - 1;
}
pFilterInfo->DataType = DATATYPE_SINC2;
pFilterInfo->DataCount += dl; //DL is the extra data input needed for filter to output first data.
AD5940_ClksCalculate(pFilterInfo,&temp);
//restore the filter info.
pFilterInfo->DataType = DATATYPE_NOTCH;
pFilterInfo->DataCount -= dl;
break;
}
case DATATYPE_DFT:
switch(pFilterInfo->DftSrc)
{
case DFTSRC_ADCRAW:
pFilterInfo->DataType = DATATYPE_ADCRAW;
AD5940_ClksCalculate(pFilterInfo, &temp);
break;
case DFTSRC_SINC3:
pFilterInfo->DataType = DATATYPE_SINC3;
AD5940_ClksCalculate(pFilterInfo, &temp);
break;
case DFTSRC_SINC2NOTCH:
if(pFilterInfo->BpNotch)
pFilterInfo->DataType = DATATYPE_SINC2;
else
pFilterInfo->DataType = DATATYPE_NOTCH;
AD5940_ClksCalculate(pFilterInfo, &temp);
break;
case DFTSRC_AVG:
pFilterInfo->DataType = DATATYPE_SINC3;
pFilterInfo->DataCount *= 1L<<(pFilterInfo->ADCAvgNum+1); /* 0: average2, 1: average4, 2: average8, 3: average16 */
AD5940_ClksCalculate(pFilterInfo, &temp);
break;
default:
break;
}
pFilterInfo->DataType = DATATYPE_DFT;
temp += 25; /* add margin */
break;
default:
break;
}
*pClocks = temp;
}
void AD5940_AGPIOClr(uint32_t uiPinSet)
{
AD5940_WriteReg(REG_AGPIO_GP0CLR,uiPinSet);
}
void AD5940_AGPIOSet(uint32_t uiPinSet)
{
AD5940_WriteReg(REG_AGPIO_GP0SET,uiPinSet);
}
void AD5940_SEQCfg(SEQCfg_Type *pSeqCfg)
{
/* check parameters */
uint32_t tempreg, fifocon;
fifocon = AD5940_ReadReg(REG_AFE_FIFOCON);
AD5940_WriteReg(REG_AFE_FIFOCON, 0); /* Disable FIFO before changing memory configuration */
/* Configure CMDDATACON register */
tempreg = AD5940_ReadReg(REG_AFE_CMDDATACON);
tempreg &= ~(BITM_AFE_CMDDATACON_CMDMEMMDE|BITM_AFE_CMDDATACON_CMD_MEM_SEL); /* Clear settings for sequencer memory */
tempreg |= (1L) << BITP_AFE_CMDDATACON_CMDMEMMDE; /* Sequencer is always in memory mode */
tempreg |= (pSeqCfg->SeqMemSize) << BITP_AFE_CMDDATACON_CMD_MEM_SEL;
AD5940_WriteReg(REG_AFE_CMDDATACON, tempreg);
if(pSeqCfg->SeqCntCRCClr)
{
AD5940_WriteReg(REG_AFE_SEQCON, 0); /* Disable sequencer firstly */
AD5940_WriteReg(REG_AFE_SEQCNT, 0); /* When sequencer is disabled, any write to SEQCNT will clear CNT and CRC register */
}
tempreg = 0;
if(pSeqCfg->SeqEnable == bTRUE)
tempreg |= BITM_AFE_SEQCON_SEQEN;
tempreg |= (pSeqCfg->SeqWrTimer) << BITP_AFE_SEQCON_SEQWRTMR;
AD5940_WriteReg(REG_AFE_SEQCON, tempreg);
AD5940_WriteReg(REG_AFE_FIFOCON, fifocon); /* restore FIFO configuration */
// tempreg = 0;
// if(pSeqCfg->SeqBreakEn)
// tempreg |= 0x01; // add register definition? bitm_afe_
// if(pSeqCfg->SeqIgnoreEn)
// tempreg |= 0x02;
// AD5940_WriteReg(0x21dc, tempreg);
}
void AD5940_FIFOCtrlS(uint32_t FifoSrc, BoolFlag FifoEn)
{
uint32_t tempreg;
tempreg = 0;
if(FifoEn == bTRUE)
tempreg |= BITM_AFE_FIFOCON_DATAFIFOEN;
tempreg |= FifoSrc << BITP_AFE_FIFOCON_DATAFIFOSRCSEL;
AD5940_WriteReg(REG_AFE_FIFOCON, tempreg);
}
void AD5940_FIFOCfg(FIFOCfg_Type *pFifoCfg)
{
uint32_t tempreg;
//check parameters
AD5940_WriteReg(REG_AFE_FIFOCON, 0); /* Disable FIFO firstly! */
/* CMDDATACON register. Configure this firstly */
tempreg = AD5940_ReadReg(REG_AFE_CMDDATACON);
tempreg &= BITM_AFE_CMDDATACON_CMD_MEM_SEL|BITM_AFE_CMDDATACON_CMDMEMMDE; /* Keep sequencer memory settings */
tempreg |= pFifoCfg->FIFOMode << BITP_AFE_CMDDATACON_DATAMEMMDE; /* Data FIFO mode: stream or FIFO */
tempreg |= pFifoCfg->FIFOSize << BITP_AFE_CMDDATACON_DATA_MEM_SEL; /* Data FIFO memory size */
/* The reset memory can be used for sequencer, configure it by function AD5940_SEQCfg() */
AD5940_WriteReg(REG_AFE_CMDDATACON, tempreg);
/* FIFO Threshold */
AD5940_WriteReg(REG_AFE_DATAFIFOTHRES, pFifoCfg->FIFOThresh << BITP_AFE_DATAFIFOTHRES_HIGHTHRES);
/* FIFOCON register. Final step is to enable FIFO */
tempreg = 0;
if(pFifoCfg->FIFOEn == bTRUE)
tempreg |= BITM_AFE_FIFOCON_DATAFIFOEN; /* Enable FIFO after everything set. */
tempreg |= pFifoCfg->FIFOSrc << BITP_AFE_FIFOCON_DATAFIFOSRCSEL;
AD5940_WriteReg(REG_AFE_FIFOCON, tempreg);
}
void AD5940_SEQGenInit(uint32_t *pBuffer, uint32_t BufferSize)
{
if(BufferSize < 2) return;
SeqGenDB.BufferSize = BufferSize;
SeqGenDB.pSeqBuff = pBuffer;
SeqGenDB.pRegInfo = (SEQGenRegInfo_Type*)pBuffer + BufferSize - 1; /* Point to the last element in buffer */
SeqGenDB.SeqLen = 0;
SeqGenDB.RegCount = 0;
SeqGenDB.LastError = AD5940ERR_OK;
SeqGenDB.EngineStart = bFALSE;
}
void AD5940_SEQInfoCfg(SEQInfo_Type *pSeq)
{
switch(pSeq->SeqId)
{
case SEQID_0:
/* Configure SEQINFO register */
AD5940_WriteReg(REG_AFE_SEQ0INFO, (pSeq->SeqLen<< 16) | pSeq->SeqRamAddr);
break;
case SEQID_1:
AD5940_WriteReg(REG_AFE_SEQ1INFO, (pSeq->SeqLen<< 16) | pSeq->SeqRamAddr);
break;
case SEQID_2:
AD5940_WriteReg(REG_AFE_SEQ2INFO, (pSeq->SeqLen<< 16) | pSeq->SeqRamAddr);
break;
case SEQID_3:
AD5940_WriteReg(REG_AFE_SEQ3INFO, (pSeq->SeqLen<< 16) | pSeq->SeqRamAddr);
break;
default:
break;
}
if(pSeq->WriteSRAM == bTRUE)
{
AD5940_SEQCmdWrite(pSeq->SeqRamAddr, pSeq->pSeqCmd, pSeq->SeqLen);
}
}
void AD5940_SEQMmrTrig(uint32_t SeqId)
{
if(SeqId > SEQID_3)
return;
AD5940_WriteReg(REG_AFECON_TRIGSEQ, 1L<<SeqId);
}
void AD5940_AFEPwrBW(uint32_t AfePwr, uint32_t AfeBw)
{
//check parameters
uint32_t tempreg;
tempreg = AfePwr;
tempreg |= AfeBw << BITP_AFE_PMBW_SYSBW;
AD5940_WriteReg(REG_AFE_PMBW, tempreg);
}
void AD5940_WGFreqCtrlS(float SinFreqHz, float WGClock)
{
uint32_t freq_word;
freq_word = AD5940_WGFreqWordCal(SinFreqHz, WGClock);
AD5940_WriteReg(REG_AFE_WGFCW, freq_word);
}
void AD5940_SleepKeyCtrlS(uint32_t SlpKey)
{
AD5940_WriteReg(REG_AFE_SEQSLPLOCK, SlpKey);
}
uint32_t AD5940_FIFOGetCnt(void)
{
return AD5940_ReadReg(REG_AFE_FIFOCNTSTA) >> BITP_AFE_FIFOCNTSTA_DATAFIFOCNTSTA;
}
void AD5940_FIFORd(uint32_t *pBuffer, uint32_t uiReadCount)
{
/* Use function AD5940_SPIReadReg to read REG_AFE_DATAFIFORD is also one method. */
uint32_t i;
if(uiReadCount < 3)
{
/* This method is more efficient when readcount < 3 */
uint32_t i;
AD5940_CsClr();
AD5940_ReadWrite8B(SPICMD_SETADDR);
AD5940_ReadWrite16B(REG_AFE_DATAFIFORD);
AD5940_CsSet();
for(i=0;i<uiReadCount;i++)
{
AD5940_CsClr();
AD5940_ReadWrite8B(SPICMD_READREG);
AD5940_ReadWrite8B(0);//Write Host status/Don't care
pBuffer[i] = AD5940_ReadWrite32B(0);
AD5940_CsSet();
}
}
else
{
AD5940_CsClr();
AD5940_ReadWrite8B(SPICMD_READFIFO);
/* 6 dummy write before valid data read back */
for(i=0;i<6;i++)
AD5940_ReadWrite8B(0);
/* Continuously read DATAFIFORD register with offset 0 */
for(i=0;i<uiReadCount-2;i++)
{
pBuffer[i] = AD5940_ReadWrite32B(0); /*Offset is 0, so we always read DATAFIFORD register */
}
/* Read back last two FIFO data with none-zero offset*/
pBuffer[i++] = AD5940_ReadWrite32B(0x44444444);
pBuffer[i] = AD5940_ReadWrite32B(0x44444444);
AD5940_CsSet();
}
}
void AD5940_Initialize(void)
{
int i;
/* Write following registers with its data sequentially whenever there is a reset happened. */
const struct
{
uint16_t reg_addr;
uint32_t reg_data;
}RegTable[]=
{
{0x0908, 0x02c9},
{0x0c08, 0x206C},
{0x21F0, 0x0010},
#ifndef CHIPSEL_M355
/* This is AD5940 */
{0x0410, 0x02c9},
{0x0A28, 0x0009},
#else
/* This is ADuCM355 */
{0x0410, 0x001a},
{0x0A28, 0x0008},
#endif
{0x238c, 0x0104},
{0x0a04, 0x4859},
{0x0a04, 0xF27B},
{0x0a00, 0x8009},
{0x22F0, 0x0000},
//
{0x2230, 0xDE87A5AF},
{0x2250, 0x103F},
{0x22B0, 0x203C},
{0x2230, 0xDE87A5A0},
};
//initialize global variables
SeqGenDB.SeqLen = 0;
SeqGenDB.RegCount = 0;
SeqGenDB.LastError = AD5940ERR_OK;
SeqGenDB.EngineStart = bFALSE;
for(i=0; i<sizeof(RegTable)/sizeof(RegTable[0]); i++){
AD5940_WriteReg(RegTable[i].reg_addr, RegTable[i].reg_data);
}
}
void AD5940_HFOSC32MHzCtrl(BoolFlag Mode32MHz)
{
uint32_t RdCLKEN1;
uint32_t RdHPOSCCON;
uint32_t bit8,bit9;
RdCLKEN1 = AD5940_ReadReg(REG_AFECON_CLKEN1);
bit8 = (RdCLKEN1>>9)&0x01;
bit9 = (RdCLKEN1>>8)&0x01; /* Fix bug in silicon, bit8 and bit9 is swapped when read back. */
RdCLKEN1 = RdCLKEN1&0xff;
RdCLKEN1 |= (bit8<<8)|(bit9<<9);
AD5940_WriteReg(REG_AFECON_CLKEN1,RdCLKEN1|BITM_AFECON_CLKEN1_ACLKDIS); /* Disable ACLK during clock changing */
RdHPOSCCON = AD5940_ReadReg(REG_AFE_HPOSCCON);
if(Mode32MHz == bTRUE)
{
AD5940_WriteReg(REG_AFE_HPOSCCON,RdHPOSCCON&(~BITM_AFE_HPOSCCON_CLK32MHZEN)); /* Enable 32MHz output(bit definition-0: 32MHz, 1: 16MHz) */
while((AD5940_ReadReg(REG_ALLON_OSCCON)&BITM_ALLON_OSCCON_HFOSCOK) == 0); /* Wait for clock ready */
}
else
{
AD5940_WriteReg(REG_AFE_HPOSCCON,RdHPOSCCON|BITM_AFE_HPOSCCON_CLK32MHZEN); /* Enable 16MHz output(bit definition-0: 32MHz, 1: 16MHz) */
while((AD5940_ReadReg(REG_ALLON_OSCCON)&BITM_ALLON_OSCCON_HFOSCOK) == 0); /* Wait for clock ready */
}
AD5940_WriteReg(REG_AFECON_CLKEN1,RdCLKEN1&(~BITM_AFECON_CLKEN1_ACLKDIS)); /* Enable ACLK */
}
void AD5940_CLKCfg(CLKCfg_Type *pClkCfg)
{
uint32_t tempreg, reg_osccon;
reg_osccon = AD5940_ReadReg(REG_ALLON_OSCCON);
/* Enable clocks */
if(pClkCfg->HFXTALEn == bTRUE)
{
reg_osccon |= BITM_ALLON_OSCCON_HFXTALEN;
AD5940_WriteReg(REG_ALLON_OSCKEY,KEY_OSCCON); /* Write Key */
AD5940_WriteReg(REG_ALLON_OSCCON, reg_osccon); /* Enable HFXTAL */
while((AD5940_ReadReg(REG_ALLON_OSCCON)&BITM_ALLON_OSCCON_HFXTALOK) == 0); /* Wait for clock ready */
}
if(pClkCfg->HFOSCEn == bTRUE)
{
reg_osccon |= BITM_ALLON_OSCCON_HFOSCEN;
AD5940_WriteReg(REG_ALLON_OSCKEY,KEY_OSCCON); /* Write Key */
AD5940_WriteReg(REG_ALLON_OSCCON, reg_osccon); /* Enable HFOSC */
while((AD5940_ReadReg(REG_ALLON_OSCCON)&BITM_ALLON_OSCCON_HFOSCOK) == 0); /* Wait for clock ready */
/* Configure HFOSC mode if it's enabled. */
if(pClkCfg->HfOSC32MHzMode == bTRUE)
AD5940_HFOSC32MHzCtrl(bTRUE);
else
AD5940_HFOSC32MHzCtrl(bFALSE);
}
if(pClkCfg->LFOSCEn == bTRUE)
{
reg_osccon |= BITM_ALLON_OSCCON_LFOSCEN;
AD5940_WriteReg(REG_ALLON_OSCKEY,KEY_OSCCON); /* Write Key */
AD5940_WriteReg(REG_ALLON_OSCCON, reg_osccon); /* Enable LFOSC */
while((AD5940_ReadReg(REG_ALLON_OSCCON)&BITM_ALLON_OSCCON_LFOSCOK) == 0); /* Wait for clock ready */
}
/* Switch clocks */
/* step1. Set clock divider */
tempreg = pClkCfg->SysClkDiv&0x3f;
tempreg |= (pClkCfg->SysClkDiv&0x3f) << BITP_AFECON_CLKCON0_SYSCLKDIV;
tempreg |= (pClkCfg->ADCClkDiv&0xf) << BITP_AFECON_CLKCON0_ADCCLKDIV;
AD5940_WriteReg(REG_AFECON_CLKCON0, tempreg);
delayMicroseconds(100);
/* Step2. set clock source */
tempreg = pClkCfg->SysClkSrc;
tempreg |= pClkCfg->ADCCLkSrc << BITP_AFECON_CLKSEL_ADCCLKSEL;
AD5940_WriteReg(REG_AFECON_CLKSEL, tempreg);
/* Disable clocks */
if(pClkCfg->HFXTALEn == bFALSE)
reg_osccon &= ~BITM_ALLON_OSCCON_HFXTALEN;
if(pClkCfg->HFOSCEn == bFALSE)
reg_osccon &= ~BITM_ALLON_OSCCON_HFOSCEN;
if(pClkCfg->LFOSCEn == bFALSE)
reg_osccon &= ~BITM_ALLON_OSCCON_LFOSCEN;
AD5940_WriteReg(REG_ALLON_OSCKEY, KEY_OSCCON); /* Write Key */
AD5940_WriteReg(REG_ALLON_OSCCON, reg_osccon);
}
void AD5940_AGPIOFuncCfg(uint32_t uiCfgSet)
{
AD5940_WriteReg(REG_AGPIO_GP0CON,uiCfgSet);
}
void AD5940_AGPIOOen(uint32_t uiPinSet)
{
AD5940_WriteReg(REG_AGPIO_GP0OEN,uiPinSet);
}
void AD5940_AGPIOIen(uint32_t uiPinSet)
{
AD5940_WriteReg(REG_AGPIO_GP0IEN,uiPinSet);
}
void AD5940_AGPIOPen(uint32_t uiPinSet)
{
AD5940_WriteReg(REG_AGPIO_GP0PE,uiPinSet);
}
void AD5940_AGPIOCfg(AGPIOCfg_Type *pAgpioCfg)
{
AD5940_AGPIOFuncCfg(pAgpioCfg->FuncSet);
AD5940_AGPIOOen(pAgpioCfg->OutputEnSet);
AD5940_AGPIOIen(pAgpioCfg->InputEnSet);
AD5940_AGPIOPen(pAgpioCfg->PullEnSet);
AD5940_WriteReg(REG_AGPIO_GP0OUT, pAgpioCfg->OutVal);
}
/* ------------------------------------------------------------------------------------------------------------------------------------------------------ */
AppBIACfg_Type AppBIACfg = {
bFALSE, // bParaChanged
0, // SeqStartAddr
0, // MaxSeqLen
0, // SeqStartAddrCal
0, // MaxSeqLenCal
bFALSE, // ReDoRtiaCal
16000000.0, // SysClkFreq
32000.0, // WuptClkFreq
16000000.0, // AdcClkFreq
20.0, // BiaODR
-1, // NumOfData
10000.0, // RcalVal
AFEPWR_LP, // PwrMod
HSTIARTIA_1K, // HstiaRtiaSel
16, // CtiaSel
EXCITBUFGAIN_2, // ExcitBufGain
HSDACGAIN_1, // HsDacGain
7, // HsDacUpdateRate
800.0, // DacVoltPP
50000.0, // SinFreq
ADCPGA_1, // ADCPgaGain
ADCSINC3OSR_2, // ADCSinc3Osr
ADCSINC2OSR_22, // ADCSinc2Osr
DFTNUM_8192, // DftNum
DFTSRC_SINC3, // DftSrc
bTRUE, // HanWinEn
{ bFALSE, 10000, 150000.0, 100, bTRUE, 0 }, // SweepCfg (order: SweepEn, SweepStart, SweepStop, SweepPoints, SweepLog, SweepIndex)
4, // FifoThresh
bFALSE, // BIAInited
bFALSE, // StopRequired
0, // MeasSeqCycleCount
0 // MaxODR (set to 0 if not used)
};
/**
This function is provided for upper controllers that want to change
application parameters specially for user defined parameters.
*/
AD5940Err AppBIAGetCfg(void *pCfg)
{
if(pCfg){
*(AppBIACfg_Type**)pCfg = &AppBIACfg;
return AD5940ERR_OK;
}
return AD5940ERR_PARA;
}
AD5940Err AppBIACtrl(int32_t BcmCtrl, void *pPara)
{
switch (BcmCtrl)
{
case BIACTRL_START:
{
WUPTCfg_Type wupt_cfg;
if(AD5940_WakeUp(10) > 10) /* Wakeup AFE by read register, read 10 times at most */
return AD5940ERR_WAKEUP; /* Wakeup Failed */
if(AppBIACfg.BIAInited == 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] = (uint32_t)(AppBIACfg.WuptClkFreq/AppBIACfg.BiaODR)-2-1;
wupt_cfg.SeqxWakeupTime[SEQID_0] = 1; /* The minimum value is 1. Do not set it to zero. Set it to 1 will spend 2 32kHz clock. */
AD5940_WUPTCfg(&wupt_cfg);
AppBIACfg.FifoDataCount = 0; /* restart */
break;
}
case BIACTRL_STOPNOW:
{
if(AD5940_WakeUp(10) > 10) /* Wakeup AFE by read register, read 10 times at most */
return AD5940ERR_WAKEUP; /* Wakeup Failed */
/* Start Wupt right now */
AD5940_WUPTCtrl(bFALSE);
/* There is chance this operation will fail because sequencer could put AFE back
to hibernate mode just after waking up. Use STOPSYNC is better. */
AD5940_WUPTCtrl(bFALSE);
break;
}
case BIACTRL_STOPSYNC:
{
AppBIACfg.StopRequired = bTRUE;
break;
}
case BIACTRL_GETFREQ:
if(pPara)
{
if(AppBIACfg.SweepCfg.SweepEn == bTRUE)
*(float*)pPara = AppBIACfg.FreqofData;
else
*(float*)pPara = AppBIACfg.SinFreq;
}
break;
case BIACTRL_SHUTDOWN:
{
AppBIACtrl(BIACTRL_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 AppBIASeqCfgGen(void)
{
AD5940Err error = AD5940ERR_OK;
uint32_t const *pSeqCmd;
uint32_t SeqLen;
AFERefCfg_Type aferef_cfg;
HSLoopCfg_Type hs_loop;
LPLoopCfg_Type lp_loop;
DSPCfg_Type dsp_cfg;
float sin_freq;
/* Start sequence generator here */
AD5940_SEQGenCtrl(bTRUE);
//AD5940_AFECtrlS(AFECTRL_ALL, bFALSE); /* Init all to disable state */
aferef_cfg.HpBandgapEn = bTRUE;
aferef_cfg.Hp1V1BuffEn = bTRUE;
aferef_cfg.Hp1V8BuffEn = bTRUE;
aferef_cfg.Disc1V1Cap = bFALSE;
aferef_cfg.Disc1V8Cap = bFALSE;
aferef_cfg.Hp1V8ThemBuff = bFALSE;
aferef_cfg.Hp1V8Ilimit = bFALSE;
aferef_cfg.Lp1V1BuffEn = bFALSE;
aferef_cfg.Lp1V8BuffEn = bFALSE;
/* LP reference control - turn off them to save power*/
aferef_cfg.LpBandgapEn = bTRUE;
aferef_cfg.LpRefBufEn = bTRUE;
aferef_cfg.LpRefBoostEn = bFALSE;
AD5940_REFCfgS(&aferef_cfg);
hs_loop.HsDacCfg.ExcitBufGain = AppBIACfg.ExcitBufGain;
hs_loop.HsDacCfg.HsDacGain = AppBIACfg.HsDacGain;
hs_loop.HsDacCfg.HsDacUpdateRate = AppBIACfg.HsDacUpdateRate;
hs_loop.HsTiaCfg.DiodeClose = bFALSE;
hs_loop.HsTiaCfg.HstiaBias = HSTIABIAS_1P1;
hs_loop.HsTiaCfg.HstiaCtia = AppBIACfg.CtiaSel; /* 31pF + 2pF */
hs_loop.HsTiaCfg.HstiaDeRload = HSTIADERLOAD_OPEN;
hs_loop.HsTiaCfg.HstiaDeRtia = HSTIADERTIA_OPEN;
hs_loop.HsTiaCfg.HstiaRtiaSel = AppBIACfg.HstiaRtiaSel;
hs_loop.SWMatCfg.Dswitch = SWD_OPEN;
hs_loop.SWMatCfg.Pswitch = SWP_PL|SWP_PL2;
hs_loop.SWMatCfg.Nswitch = SWN_NL|SWN_NL2;
hs_loop.SWMatCfg.Tswitch = SWT_TRTIA;
hs_loop.WgCfg.WgType = WGTYPE_SIN;
hs_loop.WgCfg.GainCalEn = bFALSE;
hs_loop.WgCfg.OffsetCalEn = bFALSE;
if(AppBIACfg.SweepCfg.SweepEn == bTRUE)
{
AppBIACfg.SweepCfg.SweepIndex = 0;
AppBIACfg.FreqofData = AppBIACfg.SweepCfg.SweepStart;
AppBIACfg.SweepCurrFreq = AppBIACfg.SweepCfg.SweepStart;
AD5940_SweepNext(&AppBIACfg.SweepCfg, &AppBIACfg.SweepNextFreq);
sin_freq = AppBIACfg.SweepCurrFreq;
}
else
{
sin_freq = AppBIACfg.SinFreq;
AppBIACfg.FreqofData = sin_freq;
}
hs_loop.WgCfg.SinCfg.SinFreqWord = AD5940_WGFreqWordCal(sin_freq, AppBIACfg.SysClkFreq);
hs_loop.WgCfg.SinCfg.SinAmplitudeWord = (uint32_t)(AppBIACfg.DacVoltPP/800.0f*2047 + 0.5f);
hs_loop.WgCfg.SinCfg.SinOffsetWord = 0;
hs_loop.WgCfg.SinCfg.SinPhaseWord = 0;
AD5940_HSLoopCfgS(&hs_loop);
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.DacData12Bit = (uint32_t)((1100-200)/2200.0*4095);
lp_loop.LpDacCfg.DacData6Bit = 31;
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 = LPTIARF_20K;
lp_loop.LpAmpCfg.LpTiaRload = LPTIARLOAD_SHORT;
lp_loop.LpAmpCfg.LpTiaRtia = LPTIARTIA_OPEN;
lp_loop.LpAmpCfg.LpTiaSW = LPTIASW(5)|LPTIASW(6)|LPTIASW(7)|LPTIASW(8)|LPTIASW(9)|LPTIASW(12)|LPTIASW(13); /** @todo Optimization needed for new silicon */
AD5940_LPLoopCfgS(&lp_loop);
dsp_cfg.ADCBaseCfg.ADCMuxN = ADCMUXN_HSTIA_N;
dsp_cfg.ADCBaseCfg.ADCMuxP = ADCMUXP_HSTIA_P;
dsp_cfg.ADCBaseCfg.ADCPga = AppBIACfg.ADCPgaGain;
memset(&dsp_cfg.ADCDigCompCfg, 0, sizeof(dsp_cfg.ADCDigCompCfg));
dsp_cfg.ADCFilterCfg.ADCAvgNum = ADCAVGNUM_16; /* Don't care because it's disabled */
dsp_cfg.ADCFilterCfg.ADCRate = ADCRATE_800KHZ; /* Tell filter block clock rate of ADC*/
dsp_cfg.ADCFilterCfg.ADCSinc2Osr = AppBIACfg.ADCSinc2Osr;
dsp_cfg.ADCFilterCfg.ADCSinc3Osr = AppBIACfg.ADCSinc3Osr;
dsp_cfg.ADCFilterCfg.BpSinc3 = bFALSE;
dsp_cfg.ADCFilterCfg.BpNotch = bTRUE;
dsp_cfg.ADCFilterCfg.Sinc2NotchEnable = bTRUE;
dsp_cfg.DftCfg.DftNum = AppBIACfg.DftNum;
dsp_cfg.DftCfg.DftSrc = AppBIACfg.DftSrc;
dsp_cfg.DftCfg.HanWinEn = AppBIACfg.HanWinEn;
memset(&dsp_cfg.StatCfg, 0, sizeof(dsp_cfg.StatCfg)); /* Don't care about Statistic */
AD5940_DSPCfgS(&dsp_cfg);
/* Enable all of them. They are automatically turned off during hibernate mode to save power */
AD5940_AFECtrlS(AFECTRL_HPREFPWR|AFECTRL_HSTIAPWR|AFECTRL_INAMPPWR|AFECTRL_EXTBUFPWR|\
AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\
AFECTRL_SINC2NOTCH, bTRUE);
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)
{
AppBIACfg.InitSeqInfo.SeqId = SEQID_1;
AppBIACfg.InitSeqInfo.SeqRamAddr = AppBIACfg.SeqStartAddr;
AppBIACfg.InitSeqInfo.pSeqCmd = pSeqCmd;
AppBIACfg.InitSeqInfo.SeqLen = SeqLen;
/* Write command to SRAM */
AD5940_SEQCmdWrite(AppBIACfg.InitSeqInfo.SeqRamAddr, pSeqCmd, SeqLen);
}
else
return error; /* Error */
return AD5940ERR_OK;
}
static AD5940Err AppBIARtiaCal(void)
{
HSRTIACal_Type hsrtia_cal;
hsrtia_cal.AdcClkFreq = AppBIACfg.AdcClkFreq;
hsrtia_cal.ADCSinc2Osr = AppBIACfg.ADCSinc2Osr;
hsrtia_cal.ADCSinc3Osr = AppBIACfg.ADCSinc3Osr;
hsrtia_cal.bPolarResult = bFALSE; /* We need magnitude and phase here */
hsrtia_cal.DftCfg.DftNum = AppBIACfg.DftNum;
hsrtia_cal.DftCfg.DftSrc = AppBIACfg.DftSrc;
hsrtia_cal.DftCfg.HanWinEn = AppBIACfg.HanWinEn;
hsrtia_cal.fRcal= AppBIACfg.RcalVal;
hsrtia_cal.HsTiaCfg.DiodeClose = bFALSE;
hsrtia_cal.HsTiaCfg.HstiaBias = HSTIABIAS_1P1;
hsrtia_cal.HsTiaCfg.HstiaCtia = AppBIACfg.CtiaSel;
hsrtia_cal.HsTiaCfg.HstiaDeRload = HSTIADERLOAD_OPEN;
hsrtia_cal.HsTiaCfg.HstiaDeRtia = HSTIADERTIA_TODE;
hsrtia_cal.HsTiaCfg.HstiaRtiaSel = AppBIACfg.HstiaRtiaSel;
hsrtia_cal.SysClkFreq = AppBIACfg.SysClkFreq;
hsrtia_cal.fFreq = AppBIACfg.SweepCfg.SweepStart;
if(AppBIACfg.SweepCfg.SweepEn == bTRUE)
{
uint32_t i;
AppBIACfg.SweepCfg.SweepIndex = 0; /* Reset index */
for(i=0;i<AppBIACfg.SweepCfg.SweepPoints;i++)
{
AD5940_HSRtiaCal(&hsrtia_cal, AppBIACfg.RtiaCalTable[i]);
#ifdef ADI_DEBUG
ADI_Print("Freq:%.2f, RTIA: Mag:%f Ohm, Phase:%.3f\n", hsrtia_cal.fFreq, AppBIACfg.RtiaCalTable[i][0], AppBIACfg.RtiaCalTable[i][1]);
#endif
AD5940_SweepNext(&AppBIACfg.SweepCfg, &hsrtia_cal.fFreq);
}
AppBIACfg.SweepCfg.SweepIndex = 0; /* Reset index */
AppBIACfg.RtiaCurrValue[0] = AppBIACfg.RtiaCalTable[AppBIACfg.SweepCfg.SweepIndex][0];
AppBIACfg.RtiaCurrValue[1] = AppBIACfg.RtiaCalTable[AppBIACfg.SweepCfg.SweepIndex][1];
}
else
{
hsrtia_cal.fFreq = AppBIACfg.SinFreq;
AD5940_HSRtiaCal(&hsrtia_cal, AppBIACfg.RtiaCurrValue);
Serial.println(AD5940_ReadReg(REG_AFE_ADCCON), HEX);
}
return AD5940ERR_OK;
}
static AD5940Err Measure(void)
{
SWMatrixCfg_Type sw_cfg;
sw_cfg.Dswitch = SWD_CE0;
sw_cfg.Pswitch = SWP_CE0;
sw_cfg.Nswitch = SWN_AIN1;
sw_cfg.Tswitch = SWT_AIN0 | SWT_TRTIA;//SWT_AIN1|SWT_TRTIA;
AD5940_SWMatrixCfgS(&sw_cfg);
uint32_t WaitClks;
ClksCalInfo_Type clks_cal;
clks_cal.DataType = DATATYPE_DFT;
clks_cal.DftSrc = AppBIACfg.DftSrc;
clks_cal.DataCount = 1L<<(AppBIACfg.DftNum+2); /* 2^(DFTNUMBER+2) */
clks_cal.ADCSinc2Osr = AppBIACfg.ADCSinc2Osr;
clks_cal.ADCSinc3Osr = AppBIACfg.ADCSinc3Osr;
clks_cal.ADCAvgNum = 0;
clks_cal.RatioSys2AdcClk = AppBIACfg.SysClkFreq/AppBIACfg.AdcClkFreq;
AD5940_ClksCalculate(&clks_cal, &WaitClks);
//AD5940_AGPIOClr(AGPIO_Pin2);
AD5940_ADCMuxCfgS(ADCMUXP_HSTIA_P, ADCMUXN_HSTIA_N);
AD5940_AFECtrlS(AFECTRL_WG|AFECTRL_ADCPWR, bTRUE); /* Enable Waveform generator, ADC power */
delayMicroseconds(16*500);
AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT, bTRUE); /* Start ADC convert and DFT */
delayMicroseconds(WaitClks / 10); /* wait for first data ready */
//AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT|AFECTRL_WG|AFECTRL_ADCPWR, bFALSE); /* Stop ADC convert and DFT */
AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT|AFECTRL_ADCPWR, bFALSE); /* Stop ADC convert and DFT */
AD5940_ADCMuxCfgS(ADCMUXP_AIN3, ADCMUXN_AIN2);
//AD5940_AFECtrlS(AFECTRL_WG|AFECTRL_ADCPWR, bTRUE); /* Enable Waveform generator, ADC power */
AD5940_AFECtrlS(AFECTRL_ADCPWR, bTRUE); /* Enable Waveform generator, ADC power */
delayMicroseconds(16*500); //delay for signal settling DFT_WAIT
AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT, bTRUE); /* Start ADC convert and DFT */
delayMicroseconds(WaitClks / 10); /* wait for first data ready */
//AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT|AFECTRL_WG|AFECTRL_ADCPWR, bFALSE); /* Stop ADC convert and DFT */
AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT|AFECTRL_ADCPWR, bFALSE); /* Stop ADC convert and DFT */
sw_cfg.Dswitch = SWD_OPEN;
sw_cfg.Pswitch = SWP_PL|SWP_PL2;
sw_cfg.Nswitch = SWN_NL|SWN_NL2;
sw_cfg.Tswitch = SWT_TRTIA;
AD5940_SWMatrixCfgS(&sw_cfg); /* Float switches */
//AD5940_AGPIOSet(AGPIO_Pin2);
return AD5940ERR_OK;
}
/* This function provide application initialize. */
AD5940Err AppBIAInit(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((AppBIACfg.ReDoRtiaCal == bTRUE) || \
AppBIACfg.BIAInited == bFALSE) /* Do calibration on the first initializaion */
{
AppBIARtiaCal();
AppBIACfg.ReDoRtiaCal = bFALSE;
}
// Reconfigure FIFO
AD5940_FIFOCtrlS(FIFOSRC_DFT, bFALSE); // Disable FIFO firstly
fifo_cfg.FIFOEn = bTRUE;
fifo_cfg.FIFOMode = FIFOMODE_FIFO;
fifo_cfg.FIFOSize = FIFOSIZE_4KB; // 4kB for FIFO, The reset 2kB for sequencer
fifo_cfg.FIFOSrc = FIFOSRC_DFT;
fifo_cfg.FIFOThresh = AppBIACfg.FifoThresh; // DFT result. One pair for RCAL, another for Rz. One DFT result have real part and imaginary part
AD5940_FIFOCfg(&fifo_cfg);
AD5940_INTCClrFlag(AFEINTSRC_ALLINT);
// Start sequence generator
// Initialize sequencer generator
if((AppBIACfg.BIAInited == bFALSE)||\
(AppBIACfg.bParaChanged == bTRUE))
{
if(pBuffer == 0) return AD5940ERR_PARA;
if(BufferSize == 0) return AD5940ERR_PARA;
AD5940_SEQGenInit(pBuffer, BufferSize);
// Generate initialize sequence
error = AppBIASeqCfgGen(); // Application initialization sequence using either MCU or sequencer
if(error != AD5940ERR_OK) return error;
AppBIACfg.bParaChanged = bFALSE; // Clear this flag as we already implemented the new configuration
}
// Initialization sequencer
AppBIACfg.InitSeqInfo.WriteSRAM = bFALSE;
AD5940_SEQInfoCfg(&AppBIACfg.InitSeqInfo);
seq_cfg.SeqEnable = bTRUE;
AD5940_SEQCfg(&seq_cfg); //Enable sequencer
AD5940_SEQMmrTrig(AppBIACfg.InitSeqInfo.SeqId);
while(AD5940_INTCTestFlag(AFEINTC_1, AFEINTSRC_ENDSEQ) == bFALSE);
while(AD5940_INTCTestFlag(AFEINTC_0, AFEINTSRC_DATAFIFOTHRESH) == bFALSE)
{
Measure();
}
AD5940_AFEPwrBW(AppBIACfg.PwrMod, AFEBW_250KHZ);
AD5940_WriteReg(REG_AFE_SWMUX, 1<<3);
AppBIACfg.BIAInited = bTRUE;
return AD5940ERR_OK;
}
/* Modify registers when AFE wakeup */
static AD5940Err AppBIARegModify(int32_t * const pData, uint32_t *pDataCount)
{
if(AppBIACfg.NumOfData > 0)
{
AppBIACfg.FifoDataCount += *pDataCount/4;
if(AppBIACfg.FifoDataCount >= AppBIACfg.NumOfData)
{
AD5940_WUPTCtrl(bFALSE);
return AD5940ERR_OK;
}
}
if(AppBIACfg.StopRequired == bTRUE)
{
AD5940_WUPTCtrl(bFALSE);
return AD5940ERR_OK;
}
if(AppBIACfg.SweepCfg.SweepEn) /* Need to set new frequency and set power mode */
{
AD5940_WGFreqCtrlS(AppBIACfg.SweepNextFreq, AppBIACfg.SysClkFreq);
}
return AD5940ERR_OK;
}
/* Depending on the data type, do appropriate data pre-process before return back to controller */
static AD5940Err AppBIADataProcess(int32_t * const pData, uint32_t *pDataCount)
{
uint32_t DataCount = *pDataCount;
uint32_t ImpResCount = DataCount/4;
fImpPol_Type * const pOut = (fImpPol_Type*)pData;
iImpCar_Type * pSrcData = (iImpCar_Type*)pData;
*pDataCount = 0;
DataCount = (DataCount/4)*4;/* We expect RCAL data together with Rz data. One DFT result has two data in FIFO, real part and imaginary part. */
/* Convert DFT result to int32_t type */
for(uint32_t i=0; i<DataCount; i++)
{
pData[i] &= 0x3ffff; /* @todo option to check ECC */
if(pData[i]&(1<<17)) /* Bit17 is sign bit */
{
pData[i] |= 0xfffc0000; /* Data is 18bit in two's complement, bit17 is the sign bit */
}
}
for(uint32_t i=0; i<ImpResCount; i++)
{
iImpCar_Type *pDftVolt, *pDftCurr;
pDftCurr = pSrcData++;
pDftVolt = pSrcData++;
float VoltMag,VoltPhase;
float CurrMag, CurrPhase;
VoltMag = sqrt((float)pDftVolt->Real*pDftVolt->Real+(float)pDftVolt->Image*pDftVolt->Image);
VoltPhase = atan2(-pDftVolt->Image,pDftVolt->Real);
CurrMag = sqrt((float)pDftCurr->Real*pDftCurr->Real+(float)pDftCurr->Image*pDftCurr->Image);
CurrPhase = atan2(-pDftCurr->Image,pDftCurr->Real);
VoltMag = VoltMag/CurrMag*AppBIACfg.RtiaCurrValue[0];
VoltPhase = VoltPhase - CurrPhase + AppBIACfg.RtiaCurrValue[1];
pOut[i].Magnitude = VoltMag;
pOut[i].Phase = VoltPhase;
}
*pDataCount = ImpResCount;
/* Calculate next frequency point */
if(AppBIACfg.SweepCfg.SweepEn == bTRUE)
{
AppBIACfg.FreqofData = AppBIACfg.SweepCurrFreq;
AppBIACfg.SweepCurrFreq = AppBIACfg.SweepNextFreq;
AppBIACfg.RtiaCurrValue[0] = AppBIACfg.RtiaCalTable[AppBIACfg.SweepCfg.SweepIndex][0];
AppBIACfg.RtiaCurrValue[1] = AppBIACfg.RtiaCalTable[AppBIACfg.SweepCfg.SweepIndex][1];
AD5940_SweepNext(&AppBIACfg.SweepCfg, &AppBIACfg.SweepNextFreq);
}
return AD5940ERR_OK;
}
AD5940Err AppBIAISR(void *pBuff, uint32_t *pCount)
{
uint32_t BuffCount;
uint32_t FifoCnt;
BuffCount = *pCount;
if(AppBIACfg.BIAInited == bFALSE)
return AD5940ERR_APPERROR;
// if(AD5940_WakeUp(10) > 10) /* Wakeup AFE by read register, read 10 times at most */
// return AD5940ERR_WAKEUP; /* Wakeup Failed */
AD5940_SleepKeyCtrlS(SLPKEY_LOCK); /* Don't enter hibernate */
*pCount = 0;
if(AD5940_INTCTestFlag(AFEINTC_0, AFEINTSRC_DATAFIFOTHRESH) == bTRUE)
{
/* Now there should be 4 data in FIFO */
FifoCnt = (AD5940_FIFOGetCnt()/4)*4;
if(FifoCnt > BuffCount)
{
///@todo buffer is limited.
}
AD5940_FIFORd((uint32_t *)pBuff, FifoCnt);
AD5940_INTCClrFlag(AFEINTSRC_DATAFIFOTHRESH);
AppBIARegModify((int32_t*)pBuff, &FifoCnt); /* If there is need to do AFE re-configure, do it here when AFE is in active state */
//AD5940_EnterSleepS(); /* Manually put AFE back to hibernate mode. */
AD5940_SleepKeyCtrlS(SLPKEY_UNLOCK); /* Allow AFE to enter hibernate mode */
/* Process data */
AppBIADataProcess((int32_t*)pBuff,&FifoCnt);
*pCount = FifoCnt;
while(AD5940_INTCTestFlag(AFEINTC_0, AFEINTSRC_DATAFIFOTHRESH) == bFALSE)
{
Measure();
}
return 0;
}
return 0;
}
/* It's your choice here how to do with the data. Here is just an example to print them to UART */
int32_t BIAShowResult(uint32_t *pData, uint32_t DataCount)
{
float freq;
int i = 0;
fImpPol_Type *pImp = (fImpPol_Type*)pData;
AppBIACtrl(BIACTRL_GETFREQ, &freq);
Serial.print("Freq: ");
Serial.println(freq);
/*Process data*/
for(i=0;i<DataCount;i++)
{
Serial.print("RzMag: ");
Serial.println(pImp[i].Magnitude);
Serial.print("RzPhase: ");
Serial.println(pImp[i].Phase*180/MATH_PI);
}
return 0;
}
/* Initialize AD5940 basic blocks like clock */
static int32_t AD5940PlatformCfg(void)
{
CLKCfg_Type clk_cfg;
FIFOCfg_Type fifo_cfg;
AGPIOCfg_Type gpio_cfg;
/* Use hardware reset */
/* Platform configuration */
AD5940_Initialize();
/* Step1. Configure clock */
clk_cfg.ADCClkDiv = ADCCLKDIV_1;
clk_cfg.ADCCLkSrc = ADCCLKSRC_HFOSC;
clk_cfg.SysClkDiv = SYSCLKDIV_1;
clk_cfg.SysClkSrc = SYSCLKSRC_HFOSC;
clk_cfg.HfOSC32MHzMode = bFALSE;
clk_cfg.HFOSCEn = bTRUE;
clk_cfg.HFXTALEn = bFALSE;
clk_cfg.LFOSCEn = bTRUE;
AD5940_CLKCfg(&clk_cfg);
/* Step2. Configure FIFO and Sequencer*/
fifo_cfg.FIFOEn = bFALSE;
fifo_cfg.FIFOMode = FIFOMODE_FIFO;
fifo_cfg.FIFOSize = FIFOSIZE_4KB; /* 4kB for FIFO, The reset 2kB for sequencer */
fifo_cfg.FIFOSrc = FIFOSRC_DFT;
fifo_cfg.FIFOThresh = 2;//AppBIACfg.FifoThresh; /* DFT result. One pair for RCAL, another for Rz. One DFT result have real part and imaginary part */
AD5940_FIFOCfg(&fifo_cfg); /* Disable to reset FIFO. */
fifo_cfg.FIFOEn = bTRUE;
AD5940_FIFOCfg(&fifo_cfg); /* Enable FIFO here */
/* Step3. Interrupt controller */
AD5940_INTCCfg(AFEINTC_1, AFEINTSRC_ALLINT, bTRUE); /* Enable all interrupt in Interrupt Controller 1, so we can check INTC flags */
AD5940_INTCCfg(AFEINTC_0, AFEINTSRC_DATAFIFOTHRESH, bTRUE); /* Interrupt Controller 0 will control GP0 to generate interrupt to MCU */
AD5940_INTCClrFlag(AFEINTSRC_ALLINT);
/* Step4: Reconfigure GPIO */
gpio_cfg.FuncSet = GP0_INT | GP1_GPIO;//GP6_SYNC|GP5_SYNC|GP4_SYNC|GP2_TRIG|GP1_SYNC|GP0_INT;
gpio_cfg.InputEnSet = 0;//AGPIO_Pin2;
gpio_cfg.OutputEnSet = AGPIO_Pin0 | AGPIO_Pin1; // AGPIO_Pin0|AGPIO_Pin1|AGPIO_Pin4|AGPIO_Pin5|AGPIO_Pin6;
gpio_cfg.OutVal = AGPIO_Pin0 | AGPIO_Pin1;
gpio_cfg.PullEnSet = AGPIO_Pin0 | AGPIO_Pin1;
AD5940_AGPIOCfg(&gpio_cfg);
AD5940_SleepKeyCtrlS(SLPKEY_UNLOCK); /* Allow AFE to enter sleep mode. */
return 0;
}
/* !!Change the application parameters here if you want to change it to none-default value */
void AD5940BIAStructInit(void)
{
AppBIACfg_Type *pBIACfg;
AppBIAGetCfg(&pBIACfg);
pBIACfg->SeqStartAddr = 0;
pBIACfg->MaxSeqLen = 512; /** @todo add checker in function */
pBIACfg->RcalVal = 1000.0;
pBIACfg->DftNum = DFTNUM_8192;
pBIACfg->NumOfData = -1; /* Never stop until you stop it manually by AppBIACtrl() function */
pBIACfg->BiaODR = 20; /* ODR(Sample Rate) 20Hz */
pBIACfg->FifoThresh = 2; /* 4 */
pBIACfg->ADCSinc3Osr = ADCSINC3OSR_2;
pBIACfg->DacVoltPP = 300.0; //800.0
pBIACfg->SinFreq = 10000.0; /* 10000Hz */
pBIACfg->SweepCfg.SweepEn = bFALSE;
pBIACfg->SweepCfg.SweepStart = 10000;
pBIACfg->SweepCfg.SweepStop = 80000.0;
pBIACfg->SweepCfg.SweepPoints = 20;
pBIACfg->SweepCfg.SweepLog = bTRUE;
pBIACfg->SweepCfg.SweepIndex = 0;
}
void AD5940_Main(void)
{
static uint32_t IntCount;
static uint32_t count;
uint32_t temp;
AD5940PlatformCfg();
AD5940BIAStructInit(); /* Configure your parameters in this function */
AppBIAInit(AppBuff, APPBUFF_SIZE); // Initialize BIA application. Provide a buffer, which is used to store sequencer commands
AppBIACtrl(BIACTRL_START, 0); // Control BIA measurement to start. Second parameter has no meaning with this command.
while(1)
{
// Check if interrupt flag which will be set when interrupt occurred.
if(AD5940_INTCTestFlag(AFEINTC_0, AFEINTSRC_DATAFIFOTHRESH) == bTRUE)
{
IntCount++;
//AD5940_ClrMCUIntFlag(); // Clear this flag
temp = APPBUFF_SIZE;
AppBIAISR(AppBuff, &temp); // Deal with it and provide a buffer to store data we got
BIAShowResult(AppBuff, temp); //Show the results to UART
}
}
}
void setup() {
SPI.begin();
Wire.begin();
Wire.setClock(100000);
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(CS_PIN, OUTPUT);
Serial.println("");
struct electrode_combo sw = {0, 20, 15, 7};
setMuxSwitch(sw, 24); // Use all 16 electrodes
digitalWrite(CS_PIN, HIGH); // Không chọn thiết bị ngoại vi ban đầu
Serial.println("");
AD5940_Main();
}
void loop() {
}
