diff --git a/Software/PC_Application/appwindow.cpp b/Software/PC_Application/appwindow.cpp index 19b9e82..99add0c 100644 --- a/Software/PC_Application/appwindow.cpp +++ b/Software/PC_Application/appwindow.cpp @@ -212,6 +212,11 @@ AppWindow::AppWindow(QWidget *parent) spectrumAnalyzer->setAveragingMode(Averaging::Mode::Mean); vna->setAveragingMode(Averaging::Mode::Mean); } + + // acquisition frequencies may have changed, update + UpdateAcquisitionFrequencies(); + + active->initializeDevice(); }); connect(ui->actionAbout, &QAction::triggered, [=](){ @@ -306,6 +311,7 @@ bool AppWindow::ConnectToDevice(QString serial) ui->actionReceiver_Calibration->setEnabled(true); ui->actionFrequency_Calibration->setEnabled(true); + UpdateAcquisitionFrequencies(); Mode::getActiveMode()->initializeDevice(); UpdateReference(); @@ -866,6 +872,20 @@ void AppWindow::UpdateReference() device->SendPacket(p); } +void AppWindow::UpdateAcquisitionFrequencies() +{ + if(!device) { + return; + } + Protocol::PacketInfo p; + p.type = Protocol::PacketType::AcquisitionFrequencySettings; + auto pref = Preferences::getInstance(); + p.acquisitionFrequencySettings.IF1 = pref.Acquisition.IF1; + p.acquisitionFrequencySettings.ADCprescaler = pref.Acquisition.ADCprescaler; + p.acquisitionFrequencySettings.DFTphaseInc = pref.Acquisition.DFTPhaseInc; + device->SendPacket(p); +} + void AppWindow::StartFirmwareUpdateDialog() { if(device) { diff --git a/Software/PC_Application/appwindow.h b/Software/PC_Application/appwindow.h index 7af4cbd..7bca700 100644 --- a/Software/PC_Application/appwindow.h +++ b/Software/PC_Application/appwindow.h @@ -54,6 +54,7 @@ private slots: int UpdateDeviceList(); void StartManualControl(); void UpdateReference(); + void UpdateAcquisitionFrequencies(); void StartFirmwareUpdateDialog(); void DeviceNeedsUpdate(int reported, int expected); void SourceCalibrationDialog(); diff --git a/Software/PC_Application/preferences.cpp b/Software/PC_Application/preferences.cpp index 8b2dcb6..87241e1 100644 --- a/Software/PC_Application/preferences.cpp +++ b/Software/PC_Application/preferences.cpp @@ -73,6 +73,26 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) : connect(ui->AcquisitionUseDFT, &QCheckBox::toggled, [=](bool enabled) { ui->AcquisitionDFTlimitRBW->setEnabled(enabled); }); + ui->AcquisitionIF1->setUnit("Hz"); + ui->AcquisitionIF1->setPrefixes(" kM"); + ui->AcquisitionIF1->setPrecision(6); + ui->AcquisitionADCRate->setUnit("Hz"); + ui->AcquisitionADCRate->setPrefixes(" kM"); + ui->AcquisitionADCRate->setPrecision(6); + ui->AcquisitionIF2->setUnit("Hz"); + ui->AcquisitionIF2->setPrefixes(" kM"); + ui->AcquisitionIF2->setPrecision(6); + auto updateADCRate = [=]() { + // update ADC rate, see FPGA protocol for calculation + ui->AcquisitionADCRate->setValue(102400000.0 / ui->AcquisitionADCpresc->value()); + }; + auto updateIF2 = [=]() { + auto ADCrate = ui->AcquisitionADCRate->value(); + ui->AcquisitionIF2->setValue(ADCrate * ui->AcquisitionADCphaseInc->value() / 4096); + }; + connect(ui->AcquisitionADCpresc, qOverload(&QSpinBox::valueChanged), updateADCRate); + connect(ui->AcquisitionADCpresc, qOverload(&QSpinBox::valueChanged), updateIF2); + connect(ui->AcquisitionADCphaseInc, qOverload(&QSpinBox::valueChanged), updateIF2); // General page if(p->TCPoverride) { @@ -136,6 +156,9 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) : p->Acquisition.useDFTinSAmode = ui->AcquisitionUseDFT->isChecked(); p->Acquisition.RBWLimitForDFT = ui->AcquisitionDFTlimitRBW->value(); p->Acquisition.useMedianAveraging = ui->AcquisitionAveragingMode->currentIndex() == 1; + p->Acquisition.IF1 = ui->AcquisitionIF1->value(); + p->Acquisition.ADCprescaler = ui->AcquisitionADCpresc->value(); + p->Acquisition.DFTPhaseInc = ui->AcquisitionADCphaseInc->value(); p->Graphs.showUnits = ui->GraphsShowUnit->isChecked(); p->Graphs.Color.background = ui->GraphsColorBackground->getColor(); @@ -156,6 +179,8 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) : }); setInitialGUIState(); + updateADCRate(); + updateIF2(); connect(ui->AcquisitionUseHarmonic, &QCheckBox::toggled, [=](bool enabled) { if(enabled) { @@ -208,6 +233,9 @@ void PreferencesDialog::setInitialGUIState() ui->AcquisitionUseDFT->setChecked(p->Acquisition.useDFTinSAmode); ui->AcquisitionDFTlimitRBW->setValue(p->Acquisition.RBWLimitForDFT); ui->AcquisitionAveragingMode->setCurrentIndex(p->Acquisition.useMedianAveraging ? 1 : 0); + ui->AcquisitionIF1->setValue(p->Acquisition.IF1); + ui->AcquisitionADCpresc->setValue(p->Acquisition.ADCprescaler); + ui->AcquisitionADCphaseInc->setValue(p->Acquisition.DFTPhaseInc); ui->GraphsShowUnit->setChecked(p->Graphs.showUnits); ui->GraphsColorBackground->setColor(p->Graphs.Color.background); diff --git a/Software/PC_Application/preferences.h b/Software/PC_Application/preferences.h index 475a1a2..a5091f4 100644 --- a/Software/PC_Application/preferences.h +++ b/Software/PC_Application/preferences.h @@ -68,6 +68,11 @@ public: bool useDFTinSAmode; double RBWLimitForDFT; bool useMedianAveraging; + + // advanced, hardware specific settings + double IF1; + int ADCprescaler; + int DFTPhaseInc; } Acquisition; struct { bool showUnits; @@ -108,7 +113,7 @@ private: QString name; QVariant def; }; - const std::array descr = {{ + const std::array descr = {{ {&Startup.ConnectToFirstDevice, "Startup.ConnectToFirstDevice", true}, {&Startup.RememberSweepSettings, "Startup.RememberSweepSettings", false}, {&Startup.DefaultSweep.type, "Startup.DefaultSweep.type", "Frequency"}, @@ -138,6 +143,9 @@ private: {&Acquisition.useDFTinSAmode, "Acquisition.useDFTinSAmode", true}, {&Acquisition.RBWLimitForDFT, "Acquisition.RBWLimitForDFT", 3000.0}, {&Acquisition.useMedianAveraging, "Acquisition.useMedianAveraging", false}, + {&Acquisition.IF1, "Acquisition.IF1", 62000000}, + {&Acquisition.ADCprescaler, "Acquisition.ADCprescaler", 128}, + {&Acquisition.DFTPhaseInc, "Acquisition.DFTPhaseInc", 1280}, {&Graphs.showUnits, "Graphs.showUnits", true}, {&Graphs.Color.background, "Graphs.Color.background", QColor(Qt::black)}, {&Graphs.Color.axis, "Graphs.Color.axis", QColor(Qt::white)}, diff --git a/Software/PC_Application/preferencesdialog.ui b/Software/PC_Application/preferencesdialog.ui index 52a0b65..1b0fa87 100644 --- a/Software/PC_Application/preferencesdialog.ui +++ b/Software/PC_Application/preferencesdialog.ui @@ -83,7 +83,7 @@ - 3 + 1 @@ -569,7 +569,7 @@ - + @@ -647,26 +647,141 @@ Common - - - - - Averaging mode: - - + + + + + + + Averaging mode: + + + + + + + + Mean + + + + + Median + + + + + - - - - - Mean - - - - - Median - - + + + + IF frequencies + + + + + + This section contains advanced system settings. It is recommended to leave them at default values unless you know what you are doing. Slight changes of the IF frequencies can be used to shift possible spikes to less problematic frequencies. Large changes of these frequencies may severely impact device performance. + + + true + + + + + + + + + IF 1: + + + + + + + <html><head/><body><p>Frequency of the first IF</p></body></html> + + + + + + + ADC prescaler: + + + + + + + <html><head/><body><p>ADC prescaler in FPGA. The ADC sample rate is determined by 102.4MHz/prescaler</p></body></html> + + + 112 + + + 255 + + + 128 + + + + + + + ADC sample rate: + + + + + + + false + + + + + + + Phase increment: + + + + + + + <html><head/><body><p>Phase increment per ADC sample. Together with the ADC sample rate this determines the frequency of the second IF</p></body></html> + + + 1 + + + 4095 + + + 1280 + + + + + + + IF 2: + + + + + + + false + + + + + + diff --git a/Software/VNA_embedded/Application/App.cpp b/Software/VNA_embedded/Application/App.cpp index f41e25b..ee82562 100644 --- a/Software/VNA_embedded/Application/App.cpp +++ b/Software/VNA_embedded/Application/App.cpp @@ -222,6 +222,21 @@ inline void App_Process() { Cal::setFrequencyCal(recv_packet.frequencyCorrection.ppm); Communication::SendWithoutPayload(Protocol::PacketType::Ack); break; + case Protocol::PacketType::RequestAcquisitionFrequencySettings: + Communication::SendWithoutPayload(Protocol::PacketType::Ack); + { + Protocol::PacketInfo send; + send.type = Protocol::PacketType::AcquisitionFrequencySettings; + send.acquisitionFrequencySettings.IF1 = HW::getIF1(); + send.acquisitionFrequencySettings.ADCprescaler = HW::getADCPrescaler(); + send.acquisitionFrequencySettings.DFTphaseInc = HW::getDFTPhaseInc(); + Communication::Send(send); + } + break; + case Protocol::PacketType::AcquisitionFrequencySettings: + HW::setAcquisitionFrequencies(recv_packet.acquisitionFrequencySettings); + Communication::SendWithoutPayload(Protocol::PacketType::Ack); + break; default: // this packet type is not supported Communication::SendWithoutPayload(Protocol::PacketType::Nack); diff --git a/Software/VNA_embedded/Application/Communication/Protocol.cpp b/Software/VNA_embedded/Application/Communication/Protocol.cpp index fb07b85..2384d39 100644 --- a/Software/VNA_embedded/Application/Communication/Protocol.cpp +++ b/Software/VNA_embedded/Application/Communication/Protocol.cpp @@ -100,6 +100,7 @@ uint16_t Protocol::EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_ case PacketType::SourceCalPoint: case PacketType::ReceiverCalPoint: payload_size = sizeof(packet.amplitudePoint); break; case PacketType::FrequencyCorrection: payload_size = sizeof(packet.frequencyCorrection); break; + case PacketType::AcquisitionFrequencySettings: payload_size = sizeof(packet.acquisitionFrequencySettings); break; case PacketType::Ack: case PacketType::PerformFirmwareUpdate: case PacketType::ClearFlash: @@ -109,6 +110,7 @@ uint16_t Protocol::EncodePacket(const PacketInfo &packet, uint8_t *dest, uint16_ case PacketType::RequestReceiverCal: case PacketType::SetIdle: case PacketType::RequestFrequencyCorrection: + case PacketType::RequestAcquisitionFrequencySettings: // no payload break; case PacketType::None: diff --git a/Software/VNA_embedded/Application/Communication/Protocol.hpp b/Software/VNA_embedded/Application/Communication/Protocol.hpp index 9c78004..009ab1d 100644 --- a/Software/VNA_embedded/Application/Communication/Protocol.hpp +++ b/Software/VNA_embedded/Application/Communication/Protocol.hpp @@ -4,7 +4,7 @@ namespace Protocol { -static constexpr uint16_t Version = 8; +static constexpr uint16_t Version = 9; #pragma pack(push, 1) @@ -160,6 +160,12 @@ using FrequencyCorrection = struct _frequencycorrection { float ppm; }; +using AcquisitionFrequencySettings = struct _acquisitionfrequencysettigns { + uint32_t IF1; + uint8_t ADCprescaler; + uint16_t DFTphaseInc; +}; + enum class PacketType : uint8_t { None = 0, Datapoint = 1, @@ -184,6 +190,8 @@ enum class PacketType : uint8_t { SetIdle = 20, RequestFrequencyCorrection = 21, FrequencyCorrection = 22, + RequestAcquisitionFrequencySettings = 23, + AcquisitionFrequencySettings = 24, }; using PacketInfo = struct _packetinfo { @@ -201,6 +209,7 @@ using PacketInfo = struct _packetinfo { SpectrumAnalyzerResult spectrumResult; AmplitudeCorrectionPoint amplitudePoint; FrequencyCorrection frequencyCorrection; + AcquisitionFrequencySettings acquisitionFrequencySettings; }; }; diff --git a/Software/VNA_embedded/Application/Hardware.cpp b/Software/VNA_embedded/Application/Hardware.cpp index 6a73a66..8afb45c 100644 --- a/Software/VNA_embedded/Application/Hardware.cpp +++ b/Software/VNA_embedded/Application/Hardware.cpp @@ -21,6 +21,12 @@ static bool unlevel = false; static Protocol::ReferenceSettings ref; static uint32_t lastISR; +static uint32_t IF1 = HW::DefaultIF1; +static uint32_t IF2 = HW::DefaultIF2; +static uint32_t ADCsamplerate = HW::DefaultADCSamplerate; +static uint8_t ADCprescaler = HW::DefaultADCprescaler; +static uint16_t DFTphaseInc = HW::DefaultDFTphaseInc; + using namespace HWHAL; static void HaltedCallback() { @@ -133,9 +139,9 @@ bool HW::Init() { } // Set default ADC samplerate - FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, HW::ADCprescaler); + FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, ADCprescaler); // Set phase increment according to - FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, HW::DFTphaseInc); + FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, DFTphaseInc); Exti::SetCallback(FPGA_INTR_GPIO_Port, FPGA_INTR_Pin, Exti::EdgeType::Rising, Exti::Pull::Down, FPGA_Interrupt); @@ -385,3 +391,33 @@ void HW::Ref::update() { } } } + +void HW::setAcquisitionFrequencies(Protocol::AcquisitionFrequencySettings s) { + IF1 = s.IF1; + ADCprescaler = s.ADCprescaler; + DFTphaseInc = s.DFTphaseInc; + float ADCrate = (float) FPGA::Clockrate / ADCprescaler; + IF2 = ADCrate * DFTphaseInc / 4096; + ADCsamplerate = ADCrate; +} + +uint32_t HW::getIF1() { + return IF1; +} + +uint32_t HW::getIF2() { + return IF2; +} + +uint32_t HW::getADCRate() { + return ADCsamplerate; +} + +uint8_t HW::getADCPrescaler() { + return ADCprescaler; +} + +uint16_t HW::getDFTPhaseInc() { + return DFTphaseInc; +} + diff --git a/Software/VNA_embedded/Application/Hardware.hpp b/Software/VNA_embedded/Application/Hardware.hpp index 5ebd65e..656569f 100644 --- a/Software/VNA_embedded/Application/Hardware.hpp +++ b/Software/VNA_embedded/Application/Hardware.hpp @@ -35,19 +35,19 @@ static constexpr uint32_t ExtRefOut2Frequency = 10000000; static constexpr uint32_t SI5351CPLLAlignedFrequency = 832000000; static constexpr uint32_t SI5351CPLLConstantFrequency = 800000000; static constexpr uint32_t FPGAClkInFrequency = 16000000; -static constexpr uint32_t ADCSamplerate = 800000; -static constexpr uint32_t IF1 = 62000000; -static constexpr uint32_t IF2 = 250000; +static constexpr uint32_t DefaultADCSamplerate = 800000; +static constexpr uint32_t DefaultIF1 = 62000000; +static constexpr uint32_t DefaultIF2 = 250000; static constexpr uint32_t LO1_minFreq = 25000000; static constexpr uint32_t MaxSamples = 130944; static constexpr uint32_t MinSamples = 16; static constexpr uint32_t PLLRef = 104000000; static constexpr uint32_t BandSwitchFrequency = 25000000; -static constexpr uint8_t ADCprescaler = FPGA::Clockrate / ADCSamplerate; -static_assert(ADCprescaler * ADCSamplerate == FPGA::Clockrate, "ADCSamplerate can not be reached exactly"); -static constexpr uint16_t DFTphaseInc = 4096 * IF2 / ADCSamplerate; -static_assert(DFTphaseInc * ADCSamplerate == 4096 * IF2, "DFT can not be computed for 2.IF"); +static constexpr uint8_t DefaultADCprescaler = FPGA::Clockrate / DefaultADCSamplerate; +static_assert(DefaultADCprescaler * DefaultADCSamplerate == FPGA::Clockrate, "ADCSamplerate can not be reached exactly"); +static constexpr uint16_t DefaultDFTphaseInc = 4096 * DefaultIF2 / DefaultADCSamplerate; +static_assert(DefaultDFTphaseInc * DefaultADCSamplerate == 4096 * DefaultIF2, "DFT can not be computed for 2.IF"); static constexpr uint16_t _fpga_div = SI5351CPLLConstantFrequency / FPGAClkInFrequency; static_assert(_fpga_div * FPGAClkInFrequency == SI5351CPLLConstantFrequency && _fpga_div >= 6 && _fpga_div <= 254 && (_fpga_div & 0x01) == 0, "Unable to generate FPGA clock input frequency"); @@ -83,13 +83,13 @@ static constexpr Protocol::DeviceInfo Info = { .temp_MCU = 0, .limits_minFreq = 0, .limits_maxFreq = 6000000000, - .limits_minIFBW = ADCSamplerate / MaxSamples, - .limits_maxIFBW = ADCSamplerate / MinSamples, + .limits_minIFBW = DefaultADCSamplerate / MaxSamples, + .limits_maxIFBW = DefaultADCSamplerate / MinSamples, .limits_maxPoints = FPGA::MaxPoints, .limits_cdbm_min = -4000, .limits_cdbm_max = 0, - .limits_minRBW = (uint32_t) (ADCSamplerate * 2.23f / MaxSamples), - .limits_maxRBW = (uint32_t) (ADCSamplerate * 2.23f / MinSamples), + .limits_minRBW = (uint32_t) (DefaultADCSamplerate * 2.23f / MaxSamples), + .limits_maxRBW = (uint32_t) (DefaultADCSamplerate * 2.23f / MinSamples), .limits_maxAmplitudePoints = Cal::maxPoints, .limits_maxFreqHarmonic = 18000000000, }; @@ -129,4 +129,12 @@ namespace Ref { void update(); } +// Acquisition frequency settings +void setAcquisitionFrequencies(Protocol::AcquisitionFrequencySettings s); +uint32_t getIF1(); +uint32_t getIF2(); +uint32_t getADCRate(); +uint8_t getADCPrescaler(); +uint16_t getDFTPhaseInc(); + } diff --git a/Software/VNA_embedded/Application/SpectrumAnalyzer.cpp b/Software/VNA_embedded/Application/SpectrumAnalyzer.cpp index e11da5e..e9c60b6 100644 --- a/Software/VNA_embedded/Application/SpectrumAnalyzer.cpp +++ b/Software/VNA_embedded/Application/SpectrumAnalyzer.cpp @@ -49,8 +49,8 @@ static void StartNextSample() { port2Measurement[i] = std::numeric_limits::max(); } // Use default LO frequencies - LO1freq = freq + HW::IF1; - LO2freq = HW::IF1 - HW::IF2; + LO1freq = freq + HW::getIF1(); + LO2freq = HW::getIF1() - HW::getIF2(); FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, 112); FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, 1120); negativeDFT = true; @@ -88,17 +88,17 @@ static void StartNextSample() { } break; case 1: - LO2freq = HW::IF1 - HW::IF2; + LO2freq = HW::getIF1() - HW::getIF2(); negativeDFT = false; // Shift first LO to other side // depending on the measurement frequency this is not possible or additive mixing has to be used - if(freq >= HW::IF1 + HW::LO1_minFreq) { + if(freq >= HW::getIF1() + HW::LO1_minFreq) { // frequency is high enough to shift 1.LO below measurement frequency - LO1freq = freq - HW::IF1; + LO1freq = freq - HW::getIF1(); break; - } else if(freq <= HW::IF1 - HW::LO1_minFreq) { + } else if(freq <= HW::getIF1() - HW::LO1_minFreq) { // frequency is low enough to add 1.LO to measurement frequency - LO1freq = HW::IF1 - freq; + LO1freq = HW::getIF1() - freq; break; } // unable to reach required frequency with 1.LO, skip this signal ID step @@ -106,22 +106,22 @@ static void StartNextSample() { /* no break */ case 2: // Shift second LOs to other side - LO1freq = freq + HW::IF1; - LO2freq = HW::IF1 + HW::IF2; + LO1freq = freq + HW::getIF1(); + LO2freq = HW::getIF1() + HW::getIF2(); negativeDFT = false; break; case 3: // Shift both LO to other side - LO2freq = HW::IF1 + HW::IF2; + LO2freq = HW::getIF1() + HW::getIF2(); negativeDFT = true; // depending on the measurement frequency this is not possible or additive mixing has to be used - if(freq >= HW::IF1 + HW::LO1_minFreq) { + if(freq >= HW::getIF1() + HW::LO1_minFreq) { // frequency is high enough to shift 1.LO below measurement frequency - LO1freq = freq - HW::IF1; + LO1freq = freq - HW::getIF1(); break; - } else if(freq <= HW::IF1 - HW::LO1_minFreq) { + } else if(freq <= HW::getIF1() - HW::LO1_minFreq) { // frequency is low enough to add 1.LO to measurement frequency - LO1freq = HW::IF1 - freq; + LO1freq = HW::getIF1() - freq; break; } // unable to reach required frequency with 1.LO, skip this signal ID step @@ -130,8 +130,8 @@ static void StartNextSample() { default: // Use default frequencies with different ADC samplerate to remove images in final IF negativeDFT = true; - LO1freq = freq + HW::IF1; - LO2freq = HW::IF1 - HW::IF2; + LO1freq = freq + HW::getIF1(); + LO2freq = HW::getIF1() - HW::getIF2(); FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, signalIDprescalers[signalIDstep-4]); FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, (uint16_t) signalIDprescalers[signalIDstep-4] * 10); } @@ -147,7 +147,7 @@ static void StartNextSample() { } if (s.UseDFT) { uint32_t spacing = (s.f_stop - s.f_start) / (points - 1); - uint32_t start = HW::IF2; + uint32_t start = HW::getIF2(); if(negativeDFT) { // needs to look below the start frequency, shift start start -= spacing * (DFTpoints - 1); @@ -172,13 +172,15 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) { s = settings; HW::SetMode(HW::Mode::SA); FPGA::SetMode(FPGA::Mode::FPGA); + FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, HW::getADCPrescaler()); + FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, HW::getDFTPhaseInc()); // in almost all cases a full sweep requires more points than the FPGA can handle at a time // individually start each point and do the sweep in the uC FPGA::SetNumberOfPoints(1); // calculate required samples per measurement for requested RBW // see https://www.tek.com/blog/window-functions-spectrum-analyzers for window factors constexpr float window_factors[4] = {0.89f, 2.23f, 1.44f, 3.77f}; - sampleNum = HW::ADCSamplerate * window_factors[s.WindowType] / s.RBW; + sampleNum = HW::getADCRate() * window_factors[s.WindowType] / s.RBW; // round up to next multiple of 16 if(sampleNum%16) { sampleNum += 16 - sampleNum%16; @@ -186,7 +188,7 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) { if(sampleNum >= HW::MaxSamples) { sampleNum = HW::MaxSamples; } - actualRBW = HW::ADCSamplerate * window_factors[s.WindowType] / sampleNum; + actualRBW = HW::getADCRate() * window_factors[s.WindowType] / sampleNum; FPGA::SetSamplesPerPoint(sampleNum); // calculate amount of required points points = 2 * (s.f_stop - s.f_start) / actualRBW; diff --git a/Software/VNA_embedded/Application/VNA.cpp b/Software/VNA_embedded/Application/VNA.cpp index 11bf83a..14c39e4 100644 --- a/Software/VNA_embedded/Application/VNA.cpp +++ b/Software/VNA_embedded/Application/VNA.cpp @@ -44,8 +44,8 @@ static uint16_t IFTableIndexCnt = 0; static constexpr float alternativeSamplerate = 914285.7143f; static constexpr uint8_t alternativePrescaler = 102400000UL / alternativeSamplerate; static_assert(alternativePrescaler * alternativeSamplerate == 102400000UL, "alternative ADCSamplerate can not be reached exactly"); -static constexpr uint16_t alternativePhaseInc = 4096 * HW::IF2 / alternativeSamplerate; -static_assert(alternativePhaseInc * alternativeSamplerate == 4096 * HW::IF2, "DFT can not be computed for 2.IF when using alternative samplerate"); +static constexpr uint16_t alternativePhaseInc = 4096 * HW::DefaultIF2 / alternativeSamplerate; +static_assert(alternativePhaseInc * alternativeSamplerate == 4096 * HW::DefaultIF2, "DFT can not be computed for 2.IF when using alternative samplerate"); // Constants for USB buffer overflow prevention static constexpr uint16_t maxPointsBetweenHalts = 40; @@ -84,6 +84,8 @@ bool VNA::Setup(Protocol::SweepSettings s) { } // Abort possible active sweep first FPGA::SetMode(FPGA::Mode::FPGA); + FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, HW::getADCPrescaler()); + FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, HW::getDFTPhaseInc()); if(settings.points > FPGA::MaxPoints) { settings.points = FPGA::MaxPoints; } @@ -92,12 +94,12 @@ bool VNA::Setup(Protocol::SweepSettings s) { logMultiplier = pow((double) settings.f_stop / settings.f_start, 1.0 / (settings.points-1)); // Configure sweep FPGA::SetNumberOfPoints(settings.points); - uint32_t samplesPerPoint = (HW::ADCSamplerate / s.if_bandwidth); + uint32_t samplesPerPoint = (HW::getADCRate() / s.if_bandwidth); // round up to next multiple of 16 (16 samples are spread across 5 IF2 periods) if(samplesPerPoint%16) { samplesPerPoint += 16 - samplesPerPoint%16; } - actualBandwidth = HW::ADCSamplerate / samplesPerPoint; + actualBandwidth = HW::getADCRate() / samplesPerPoint; // has to be one less than actual number of samples FPGA::SetSamplesPerPoint(samplesPerPoint); @@ -129,7 +131,7 @@ bool VNA::Setup(Protocol::SweepSettings s) { FPGA::WriteMAX2871Default(Source.GetRegisters()); - uint32_t last_LO2 = HW::IF1 - HW::IF2; + uint32_t last_LO2 = HW::getIF1() - HW::getIF2(); Si5351.SetCLK(SiChannel::Port1LO2, last_LO2, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); Si5351.SetCLK(SiChannel::Port2LO2, last_LO2, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); Si5351.SetCLK(SiChannel::RefLO2, last_LO2, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); @@ -180,7 +182,7 @@ bool VNA::Setup(Protocol::SweepSettings s) { // additional halt before first highband point to enable highband source needs_halt = true; } - uint64_t LOFreq = freq + HW::IF1; + uint64_t LOFreq = freq + HW::getIF1(); if(harmonic_mixing) { LOFreq /= LOHarmonic; } @@ -191,7 +193,7 @@ bool VNA::Setup(Protocol::SweepSettings s) { } uint32_t actualFirstIF = actualLO1 - actualSourceFreq; uint32_t actualFinalIF = actualFirstIF - last_LO2; - uint32_t IFdeviation = abs(actualFinalIF - HW::IF2); + uint32_t IFdeviation = abs(actualFinalIF - HW::getIF2()); bool needs_LO2_shift = false; if(IFdeviation > actualBandwidth / 2) { needs_LO2_shift = true; @@ -204,7 +206,7 @@ bool VNA::Setup(Protocol::SweepSettings s) { if(IFTableIndexCnt < IFTableNumEntries - 1) { // Configure LO2 for the changed IF1. This is not necessary right now but it will generate // the correct clock settings - last_LO2 = actualFirstIF - HW::IF2; + last_LO2 = actualFirstIF - HW::getIF2(); LOG_INFO("Changing 2.LO to %lu at point %lu (%lu%06luHz) to reach correct 2.IF frequency (1.LO: %lu%06luHz, 1.IF: %lu%06luHz)", last_LO2, i, (uint32_t ) (freq / 1000000), (uint32_t ) (freq % 1000000), (uint32_t ) (actualLO1 / 1000000), @@ -212,7 +214,7 @@ bool VNA::Setup(Protocol::SweepSettings s) { (uint32_t ) (actualFirstIF % 1000000)); } else { // last entry in IF table, revert LO2 to default - last_LO2 = HW::IF1 - HW::IF2; + last_LO2 = HW::getIF1() - HW::getIF2(); } Si5351.SetCLK(SiChannel::RefLO2, last_LO2, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); @@ -259,10 +261,10 @@ bool VNA::Setup(Protocol::SweepSettings s) { last_lowband = lowband; } // revert clk configuration to previous value (might have been changed in sweep calculation) - Si5351.SetCLK(SiChannel::RefLO2, HW::IF1 - HW::IF2, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); + Si5351.SetCLK(SiChannel::RefLO2, HW::getIF1() - HW::getIF2(), Si5351C::PLL::B, Si5351C::DriveStrength::mA2); Si5351.ResetPLL(Si5351C::PLL::B); // Enable mixers/amplifier/PLLs - FPGA::SetWindow(FPGA::Window::None); + FPGA::SetWindow(FPGA::Window::Kaiser); FPGA::Enable(FPGA::Periphery::Port1Mixer); FPGA::Enable(FPGA::Periphery::Port2Mixer); FPGA::Enable(FPGA::Periphery::RefMixer); @@ -399,14 +401,17 @@ void VNA::SweepHalted() { Delay::us(1300); } - // At low frequencies the 1.LO feedtrough mixes with the 2.LO in the second mixer. + // At low frequencies the 1.LO feedthrough mixes with the 2.LO in the second mixer. // Depending on the stimulus frequency, the resulting mixing product might alias to the 2.IF // in the ADC which causes a spike. Check for this and shift the ADC sampling frequency if necessary - uint32_t LO_mixing = (HW::IF1 + frequency) - (HW::IF1 - HW::IF2); - if(abs(Util::Alias(LO_mixing, HW::ADCSamplerate) - HW::IF2) <= actualBandwidth * 2) { + + uint32_t LO_mixing = (HW::getIF1() + frequency) - (HW::getIF1() - HW::getIF2()); + if(abs(Util::Alias(LO_mixing, HW::getADCRate()) - HW::getIF2()) <= actualBandwidth * 2) { // the image is in or near the IF bandwidth and would cause a peak - // Use a slightly different ADC samplerate - adcShiftRequired = true; + // Use a slightly different ADC sample rate if possible + if(HW::getIF2() == HW::DefaultIF2) { + adcShiftRequired = true; + } } } else if(!FPGA::IsEnabled(FPGA::Periphery::SourceRF)){ // first sweep point in highband is also halted, disable lowband source @@ -420,8 +425,8 @@ void VNA::SweepHalted() { adcShifted = true; } else if(adcShifted) { // reset to default value - FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, HW::ADCprescaler); - FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, HW::DFTphaseInc); + FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, HW::getADCPrescaler()); + FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, HW::getDFTPhaseInc()); adcShifted = false; }