基于FPGA的TDC延时设计方案

1、参考
https://cas.tudelft.nl/fpga_tdc/tdc_basic.html
2、原理
采用fpga的carry4进位单元,每个carry4的cout连接到下一个carry4的cin,这样级联起来,形成延时链;每个cout做为抽头输出到触发器,通过本地时钟进行数据采样。假定每个延时链的延时是固定的(最后需要标定),可通过采样值大致估算所测信号与本地时钟上升沿之间的间隔,当得到适当的标定后,可获得较高的精度。
3、当前测试的芯片是xc7k325tffg900 -2
仿真中的carry4 除第一级外,其他的carry4输出到输入延迟固定都是53ps,但是这是4个进位的延迟时间,只是vivado仿真工具有限制,且需要后仿真。
4、源代码
顶层
tdc_top.v
module tdc_top#(
parameter stage = 200,
parameter gap_bits = 8
)(
input wire sg_start,
input wire clk_sys,
input wire reset ,
output wire cs_gap,
output wire [gap_bits-1:0] value_gap
);
wire clk_bufg;
clk_wiz_0 clk_wiz_0_inst(
.clk_out1(clk_bufg),
.clk_in1(clk_sys)
);
wire valid_pre;
wire valid;
wire [stage-1:0] value_latch;
wire bin_cs;
wire [gap_bits-1:0] bin;
wire sg_bufr;
bufr #(
.bufr_divide(bypass), // values: bypass, 1, 2, 3, 4, 5, 6, 7, 8
.sim_device(7series) // must be set to 7series
)
bufr_inst (
.o(sg_bufr), // 1-bit output: clock output port
.ce(1'b1), // 1-bit input: active high, clock enable (divided modes only)
.clr(1'b0), // 1-bit input: active high, asynchronous clear (divided modes only)
.i(sg_start) // 1-bit input: clock buffer input driven by an ibuf, mmcm or local interconnect
);
fdce #(
.init(1'b0) // initial value of register (1'b0 or 1'b1)
)
fdce_inst2 (
.q(valid_pre), // 1-bit data output
.c(clk_bufg), // 1-bit clock input
.ce(1'b1), // 1-bit clock enable input
.clr(1'b0), // 1-bit asynchronous clear input
.d(sg_bufr) // 1-bit data input
);
fdce #(
.init(1'b0) // initial value of register (1'b0 or 1'b1)
)
fdce_inst3 (
.q(valid), // 1-bit data output
.c(clk_bufg), // 1-bit clock input
.ce(1'b1), // 1-bit clock enable input
.clr(1'b0), // 1-bit asynchronous clear input
.d(valid_pre) // 1-bit data input
);
line_tdc#(
.stage (stage)
) line_tdc_inst(
.sg_start (sg_bufr),
.clk_bufg (clk_bufg),
.reset (reset),
.value_latch (value_latch)
);
latch2bin#(
.gap_bits (gap_bits)
) latch2bin_inst(
.clk_bufg (clk_bufg),
.reset (reset),
.valid (valid),
.value_latch (value_latch),
.bin_cs (cs_gap),
.bin (value_gap)
);
延迟线代码
line_tdc.v
module line_tdc#(
parameter stage = 256
)(
input wire sg_start,
input wire clk_bufg,
input wire reset,
output wire [stage - 1:0] value_latch
);
wire [stage - 1:0] dat_reg0;
wire [stage - 1:0] dat_reg1;
genvar i;
generate
for (i = 0; i if(i == 0) begin :carry4_first
carry4 carry4_inst (
.co (dat_reg0[3:0]), // 4-bit carry out
.o (), // 4-bit carry chain xor data out
.ci (1'b0), // 1-bit carry cascade input
.cyinit (sg_start), // 1-bit carry initialization
.di (4'b0000), // 4-bit carry-mux data in
.s (4'b1111) // 4-bit carry-mux select input
);
end
if (i > 0) begin :carry4_others
carry4 carry4_others (
.co (dat_reg0[4*(i+1)-1:4*i]), // 4-bit carry out
.o (), // 4-bit carry chain xor data out
.ci (dat_reg0[4*i-1]), // 1-bit carry cascade input
.cyinit (1'b0), // 1-bit carry initialization
.di (4'b0000), // 4-bit carry-mux data in
.s (4'b1111) // 4-bit carry-mux select input
);
end
end
endgenerate
genvar j;
generate
for (j = 0; j fdre #(
.init (1'b0) // initial value of register (1'b0 or 1'b1)
) fdre_inst0 (
.q (dat_reg1[j]), // 1-bit data output
.c (clk_bufg), // 1-bit clock input
.ce (1'b1), // 1-bit clock enable input
.r (reset), // 1-bit synchronous reset input
.d (dat_reg0[j]) // 1-bit data input
);
fdre #(
.init (1'b0) // initial value of register (1'b0 or 1'b1)
) fdre_inst1 (
.q (value_latch[j]), // 1-bit data output
.c (clk_bufg), // 1-bit clock input
.ce (1'b1), // 1-bit clock enable input
.r (reset), // 1-bit synchronous reset input
.d (dat_reg1[j]) // 1-bit data input
);
end
endgenerate
endmodule
延迟线数字码转换二进制输出
latch2bin.v
module latch2bin#(
parameter gap_bits = 8
)(
input wire clk_bufg,
input wire reset,
input wire valid,
input wire [(2**gap_bits)-1:0] value_latch,
output reg bin_cs,
output reg [gap_bits-1:0] bin
);
(* *)reg [(2**gap_bits)-2:0] decoding [0:gap_bits-4];
(* *)reg [gap_bits:0] binary [0:gap_bits-3];
(* *)reg [gap_bits-2:0] data_valid;
(* *)reg [15:0] decode_final;
(* *)reg [gap_bits-1:0] bin_final;
(* *)reg [3:0] ones;
(* *)reg [gap_bits:0] binary_r;
always@(*) begin
decoding[0] = value_latch[(2**gap_bits)-2:0];
data_valid[0] end
genvar i;
generate
for (i = 0; i always@(posedge clk_bufg) begin
if(reset) begin
decoding[i+1] binary[i+1] data_valid[i+1] end
else begin
binary[i+1][gap_bits:gap_bits-1-i] data_valid[i+1] if(decoding[i][((2**(gap_bits-i))-2)/2]==1'b1) begin
decoding[i+1][((2**(gap_bits-i))-2)/2-1:0] end
else begin
decoding[i+1][((2**(gap_bits-i))-2)/2-1:0] end
end
end
end
endgenerate
always@(posedge clk_bufg) begin
if(reset) begin
ones data_valid[gap_bits-3] binary[gap_bits-3] bin_final end
else begin
ones decoding[gap_bits-4][0] + decoding[gap_bits-4][1] + decoding[gap_bits-4][2] + decoding[gap_bits-4][3] +
decoding[gap_bits-4][4] + decoding[gap_bits-4][5] + decoding[gap_bits-4][6] + decoding[gap_bits-4][7] +
decoding[gap_bits-4][8] + decoding[gap_bits-4][9] + decoding[gap_bits-4][10] + decoding[gap_bits-4][11] +
decoding[gap_bits-4][12] + decoding[gap_bits-4][13] + decoding[gap_bits-4][14] + decoding[gap_bits-4][15];
data_valid[gap_bits-3] binary[gap_bits-3]
data_valid[gap_bits-2] bin_final end
end
always@(posedge clk_bufg) begin
if(reset) begin
bin_cs bin end
else begin
if(data_valid[gap_bits-2] == 1'b1) begin
bin_cs bin end
else begin
bin_cs bin end
end
end
endmodule
测试
tb_tdc_top.v
module tb_tdc_top;
reg clk_sys;
reg sg_start;
reg reset;
wire [7:0] value_gap;
tdc_top tdc_top_inst(
.sg_start (sg_start),
.clk_sys (clk_sys),
.reset (reset),
.value_gap (value_gap)
);
initial begin
clk_sys = 0;
sg_start = 0;
reset = 1;
#1000;
reset = 0;
#116;
sg_start = 1;
#3;
sg_start = 0;
end
always #(5) clk_sys = ~clk_sys;
endmodule
时钟模块100m输入,400m输出,并经过bufg资源。
由于每个carry4的延迟时间是53ps,每个时钟周期是2.5ns,最多需要50个carry4级联即可。
5、约束
手册上有写,对于carry4的第一级约束后,下一级的carry4会以最邻近的摆放。tdc.xdc
set_property package_pin ad21 [get_ports reset]
set_property package_pin ae23 [get_ports sg_start]
set_property package_pin ad23 [get_ports clk_sys]
set_property iostandard lvcmos33 [get_ports {value_gap[7]}]
set_property iostandard lvcmos33 [get_ports {value_gap[6]}]
set_property iostandard lvcmos33 [get_ports {value_gap[5]}]
set_property iostandard lvcmos33 [get_ports {value_gap[4]}]
set_property iostandard lvcmos33 [get_ports {value_gap[3]}]
set_property iostandard lvcmos33 [get_ports {value_gap[2]}]
set_property iostandard lvcmos33 [get_ports {value_gap[1]}]
set_property iostandard lvcmos33 [get_ports {value_gap[0]}]
set_property iostandard lvcmos33 [get_ports cs_gap]
set_property iostandard lvcmos33 [get_ports reset]
set_property iostandard lvcmos33 [get_ports sg_start]
set_property iostandard lvcmos33 [get_ports clk_sys]
set_property loc slice_x0y0 [get_cells line_tdc_inst/genblk1[0].carry4_first.carry4_inst]
6、后仿真测试结果
7、以上可以对sg_start和clk_bufg两个信号的间隔进行大致估算,通过计算大致可计算出第一级carry4输入的延时。


SOC芯片是什么?SOC芯片的优缺点和设计流程
关于土壤pH检测仪的简单介绍
关于粗筛喂料泵轴承室磨损高效节省的维修方法
小米手机新外观曝光采用了双挖孔设计方案手机屏占比极高
5G技术将使哪些行业受益
基于FPGA的TDC延时设计方案
智能时代,联接产业正迎来五大变化
实体零售店的痛点可以让物联网来解决吗
华为P10数据大盘点,这颜值也是没谁了!
集成数值比较器
采用200V的SOI晶圆技术降低LED TV背光驱动方案的成本
元年瞭望:智能照明、物联网、手机摄像头、触控
MAX985-MAX994满摆幅输入/输出比较器
LG 16摄智能手机震撼来袭
江波龙受邀出席2022开放数据中心峰会,分享企业级数据存储质量管理流程
嵌入式Linux设备驱动原理原来是这样编写的!
俄罗斯将与华为开展5G合作_华为将为俄罗斯第一个提供5G技术支持
三星的一份专利显示,三星正在着手研究“屏中屏”
高效CDTE和CIGS薄膜太阳能电池的亮点与挑战
基于GaN功率器件的大功率和高功率密度EV逆变器