Генерация сигналов с фазовым сдвигом при помощи Si5351

8 сентября 2021

Ранее мы узнали, как генерировать сигналы с требуемым фазовым сдвигом при помощи цепей на пассивных компонентах, а также при помощи D-триггеров. Оказывается, что наш старый знакомый, Si5351, тоже годится для этой задачи. Интересно, хорошо ли он с ней справляется?

Примечание: Для понимания представленного далее материала рекомендуется прочитать статью Микроконтроллеры STM32: пишем драйвер для Si5351, если вдруг вы ее пропустили.

Открыв 10-ю страницу AN619 [PDF] мы узнаем, что фазовым сдвигом сигналов управляют регистры CLKx_PHOFF. Документ содержит неоднозначности касаемо размера этих регистров. Практика показывает, что они 7-и битные.

Также приводится немного запутанная формула для расчета значения регистра. Переписав ее в другом виде, мы понимаем, что для получения сигнала с частотой Fclk и фазовым сдвигом N°, в регистре должно быть записано:

CLKx_PHOFF[6:0] = round( (N/360)*(4*Fpll/Fclk) )

… где Fpll — это частота PLL. Само собой разумеется, необходимо два канала, работающих на одной частоте. Ведь фазовый сдвиг нужно мерить относительно чего-то. Каналы должны использовать общий PLL.

Важное ограничение на использование регистров CLKx_PHOFF заключается в том, что они не работают в integer mode. Другими словами, в регистрах MSx_INT соответствующих каналов должен быть записан 0. Как результат, MultiSynth divider не сможет делить на значение 8 или меньше, поскольку это работает только в integer mode.

Хотя мы и можем получить более-менее произвольный фазовый сдвиг (как мы скоро убедимся, в реальности все сложнее), на практике чаще всего нужны сигналы со сдвигом 90°. Поэтому далее мы сосредоточимся исключительно на этой задаче. Полученных в процессе знаний должно хватить для решения задач, где нужен какой-то другой фазовый сдвиг.

Подставив вместо N значение 90 в приведенную выше формулу, мы понимаем, что Fpll и Fclk просто должны быть кратны друг другу. Кратность должна быть целым числом от 9 до 127 в силу тех фактов, что (1) CLKx_PHOFF хранит целое 7-и битное число и (2) мы не можем использовать integer mode, то есть, число должно быть строго больше 8-и. Ведь нам еще нужно поделить Fpll на MultiSynth divider, чтобы получить Fclk. Еще стоит учесть, что частота PLL, согласно AN619, должна быть от 600 МГц до 900 МГц.

Обладая этой информацией, несложно придумать алгоритм, вычисляющий параметры PLL и MS для получения пары сигналов с фазовым сдвигом 90°:

void si5351_CalcIQ(int32_t Fclk, si5351PLLConfig_t* pll_conf,
                                 si5351OutputConfig_t* out_conf) {
    const int32_t Fxtal = 25000000;
    int32_t Fpll;

    if(Fclk < 1400000) Fclk = 1400000;
    else if(Fclk > 100000000) Fclk = 100000000;

    // apply correction
    Fclk = Fclk - ((Fclk/1000000)*si5351Correction)/100;

    // disable integer mode
    out_conf->allowIntegerMode = 0;

    // RDivider can't be is used
    out_conf->rdiv = 0;

    if(Fclk < 4900000) {
        // a little hack: run PLL below 600 MHz
        // to cover 1.4 MHz .. 4.725 MHz range
        out_conf->div = 127;
    } else if(Fclk < 8000000) {
        out_conf->div = 625000000 / Fclk;
    } else {
        out_conf->div = 900000000 / Fclk;
    }

    out_conf->num = 0;
    out_conf->denom = 1;

    Fpll = Fclk * out_conf->div;
    pll_conf->mult = Fpll / Fxtal;
    pll_conf->num = (Fpll % Fxtal) / 24;
    pll_conf->denom = Fxtal / 24; // denom can't exceed 0xFFFFF
}

Здесь просто находится Fpll, кратный требуемому Fclk, а кратность записывается в out_conf->div. Это значение будет одновременно и делитем MS, и значением регистра CLKx_PHOFF.

Пример использования:

si5351PLLConfig_t pll_conf;
si5351OutputConfig_t out_conf;
si5351_CalcIQ(7000000, &pll_conf, &out_conf);

uint8_t phaseOffset = (uint8_t)out_conf.div;
si5351_SetupOutput(0, SI5351_PLL_A, SI5351_DRIVE_STRENGTH_8MA,
                   &out_conf, 0);
si5351_SetupOutput(2, SI5351_PLL_A, SI5351_DRIVE_STRENGTH_8MA,
                   &out_conf, phaseOffset);
si5351_SetupPLL(SI5351_PLL_A, &pll_conf);
si5351_EnableOutputs((1<<0) | (1<<2));

Обратите внимание на порядок вызовов, он важен. Процедура si5351_SetupPLL должна вызываться после si5351_SetupOutput. Это связано с тем, что после заполнения CLKx_PHOFF требуется сделать сброс PLL, что происходит в теле si5351_SetupPLL. Иначе фазовый сдвиг между сигналами будет каким угодно.

Другая тонкость заключается в том, что мы не можем использовать RDivider’s. Включение RDivider’s изменяет фазовый сдвиг, и AN619 не дает никаких гарантий относительно характера этих изменений. Учитывая, что RDivider’s недоступны, минимальное значение Fpll составляет 600 МГц, а максимальное значение CLKx_PHOFF равно 127, мы никак не можем получить частоту, скажем, 3.5 МГц.

Для решения этой проблемы в коде есть небольшой хак. Для частот в интервале 1.4-4.725 МГц используется частота Fpll ниже 600 МГц. AN619 написан не вполне однозначно. При буквальном его прочтении возможны две интерпретации. В первой он рекомендует частоту PLL не ниже 600 МГц. Во второй он говорит, что частота ни в коем случае не может быть ниже этого значения. Таким образом, насколько такой код является хаком или нет, определяется вашей интерпретацией написанного.

Но независимо от интерпретации, на практике это прекрасно работает:

Генерация сигналов с частотой 3.5 МГц и фазовым сдвигом 90° с помощью Si5351

Эксперименты показали, что PLL срывает, когда он работает на частотах ниже 177 МГц. Это дает минимальную частоту 177 / 127 = 1.4 МГц.

Fun fact! Есть правдоподобная теория, что RDivider’s игнорируют каждый N-ый такт на выходе MultiSynth divider. В этом случае мы можем генерировать сигналы с фазовым сдвигом 180° (то есть, перевернутые), при помощи регистра CLKx_INV. Деление таких сигналов на 2 описанным выше образом даст фазовый сдвиг 90°. Это позволит покрыть частоты от 600 / 127 / 2 = 2.363 МГц, используя частоту PLL ≥ 600 МГц. Но учитывая, что AN619 ничего не говорит о влиянии RDivider’s на фазовый сдвиг, даже если это сработает, то будет таким же хаком. Только более сложным и покрывающим меньший интервал частот.

В отличие от D-триггеров, Si5351 прекрасно справляется с задачей на высоких частотах. Но есть и недостатки. В частности, изменение параметров PLL — относительно медленная операция. При ее выполнении сигнал временно пропадает с выхода генератора. Приведет ли это к заметным проблемам или нет, нужно смотреть в конкретном проекте.

Полная версия кода доступна в обновленной версии драйвера для Si5351 на GitHub’е. Там же вы найдете примеры и дополнительные комментарии в исходниках.

Дополнение: Самодельный генератор сигналов на основе Si5351

Метки: , , .