вот документация по настройке регистров.
Всё сводится к нахождению множителя и делителя для частоты кварца.
output_frequency = xtal_frequency * multiplier / divider
Добавлено через 20 минут(ы):
когда множитель и делитель в форме a + b / c найдены, их параметры можно записать в сишку, я для этого написал вот такие функции.
Запись параметров PLL:
Код:
struct si5351_pll_info
{
uint32_t a;
uint32_t b;
uint32_t c;
};
void si5351_set_pll(enum si5351_pll pll, struct si5351_pll_info* pi)
{
uint32_t p1;
uint32_t p2;
uint32_t p3;
ASSERT( pi->a >= 15 && pi->a <= 90 ); // mult = 15..90
ASSERT( pi->b <= 0xFFFFF ); // 20-bit limit
ASSERT( pi->c <= 0xFFFFF ); // 20-bit limit
ASSERT( pi->c > 0 ); // avoid divide by zero
// p1[17:0] = 128 * a + floor( 128 * b / c ) - 512
// p2[19:0] = 128 * b - c * floor( 128 * b / c)
// p3[19:0] = c
if (pi->b == 0)
{
p1 = 128 * pi->a - 512;
p2 = 0;
p3 = pi->c;
}
else
{
uint32_t frac = (128 * pi->b) / pi->c;
p1 = 128 * pi->a + frac - 512;
p2 = 128 * pi->b - pi->c * frac;
p3 = pi->c;
}
si5351_write_pll(pll, p1, p2, p3);
}
void si5351_write_pll(enum si5351_pll pll, uint32_t p1, uint32_t p2, uint32_t p3)
{
uint8_t params[8] =
{
(p3 & 0x0000FF00) >> 8,
(p3 & 0x000000FF),
(p1 & 0x00030000) >> 16,
(p1 & 0x0000FF00) >> 8,
(p1 & 0x000000FF),
((p3 & 0x000F0000) >> 12) | ((p2 & 0x000F0000) >> 16),
(p2 & 0x0000FF00) >> 8,
(p2 & 0x000000FF),
};
switch (pll)
{
case SI5351_PLLA:
si5351_write_bulk(SI5351_PLLA_PARAMETERS, params, 8);
break;
case SI5351_PLLB:
si5351_write_bulk(SI5351_PLLB_PARAMETERS, params, 8);
break;
}
}
Запись параметров мультисинта:
Код:
struct si5351_msx_info
{
uint32_t a;
uint32_t b;
uint32_t c;
uint8_t rdiv;
bool divby4;
};
void si5351_set_msx(enum si5351_clock output, struct si5351_msx_info* mi)
{
uint32_t p1;
uint32_t p2;
uint32_t p3;
ASSERT( mi->a >= 4 ); // min 4
ASSERT( mi->a <= 1800 ); // max 900
ASSERT( mi->b <= 0xFFFFF ); // 20-bit limit
ASSERT( mi->c <= 0xFFFFF ); // 20-bit limit
ASSERT( mi->c > 0 ); // avoid divide by zero
ASSERT( (mi->a + mi->b / mi->c) >= 6 && (mi->a + mi->b / mi->c) <= 1800 );
// P1[17:0] = 128 * a + floor( 128 * b / c ) - 512
// P2[19:0] = 128 * b - c * floor( 128 * b / c )
// P3[19:0] = c
if (mi->b == 0)
{
p1 = 128 * mi->a - 512;
p2 = 0;
p3 = mi->c;
}
else
{
uint32_t frac = (128 * mi->b) / mi->c;
p1 = 128 * mi->a + frac - 512;
p2 = 128 * mi->b - mi->c * frac;
p3 = mi->c;
}
si5351_write_msx(output, p1, p2, p3, mi->rdiv, mi->divby4);
}
void si5351_write_msx(enum si5351_clock output, uint32_t p1, uint32_t p2, uint32_t p3, uint8_t rdiv, bool divby4)
{
uint8_t params[8] =
{
(p3 & 0x0000FF00) >> 8,
(p3 & 0x000000FF),
((p1 & 0x00030000) >> 16) | ((rdiv & 7) << 4) | (divby4 ? 0x0C : 0x00),
(p1 & 0x0000FF00) >> 8,
(p1 & 0x000000FF),
((p3 & 0x000F0000) >> 12) | ((p2 & 0x000F0000) >> 16),
(p2 & 0x0000FF00) >> 8,
(p2 & 0x000000FF),
};
switch (output)
{
case SI5351_CLK0:
si5351_write_bulk(SI5351_CLK0_PARAMETERS, params, 8);
break;
case SI5351_CLK1:
si5351_write_bulk(SI5351_CLK1_PARAMETERS, params, 8);
break;
case SI5351_CLK2:
si5351_write_bulk(SI5351_CLK2_PARAMETERS, params, 8);
break;
}
}
Не забываем, что после изменения частоты PLL нужно делать сброс PLL.