Проблема решена на CycloneIV следующим образом:
на передатчике:с передатчика отправляется сигнал 100МГц с вырезанным в момент прихода PPS импульсом:
assign tx = pps ? 0 : clk_1;
время прихода pps относительно фронта clk подтягивается с помощью задержки:
lcell delay (.in(clk), .out(clk_1));
на приемнике:генерируются 2 тактовые частоты с помощью ФАПЧ с частотой 400МГц, одна с отклонением на 90 град.
введен 1 счетчик по переднему фронту и 2-й счетчик по заднему фронту тактовой частоты 400МГц синхронно сбрасывающийся по приходу фронта принимаемой частоты 100МГц
аналогичные счетчики введены для частоты сдвинутой на 90 град.
коэфф. счета счетчиков равен трем
при срабатывании хотя бы двух из всех четырех счетчиков в приемнике формируется сигнал PPS, в результате получаем джиттер в пределах 1,25нс
для интереса также было испытано при генерировании двух тактовых частот по 1 ГГц, результат давал джиттер около 0.5 нс
также имеется возможность уменьшить джиттер добавлением частот с меньшим отклонением по углу.
остались некоторые вопросы:
1. планируется все таки использовать CDR, каковы на практике CDR встроенные в плис например Cyclone IV GX? имются ли какие -либо подводные камни? какие рабочие частоты? (на сколько я понимаю они оптимизированы под стандарты передачи данных)
2. реализовывал ли кто-либо White-rabbit синхронизацию?, если да то поделитесь пожалуйста ссылкой или соображениями по принципам реализации синхронизации до единиц наносекунд.
3. возможно есть какие-либо недочеты/ошибки в коде, прошу дать знать.
приемник:
пример с использованием несущей в 24МГц:Код
/*Обнаружение PPS и восстановление частоты*/
//Параметр - число тактов от обнаруженного заднего фронта mdi, при превышении значения >
parameter n_c = 9; // > обнаружение PPS
parameter n_cnt = 16; // > сброс счетчика, чем больше тем шире восстановленный импульс в clk_r
parameter n_c_p =8; // > запуск на восстановления импульса, может срабатывать не только в момент прихода PPS, вносит ошибку в восстановленную частоту
//при изменении параметра проверить размер счетчика на соответствие
//Обнаружение тактированием от 400МГц_0град
reg [4:0] p = 0; //счетчик переднего фронта
reg [4:0] n = 0; //счетчик заднего фронта
always @(posedge clk_ref) //счет передних фронтов, когда mdi = 0
begin
if(!mdi)
if(p < n_cnt)
begin
p <= p + 1'b1;
end
else
begin
p <= 0;
end
else p <= 0;
end
always @(negedge clk_ref) //счет задних фронтов, когда mdi = 0
begin
if(!mdi)
if(n < n_cnt)
begin
n <= n + 1'b1;
end
else
begin
n <= 0;
end
else n <= 0;
end
/////////////////////////////////////
//Обнаружение тактированием от 400МГц_90град
reg [4:0] p_2 = 0;//счетчик переднего фронта
reg [4:0] n_2 = 0;//счетчик заднего фронта
always @(posedge clk_ref_2) //счет передних фронтов, когда mdi = 0
begin
if(!mdi)
if(p_2 < n_cnt)
begin
p_2 <= p_2 + 1'b1;
end
else
begin
p_2 <= 0;
end
else p_2 <= 0;
end
always @(negedge clk_ref_2) //счет задних фронтов, когда mdi = 0
begin
if(!mdi)
if(n_2 < n_cnt)
begin
n_2 <= n_2 + 1'b1;
end
else
begin
n_2 <= 0;
end
else n_2 <= 0;
end
//Обнаружение PPS (если хотябы два будут больше чем n_c PPS = 1)
assign data = ((p_2 > n_c)&&(n_2 > n_c))||((p > n_c)&&(n > n_c))||((n > n_c)&&(n_2 > n_c))||((p > n_c)&&(n_2 > n_c))||((p > n_c)&&(p_2 > n_c))||((n > n_c)&&(p_2 > n_c));
//Обнаружение вырезаного импульса (если хотябы два будут больше чем n_c_p pulse = 1)
assign pulse = ((p_2 > n_c_p)&&(n_2 > n_c_p))||((p > n_c_p)&&(n > n_c_p))||((n > n_c_p)&&(n_2 > n_c_p))||((p > n_c_p)&&(n_2 > n_c_p))||((p > n_c_p)&&(p_2 > n_c_p))||((n > n_c_p)&&(p_2 > n_c_p));
//Восстановление частоты (восстановление срезанного импульса)
assign clk_r = pulse? pulse : mdi;
/*-----------------------------*/