В проекте имеется 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
Подробнее...