Предположим есть задача - измерить время распространения сигнала в линии задержки, как на рисунке выше.
Самый простой и очевидный способ измерения требует высокой частоты проекта. Период тактовой частоты измерений - это эталонный интервал, с помощью которого производятся измерения. Считаем сколько в измеряемом интервале времени укладывается эталонных периодов тактовой частоты, умножаем полученное число на период тактовой частоты и получаем значение времени. Таким образом, получается, что чем меньше период частоты, используемой для измерений, тем точнее измерения.
Частоты, используемые в проектах для ПЛИС, - это обычно 100-200МГц, пусть 300МГц. По технической спецификации Cyclone IV (speed grade C8) и MAX10 (C8) максимальная частота Clock Tree Performance внутри ПЛИС: 402 MHz. Это примерно соответствует периоду 2,5 наносекунды. Получается, что точнее 2,5 наносекунды интервалы и не измерить?
А что если использовать динамическое изменение фазы тактовой частоты с PLL ПЛИС? Про изменение фазы тактовой частоты PLL я писал в предыдущей статье. Если настроить частоту Fvco близкую к предельной, а у PLL ПЛИС Альтеры это 1300МГц, то сдвигать фазу отдельного выхода PLL можно на очень малые углы, ведь разрешение по фазе у PLL - это 1/8 периода Fvco.
Идея измерителя интервалов состоит в следующем. Берем с PLL ПЛИС две тактовых частоты с одинаковым периодом. Это будет два независимых клоковых домена. На первой частоте работает схема, которая запускает тестовый импульс, а на второй тактовой частоте работает схема, которая "ловит" ответный импульс после измеряемой линии задержки. Измерение проводится серией попыток. Каждая новая попытка измерения делается со сдвигом фазы первой тактовой частоты. Сдвигать фазу буду примерно на 100 пикосекунд. Попыток придется сделать довольно много. Сдвигать фазу я буду многократно в одну сторону, а потом многократно в обратную сторону, чтобы вернуться в исходное состояние фаз тактовых частот.
Эта анимация иллюстрирует предлагаемый метод измерений.
Я делаю проект для платы Марсоход3bis, ПЛИС MAX10, однако его можно адаптировать для других ПЛИС. Проект написан на Verilog HDL и компилируется в среде Intel Quartus Prime Lite Edition. Далее подробней о проекте.
В проекте имеется PLL, на ее входе 100МГц.
Из PLL три выхода:
- два выхода PLL с соотношением коэффициентов умножения и деления 98/99, итоговая частота 98.974359МГц
- третий выход PLL 182/99, выходнаЯ частота 183.809524 МГц
Третий выход нигде не используется, но его наличие важно: такими странными настройками я добиваюсь того, что PLL имеет высокую, почти предельную частоту Fvco = 1286,6666МГц.
При этом точность установки фазы для частот PLL получается около 97,15 пикосекунд.
Тестовый импульс (длительностью 4 такта) посылается периодически (каждые 64 такта) на частоте wc1:
localparam TEST_PERIOD = 64;
localparam TEST_IMP_LENGTH = 4;
localparam TEST_IMP_START = TEST_PERIOD-TEST_IMP_LENGTH;
//test impulse is sent on wc1 clock
reg test_impulse;
reg [7:0]wc1_timer;
always @( posedge wc1 or negedge wlocked )
begin
if( ~wlocked ) begin
wc1_timer <= 0;
test_impulse <= 1'b0;
end
else begin
if( wc1_timer==TEST_PERIOD-1 )
wc1_timer <= 0;
else
wc1_timer <= wc1_timer + 1;
test_impulse <= ( wc1_timer>=TEST_IMP_START );
end
end
Тестовый импульс выводится на пин платы Марсоход3bis IO[6], а ответный импульс забирается с пина IO[7]:
assign IO[6] = test_impulse; //send test impulse to output pin
wire echo_impulse;
assign echo_impulse = IO[7]; //echo impulse received after delay from input pin
Ответный импульс ловится на частоте wc0 в регистр echo_fixed и затем переписывается в массив регистров echo_fixed_array[try]:
reg echo_fixed; //fix echo input into this reg
reg [127:0]echo_fixed_array;
always @( posedge wc0 or negedge wlocked )
begin
if( ~wlocked ) begin
wc0_timer <= 0;
echo_fixed <= 1'b0;
echo_fixed_array <= 0;
end
else begin
if( wc0_timer==TEST_PERIOD-1 )
wc0_timer <= 0;
else
wc0_timer <= wc0_timer + 1;
if( capture0 )
echo_fixed <= echo_impulse;
if( capture1 )
echo_fixed_array[try] <= echo_fixed;
end
end
Здесь переменная try как раз определяет текущую фазу частоты wc1:
значение в try "качается" от нуля до 127 включительно и обратно от 127 до нуля.
reg [7:0]try;
reg dir;
always @( posedge wc0 or negedge wlocked )
if( ~wlocked ) begin
try <= 0;
dir <= 1'b0;
end
else begin
if( wc0_timer==PHASE_CHANGE_TIME-1 ) begin
if( dir )
try <= try-1'b1;
else
try <= try+1'b1;
if( (dir==0 && try==MAX_TRIES-1) || (dir==1 && try==1) )
dir <= ~dir;
end
end
С каждой новой попыткой измерения try фаза частоты wc1 сдвигается в ту или иную сторону на один шаг, на 97,15 пикосекунд в зависимости от направления dir. Сдвиг фазы частоты wc1 из PLL управляется сигналами phase_step, dir и wpdone.
//on every new try change phase of wc1
reg phase_step = 1'b0;
wire wpdone; wire phase_done; assign phase_done = ~wpdone;
always @( negedge wc0 )
if( wc0_timer==PHASE_CHANGE_TIME )
phase_step<=1'b1;
else
if( phase_done )
phase_step<=1'b0;
//PLL
mypll mypll_ (
.areset( 1'b0 ),
.inclk0( CLK100MHZ ),
.phasecounterselect( 3'b011 ),
.phasestep( phase_step ),
.phaseupdown( dir ),
.scanclk( wc0 ),
.c0( wc0 ),
.c1( wc1 ),
.c2( wc2 ),
.locked( wlocked ),
.phasedone( wpdone )
);
Теперь, когда после многих попыток измерения я накопил массив данных echo_fixed_array[] их нужно куда-то отобразить. Я посылаю весь массив в последовательный порт платы, через выходной пин платы Марсоход3bis FTDI_BD1. Я буду посылать в последовательный порт код 0х31 - это код символа "1", если в моем накопленном массие стоит единица и буду посылать код 0x30 - это код символа "0", если в накопленном массиве измерений стоит ноль. Когда вся строка измеренных значений передана, буду посылать коды 0x0D и 0x0A - это коды перевода строки. Таким образом, я могу подключить текстовый терминал Putty на скорости 230400 и в его окне видеть весь измеренный массив в "реальном времени".
Весь проект можно взять на github https://github.com/marsohod4you/FpgaTDC или скачать на нашем сайте в разделе загрузки:
Что я буду измерять? В качестве измеряемой и изменяемой линии задержки я буду использовать простой керамический конденсатор малой емкости, 5/20 пикофарад, подключенный к выводам IO[7] и IO[6] и к земле платы Марсоход3bis. Получится такая RC-цепь.
Резисторы R уже стоят на плате на каждом входе ПЛИС. Это сделано для защиты ПЛИС от возможных больших токов при не удачном подключении платы к внешним устройствам. Остается только подключить подстроечный конденсатор. Вот так он выглядит, установленный на плату Марсоход3bis:
Переходные процессы в RC-цепи описываются экспоненциальными законами, нарастает и спадает не мгновенно. Поэтому RC-цепь в моем эксперименте можно считать простейшей линией задержки.
Демонстрация работы измерителя:
С помощью отвертки перенастраиваю емкость конденсатора и вижу, как меняется задержка сигнала - сдвигается фронт принятого импульса. Каждый символ "1" или "0" в принятой текстовой строке эквивалентен принятому биту с разрешением ~100 ps.
Чтобы было понятней, я сделал скриншот окна текстового терминала:
Нули слева - это сигнал до приема эхо импульса. Единицы справа - это изображение принятого эхо импульса.
Здесь хорошо видно, что есть зона неуверенного приема в два знакоместа, где при очередном измерении, от попытки к попытке принимаются то ноль, то единица. Видимо фаза одной частоты PLL дрожит относительно фазы другой частоты PLL в довольно широких пределах, получается около 200 пикосекунд. Чем еще можно объяснить эту "зону неуверенного приема"? Может быть это наведенные шумы на входе ПЛИС? Возможно путем многократных измерений и накопления и усреднения результата можно уточнить результат? Я честно не знаю.
Тем не менее, мне кажется, что и 200 пикосекунд разрешения при измерении - это довольно хороший результат.
Днем позже немного зачеркнул здесь.. Оказывается в проекте просто была ошибка.. Смотрите апдейт статьи ниже: нет никакого дрожания. А точность будет действительно около 100 пикосекунд.
Подведу небольшой итог:
- Использовать метод динамического сдвига фазы для измерения задержки распространения сигнала возможно и это позволяет поднять точность измерений.
- Метод требует многократных измерений, а это значит, что он подходит для измерения задержек, которые либо не меняются во времени, либо меняются медленно.
- В этой статье не рассматриваются вопросы "начальной калибровки", заранее не известно насколько фазы частот wc0 и wc1 совпадают или наоборот различаются при старте проекта в ПЛИС. За интервал времени в 100ps электромагнитный импульс распространяется в линии передачи примерно на 3 сантиметра. Здесь уже играют роль длина трассировки проводников внутри ПЛИС или длина дорожек на плате.
---------------------------- UPDATE!!!!!!! --------------------------------
Кое-что исправил в этом проекте....
А именно:
1) поставил галочку в мегавизарде "enable phase shift step resolution", как посоветовал Leka.
Действительно это работает, теперь не нужно выбирать странные частоты, а можно просто поставить 100МГц, но Fvco будет 1300MHz. При этом разрешение по фазе получается 96,15 пикосекунд:
2) Исправил баг в Verilog программе: похоже я там напутал со счетчиками try и направлением dir сдвига фазы. В результате, поскольку фаза двигалась то вперед, то назад, реальный сдвиг фазы не соответствовал внутреннему счетчику фазы в PLL. Именно это являлось причиной "дрожания" двух битов в выборке. Просто сканирование вперед и назад оказывались сдвинутыми друг относительно друга. Теперь этой ошибки нет, исправлена. При измерениях фронт захваченного сигнала больше НЕ ДРОЖИТ! В доказательство прилагаю скриншот:
Таким образом сомнения отпадают, метод работает и позволяет действительно измерять задержки распространения сигнала с высокой точностью.
Исправленный проект на https://github.com/marsohod4you/FpgaTDC
Подробнее...