В проекте имеется 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-цепь.

schema2

Резисторы R уже стоят на плате на каждом входе ПЛИС. Это сделано для защиты ПЛИС от возможных больших токов при не удачном подключении платы к внешним устройствам.  Остается только подключить подстроечный конденсатор. Вот так он выглядит, установленный на плату Марсоход3bis:

capacitor

Переходные процессы в RC-цепи описываются экспоненциальными законами, нарастает и спадает не мгновенно. Поэтому RC-цепь в моем эксперименте можно считать простейшей линией задержки.

 Демонстрация работы измерителя:

С помощью отвертки перенастраиваю емкость конденсатора и вижу, как меняется задержка сигнала - сдвигается фронт принятого импульса. Каждый символ "1" или "0" в принятой текстовой строке эквивалентен принятому биту с разрешением ~100 ps.

Чтобы было понятней, я сделал скриншот окна текстового терминала:

capture terminal

Нули слева - это сигнал до приема эхо импульса. Единицы справа - это изображение принятого эхо импульса.

Здесь хорошо видно, что есть зона неуверенного приема в два знакоместа, где при очередном измерении, от попытки к попытке принимаются то ноль, то единица. Видимо фаза одной частоты PLL дрожит относительно фазы другой частоты PLL в довольно широких пределах, получается около 200 пикосекунд. Чем еще можно объяснить эту "зону неуверенного приема"? Может быть это наведенные шумы на входе ПЛИС? Возможно путем многократных измерений и накопления и усреднения результата можно уточнить результат? Я честно не знаю.   

Тем не менее, мне кажется, что и 200 пикосекунд разрешения при измерении - это довольно хороший результат.

Днем позже немного зачеркнул здесь.. Оказывается в проекте просто была ошибка.. Смотрите апдейт статьи ниже: нет никакого дрожания. А точность будет действительно около 100 пикосекунд.

Подведу небольшой итог:

  1. Использовать метод динамического сдвига фазы для измерения задержки распространения сигнала возможно и это позволяет поднять точность измерений.
  2. Метод требует многократных измерений, а это значит, что он подходит для измерения задержек, которые либо не меняются во времени, либо меняются медленно.
  3. В этой статье не рассматриваются вопросы "начальной калибровки", заранее не известно насколько фазы частот wc0 и wc1 совпадают или наоборот различаются при старте проекта в ПЛИС. За интервал времени в 100ps электромагнитный импульс распространяется в линии передачи примерно на 3 сантиметра. Здесь уже играют роль длина трассировки проводников внутри ПЛИС или длина дорожек на плате.

---------------------------- UPDATE!!!!!!! --------------------------------

Кое-что исправил в этом проекте....

А именно:

1) поставил галочку в мегавизарде "enable phase shift step resolution", как посоветовал Leka. 

pll1

Действительно это работает, теперь не нужно выбирать странные частоты, а можно просто поставить 100МГц, но Fvco будет 1300MHz. При этом разрешение по фазе получается 96,15 пикосекунд:

pll2

2) Исправил баг в Verilog программе: похоже я там напутал со счетчиками try и направлением dir сдвига фазы. В результате, поскольку фаза двигалась то вперед, то назад, реальный сдвиг фазы не соответствовал внутреннему счетчику фазы в PLL. Именно это являлось причиной "дрожания" двух битов в выборке. Просто сканирование вперед и назад оказывались сдвинутыми друг относительно друга. Теперь этой ошибки нет, исправлена. При измерениях фронт захваченного сигнала больше НЕ ДРОЖИТ! В доказательство прилагаю скриншот:

impulse capture

Таким образом сомнения отпадают, метод работает и позволяет действительно измерять задержки распространения сигнала с высокой точностью.

Исправленный проект на https://github.com/marsohod4you/FpgaTDC

 

Добавить комментарий