mirror of
https://github.com/jankae/LibreVNA.git
synced 2026-04-05 06:25:16 +00:00
mitigation for peaks caused by limited fractional divider in PLLs
This commit is contained in:
parent
fc3ce7a828
commit
57b4ebfb26
23 changed files with 654 additions and 274 deletions
Binary file not shown.
|
|
@ -193,9 +193,9 @@ SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window)
|
|||
settings.f_stop = 1050000000;
|
||||
ConstrainAndUpdateFrequencies();
|
||||
SetRBW(10000);
|
||||
settings.pointNum = 1001;
|
||||
settings.WindowType = 1;
|
||||
settings.Detector = 0;
|
||||
settings.pointNum = 1001;
|
||||
settings.SignalID = 0;
|
||||
// }
|
||||
|
||||
|
|
@ -230,6 +230,12 @@ void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult d)
|
|||
|
||||
void SpectrumAnalyzer::SettingsChanged()
|
||||
{
|
||||
if(settings.f_stop - settings.f_start >= 1000) {
|
||||
settings.pointNum = 1001;
|
||||
} else {
|
||||
settings.pointNum = settings.f_stop - settings.f_start + 1;
|
||||
}
|
||||
|
||||
if(window->getDevice()) {
|
||||
window->getDevice()->Configure(settings);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ private:
|
|||
|
||||
Preferences &pref;
|
||||
|
||||
Protocol::SpectrumAnalyzerSettings settings;
|
||||
Protocol::SpectrumAnalyzerSettings settings;
|
||||
unsigned int averages;
|
||||
TraceModel traceModel;
|
||||
TraceMarkerModel *markerModel;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include <fstream>
|
||||
#include <QDateTime>
|
||||
#include "unit.h"
|
||||
#include <queue>
|
||||
#include "CustomWidgets/toggleswitch.h"
|
||||
#include "Device/manualcontroldialog.h"
|
||||
#include "Traces/tracemodel.h"
|
||||
|
|
@ -472,7 +473,7 @@ void VNA::initializeDevice()
|
|||
removeDefaultCal->setEnabled(false);
|
||||
}
|
||||
// Configure initial state of device
|
||||
window->getDevice()->Configure(settings);
|
||||
SettingsChanged();
|
||||
}
|
||||
|
||||
void VNA::deviceDisconnected()
|
||||
|
|
@ -538,6 +539,7 @@ void VNA::UpdateStatusPanel()
|
|||
|
||||
void VNA::SettingsChanged()
|
||||
{
|
||||
settings.suppressPeaks = pref.Acquisition.suppressPeaks ? 1 : 0;
|
||||
if(window->getDevice()) {
|
||||
window->getDevice()->Configure(settings);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) :
|
|||
p->Startup.DefaultSweep.points = ui->StartupSweepPoints->value();
|
||||
p->Startup.DefaultSweep.excitation = ui->StartupSweepLevel->value();
|
||||
p->Acquisition.alwaysExciteBothPorts = ui->AcquisitionAlwaysExciteBoth->isChecked();
|
||||
p->Acquisition.suppressPeaks = ui->AcquisitionSuppressPeaks->isChecked();
|
||||
accept();
|
||||
});
|
||||
|
||||
|
|
@ -93,6 +94,7 @@ void PreferencesDialog::setInitialGUIState()
|
|||
ui->StartupSweepLevel->setValue(p->Startup.DefaultSweep.excitation);
|
||||
|
||||
ui->AcquisitionAlwaysExciteBoth->setChecked(p->Acquisition.alwaysExciteBothPorts);
|
||||
ui->AcquisitionSuppressPeaks->setChecked(p->Acquisition.suppressPeaks);
|
||||
}
|
||||
|
||||
void Preferences::load()
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ public:
|
|||
} Startup;
|
||||
struct {
|
||||
bool alwaysExciteBothPorts;
|
||||
bool suppressPeaks;
|
||||
} Acquisition;
|
||||
private:
|
||||
using SettingDescription = struct {
|
||||
|
|
@ -55,7 +56,7 @@ private:
|
|||
QString name;
|
||||
QVariant def;
|
||||
};
|
||||
const std::array<SettingDescription, 8> descr = {{
|
||||
const std::array<SettingDescription, 9> descr = {{
|
||||
{&Startup.ConnectToFirstDevice, "Startup.ConnectToFirstDevice", true},
|
||||
{&Startup.RememberSweepSettings, "Startup.RememberSweepSettings", false},
|
||||
{&Startup.DefaultSweep.start, "Startup.DefaultSweep.start", 1000000.0},
|
||||
|
|
@ -64,6 +65,7 @@ private:
|
|||
{&Startup.DefaultSweep.bandwidth, "Startup.DefaultSweep.bandwidth", 1000.0},
|
||||
{&Startup.DefaultSweep.excitation, "Startup.DefaultSweep.excitation", -10.00},
|
||||
{&Acquisition.alwaysExciteBothPorts, "Acquisition.alwaysExciteBothPorts", true},
|
||||
{&Acquisition.suppressPeaks, "Acquisition.suppressPeaks", true},
|
||||
}};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -241,6 +241,16 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="AcquisitionSuppressPeaks">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Due to limited fractional divider settings, the source and 1.LO PLLs are not able to reach every frequency exactly. At some specific frequencies this causes the final IF to shift. At these frequencies there will be a positive or negative peak in the trace measurement that is not actually there.<br/><br/>Checking this option shifts the 2.LO for points where this could be an issue. This will remove the peaks but slow down the sweep slightly.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Suppress invalid peaks</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
|
|
|
|||
|
|
@ -176,6 +176,7 @@ static Protocol::SweepSettings DecodeSweepSettings(uint8_t *buf) {
|
|||
e.get<int16_t>(d.cdbm_excitation);
|
||||
d.excitePort1 = e.getBits(1);
|
||||
d.excitePort2 = e.getBits(1);
|
||||
d.suppressPeaks = e.getBits(1);
|
||||
return d;
|
||||
}
|
||||
static int16_t EncodeSweepSettings(Protocol::SweepSettings d, uint8_t *buf,
|
||||
|
|
@ -188,6 +189,7 @@ static int16_t EncodeSweepSettings(Protocol::SweepSettings d, uint8_t *buf,
|
|||
e.add<int16_t>(d.cdbm_excitation);
|
||||
e.addBits(d.excitePort1, 1);
|
||||
e.addBits(d.excitePort2, 1);
|
||||
e.addBits(d.suppressPeaks, 1);
|
||||
return e.getSize();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ using SweepSettings = struct _sweepSettings {
|
|||
int16_t cdbm_excitation; // in 1/100 dbm
|
||||
uint8_t excitePort1:1;
|
||||
uint8_t excitePort2:1;
|
||||
uint8_t suppressPeaks:1;
|
||||
};
|
||||
|
||||
using ReferenceSettings = struct _referenceSettings {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "usbd_core.h"
|
||||
|
||||
USBD_HandleTypeDef hUsbDeviceFS;
|
||||
extern PCD_HandleTypeDef hpcd_USB_FS;
|
||||
|
||||
#define EP_DATA_IN_ADDRESS 0x81
|
||||
#define EP_DATA_OUT_ADDRESS 0x01
|
||||
|
|
@ -186,7 +187,9 @@ void usb_init(usbd_callback_t callback) {
|
|||
USBD_Init(&hUsbDeviceFS, &FS_Desc, 0);
|
||||
USBD_RegisterClass(&hUsbDeviceFS, &USBD_ClassDriver);
|
||||
USBD_Start(&hUsbDeviceFS);
|
||||
HAL_NVIC_EnableIRQ(USB_HP_IRQn);
|
||||
HAL_NVIC_SetPriority(USB_HP_IRQn, 6, 0);
|
||||
HAL_NVIC_EnableIRQ(USB_HP_IRQn);
|
||||
HAL_NVIC_SetPriority(USB_LP_IRQn, 6, 0);
|
||||
HAL_NVIC_EnableIRQ(USB_LP_IRQn);
|
||||
}
|
||||
|
||||
|
|
@ -217,3 +220,12 @@ void usb_log(const char *log, uint16_t length) {
|
|||
// still busy, unable to send log
|
||||
}
|
||||
}
|
||||
|
||||
void USB_HP_IRQHandler(void)
|
||||
{
|
||||
HAL_PCD_IRQHandler(&hpcd_USB_FS);
|
||||
}
|
||||
void USB_LP_IRQHandler(void)
|
||||
{
|
||||
HAL_PCD_IRQHandler(&hpcd_USB_FS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@ bool MAX2871::Init(uint32_t f_ref, bool doubler, uint16_t r, bool div2) {
|
|||
// automatically switch to integer mode if F = 0
|
||||
regs[5] |= (1UL << 24);
|
||||
|
||||
// recommended phase setting
|
||||
regs[1] |= (1UL << 15);
|
||||
|
||||
SetMode(Mode::LowSpur2);
|
||||
// for all other CP modes the PLL reports unlock condition (output signal appears to be locked)
|
||||
SetCPMode(CPMode::CP20);
|
||||
|
|
|
|||
|
|
@ -92,9 +92,9 @@ bool HW::Init(WorkRequest wr) {
|
|||
Si5351.Disable(SiChannel::ReferenceOut);
|
||||
|
||||
// Both MAX2871 get a 100MHz reference
|
||||
Si5351.SetCLK(SiChannel::Source, 100000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA2);
|
||||
Si5351.SetCLK(SiChannel::Source, HW::PLLRef, Si5351C::PLL::A, Si5351C::DriveStrength::mA2);
|
||||
Si5351.Enable(SiChannel::Source);
|
||||
Si5351.SetCLK(SiChannel::LO1, 100000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA2);
|
||||
Si5351.SetCLK(SiChannel::LO1, HW::PLLRef, Si5351C::PLL::A, Si5351C::DriveStrength::mA2);
|
||||
Si5351.Enable(SiChannel::LO1);
|
||||
// 16MHz FPGA clock
|
||||
Si5351.SetCLK(SiChannel::FPGA, 16000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA2);
|
||||
|
|
@ -133,7 +133,7 @@ bool HW::Init(WorkRequest wr) {
|
|||
// enable source synthesizer
|
||||
FPGA::Enable(FPGA::Periphery::SourceChip);
|
||||
FPGA::SetMode(FPGA::Mode::SourcePLL);
|
||||
Source.Init(100000000, false, 1, false);
|
||||
Source.Init(HW::PLLRef, false, 1, false);
|
||||
Source.SetPowerOutA(MAX2871::Power::n4dbm);
|
||||
// output B is not used
|
||||
Source.SetPowerOutB(MAX2871::Power::n4dbm, false);
|
||||
|
|
@ -150,7 +150,7 @@ bool HW::Init(WorkRequest wr) {
|
|||
FPGA::Disable(FPGA::Periphery::SourceChip);
|
||||
FPGA::Enable(FPGA::Periphery::LO1Chip);
|
||||
FPGA::SetMode(FPGA::Mode::LOPLL);
|
||||
LO1.Init(100000000, false, 1, false);
|
||||
LO1.Init(HW::PLLRef, false, 1, false);
|
||||
LO1.SetPowerOutA(MAX2871::Power::n4dbm);
|
||||
LO1.SetPowerOutB(MAX2871::Power::n4dbm);
|
||||
if(!LO1.BuildVCOMap()) {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,11 @@
|
|||
namespace HW {
|
||||
|
||||
static constexpr uint32_t ADCSamplerate = 914000;
|
||||
static constexpr uint32_t IF1 = 60100000;
|
||||
static constexpr uint32_t IF1 = 60000000;
|
||||
static constexpr uint32_t IF2 = 250000;
|
||||
static constexpr uint32_t LO1_minFreq = 25000000;
|
||||
static constexpr uint32_t MaxSamples = 130944;
|
||||
static constexpr uint32_t PLLRef = 100000000;
|
||||
|
||||
enum class Mode {
|
||||
Idle,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ static uint32_t sampleNum;
|
|||
static Protocol::PacketInfo p;
|
||||
static bool active = false;
|
||||
static uint32_t lastLO2;
|
||||
static uint32_t actualRBW;
|
||||
|
||||
static float port1Measurement, port2Measurement;
|
||||
|
||||
|
|
@ -40,20 +41,42 @@ static void StartNextSample() {
|
|||
FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, 1120);
|
||||
break;
|
||||
case 1:
|
||||
// Shift first LO to other side
|
||||
LO1freq = freq - HW::IF1;
|
||||
LO2freq = HW::IF1 - HW::IF2;
|
||||
break;
|
||||
// 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) {
|
||||
// frequency is high enough to shift 1.LO below measurement frequency
|
||||
LO1freq = freq - HW::IF1;
|
||||
break;
|
||||
} else if(freq <= HW::IF1 - HW::LO1_minFreq) {
|
||||
// frequency is low enough to add 1.LO to measurement frequency
|
||||
LO1freq = HW::IF1 - freq;
|
||||
break;
|
||||
}
|
||||
// unable to reach required frequency with 1.LO, skip this signal ID step
|
||||
signalIDstep++;
|
||||
/* no break */
|
||||
case 2:
|
||||
// Shift both LOs to other side
|
||||
LO1freq = freq + HW::IF1;
|
||||
LO2freq = HW::IF1 + HW::IF2;
|
||||
break;
|
||||
case 3:
|
||||
// Shift second LO to other side
|
||||
LO1freq = freq - HW::IF1;
|
||||
LO2freq = HW::IF1 + HW::IF2;
|
||||
break;
|
||||
// Shift second 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) {
|
||||
// frequency is high enough to shift 1.LO below measurement frequency
|
||||
LO1freq = freq - HW::IF1;
|
||||
break;
|
||||
} else if(freq <= HW::IF1 - HW::LO1_minFreq) {
|
||||
// frequency is low enough to add 1.LO to measurement frequency
|
||||
LO1freq = HW::IF1 - freq;
|
||||
break;
|
||||
}
|
||||
// unable to reach required frequency with 1.LO, skip this signal ID step
|
||||
signalIDstep++;
|
||||
/* no break */
|
||||
case 4:
|
||||
// Use default frequencies with different ADC samplerate to remove images in final IF
|
||||
LO1freq = freq + HW::IF1;
|
||||
|
|
@ -66,7 +89,7 @@ static void StartNextSample() {
|
|||
int32_t LO1deviation = (int64_t) LO1.GetActualFrequency() - LO1freq;
|
||||
LO2freq += LO1deviation;
|
||||
// only adjust LO2 PLL if necessary (if the deviation is significantly less than the RBW it does not matter)
|
||||
if((uint32_t) abs(LO2freq - lastLO2) > s.RBW / 2) {
|
||||
if((uint32_t) abs(LO2freq - lastLO2) > actualRBW / 2) {
|
||||
Si5351.SetCLK(SiChannel::Port1LO2, LO2freq, Si5351C::PLL::B, Si5351C::DriveStrength::mA2);
|
||||
Si5351.SetCLK(SiChannel::Port2LO2, LO2freq, Si5351C::PLL::B, Si5351C::DriveStrength::mA2);
|
||||
lastLO2 = LO2freq;
|
||||
|
|
@ -88,19 +111,23 @@ void SA::Setup(Protocol::SpectrumAnalyzerSettings settings) {
|
|||
// 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 amount of required points
|
||||
points = 2 * (s.f_stop - s.f_start) / s.RBW;
|
||||
// adjust to integer multiple of requested result points (in order to have the same amount of measurements in each bin)
|
||||
points += s.pointNum - points % s.pointNum;
|
||||
binSize = points / s.pointNum;
|
||||
LOG_DEBUG("%u displayed points, resulting in %lu points and bins of size %u", s.pointNum, points, binSize);
|
||||
// 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;
|
||||
// round up to next multiple of 128
|
||||
sampleNum += 128 - sampleNum%128;
|
||||
if(sampleNum >= HW::MaxSamples) {
|
||||
sampleNum = HW::MaxSamples;
|
||||
}
|
||||
actualRBW = HW::ADCSamplerate * window_factors[s.WindowType] / sampleNum;
|
||||
FPGA::SetSamplesPerPoint(sampleNum);
|
||||
// calculate amount of required points
|
||||
points = 2 * (s.f_stop - s.f_start) / actualRBW;
|
||||
// adjust to integer multiple of requested result points (in order to have the same amount of measurements in each bin)
|
||||
points += s.pointNum - points % s.pointNum;
|
||||
binSize = points / s.pointNum;
|
||||
LOG_DEBUG("%u displayed points, resulting in %lu points and bins of size %u", s.pointNum, points, binSize);
|
||||
// set initial state
|
||||
pointCnt = 0;
|
||||
// enable the required hardware resources
|
||||
|
|
|
|||
|
|
@ -14,10 +14,6 @@
|
|||
#define LOG_MODULE "VNA"
|
||||
#include "Log.h"
|
||||
|
||||
static constexpr uint32_t IF1 = 60100000;
|
||||
static constexpr uint32_t IF1_alternate = 57000000;
|
||||
static constexpr uint32_t IF2 = 250000;
|
||||
|
||||
static VNA::SweepCallback sweepCallback;
|
||||
static Protocol::SweepSettings settings;
|
||||
static uint16_t pointCnt;
|
||||
|
|
@ -27,11 +23,10 @@ static bool active = false;
|
|||
|
||||
using IFTableEntry = struct {
|
||||
uint16_t pointCnt;
|
||||
uint32_t IF1;
|
||||
uint8_t clkconfig[8];
|
||||
};
|
||||
|
||||
static constexpr uint16_t IFTableNumEntries = 100;
|
||||
static constexpr uint16_t IFTableNumEntries = 500;
|
||||
static IFTableEntry IFTable[IFTableNumEntries];
|
||||
static uint16_t IFTableIndexCnt = 0;
|
||||
|
||||
|
|
@ -58,6 +53,7 @@ bool VNA::Setup(Protocol::SweepSettings s, SweepCallback cb) {
|
|||
uint32_t samplesPerPoint = (HW::ADCSamplerate / s.if_bandwidth);
|
||||
// round up to next multiple of 128 (128 samples are spread across 35 IF2 periods)
|
||||
samplesPerPoint = ((uint32_t) ((samplesPerPoint + 127) / 128)) * 128;
|
||||
uint32_t actualBandwidth = HW::ADCSamplerate / samplesPerPoint;
|
||||
// has to be one less than actual number of samples
|
||||
FPGA::SetSamplesPerPoint(samplesPerPoint);
|
||||
|
||||
|
|
@ -70,89 +66,82 @@ bool VNA::Setup(Protocol::SweepSettings s, SweepCallback cb) {
|
|||
attenuator = (-1000 - s.cdbm_excitation) / 25;
|
||||
}
|
||||
|
||||
uint32_t last_IF1 = IF1;
|
||||
uint32_t last_LO2 = HW::IF1 - HW::IF2;
|
||||
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);
|
||||
Si5351.ResetPLL(Si5351C::PLL::B);
|
||||
|
||||
IFTableIndexCnt = 0;
|
||||
|
||||
bool last_lowband = false;
|
||||
|
||||
if(!s.suppressPeaks) {
|
||||
// invalidate first entry of IFTable, preventing switing of 2.LO in halted callback
|
||||
IFTable[0].pointCnt = 0xFFFF;
|
||||
}
|
||||
|
||||
// Transfer PLL configuration to FPGA
|
||||
for (uint16_t i = 0; i < points; i++) {
|
||||
uint64_t freq = s.f_start + (s.f_stop - s.f_start) * i / (points - 1);
|
||||
// SetFrequency only manipulates the register content in RAM, no SPI communication is done.
|
||||
// No mode-switch of FPGA necessary here.
|
||||
|
||||
// Check which IF frequency is a better fit
|
||||
uint32_t used_IF = IF1;
|
||||
// if (freq < 290000000) {
|
||||
// // for low frequencies the harmonics of the IF and source frequency should not be too close
|
||||
// uint32_t dist_primary;
|
||||
// if(freq < IF1) {
|
||||
// dist_primary = IF1 - freq * (IF1 / freq);
|
||||
// if (dist_primary > freq / 2) {
|
||||
// dist_primary = freq - dist_primary;
|
||||
// }
|
||||
// } else {
|
||||
// dist_primary = freq - IF1 * (freq / IF1);
|
||||
// if (dist_primary > IF1 / 2) {
|
||||
// dist_primary = IF1 - dist_primary;
|
||||
// }
|
||||
// }
|
||||
// uint32_t dist_alternate;
|
||||
// if(freq < IF1_alternate) {
|
||||
// dist_alternate = IF1_alternate - freq * (IF1_alternate / freq);
|
||||
// if (dist_alternate > freq / 2) {
|
||||
// dist_alternate = freq - dist_primary;
|
||||
// }
|
||||
// } else {
|
||||
// dist_alternate = freq - IF1_alternate * (freq / IF1_alternate);
|
||||
// if (dist_alternate > IF1_alternate / 2) {
|
||||
// dist_alternate = IF1_alternate - dist_primary;
|
||||
// }
|
||||
// }
|
||||
// if(dist_alternate > dist_primary) {
|
||||
// used_IF = IF1_alternate;
|
||||
// }
|
||||
// LOG_INFO("Distance: %lu/%lu", dist_primary, dist_alternate);
|
||||
// }
|
||||
bool needs_halt = false;
|
||||
if (used_IF != last_IF1) {
|
||||
last_IF1 = used_IF;
|
||||
LOG_INFO("Changing IF1 to %lu at point %u (f=%lu)", used_IF, i, (uint32_t) freq);
|
||||
needs_halt = true;
|
||||
if (IFTableIndexCnt >= IFTableNumEntries) {
|
||||
LOG_ERR("IF table full, unable to add new entry");
|
||||
return false;
|
||||
}
|
||||
IFTable[IFTableIndexCnt].pointCnt = i;
|
||||
IFTable[IFTableIndexCnt].IF1 = used_IF;
|
||||
// Configure LO2 for the changed IF1. This is not necessary right now but it will generate
|
||||
// the correct clock settings
|
||||
Si5351.SetCLK(SiChannel::RefLO2, used_IF + IF2, Si5351C::PLL::A, Si5351C::DriveStrength::mA2);
|
||||
// store calculated clock configuration for later change
|
||||
Si5351.ReadRawCLKConfig(1, IFTable[IFTableIndexCnt].clkconfig);
|
||||
IFTableIndexCnt++;
|
||||
}
|
||||
uint64_t actualSourceFreq;
|
||||
bool lowband = false;
|
||||
if (freq < BandSwitchFrequency) {
|
||||
needs_halt = true;
|
||||
lowband = true;
|
||||
actualSourceFreq = freq;
|
||||
} else {
|
||||
Source.SetFrequency(freq);
|
||||
actualSourceFreq = Source.GetActualFrequency();
|
||||
}
|
||||
if (last_lowband && !lowband) {
|
||||
// additional halt before first highband point to enable highband source
|
||||
needs_halt = true;
|
||||
}
|
||||
LO1.SetFrequency(freq + used_IF);
|
||||
LO1.SetFrequency(freq + HW::IF1);
|
||||
uint32_t actualFirstIF = LO1.GetActualFrequency() - actualSourceFreq;
|
||||
uint32_t actualFinalIF = actualFirstIF - last_LO2;
|
||||
uint32_t IFdeviation = abs(actualFinalIF - HW::IF2);
|
||||
bool needs_LO2_shift = false;
|
||||
if(IFdeviation > actualBandwidth / 2) {
|
||||
needs_LO2_shift = true;
|
||||
}
|
||||
if (s.suppressPeaks && needs_LO2_shift) {
|
||||
if (IFTableIndexCnt < IFTableNumEntries) {
|
||||
// still room in table
|
||||
LOG_INFO("Changing 2.LO at point %lu to reach correct 2.IF frequency");
|
||||
needs_halt = true;
|
||||
IFTable[IFTableIndexCnt].pointCnt = i;
|
||||
// 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;
|
||||
Si5351.SetCLK(SiChannel::RefLO2, last_LO2,
|
||||
Si5351C::PLL::B, Si5351C::DriveStrength::mA2);
|
||||
// store calculated clock configuration for later change
|
||||
Si5351.ReadRawCLKConfig(1, IFTable[IFTableIndexCnt].clkconfig);
|
||||
IFTableIndexCnt++;
|
||||
needs_LO2_shift = false;
|
||||
}
|
||||
}
|
||||
if(needs_LO2_shift) {
|
||||
// if shift is still needed either peak suppression is disabled or no more room in IFTable was available
|
||||
LOG_WARN(
|
||||
"PLL deviation of %luHz for measurement at %lu%06luHz, will cause a peak",
|
||||
IFdeviation, (uint32_t ) (freq / 1000000), (uint32_t ) (freq % 1000000));
|
||||
}
|
||||
|
||||
FPGA::WriteSweepConfig(i, lowband, Source.GetRegisters(),
|
||||
LO1.GetRegisters(), attenuator, freq, FPGA::SettlingTime::us20,
|
||||
FPGA::Samples::SPPRegister, needs_halt);
|
||||
last_lowband = lowband;
|
||||
}
|
||||
// // revert clk configuration to previous value (might have been changed in sweep calculation)
|
||||
// Si5351.SetCLK(1, IF1 + IF2, Si5351C::PLL::B, Si5351C::DriveStrength::mA2);
|
||||
// Si5351.ResetPLL(Si5351C::PLL::B);
|
||||
// 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.ResetPLL(Si5351C::PLL::B);
|
||||
// Enable mixers/amplifier/PLLs
|
||||
FPGA::SetWindow(FPGA::Window::None);
|
||||
FPGA::Enable(FPGA::Periphery::Port1Mixer);
|
||||
|
|
@ -249,15 +238,15 @@ void VNA::SweepHalted() {
|
|||
}
|
||||
LOG_DEBUG("Halted before point %d", pointCnt);
|
||||
// Check if IF table has entry at this point
|
||||
// if (IFTable[IFTableIndexCnt].pointCnt == pointCnt) {
|
||||
// LOG_DEBUG("Shifting IF to %lu at point %u",
|
||||
// IFTable[IFTableIndexCnt].IF1, pointCnt);
|
||||
// Si5351.WriteRawCLKConfig(1, IFTable[IFTableIndexCnt].clkconfig);
|
||||
// Si5351.WriteRawCLKConfig(4, IFTable[IFTableIndexCnt].clkconfig);
|
||||
// Si5351.WriteRawCLKConfig(5, IFTable[IFTableIndexCnt].clkconfig);
|
||||
// Si5351.ResetPLL(Si5351C::PLL::B);
|
||||
// IFTableIndexCnt++;
|
||||
// }
|
||||
if (IFTable[IFTableIndexCnt].pointCnt == pointCnt) {
|
||||
Si5351.WriteRawCLKConfig(SiChannel::Port1LO2, IFTable[IFTableIndexCnt].clkconfig);
|
||||
Si5351.WriteRawCLKConfig(SiChannel::Port2LO2, IFTable[IFTableIndexCnt].clkconfig);
|
||||
Si5351.WriteRawCLKConfig(SiChannel::RefLO2, IFTable[IFTableIndexCnt].clkconfig);
|
||||
Si5351.ResetPLL(Si5351C::PLL::B);
|
||||
IFTableIndexCnt++;
|
||||
// PLL reset causes the 2.LO to turn off briefly and then ramp on back, needs delay before next point
|
||||
Delay::us(1300);
|
||||
}
|
||||
uint64_t frequency = settings.f_start
|
||||
+ (settings.f_stop - settings.f_start) * pointCnt
|
||||
/ (settings.points - 1);
|
||||
|
|
|
|||
|
|
@ -57,8 +57,6 @@ void DMA1_Channel1_IRQHandler(void);
|
|||
void DMA1_Channel2_IRQHandler(void);
|
||||
void DMA1_Channel3_IRQHandler(void);
|
||||
void DMA1_Channel4_IRQHandler(void);
|
||||
void USB_HP_IRQHandler(void);
|
||||
void USB_LP_IRQHandler(void);
|
||||
void TIM1_TRG_COM_TIM17_IRQHandler(void);
|
||||
void UCPD1_IRQHandler(void);
|
||||
/* USER CODE BEGIN EFP */
|
||||
|
|
|
|||
|
|
@ -507,11 +507,6 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef* hpcd)
|
|||
|
||||
/* Peripheral clock enable */
|
||||
__HAL_RCC_USB_CLK_ENABLE();
|
||||
/* USB interrupt Init */
|
||||
HAL_NVIC_SetPriority(USB_HP_IRQn, 6, 0);
|
||||
// HAL_NVIC_EnableIRQ(USB_HP_IRQn);
|
||||
HAL_NVIC_SetPriority(USB_LP_IRQn, 6, 0);
|
||||
// HAL_NVIC_EnableIRQ(USB_LP_IRQn);
|
||||
/* USER CODE BEGIN USB_MspInit 1 */
|
||||
|
||||
/* USER CODE END USB_MspInit 1 */
|
||||
|
|
@ -541,9 +536,6 @@ void HAL_PCD_MspDeInit(PCD_HandleTypeDef* hpcd)
|
|||
*/
|
||||
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);
|
||||
|
||||
/* USB interrupt DeInit */
|
||||
HAL_NVIC_DisableIRQ(USB_HP_IRQn);
|
||||
HAL_NVIC_DisableIRQ(USB_LP_IRQn);
|
||||
/* USER CODE BEGIN USB_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END USB_MspDeInit 1 */
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@
|
|||
extern DMA_HandleTypeDef hdma_spi1_rx;
|
||||
extern DMA_HandleTypeDef hdma_spi1_tx;
|
||||
extern TIM_HandleTypeDef htim1;
|
||||
extern PCD_HandleTypeDef hpcd_USB_FS;
|
||||
extern TIM_HandleTypeDef htim17;
|
||||
|
||||
/* USER CODE BEGIN EV */
|
||||
|
|
@ -219,34 +218,6 @@ void DMA1_Channel4_IRQHandler(void)
|
|||
/* USER CODE END DMA1_Channel4_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles USB high priority interrupt remap.
|
||||
*/
|
||||
void USB_HP_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN USB_HP_IRQn 0 */
|
||||
|
||||
/* USER CODE END USB_HP_IRQn 0 */
|
||||
HAL_PCD_IRQHandler(&hpcd_USB_FS);
|
||||
/* USER CODE BEGIN USB_HP_IRQn 1 */
|
||||
|
||||
/* USER CODE END USB_HP_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles USB low priority interrupt remap.
|
||||
*/
|
||||
void USB_LP_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN USB_LP_IRQn 0 */
|
||||
|
||||
/* USER CODE END USB_LP_IRQn 0 */
|
||||
HAL_PCD_IRQHandler(&hpcd_USB_FS);
|
||||
/* USER CODE BEGIN USB_LP_IRQn 1 */
|
||||
|
||||
/* USER CODE END USB_LP_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles TIM1 trigger and commutation interrupts and TIM17 global interrupt.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -165,8 +165,6 @@ NVIC.TIM1_TRG_COM_TIM17_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true
|
|||
NVIC.TimeBase=TIM1_TRG_COM_TIM17_IRQn
|
||||
NVIC.TimeBaseIP=TIM17
|
||||
NVIC.UCPD1_IRQn=true\:6\:0\:true\:false\:true\:true\:true\:false
|
||||
NVIC.USB_HP_IRQn=true\:6\:0\:true\:false\:true\:true\:true\:true
|
||||
NVIC.USB_LP_IRQn=true\:6\:0\:true\:false\:true\:true\:true\:true
|
||||
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
PA1.GPIOParameters=GPIO_Label
|
||||
PA1.GPIO_Label=FPGA_AUX1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue