Skip to content

Commit b133728

Browse files
committed
switch PLL reference to avoid integer spurs
1 parent 224b2ab commit b133728

File tree

1 file changed

+72
-16
lines changed
  • Software/VNA_embedded/Application

1 file changed

+72
-16
lines changed

Software/VNA_embedded/Application/VNA.cpp

Lines changed: 72 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ static constexpr uint16_t maxPointsBetweenHalts = 40;
5050
static constexpr uint16_t full2portDatapointSize = 66;// See Protocol::VNADatapoint::
5151
static constexpr uint32_t reservedUSBbuffer = (maxPointsBetweenHalts + 2 /*additional buffer*/) * (full2portDatapointSize + 8 /*USB packet overhead*/);
5252

53+
static uint32_t PLLRefFreqs[] = {HW::PLLRef, HW::PLLRef - 1000000};
54+
static constexpr uint8_t PLLRefFreqsNum = sizeof(PLLRefFreqs)/sizeof(PLLRefFreqs[0]);
55+
static uint8_t sourceRefIndex, LO1RefIndex;
56+
5357
using namespace HWHAL;
5458

5559
static uint64_t getPointFrequency(uint16_t pointNum) {
@@ -71,16 +75,43 @@ static uint64_t getPointFrequency(uint16_t pointNum) {
7175
}
7276
}
7377

74-
static void setPLLFrequencies(uint64_t f) {
78+
static bool setPLLFrequencies(uint64_t f) {
79+
uint64_t sourceFreq = 0;
80+
uint64_t LOFreq = 0;
7581
if(f > HW::Info.limits_maxFreq) {
76-
Source.SetFrequency(f / sourceHarmonic);
77-
LO1.SetFrequency((f + HW::getIF1()) / LOHarmonic);
82+
sourceFreq = f / sourceHarmonic;
83+
LOFreq = (f + HW::getIF1()) / LOHarmonic;
7884
} else {
7985
if(f >= HW::BandSwitchFrequency) {
80-
Source.SetFrequency(f);
86+
sourceFreq = f;
8187
}
82-
LO1.SetFrequency(f + HW::getIF1());
88+
LOFreq = f + HW::getIF1();
89+
}
90+
if(sourceFreq > 0) {
91+
Source.SetFrequency(sourceFreq);
8392
}
93+
LO1.SetFrequency(LOFreq);
94+
bool needsRefSwitch = false;
95+
if(settings.suppressPeaks) {
96+
// Integer spurs can cause a small peak.
97+
uint32_t sourceDist = Source.DistanceToIntegerSpur();
98+
uint32_t LODist = LO1.DistanceToIntegerSpur();
99+
if((sourceDist > 0) && (sourceDist < 3 * HW::getIF2())) {
100+
LOG_INFO("Source spur at %lu: %lu", (uint32_t) f, sourceDist);
101+
sourceRefIndex = !sourceRefIndex;
102+
Source.SetReference(PLLRefFreqs[sourceRefIndex], false, 1, false);
103+
Source.SetFrequency(sourceFreq);
104+
needsRefSwitch = true;
105+
}
106+
if((LODist > 0) && (LODist < 3 * HW::getIF2())) {
107+
LOG_INFO("LO spur at %lu", (uint32_t) f);
108+
LO1RefIndex = !LO1RefIndex;
109+
LO1.SetReference(PLLRefFreqs[LO1RefIndex], false, 1, false);
110+
LO1.SetFrequency(LOFreq);
111+
needsRefSwitch = true;
112+
}
113+
}
114+
return needsRefSwitch;
84115
}
85116

86117
static bool needs2LOshift(uint64_t f, uint32_t current2LO, uint32_t IFBW, uint32_t *new2LO) {
@@ -108,11 +139,17 @@ static bool needs2LOshift(uint64_t f, uint32_t current2LO, uint32_t IFBW, uint32
108139
}
109140

110141
bool VNA::Setup(Protocol::SweepSettings s) {
142+
// Abort possible active sweep first
111143
VNA::Stop();
112144
vTaskDelay(5);
113145
data.clear();
114146
HW::SetMode(HW::Mode::VNA);
115-
// Abort possible active sweep first
147+
148+
sourceRefIndex = 0;
149+
LO1RefIndex = 0;
150+
Source.SetReference(PLLRefFreqs[sourceRefIndex], false, 1, false);
151+
LO1.SetReference(PLLRefFreqs[LO1RefIndex], false, 1, false);
152+
116153
FPGA::SetMode(FPGA::Mode::FPGA);
117154
FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, HW::getADCPrescaler());
118155
FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, HW::getDFTPhaseInc());
@@ -199,7 +236,9 @@ bool VNA::Setup(Protocol::SweepSettings s) {
199236
}
200237
// SetFrequency only manipulates the register content in RAM, no SPI communication is done.
201238
// No mode-switch of FPGA necessary here.
202-
setPLLFrequencies(freq);
239+
if(setPLLFrequencies(freq)) {
240+
needs_halt = true;
241+
}
203242
uint32_t new_LO2;
204243
auto needs_shift = needs2LOshift(freq, last_LO2, actualBandwidth, &new_LO2);
205244
if(needs_shift) {
@@ -249,6 +288,11 @@ bool VNA::Setup(Protocol::SweepSettings s) {
249288
FPGA::Samples::SPPRegister, needs_halt);
250289
last_lowband = lowband;
251290
}
291+
// reset a possibly changed PLL reference index
292+
sourceRefIndex = 0;
293+
LO1RefIndex = 0;
294+
Source.SetReference(PLLRefFreqs[sourceRefIndex], false, 1, false);
295+
LO1.SetReference(PLLRefFreqs[LO1RefIndex], false, 1, false);
252296
// revert clk configuration to previous value (might have been changed in sweep calculation)
253297
Si5351.SetCLK(SiChannel::RefLO2, HW::getIF1() - HW::getIF2(), Si5351C::PLL::B, Si5351C::DriveStrength::mA2);
254298
Si5351.ResetPLL(Si5351C::PLL::B);
@@ -438,10 +482,30 @@ void VNA::SweepHalted() {
438482
Si5351.Disable(SiChannel::LowbandSource);
439483
FPGA::Enable(FPGA::Periphery::SourceRF);
440484
}
485+
486+
if (pointCnt == 0 && settings.suppressPeaks) {
487+
sourceRefIndex = 0;
488+
LO1RefIndex = 0;
489+
Source.SetReference(PLLRefFreqs[sourceRefIndex], false, 1, false);
490+
LO1.SetReference(PLLRefFreqs[LO1RefIndex], false, 1, false);
491+
// update PLL reference frequencies
492+
Si5351.SetCLK(SiChannel::Source, PLLRefFreqs[sourceRefIndex], Si5351C::PLL::A, Si5351C::DriveStrength::mA8);
493+
Si5351.SetCLK(SiChannel::LO1, PLLRefFreqs[LO1RefIndex], Si5351C::PLL::A, Si5351C::DriveStrength::mA8);
494+
last_LO2 = HW::getIF1() - HW::getIF2();
495+
Si5351.SetPLL(Si5351C::PLL::B, last_LO2*HW::LO2Multiplier, HW::Ref::getSource());
496+
Si5351.ResetPLL(Si5351C::PLL::B);
497+
Si5351.WaitForLock(Si5351C::PLL::B, 10);
498+
HAL_Delay(2);
499+
}
500+
441501
if(settings.suppressPeaks) {
442502
// does not actually change PLL settings, just calculates the register values and
443503
// is required to determine the need for a 2.LO shift
444-
setPLLFrequencies(frequency);
504+
if(setPLLFrequencies(frequency)) {
505+
// update PLL reference frequencies
506+
Si5351.SetCLK(SiChannel::Source, PLLRefFreqs[sourceRefIndex], Si5351C::PLL::A, Si5351C::DriveStrength::mA8);
507+
Si5351.SetCLK(SiChannel::LO1, PLLRefFreqs[LO1RefIndex], Si5351C::PLL::A, Si5351C::DriveStrength::mA8);
508+
}
445509
if(needs2LOshift(frequency, last_LO2, actualBandwidth, &last_LO2)) {
446510
Si5351.SetPLL(Si5351C::PLL::B, last_LO2*HW::LO2Multiplier, HW::Ref::getSource());
447511
Si5351.ResetPLL(Si5351C::PLL::B);
@@ -451,14 +515,6 @@ void VNA::SweepHalted() {
451515
}
452516
}
453517

454-
if (pointCnt == 0) {
455-
last_LO2 = HW::getIF1() - HW::getIF2();
456-
Si5351.SetPLL(Si5351C::PLL::B, last_LO2*HW::LO2Multiplier, HW::Ref::getSource());
457-
Si5351.ResetPLL(Si5351C::PLL::B);
458-
Si5351.WaitForLock(Si5351C::PLL::B, 10);
459-
HAL_Delay(2);
460-
}
461-
462518
if(adcShiftRequired) {
463519
FPGA::WriteRegister(FPGA::Reg::ADCPrescaler, alternativePrescaler);
464520
FPGA::WriteRegister(FPGA::Reg::PhaseIncrement, alternativePhaseInc);

0 commit comments

Comments
 (0)