minor spur/phase noise improvements
This commit is contained in:
parent
ac1e9fcec6
commit
06a7365a0c
@ -119,6 +119,29 @@ bool Si5351C::SetCLK(uint8_t clknum, uint32_t frequency, PLL source, DriveStreng
|
||||
return WriteClkConfig(c, clknum);
|
||||
}
|
||||
|
||||
bool Si5351C::SetBypass(uint8_t clknum, PLLSource source, DriveStrength strength) {
|
||||
// compile CLKControl register
|
||||
uint8_t clkcontrol = 0x00;
|
||||
if (source == PLLSource::CLKIN) {
|
||||
clkcontrol |= 0x04;
|
||||
}
|
||||
switch (strength) {
|
||||
case DriveStrength::mA2:
|
||||
break;
|
||||
case DriveStrength::mA4:
|
||||
clkcontrol |= 0x01;
|
||||
break;
|
||||
case DriveStrength::mA6:
|
||||
clkcontrol |= 0x02;
|
||||
break;
|
||||
case DriveStrength::mA8:
|
||||
clkcontrol |= 0x03;
|
||||
break;
|
||||
}
|
||||
Reg reg = (Reg) ((int) Reg::CLK0Control + clknum);
|
||||
return WriteRegister(reg, clkcontrol);
|
||||
}
|
||||
|
||||
bool Si5351C::SetCLKtoXTAL(uint8_t clknum) {
|
||||
Reg reg = (Reg) ((int) Reg::CLK0Control + clknum);
|
||||
LOG_INFO("Connecting CLK%d to XTAL", clknum);
|
||||
@ -163,8 +186,15 @@ bool Si5351C::WritePLLConfig(PLLConfig config, PLL pll) {
|
||||
PllData[5] = ((config.P3 >> 12) & 0xF0) | ((config.P2 >> 16) & 0x0F);
|
||||
PllData[6] = (config.P2 >> 8) & 0xFF;
|
||||
PllData[7] = config.P2 & 0xFF;
|
||||
// Check if integer mode is applicable
|
||||
Reg reg = pll == PLL::A ? Reg::CLK6Control : Reg::CLK7Control;
|
||||
if (config.P2 == 0 && config.P1 % 128 == 0) {
|
||||
SetBits(reg, 0x40);
|
||||
} else {
|
||||
ClearBits(reg, 0x40);
|
||||
}
|
||||
bool success = true;
|
||||
Reg reg = pll == PLL::A ? Reg::MSNA_CONFIG : Reg::MSNB_CONFIG;
|
||||
reg = pll == PLL::A ? Reg::MSNA_CONFIG : Reg::MSNB_CONFIG;
|
||||
success &= WriteRegisterRange(reg, PllData, sizeof(PllData));
|
||||
reg = pll == PLL::A ? Reg::CLK6Control : Reg::CLK7Control;
|
||||
if (config.IntegerMode) {
|
||||
@ -229,6 +259,11 @@ bool Si5351C::WriteClkConfig(ClkConfig config, uint8_t clknum) {
|
||||
clkcontrol |= 0x03;
|
||||
break;
|
||||
}
|
||||
// Check if integer mode is applicable
|
||||
if(config.P2 == 0 && config.P1%128 == 0) {
|
||||
// Use integer mode
|
||||
clkcontrol |= 0x40;
|
||||
}
|
||||
Reg reg = (Reg) ((int) Reg::CLK0Control + clknum);
|
||||
success &= WriteRegister(reg, clkcontrol);
|
||||
if (clknum <= 5) {
|
||||
@ -242,6 +277,7 @@ bool Si5351C::WriteClkConfig(ClkConfig config, uint8_t clknum) {
|
||||
ClkData[5] = ((config.P3 >> 12) & 0xF0) | ((config.P2 >> 16) & 0x0F);
|
||||
ClkData[6] = (config.P2 >> 8) & 0xFF;
|
||||
ClkData[7] = config.P2 & 0xFF;
|
||||
|
||||
// Calculate address of register control block
|
||||
reg = (Reg) ((int) Reg::MS0_CONFIG + 8 * clknum);
|
||||
success &= WriteRegisterRange(reg, ClkData, sizeof(ClkData));
|
||||
@ -318,28 +354,6 @@ void Si5351C::FindOptimalDivider(uint32_t f_pll, uint32_t f, uint32_t &P1,
|
||||
// always using the highest modulus divider results in less than 1Hz deviation for all frequencies, that is good enough
|
||||
uint32_t best_c = (1UL << 20) - 1;
|
||||
uint32_t best_b = (uint64_t) f_rem * best_c / f;
|
||||
// uint32_t best_deviation = UINT32_MAX;
|
||||
// for (uint32_t c = (1UL << 20) - 1; c >= (1UL << 19); c--) {
|
||||
// uint32_t guess_b = (uint64_t) f_rem * c / f;
|
||||
// for (uint32_t b = guess_b; b <= guess_b + 1; b++) {
|
||||
// int32_t f_div = (uint64_t) f * b / c;
|
||||
// uint32_t deviation = abs(f_rem - f_div);
|
||||
// if (deviation < best_deviation) {
|
||||
// best_b = b;
|
||||
// best_c = c;
|
||||
// best_deviation = deviation;
|
||||
// if (deviation <= 3) {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (best_deviation <= 3) {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// LOG_DEBUG(
|
||||
// "Optimal divider for %luHz/%luHz is: a=%lu, b=%lu, c=%lu (%luHz deviation)",
|
||||
// f_pll, f, a, best_b, best_c, best_deviation);
|
||||
// convert to Si5351C parameters
|
||||
uint32_t floor = 128 * best_b / best_c;
|
||||
P1 = 128 * a + floor - 512;
|
||||
@ -360,4 +374,3 @@ bool Si5351C::ReadRawCLKConfig(uint8_t clknum, uint8_t *config) {
|
||||
return ReadRegisterRange(reg, config, 8);
|
||||
}
|
||||
|
||||
|
||||
|
@ -33,6 +33,7 @@ public:
|
||||
bool ConfigureCLKIn(uint32_t clkin_freq);
|
||||
bool SetPLL(PLL pll, uint32_t frequency, PLLSource src);
|
||||
bool SetCLK(uint8_t clknum, uint32_t frequency, PLL source, DriveStrength strength = DriveStrength::mA2, uint32_t PLLFreqOverride = 0);
|
||||
bool SetBypass(uint8_t clknum, PLLSource source, DriveStrength strength = DriveStrength::mA2);
|
||||
bool SetCLKtoXTAL(uint8_t clknum);
|
||||
bool SetCLKToCLKIN(uint8_t clknum);
|
||||
bool Enable(uint8_t clknum);
|
||||
|
@ -42,7 +42,7 @@ bool MAX2871::Init(uint32_t f_ref, bool doubler, uint16_t r, bool div2) {
|
||||
// recommended phase setting
|
||||
regs[1] |= (1UL << 15);
|
||||
|
||||
SetMode(Mode::LowSpur2);
|
||||
SetMode(Mode::LowNoise);
|
||||
// for all other CP modes the PLL reports unlock condition (output signal appears to be locked)
|
||||
SetCPMode(CPMode::CP20);
|
||||
SetCPCurrent(15);
|
||||
|
@ -92,10 +92,10 @@ bool HW::Init() {
|
||||
Si5351.Init();
|
||||
|
||||
// Use Si5351 to generate reference frequencies for other PLLs and ADC
|
||||
Si5351.SetPLL(Si5351C::PLL::A, 800000000, Si5351C::PLLSource::XTAL);
|
||||
Si5351.SetPLL(Si5351C::PLL::A, 832000000, Si5351C::PLLSource::XTAL);
|
||||
while(!Si5351.Locked(Si5351C::PLL::A));
|
||||
|
||||
Si5351.SetPLL(Si5351C::PLL::B, 800000000, Si5351C::PLLSource::XTAL);
|
||||
Si5351.SetPLL(Si5351C::PLL::B, 832000000, Si5351C::PLLSource::XTAL);
|
||||
while(!Si5351.Locked(Si5351C::PLL::B));
|
||||
|
||||
extRefInUse = 0;
|
||||
@ -103,8 +103,10 @@ bool HW::Init() {
|
||||
Si5351.Disable(SiChannel::ReferenceOut);
|
||||
|
||||
// Both MAX2871 get a 100MHz reference
|
||||
// Si5351.SetBypass(SiChannel::Source, Si5351C::PLLSource::XTAL);
|
||||
Si5351.SetCLK(SiChannel::Source, HW::PLLRef, Si5351C::PLL::A, Si5351C::DriveStrength::mA2);
|
||||
Si5351.Enable(SiChannel::Source);
|
||||
// Si5351.SetBypass(SiChannel::LO1, Si5351C::PLLSource::XTAL);
|
||||
Si5351.SetCLK(SiChannel::LO1, HW::PLLRef, Si5351C::PLL::A, Si5351C::DriveStrength::mA2);
|
||||
Si5351.Enable(SiChannel::LO1);
|
||||
// 16MHz FPGA clock
|
||||
|
@ -34,7 +34,7 @@ static constexpr uint32_t IF2 = 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 = 100000000;
|
||||
static constexpr uint32_t PLLRef = 104000000;
|
||||
static constexpr uint32_t BandSwitchFrequency = 25000000;
|
||||
|
||||
static constexpr uint8_t ADCprescaler = FPGA::Clockrate / ADCSamplerate;
|
||||
|
Loading…
Reference in New Issue
Block a user