I think I figured this out. By looking at VFO with an oscilloscope I could catch a brief glitch (~1.5ms) in the signal when the frequency is changed:
It was hard to notice because you can't easily trigger on this. I had to manually trigger single captures while tuning for some time to see this.
Then by googling "si5351 output glitches" I've found this piece of code on the QRP Labs website. The comment states:
Reset the PLL. This causes a glitch in the output. For small changes to
the parameters, you don't need to reset the PLL, and there is no glitch.
Then I realized the source of the problem and how to fix it. Here is the original version of my code:
void changeFrequency(int32_t delta) {
targetFrequency += frequencyStep*delta;
if(targetFrequency < 7000000) {
targetFrequency = 7000000;
} else if(targetFrequency > 7200000) {
targetFrequency = 7200000;
}
if(targetFrequency < 10000000) {
Fvfo = Fbfo-targetFrequency; // LSB
} else {
Fvfo = Fbfo+targetFrequency; // USB
}
si5351_EnableOutputs((1<<2));
si5351_SetupCLK0(Fvfo, SI5351_DRIVE_STRENGTH_4MA);
si5351_EnableOutputs((1 << 2)|(1<<0));
}
Here si5351_SetupCLK0
is called every time the frequency is changed. The procedure changes the PLL, MS and Rdiv settings for the channel. As an author of this Si5351 driver I'm well aware that PLL settings are always the same for frequencies below 81 MHz (also this is a documented behavior which can be relied on in the future versions).
Thus the code was changed as following:
void changeFrequency(int32_t delta) {
static bool pllSetupDone = false;
si5351PLLConfig_t pll_conf;
si5351OutputConfig_t out_conf;
targetFrequency += frequencyStep*delta;
if(targetFrequency < 7000000) {
targetFrequency = 7000000;
} else if(targetFrequency > 7200000) {
targetFrequency = 7200000;
}
if(targetFrequency < 10000000) {
Fvfo = Fbfo-targetFrequency; // LSB
} else {
Fvfo = Fbfo+targetFrequency; // USB
}
si5351_EnableOutputs((1<<2));
si5351_Calc(Fvfo, &pll_conf, &out_conf);
if(!pllSetupDone) {
// Setting up the PLL causes a brief (~1.5ms) glitch in the VFO output
// which sounds like a loud popping sound the the speaker.
// By setting up the PLL only once we get rid of this popping sound.
si5351_SetupPLL(SI5351_PLL_A, &pll_conf);
pllSetupDone = true;
}
si5351_SetupOutput(0, SI5351_PLL_A, SI5351_DRIVE_STRENGTH_4MA, &out_conf);
si5351_EnableOutputs((1 << 2)|(1<<0));
}
Now the expansive call si5351_SetupPLL
is made only once, the glitch is gone and the popping sound is eliminated. Well, almost. You can still hear a very quiet popping when the antenna is disconnected. But there is no popping when the antenna is connected. Interestingly you can observe the exactly same behavior in QCX transceiver made by guess which company.