diff --git a/Impedance.c b/Impedance.c index e92b0cd..a3a66f2 100644 --- a/Impedance.c +++ b/Impedance.c @@ -1,4 +1,4 @@ -// Impedance.c +// File: Impedance.c #include "ad5940.h" #include #include "string.h" @@ -295,7 +295,8 @@ static AD5940Err AppIMPSeqMeasureGen(void) AFECTRL_WG|AFECTRL_DACREFPWR|AFECTRL_HSDACPWR|\ AFECTRL_SINC2NOTCH, bTRUE); AD5940_AFECtrlS(AFECTRL_WG|AFECTRL_ADCPWR, bTRUE); - AD5940_SEQGenInsert(SEQ_WAIT(16*10)); // Settling + // Increased settling time to 2000us (16*2000) to ensure stability + AD5940_SEQGenInsert(SEQ_WAIT(16*2000)); AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT, bTRUE); AD5940_SEQGenFetchSeq(NULL, &AppIMPCfg.SeqWaitAddr[0]); @@ -317,7 +318,8 @@ static AD5940Err AppIMPSeqMeasureGen(void) AD5940_ADCMuxCfgS(ADCMUXP_HSTIA_P, ADCMUXN_HSTIA_N); AD5940_AFECtrlS(AFECTRL_ADCPWR|AFECTRL_WG, bTRUE); - AD5940_SEQGenInsert(SEQ_WAIT(16*10)); + // Increased settling time to 2000us + AD5940_SEQGenInsert(SEQ_WAIT(16*2000)); AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT, bTRUE); AD5940_SEQGenFetchSeq(NULL, &AppIMPCfg.SeqWaitAddr[1]); @@ -335,7 +337,8 @@ static AD5940Err AppIMPSeqMeasureGen(void) AD5940_ADCMuxCfgS(ADCMUXP_AIN2, ADCMUXN_AIN3); AD5940_AFECtrlS(AFECTRL_ADCPWR|AFECTRL_WG, bTRUE); - AD5940_SEQGenInsert(SEQ_WAIT(16*10)); + // Increased settling time to 2000us + AD5940_SEQGenInsert(SEQ_WAIT(16*2000)); AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT, bTRUE); AD5940_SEQGenFetchSeq(NULL, &AppIMPCfg.SeqWaitAddr[2]); @@ -370,7 +373,6 @@ AD5940Err AppIMPCheckFreq(float freq) { ADCFilterCfg_Type filter_cfg; DFTCfg_Type dft_cfg; - // HSDACCfg_Type hsdac_cfg; // Removed to prevent override uint32_t WaitClks; ClksCalInfo_Type clks_cal; FreqParams_Type freq_params; @@ -379,64 +381,24 @@ AD5940Err AppIMPCheckFreq(float freq) freq_params = AD5940_GetFreqParameters(freq); - // CRITICAL FIX: Removed HSDAC and HSRTIA overrides. - // The configuration set in AppIMPSeqCfgGen (based on user config) should persist. - // Overriding HSTIARTIA_5K here while RtiaVal remains 200 causes massive math errors. - - if(freq < 0.51) + // Only switch modes if necessary to avoid glitching the sequencer + if(freq < 80000) { - // hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_2; - // hsdac_cfg.HsDacGain = HSDACGAIN_1; - // hsdac_cfg.HsDacUpdateRate = 0x1B; - // AD5940_HSDacCfgS(&hsdac_cfg); - // AD5940_HSRTIACfgS(HSTIARTIA_40K); - filter_cfg.ADCRate = ADCRATE_800KHZ; - AppIMPCfg.AdcClkFreq = 16e6; - AD5940_HPModeEn(bFALSE); + if (AppIMPCfg.SysClkFreq != 16000000.0) { + filter_cfg.ADCRate = ADCRATE_800KHZ; + AppIMPCfg.AdcClkFreq = 16e6; + AppIMPCfg.SysClkFreq = 16000000.0; + AD5940_HPModeEn(bFALSE); + } } - else if(freq < 5 ) + else { - // hsdac_cfg.ExcitBufGain = EXCITBUFGAIN_2; - // hsdac_cfg.HsDacGain = HSDACGAIN_1; - // hsdac_cfg.HsDacUpdateRate = 0x1B; - // AD5940_HSDacCfgS(&hsdac_cfg); - // AD5940_HSRTIACfgS(HSTIARTIA_40K); - filter_cfg.ADCRate = ADCRATE_800KHZ; - AppIMPCfg.AdcClkFreq = 16e6; - AD5940_HPModeEn(bFALSE); - } - else if(freq < 450) - { - // hsdac_cfg.ExcitBufGain = AppIMPCfg.ExcitBufGain; - // hsdac_cfg.HsDacGain = AppIMPCfg.HsDacGain; - // hsdac_cfg.HsDacUpdateRate = 0x1B; - // AD5940_HSDacCfgS(&hsdac_cfg); - // AD5940_HSRTIACfgS(HSTIARTIA_5K); - filter_cfg.ADCRate = ADCRATE_800KHZ; - AppIMPCfg.AdcClkFreq = 16e6; - AD5940_HPModeEn(bFALSE); - } - else if(freq<80000) - { - // hsdac_cfg.ExcitBufGain = AppIMPCfg.ExcitBufGain; - // hsdac_cfg.HsDacGain = AppIMPCfg.HsDacGain; - // hsdac_cfg.HsDacUpdateRate = 0x1B; - // AD5940_HSDacCfgS(&hsdac_cfg); - // AD5940_HSRTIACfgS(HSTIARTIA_5K); - filter_cfg.ADCRate = ADCRATE_800KHZ; - AppIMPCfg.AdcClkFreq = 16e6; - AD5940_HPModeEn(bFALSE); - } - if(freq >= 80000) - { - // hsdac_cfg.ExcitBufGain = AppIMPCfg.ExcitBufGain; - // hsdac_cfg.HsDacGain = AppIMPCfg.HsDacGain; - // hsdac_cfg.HsDacUpdateRate = 0x07; - // AD5940_HSDacCfgS(&hsdac_cfg); - // AD5940_HSRTIACfgS(HSTIARTIA_5K); - filter_cfg.ADCRate = ADCRATE_1P6MHZ; - AppIMPCfg.AdcClkFreq = 32e6; - AD5940_HPModeEn(bTRUE); + if (AppIMPCfg.SysClkFreq != 32000000.0) { + filter_cfg.ADCRate = ADCRATE_1P6MHZ; + AppIMPCfg.AdcClkFreq = 32e6; + AppIMPCfg.SysClkFreq = 32000000.0; + AD5940_HPModeEn(bTRUE); + } } filter_cfg.ADCAvgNum = ADCAVGNUM_16; @@ -463,8 +425,15 @@ AD5940Err AppIMPCheckFreq(float freq) // Update Wait Times for all 3 measurements for (int i = 0; i < 3; i++) { SRAMAddr = AppIMPCfg.MeasureSeqInfo.SeqRamAddr + AppIMPCfg.SeqWaitAddr[i]; - SeqCmdBuff[0] = SEQ_WAIT(WaitClks/2); - SeqCmdBuff[1] = SEQ_WAIT(WaitClks/2); + + // CRITICAL FIX: Double the wait time for High Power Mode (>=80kHz) + uint32_t finalWait = WaitClks/2; + if (freq >= 80000) { + finalWait *= 2; + } + + SeqCmdBuff[0] = SEQ_WAIT(finalWait); + SeqCmdBuff[1] = SEQ_WAIT(finalWait); AD5940_SEQCmdWrite(SRAMAddr, SeqCmdBuff, 2); } @@ -551,6 +520,7 @@ int32_t AppIMPRegModify(int32_t * const pData, uint32_t *pDataCount) if(AppIMPCfg.FifoDataCount >= AppIMPCfg.NumOfData) { AD5940_WUPTCtrl(bFALSE); + AD5940_SEQCtrlS(bFALSE); // Added safety return AD5940ERR_OK; } } @@ -662,7 +632,12 @@ int32_t AppIMPISR(void *pBuff, uint32_t *pCount) } AD5940_FIFORd((uint32_t *)pBuff, FifoCnt); AD5940_INTCClrFlag(AFEINTSRC_DATAFIFOTHRESH); - AppIMPRegModify(pBuff, &FifoCnt); + + // Check if sweep is done + if (AppIMPRegModify(pBuff, &FifoCnt) != AD5940ERR_OK) { + // If sweep is done, we might want to signal main loop + } + AD5940_SleepKeyCtrlS(SLPKEY_UNLOCK); AppIMPDataProcess((int32_t*)pBuff, &FifoCnt); *pCount = FifoCnt; diff --git a/host/src/GraphWidget.cpp b/host/src/GraphWidget.cpp index b060aac..c85a31d 100644 --- a/host/src/GraphWidget.cpp +++ b/host/src/GraphWidget.cpp @@ -1,3 +1,4 @@ +// File: host/src/GraphWidget.cpp #include "GraphWidget.h" #include #include @@ -13,26 +14,39 @@ GraphWidget::GraphWidget(QWidget *parent) : QWidget(parent) { // Setup Graphs graph1 = plot->addGraph(); graph2 = plot->addGraph(plot->xAxis, plot->yAxis2); + graph3 = plot->addGraph(plot->xAxis, plot->yAxis2); // Hilbert Trace - // Style Graph 1 (Primary - Left Axis) + // Style Graph 1 (Real - Blue) QPen pen1(Qt::blue); pen1.setWidth(2); graph1->setPen(pen1); graph1->setLineStyle(QCPGraph::lsLine); graph1->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, 3)); - graph1->setName("Primary"); + graph1->setName("Real"); - // Style Graph 2 (Secondary - Right Axis) + // Style Graph 2 (Imaginary - Red) QPen pen2(Qt::red); pen2.setWidth(2); graph2->setPen(pen2); graph2->setLineStyle(QCPGraph::lsLine); graph2->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssTriangle, 3)); - graph2->setName("Secondary"); + graph2->setName("Imaginary"); + + // Style Graph 3 (Hilbert - Green Dashed) + QPen pen3(Qt::green); + pen3.setWidth(2); + pen3.setStyle(Qt::DashLine); + graph3->setPen(pen3); + graph3->setLineStyle(QCPGraph::lsLine); + graph3->setName("Hilbert (Analytic)"); // Enable Right Axis plot->yAxis2->setVisible(true); plot->yAxis2->setTickLabels(true); + + // Link Axes for Zooming + connect(plot->yAxis, SIGNAL(rangeChanged(QCPRange)), plot->yAxis2, SLOT(setRange(QCPRange))); + connect(plot->yAxis2, SIGNAL(rangeChanged(QCPRange)), plot->yAxis, SLOT(setRange(QCPRange))); // Interactions plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); @@ -45,37 +59,7 @@ GraphWidget::GraphWidget(QWidget *parent) : QWidget(parent) { plot->legend->setBrush(QBrush(QColor(255, 255, 255, 230))); // Default Mode - configureBodePlot(); -} - -void GraphWidget::configureBodePlot() { - clear(); - - // X Axis: Frequency (Log) - plot->xAxis->setLabel("Frequency (Hz)"); - plot->xAxis->setScaleType(QCPAxis::stLogarithmic); - QSharedPointer logTicker(new QCPAxisTickerLog); - plot->xAxis->setTicker(logTicker); - plot->xAxis->setNumberFormat("eb"); - - // Y Axis 1: Impedance (Log) - plot->yAxis->setLabel("Impedance (Ohms)"); - plot->yAxis->setScaleType(QCPAxis::stLogarithmic); - plot->yAxis->setTicker(logTicker); - plot->yAxis->setNumberFormat("eb"); - - // Y Axis 2: Phase (Linear) - plot->yAxis2->setLabel("Phase (Degrees)"); - plot->yAxis2->setScaleType(QCPAxis::stLinear); - QSharedPointer linTicker(new QCPAxisTicker); - plot->yAxis2->setTicker(linTicker); - plot->yAxis2->setNumberFormat("f"); - plot->yAxis2->setRange(-180, 180); - - graph1->setName("Impedance"); - graph2->setName("Phase"); - - plot->replot(); + configureRawPlot(); } void GraphWidget::configureRawPlot() { @@ -86,6 +70,7 @@ void GraphWidget::configureRawPlot() { plot->xAxis->setScaleType(QCPAxis::stLogarithmic); QSharedPointer logTicker(new QCPAxisTickerLog); plot->xAxis->setTicker(logTicker); + plot->xAxis->setNumberFormat("eb"); // Y Axis 1: Real (Linear) plot->yAxis->setLabel("Real (Ohms)"); @@ -99,50 +84,82 @@ void GraphWidget::configureRawPlot() { plot->yAxis2->setScaleType(QCPAxis::stLinear); plot->yAxis2->setTicker(linTicker); plot->yAxis2->setNumberFormat("f"); + plot->yAxis2->setVisible(true); graph1->setName("Real"); graph2->setName("Imaginary"); + graph2->setVisible(true); + graph3->setVisible(true); plot->replot(); } -void GraphWidget::addData(double freq, double val1, double val2) { - // 1. Validate X-Axis (Frequency) - // If Log scale, Frequency must be > 0. - if (plot->xAxis->scaleType() == QCPAxis::stLogarithmic && freq <= 0) { - return; - } - - // 2. Validate Y-Axis 1 (Impedance/Real) - // If Log scale (Impedance), value must be > 0. - if (plot->yAxis->scaleType() == QCPAxis::stLogarithmic) { - // If we have a zero/negative impedance in log mode, skip it. - // Clamping to 1e-12 causes massive axis scaling issues (squished plots). - if (val1 <= 1e-7) { - val1 = std::numeric_limits::quiet_NaN(); - } - } - - // 3. Add Data - // QCustomPlot handles NaN by creating a line gap, which is visually correct for missing/bad data. - if (!std::isnan(val1)) { - graph1->addData(freq, val1); - } +void GraphWidget::configureNyquistPlot() { + clear(); - // Graph 2 (Phase/Imag) is usually Linear. - graph2->addData(freq, val2); + // X Axis: Real (Z') + plot->xAxis->setLabel("Real (Z')"); + plot->xAxis->setScaleType(QCPAxis::stLinear); + QSharedPointer linTicker(new QCPAxisTicker); + plot->xAxis->setTicker(linTicker); + plot->xAxis->setNumberFormat("f"); + + // Y Axis 1: -Imaginary (-Z'') + plot->yAxis->setLabel("-Imaginary (-Z'')"); + plot->yAxis->setScaleType(QCPAxis::stLinear); + plot->yAxis->setTicker(linTicker); + plot->yAxis->setNumberFormat("f"); - // 4. Auto-scale - // We remove 'true' (onlyEnlarge). We want the axes to shrink - // if we zoom in or if the data range stabilizes. + // Disable Secondary Axis for Nyquist + plot->yAxis2->setVisible(false); + graph2->setVisible(false); + graph3->setVisible(false); + + graph1->setName("Nyquist"); + graph1->setLineStyle(QCPGraph::lsLine); + graph1->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, 4)); + + plot->replot(); +} + +void GraphWidget::addData(double x, double val1, double val2) { + // Mode Detection based on Axis Labels (Simple state check) + bool isNyquist = (plot->xAxis->label() == "Real (Z')"); + + if (isNyquist) { + // For Nyquist: x = Real, val1 = Imaginary + // We plot Real vs -Imaginary + graph1->addData(x, -val1); + } else { + // Raw Plot: x = Freq, val1 = Real, val2 = Imag + if (plot->xAxis->scaleType() == QCPAxis::stLogarithmic && x <= 0) return; + + graph1->addData(x, val1); + graph2->addData(x, val2); + } + + // Auto-scale graph1->rescaleAxes(false); - graph2->rescaleAxes(false); + if (!isNyquist) { + graph2->rescaleAxes(false); + graph3->rescaleAxes(false); + } plot->replot(); } +void GraphWidget::addHilbertData(const QVector& freq, const QVector& hilbertImag) { + // Only valid for Raw Plot + if (plot->xAxis->label() != "Frequency (Hz)") return; + + graph3->setData(freq, hilbertImag); + graph3->rescaleAxes(false); + plot->replot(); +} + void GraphWidget::clear() { graph1->data()->clear(); graph2->data()->clear(); + graph3->data()->clear(); plot->replot(); } \ No newline at end of file diff --git a/host/src/GraphWidget.h b/host/src/GraphWidget.h index 210605e..16ebc64 100644 --- a/host/src/GraphWidget.h +++ b/host/src/GraphWidget.h @@ -1,3 +1,4 @@ +// File: host/src/GraphWidget.h #pragma once #include @@ -12,15 +13,17 @@ public: // Data Handling void addData(double freq, double val1, double val2); + void addHilbertData(const QVector& freq, const QVector& hilbertImag); void clear(); // View Configurations - void configureBodePlot(); void configureRawPlot(); + void configureNyquistPlot(); private: QVBoxLayout *layout; QCustomPlot *plot; - QCPGraph *graph1; - QCPGraph *graph2; + QCPGraph *graph1; // Real + QCPGraph *graph2; // Imaginary + QCPGraph *graph3; // Hilbert (Analytic Imaginary) }; \ No newline at end of file diff --git a/host/src/MainWindow.cpp b/host/src/MainWindow.cpp index 9326420..bf07a89 100644 --- a/host/src/MainWindow.cpp +++ b/host/src/MainWindow.cpp @@ -1,4 +1,4 @@ -// host/src/MainWindow.cpp +// File: host/src/MainWindow.cpp #include "MainWindow.h" #include #include @@ -10,6 +10,44 @@ #include #include #include +#include +#include + +// Simple FFT Implementation (Cooley-Tukey) +// Note: Size must be power of 2 +void fft(std::vector>& a) { + int n = a.size(); + if (n <= 1) return; + + std::vector> a0(n / 2), a1(n / 2); + for (int i = 0; i < n / 2; i++) { + a0[i] = a[2 * i]; + a1[i] = a[2 * i + 1]; + } + fft(a0); + fft(a1); + + double ang = 2 * M_PI / n; + std::complex w(1), wn(cos(ang), sin(ang)); + for (int i = 0; i < n / 2; i++) { + a[i] = a0[i] + w * a1[i]; + a[i + n / 2] = a0[i] - w * a1[i]; + w *= wn; + } +} + +void ifft(std::vector>& a) { + int n = a.size(); + // Conjugate + for (int i = 0; i < n; i++) a[i] = std::conj(a[i]); + // Forward FFT + fft(a); + // Conjugate again and scale + for (int i = 0; i < n; i++) { + a[i] = std::conj(a[i]); + a[i] /= n; + } +} MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { serial = new QSerialPort(this); @@ -37,13 +75,16 @@ void MainWindow::setupUi() { // Tab Widget for Graphs tabWidget = new QTabWidget(this); - finalGraph = new GraphWidget(this); - finalGraph->configureBodePlot(); + rawGraph = new GraphWidget(this); rawGraph->configureRawPlot(); + + nyquistGraph = new GraphWidget(this); + nyquistGraph->configureNyquistPlot(); - tabWidget->addTab(finalGraph, "Bode Plot"); + // Raw Data is now Default (Index 0) tabWidget->addTab(rawGraph, "Raw Data"); + tabWidget->addTab(nyquistGraph, "Nyquist Plot"); // Log Widget logWidget = new QTextEdit(this); @@ -211,8 +252,12 @@ void MainWindow::runCalibration() { void MainWindow::startSweep() { if (!serial->isOpen()) return; - finalGraph->clear(); rawGraph->clear(); + nyquistGraph->clear(); + + // Clear accumulated data + sweepFreqs.clear(); + sweepReals.clear(); // Use Firmware Sweep Command: s // Example: 100Hz to 200kHz, 50 steps @@ -260,15 +305,69 @@ void MainWindow::parseData(const QString &data) { QStringList parts = data.split(','); if (parts.size() < 6) return; - bool okF, okM, okP, okR, okI; + bool okF, okR, okI; double freq = parts[1].toDouble(&okF); - double mag = parts[2].toDouble(&okM); - double phase= parts[3].toDouble(&okP); double real = parts[4].toDouble(&okR); double imag = parts[5].toDouble(&okI); - if (okF && okM && okP) finalGraph->addData(freq, mag, phase); - if (okF && okR && okI) rawGraph->addData(freq, real, imag); + if (okF && okR && okI) { + // Add to Raw Graph (Freq vs Real/Imag) + rawGraph->addData(freq, real, imag); + + // Add to Nyquist Graph (Real vs Imag) + nyquistGraph->addData(real, imag, 0); + + // Accumulate for Hilbert + sweepFreqs.append(freq); + sweepReals.append(real); + + // Check if sweep is done (e.g., 50 points) + // For now, update Hilbert every 10 points or at end + if (sweepReals.size() >= 50) { + computeHilbert(); + } + } +} + +void MainWindow::computeHilbert() { + int n = sweepReals.size(); + if (n == 0) return; + + // 1. Zero-pad to next power of 2 + int n_fft = 1; + while (n_fft < n) n_fft *= 2; + + std::vector> signal(n_fft); + for (int i = 0; i < n; i++) { + signal[i] = std::complex(sweepReals[i], 0.0); + } + + // 2. FFT + fft(signal); + + // 3. Create Analytic Signal in Frequency Domain + // H[0] = H[0] + // H[i] = 2*H[i] for 0 < i < N/2 + // H[N/2] = H[N/2] + // H[i] = 0 for N/2 < i < N + for (int i = 1; i < n_fft / 2; i++) { + signal[i] *= 2.0; + } + for (int i = n_fft / 2 + 1; i < n_fft; i++) { + signal[i] = 0.0; + } + + // 4. IFFT + ifft(signal); + + // 5. Extract Imaginary Part (Hilbert Transform) + QVector hilbertImag; + for (int i = 0; i < n; i++) { + hilbertImag.append(signal[i].imag()); + } + + // 6. Plot + rawGraph->addHilbertData(sweepFreqs, hilbertImag); } bool MainWindow::event(QEvent *event) { diff --git a/host/src/MainWindow.h b/host/src/MainWindow.h index 3bcde90..d77b26b 100644 --- a/host/src/MainWindow.h +++ b/host/src/MainWindow.h @@ -1,4 +1,4 @@ -// host/src/MainWindow.h +// File: host/src/MainWindow.h #pragma once #include @@ -42,13 +42,14 @@ private: void setupUi(); void parseData(const QString &data); void handleSwipe(QSwipeGesture *gesture); + void computeHilbert(); QSerialPort *serial; // Views - GraphWidget *finalGraph; // Bode Plot - GraphWidget *rawGraph; // Raw Data - QTextEdit *logWidget; // Serial Log + GraphWidget *rawGraph; // Raw Data (Freq vs Real/Imag) + GraphWidget *nyquistGraph; // Nyquist (Real vs -Imag) + QTextEdit *logWidget; // Serial Log // Layout QTabWidget *tabWidget; @@ -62,4 +63,8 @@ private: QDoubleSpinBox *spinFreq; bool isMeasuring = false; + + // Data Accumulation for Hilbert + QVector sweepFreqs; + QVector sweepReals; }; \ No newline at end of file diff --git a/main.c b/main.c index 2d1dc2e..0e37c06 100644 --- a/main.c +++ b/main.c @@ -1,4 +1,4 @@ -// main.c +// File: main.c #include #include #include @@ -182,41 +182,50 @@ void ImpedanceShowResult(uint32_t *pData, uint32_t DataCount) char input_buffer[64]; int input_pos = 0; +// Helper for robust state cleanup +void AD5940_Main_Cleanup(void) { + // Ensure chip is awake before sending commands + AD5940_WakeUp(10); + + // 1. Stop Sequencer and Wakeup Timer + AD5940_WUPTCtrl(bFALSE); + AD5940_SEQCtrlS(bFALSE); + + // 2. Stop any active conversions/WG, but KEEP Reference/LDOs ON + // This prevents settling issues on restart + AD5940_AFECtrlS(AFECTRL_ADCCNV|AFECTRL_DFT|AFECTRL_WG, bFALSE); + + // 3. Reset FIFO + FIFOCfg_Type fifo_cfg; + fifo_cfg.FIFOEn = bFALSE; + AD5940_FIFOCfg(&fifo_cfg); + + fifo_cfg.FIFOEn = bTRUE; + fifo_cfg.FIFOMode = FIFOMODE_FIFO; + fifo_cfg.FIFOSize = FIFOSIZE_4KB; + fifo_cfg.FIFOSrc = FIFOSRC_DFT; + fifo_cfg.FIFOThresh = 6; + AD5940_FIFOCfg(&fifo_cfg); + + // 4. Clear Interrupts + AD5940_INTCClrFlag(AFEINTSRC_ALLINT); +} + void process_command() { char cmd = input_buffer[0]; AppIMPCfg_Type *pCfg; AppIMPGetCfg(&pCfg); - // CRITICAL: Stop any running measurement before reconfiguration - AppIMPCtrl(IMPCTRL_STOPNOW, 0); - sleep_ms(10); // Give AFE time to halt + // CRITICAL: Perform robust cleanup before any new operation + AD5940_Main_Cleanup(); + sleep_ms(10); // Give AFE time to settle if (cmd == 'v') { uint32_t id = AD5940_ReadReg(REG_AFECON_CHIPID); printf("CHIP_ID:0x%04X\n", id); } else if (cmd == 'c') { - // 1. CRITICAL FIX: Force System to 16MHz Low Power Mode - // This prevents the 32MHz post-sweep state from corrupting calibration timing - AD5940_HPModeEn(bFALSE); - - // 2. Reset Analog Blocks to ensure clean state - AD5940_AFECtrlS(AFECTRL_ALL, bFALSE); - - // 3. Disable and Reset the FIFO to stop "DATA" interrupts - FIFOCfg_Type fifo_cfg; - fifo_cfg.FIFOEn = bFALSE; - AD5940_FIFOCfg(&fifo_cfg); - - fifo_cfg.FIFOEn = bTRUE; - fifo_cfg.FIFOMode = FIFOMODE_FIFO; - fifo_cfg.FIFOSize = FIFOSIZE_4KB; - fifo_cfg.FIFOSrc = FIFOSRC_DFT; - fifo_cfg.FIFOThresh = 6; - AD5940_FIFOCfg(&fifo_cfg); - - // 4. Clear any pending interrupts - AD5940_INTCClrFlag(AFEINTSRC_ALLINT); + // Cleanup already done by AD5940_Main_Cleanup() above // 5. Perform ADC Calibration (Offset) ADCPGACal_Type adcpga_cal; @@ -282,7 +291,11 @@ void process_command() { pCfg->SweepCfg.SweepEn = bFALSE; pCfg->SinFreq = freq; pCfg->NumOfData = -1; // Continuous - pCfg->bParaChanged = bTRUE; // Force sequence regeneration + + // CRITICAL FIX: Force parameter change flag to TRUE. + // This ensures AppIMPInit calls AppIMPSeqCfgGen, which re-enables + // the analog blocks (DAC, TIA, etc.) that AD5940_Main_Cleanup turned off. + pCfg->bParaChanged = bTRUE; if(AppIMPInit(AppBuff, APPBUFF_SIZE) == AD5940ERR_OK) { AppIMPCtrl(IMPCTRL_START, 0); @@ -302,7 +315,9 @@ void process_command() { pCfg->SweepCfg.SweepPoints = steps; pCfg->SweepCfg.SweepLog = bTRUE; pCfg->NumOfData = steps; // Stop after sweep - pCfg->bParaChanged = bTRUE; // Force sequence regeneration + + // CRITICAL FIX: Force parameter change flag to TRUE. + pCfg->bParaChanged = bTRUE; if(AppIMPInit(AppBuff, APPBUFF_SIZE) == AD5940ERR_OK) { AppIMPCtrl(IMPCTRL_START, 0); @@ -312,7 +327,7 @@ void process_command() { } else if (cmd == 'x') { // Stop Measurement - AppIMPCtrl(IMPCTRL_STOPNOW, 0); + // Cleanup already done by AD5940_Main_Cleanup() at start of function printf("STOPPED\n"); } else if (cmd == 'z') { @@ -348,6 +363,14 @@ int main() { AppIMPISR(AppBuff, &temp); if(temp > 0) { ImpedanceShowResult(AppBuff, temp); + + // Check if sweep is done (simple check based on config) + AppIMPCfg_Type *pCfg; + AppIMPGetCfg(&pCfg); + if (pCfg->SweepCfg.SweepEn && pCfg->FifoDataCount >= pCfg->NumOfData) { + printf("DONE\n"); + AD5940_Main_Cleanup(); // Ensure clean stop + } } } }