¿ªÔÆÌåÓý

ctrl + shift + ? for shortcuts
© 2025 Groups.io

Re: Where does this noise/instability come from at and around 300MHz?


 

This is the code I use to find the PLL min/max limits, but any desired code will do ..

uint32_t si5351a_pllLocked(const uint8_t pll, const uint32_t timeout_us)
{
uint8_t pll_bit;
uint32_t locked_cycles = 0;

if (rev_id == 0 || pll >= 2)
return 0; // error

switch (pll)
{
default: return 0;
case 0: pll_bit = 1u << 5; break; // PLL-A
case 1: pll_bit = 1u << 6; break; // PLL-B
}

if (timeout_us > 0)
{ // wait for the PLL to lock (with timeout)
uint32_t lock_cycle = 0;

//ITM->LAR = 0xC5ACCE55; // unlock the debug registers
//CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; //
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; // turn on the cycle counter
const uint32_t start_cycle = DWT->CYCCNT; //

const uint32_t timeout_cycles = ((uint64_t)SystemCoreClock * timeout_us) / 1000000;
const uint32_t lock_cycles = ((uint64_t)SystemCoreClock * 10) / 1000000; // PLL needs to stay locked for at least 10us

while (1)
{
const uint32_t cycle = DWT->CYCCNT;
const uint32_t cycles = cycle - start_cycle;

if (cycles >= timeout_cycles)
break; // timed out

if (si5351a_read(SI5351_DEV_STATUS) & pll_bit)
{ // unlocked
lock_cycle = 0;
locked_cycles = 0;
continue;
}

if (lock_cycle == 0)
lock_cycle = cycle; // start of lock

// length of time it's been locked
locked_cycles = cycles - lock_cycle;

if (locked_cycles >= lock_cycles)
break; // been locked for long enough
}
}

return (si5351a_read(SI5351_DEV_STATUS) & pll_bit) ? 0 : ((uint64_t)locked_cycles * 1000000) / SystemCoreClock; // 0 = unlocked, otherwise return the time it took to lock
}

void si5351a_findVCOLimits(void)
{ // scan the PLL's VCO's across a frequency range to find their min and max tuning limits

const uint32_t start_Hz = xtal_Hz * 15;
const uint32_t stop_Hz = xtal_Hz * 90;
const uint32_t step_Hz = 20000000; // step the PLL's in 20MHz steps .. seems as good as any?
/*
uint32_t min_lock_time_us = 0;
uint32_t max_lock_time_us = 0;
*/
uint8_t pll;

min_pll_Hz = 0;
max_pll_Hz = 0;

// scan both PLL's across a wide frequency range
for (pll = 0; pll < 2; pll++)
{
uint32_t min_Hz = 0;
uint32_t max_Hz = 0;

uint32_t fvco_Hz = start_Hz;

// disable PLL INTEGER mode
si5351a_write(SI5351_CLK_CONTROL + 6 + pll, si5351a_read(SI5351_CLK_CONTROL + 6 + pll) & ~(1u << 6));

// scan from low to high frequency
while (fvco_Hz <= stop_Hz)
{
uint32_t pll_a;
uint32_t pll_b;
uint32_t pll_c;

// calculate the PLL register values
const uint32_t vco_Hz = calcPLL((uint64_t)fvco_Hz * SI5351_FREQ_MULT, &pll_a, &pll_b, &pll_c) / SI5351_FREQ_MULT;

if (vco_Hz == fvco_Hz)
{
// set the PLL registers
si5351a_setPLL(pll, pll_a, pll_b, pll_c, 1);

// see if the PLL locks OK
const uint32_t lock_time_us = si5351a_pllLocked(pll, 1500); // wait for up to 1.5ms for the PLL to lock .. avg around 618us, max around 1200us

if (lock_time_us > 0)
{ // PLL acquired lock at this particular frequency
if (min_Hz == 0)
min_Hz = vco_Hz; // remeber the min frequency
max_Hz = vco_Hz; // remeber the max frequenct
}
}

fvco_Hz += step_Hz;
}

if (min_pll_Hz == 0 || min_pll_Hz < min_Hz)
min_pll_Hz = min_Hz;

if (max_pll_Hz == 0 || max_pll_Hz > max_Hz)
max_pll_Hz = max_Hz;
}
}

Join [email protected] to automatically receive all group messages.