TDCTime-to-Digital Converter时间数字转换器。如果你正在搜这个词多半是激光测距、PET、粒子探测、高速仪器校时之类的项目如果你还是个FPGA学习者那我建议先把这篇读完再动手它能帮你省下大半年走弯路的时间。说白了TDC要解决的就是皮秒级时间测量用数字电路把两个电信号沿之间的时间间隔量化成数字码。这个场景的边界条件通常很苛刻比如测距终端要求单发分辨率做到几十皮秒、通道数量要够多、死时间要够短这些条件凑在一起通用MCU完全无能为力ASIC又贵又得等流片周期。FPGA凭借可重构、高并行、成熟的厂商生态成了做TDC原型验证和中小批量设备最靠谱的载体。这篇文章会从TDC的原理讲起重点落在FPGA上的抽头延迟链实现包括RTL怎么写、布局怎么约束、校准怎么做、常见坑怎么避。适合有一定FPGA基础、正准备做高速时间测量相关项目的工程师也适合想理解TDC底层逻辑的硬件研发。1. 从应用场景看TDC为什么需要皮秒级时间测量1.1 先把TDC到底是什么说清楚TDC输入的是时间输出的是数字。它和ADC是平级的概念——ADC把连续变化的电压变成数字码TDC把连续变化的时间差变成数字码。时间差精度一旦做到皮秒量级任何环节的抖动、偏斜、温度漂移都会直接叠加进结果里。我常给第一次接触TDC的同事打一个比方用普通计数器测量时间就像拿着一把分米尺去量头发丝量出来永远是“0”没有任何意义。TDC的工作就是把分米尺打碎成更细的刻度逼近皮秒量级。但物理上不存在无限密的尺子所以核心工程问题就是——用有限的逻辑资源和带宽把时间分辨率尽量往下压同时还得保证测量结果可重复、可校准。理解这段之后你就明白TDC为什么不能靠简单堆高频时钟解决。就算给你一个1GHz的时钟计数分辨率也只有1ns离皮秒还差着两个数量级。真要硬上高频PLL时钟抖动本身就会把精度吃掉板级设计难度还会成倍上升性价比极低。1.2 真实场景拆解哪类项目离不开TDCTDC覆盖的领域比很多人想象中广我挑四个最典型的场景来说激光雷达和ToF相机。发射光脉冲和回波光脉冲的时间差乘以光速再除以2就是目标距离。1ps时间误差对应0.15mm距离误差想做毫米级测距时间测量误差就得控制在几十ps以内。这是消费电子和车载雷达里TDC需求量最大的方向。PET探测器。正电子湮灭会产生一对反向的伽马光子探测器收到两个光子信号的时间差用于符合判选时间分辨率直接影响重建图像的信噪比。现在高性能PET系统的时间分辨率已经从纳秒级往百皮秒级压缩TDC是核心测量电路。高能物理与核子实验。飞行时间谱仪TOF、快前沿脉冲分析这类系统对通道密度和时间精度要求都很高。一套实验设备里动辄几十上百个通道每个通道都要独立的时间测量FPGA并行优势在这里体现得最明显。高速仪器的内部校准。比如示波器里做时间交织采集时需要对多片ADC的采样时钟做精确校相这也是TDC的活。这些场景对精度的要求不尽相同但共同点是时间差必须可测、可复现、可校准。这就是TDC存在的意义也是FPGA方案能站住脚的原因。1.3 不同实现方案的横向对比做TDC之前先把手上的方案盘一遍别一上来就写代码。常见实现路径大概有四类放到一张表里看得清楚实现方案典型分辨率资源/复杂度适用场景直接计数法10ns100MHz极低粗时间戳、秒表逻辑抽头延迟链TDL10~30ps中FPGA主流方案本文重点游标法皮秒级高专用芯片、实验室仪器时间放大法皮秒级高单通道极致精度设备你打开Xilinx官方应用笔记XAPP523本质上就是TDL思路的FPGA化。业内做激光雷达TDC芯片的公司很多也是TDL架构的变种。所以这篇文章后面的内容基本就是沿着TDL这条主线往下走。2. TDC主流实现原理四种方案的取舍2.1 直接计数法入门简单但天花板明显直接计数法的逻辑很直白让一个计数器以固定时钟周期累加START信号到来时锁存一次计数值STOP到来时再锁存一次两次计数值之差乘以时钟周期就是时间间隔。整个过程跟秒表没区别。但它的性能瓶颈有三个。第一时间分辨率直接等于时钟周期100MHz时钟对应10ns分辨率想要更高只能拼命砌高时钟频率。第二计数器的位宽决定了最大可测时间做大范围测量就得加宽寄存器但高频计数的功耗和时序收敛都会变麻烦。第三输入信号和采样时钟是异步的计数器锁存瞬间存在亚稳态窗口触发沿离时钟沿越近锁存越不可靠这就是孔径抖动。所以直接计数法在工程里基本不会单独承担高精度任务它更适合做“粗测通道”大范围计数保证不漏测、不溢出。精测部分再用延迟链补上。2.2 抽头延迟链TDLFPGA里最实用的一招TDL的核心思想是把一个时钟周期“切”成很多份。信号进入一串延迟单元每个延迟单元的输出都接一个D触发器的数据端所有D触发器由同一个采样时钟同时锁存。当信号在延迟链里传播时采样时钟到来那一刻信号走到第几个延迟单元锁存出来的结果就会在第几个位置出现翻转这个翻转位置就对应信号边沿与采样时钟边沿之间的时间偏移。用生活例子来解释一根水管上每隔一厘米开一个小孔水从一头灌进去你站在远处同时看所有小孔水从哪个孔喷出来你就知道水已经流了多远。延迟链就是那根水管D触发器阵列就是那一排小孔采样时钟就是那声“看”。FPGA里最常用来做延迟单元的资源是进位链。Xilinx 7系列的CARRY4每级有4个输出级与级之间典型延迟在十几皮秒到几十皮秒具体参数取决于速度等级、电压和温度。UltraScale/UltraScale 架构则提供CARRY8级延迟特性和7系列不同要实测确认。TDL方案的优点非常直观纯数字逻辑资源就能实现不需要模拟器件并行度高一个时钟沿就能把所有抽头锁存下来布局可控多通道做起来相对容易。代价是bin宽度不均匀所以必须要校准校准方法后面单独讲。2.3 游标法和时间放大法什么时候才用它们游标法的名字来自游标卡尺。两个振荡器频率略有不同一个由START事件驱动另一个由STOP事件驱动通过两个计数器的差值把时间差按比例放大。两个振荡器频率差越小放大倍数越大。理论上分辨率可以无限细但振荡器起振时间、相位噪声、温度漂移都会破坏精度在FPGA里实现难度非常高更多出现在专用TDC芯片里。时间放大法更偏模拟把时间差先转换成电容充电量再用低速TDC去量化。精度上限高但模拟电路对PCB布局、电源纹波、温度变化都非常敏感调试周期长。结论很直接除非你的应用场景明确要求单通道极致性能、且你手上有足够的模拟调试预算否则FPGA项目优先TDL。后面所有实操内容都以TDL为例展开。3. FPGA实现TDC的核心架构设计3.1 器件选型思路与资源评估选型阶段我一般按四个维度卡延迟单元优先选CARRY4/CARRY8体系成熟的器件。Xilinx 7系列资料多、案例多新手练手首选Artix-7性价比高上量之后可以考虑国产FPGA但CARRY结构是否适合做TDL必须实测别只看手册。通道数每个通道需要一组延迟链和一组触发器阵列资源量不太大。举例来说我做过一个Artix-7 35T上的4通道TDC每通道128个bin配套激光测距逻辑整体资源占用不超过20%所以不需要为TDC本身选大容量芯片。采样时钟TDC的采样时钟定了测量范围和触发模式。通常用内部PLL/MMCM输出低抖动时钟Artix-7内部的MMCM足够满足要求。板级信号链输入信号在进入FPGA前要调理干净高速比较器、施密特触发器、ESD保护和阻抗匹配都得做。很多TDC精度差的问题不在逻辑而在模拟前端。3.2 模块划分与数据流设计我在工程里习惯把TDC系统拆成5个模块边界清晰后续换芯片或者换校准算法都只改局部输入调理差分转单端、去毛刺、电平整形。延迟链采样TDL抽头阵列加D触发器完成皮秒级粗量化。编码模块把温度计码转成二进制数值。校准模块查表修正bin宽度不均匀。统计输出FIFO缓存结果或累加直方图后上传上位机。数据流方向是外部触发信号进输入调理经过延迟链传播采样时钟把所有抽头值同时锁存编码模块把锁存结果转成一个数值该数值作为地址查校准表得到对应时间值最后由状态机打包上传或者交给后续测距/符合模块。整个链路看起来长但每个模块都能独立测试这在后面调试时会省很多事。3.3 布局约束为什么必须管物理位置很多FPGA工程师写普通逻辑时不关心物理位置交给工具摆就行但TDC完全不是这么回事。延迟链抽头之间的延迟误差除了进位链本身的级延迟还有走线延迟、LUT输入延迟、时钟偏斜。如果CARRY4散落在不同的CLB列抽头的真实延迟会掺入大量布线延迟bin宽度会乱到没法校准。两个必须注意的点用Pblock把延迟链约束在同一个区域最好是在同一列CLB上串下来让进位链传播方向与CLB列方向一致相邻抽头落在相邻CARRY4上走线延迟基本可控。所有采样触发器尽量放在同一个时钟区域避免跨BufG/BufH导致时钟偏斜差异。理论上时钟偏斜可以通过校准修正但能避免就别给自己挖坑。4. 关键RTL设计与约束实现4.1 延迟链原语例化与注意事项TDL的RTL写法跟普通逻辑不一样不能靠always块推断必须手动例化原语。Xilinx 7系列的核心是CARRY4每个CARRY4的S端口接1DI端口接0CIN接上一级的COUTO[3:0]就是4个抽头每一级O端口接到FDRE的D端FDRE由同一个采样时钟统一触发。给你一段风格参考实际项目里需要按器件和位宽适配(* DONT_TOUCH TRUE *) wire [3:0] tap; (* DONT_TOUCH TRUE *) wire [3:0] dout; CARRY4 chain_u ( .CO(), .O(tap), .CI(ci[0]), .CYINIT(1b1), .DI(4b0), .S(4b1) ); genvar i; generate for (i 0; i 4; i i 1) begin : fdre_inst FDRE samp_reg ( .C(clk_samp), .CE(1b1), .R(1b0), .D(tap[i]), .Q(dout[i]) ); end endgenerate三个关键注意点。第一DONT_TOUCH和KEEP属性一定要加在链和抽头信号上否则综合器觉得“这些节点输出固定不变”直接给你优化掉延迟链就废了。第二链路两端信号也要打上DONT_TOUCH防止综合器对首尾做常量传播。第三综合完成后打开报告搜索CARRY4实例数量确认链还在再往下走。4.2 温度计码转二进制的工程做法延迟链采样出来的结果是温度计码形态是一串连续的1后面跟着一串连续的0翻转沿位置对应时间差。编码模块的任务就是把翻转位置找出来输出一个二进制数。最直接的实现是优先编码器从高位往低位找碰到第一个0就输出对应地址。但实际效果不好因为温度计码在翻转沿附近经常有毛刺会出现孤立的0或1直接找第一个翻转位置容易跳变。工程上更稳的做法先对128个抽头做一次“找最长连续1段”的处理用移位寄存器统计连续簇长度取连续段的中点作为翻转位置。或者采用Wallace树多级编码输入多bit找第一个0逻辑层级可控时序更容易收敛。如果延迟链宽度较大可以把bin分成高低两组每组分别编码后用LUT6合并减少关键路径长度。编码逻辑写完后最好在仿真里灌入扫频激励验证所有bin都能正确编码不要只测几个点。我用ILA实测的时候发现有一类编码错误是特定码型才会触发仿真全覆盖可以提前暴露。4.3 时钟网络与异步信号处理TDL采样必须用统一的全局时钟绝对不要用数据选择出来的时钟。全局时钟路径经过专用布线资源偏斜可控这是TDC精度的底线。另一个容易犯错的地方在异步信号处理。输入脉冲和采样时钟天然是异步的如果你先做两级触发器同步再同步后的信号进延迟链那TDC测到的就不再是真实到达时间而是经过同步逻辑后的信号沿额外插入了几个纳秒固定延迟和几十皮秒抖动。正确做法是真实信号直接进延迟链做异步采样锁存结果再用同步逻辑读出时间重建放在后处理里。这样做会带来亚稳态风险但通过后面温度计码的毛刺处理和后端平均能把影响压到可接受范围。4.4 Pblock的约束脚本参考布局约束在XDC里写先建Pblock再把延迟链相关的实例加进去。以一个2x2时钟区域为例create_pblock pblock_tdc add_cells_to_pblock pblock_tdc [get_cells {tdc_inst/tdl_chain[*]}] resize_pblock pblock_tdc -add {CLOCKREGION_X0Y0:CLOCKREGION_X0Y1}如果延迟链资源更多可以扩大约束范围。Pblock只是给工具划了边界真正要精细控制每一级CARRY4的位置就用set_property LOC指定坐标。但坐标约束维护成本高换了器件版本就全废。我的经验是先用Pblock圈出大区域让工具自己在里面摆放实测bin宽度和温度计码质量如果某个区域存在系统性偏差再针对那一段追加LOC约束。5. 测试校准与性能分析5.1 码密度校准把不均匀的bin拉直TDL的bin宽度天生不均匀原因包括进位链自身工艺偏差、布局差异、时钟偏斜。如果不做校准直接拿bin序号当时间值误差会达到几十ps甚至更大。工程里最常用的校准法是码密度法。原理是这样给TDC输入大量时间差均匀分布的“随机”信号统计落入每个bin的计数。如果TDC完全线性每个bin的计数应该近似相等但实际情况是宽bin计数多、窄bin计数少计数比例正好反映bin宽度比例。于是每个bin的相对宽度可以通过计数比算出来bin宽度比例 该bin计数 / 总样本数总测量范围可以用外部已知时间间隔标定比如用时间间隔发生器产生一个精确的固定时间差或者用另一个高精度仪器做基准把计数比例换算成绝对时间。校准样本量要够大几十万次起步才能把统计噪声压到1%以内。校准表建立之后每个测量值都查表累加bin宽度得到最终时间值。这样处理完TDC的线性度会明显改善。5.2 单发分辨率、DNL和INL怎么测测试TDC性能分三步走用精密信号源产生周期性脉冲经过步进可调的精密延时线改变延时对每个延时点采集TDC输出画出转移曲线。根据转移曲线计算每个bin实际宽度再与码密度法结果交叉验证。统计单次测量的标准差作为单发分辨率不要只看bin宽度平均值。硬件噪声、时钟抖动、比较器抖动都会让单发噪声比单个bin宽好几倍。DNL和INL这两个指标也要会读。DNL是相邻bin宽度相对于理想bin宽度的偏差百分比INL是累计偏差对应的皮秒数。画直方图时如果累计曲线歪得厉害大概率是进位链的进位点分布不均或者布局跨了CLB列需要回去调Pblock。5.3 死时间优化与双链结构死时间是指TDC完成一次测量之后到下一次能重新开始测量的最短时间。单链结构下编码、复位、校准都要占时间典型死时间在几十纳秒到几百纳秒之间。对单发测量没问题但对连续脉冲流测距或者粒子物理事件率高的情况死时间直接限制系统吞吐量。工程解决方案是双链乒乓结构两套延迟链交替工作A链测量时B链在编码复位B链测量时A链在编码复位两组输出用多路选择器切换。代价是双倍延迟链资源以及两条链之间要做对齐校准。另一个被忽略的点是复位信号的处理。复位路径越短越好复位释放时刻要和采样时钟相位对齐否则复位后第一拍可能出现异常采样值浪费一个测量周期。5.4 温度漂移问题与在线校准策略FPGA内部延迟随温度变化非常明显。实测下来温度每升高10度CARRY4链的bin宽度可能漂移1%~3%累积误差到几百皮秒完全能毁掉测量精度。所以一次性校准的TDC很难长期稳定工程上必须做在线校准。我的做法有三个层次板上放温度传感器软件定时读数用线性系数或查表修正bin宽度。定期注入已知时间间隔的校准脉冲重新跑码密度校准更新bin宽度查找表。周期可以按秒到分钟量级调根据系统对稳定性的要求权衡。如果系统有稳定的参考时钟还可以用TDC测参考时钟周期反推出总测量范围实现闭环标定。6. 常见问题与排查实录6.1 温度计码毛刺与亚稳态问题现象是在ILA里看采样结果温度计码不是干净的连续1和连续0中间出现孤立的0或1。常见原因有两个输入信号边沿恰好和采样时钟沿重合触发器进入亚稳态或者延迟链信号边沿在相邻bin之间扫描时锁存沿不正交。处理方式编码逻辑不要简单找第一个翻转位置改成找最长连续1段的中心毛刺影响大幅下降。多通道多次采样求平均随机噪声可以被压掉一部分。用两个相位错开的采样时钟交叠采样两路结果互相校验鲁棒性更好。约束文件里把TDC相关路径设为异步路径或伪路径避免时序分析误报也避免工具为了满足时序悄悄挪位置。6.2 综合优化把延迟链“优化”没了怎么办第一次写TDL的朋友很容易踩这个坑例化完CARRY4跑综合发现资源面板里CARRY4数量很少或者仿真波形完全不对。原因通常是综合器认为这些单元输出固定不值得保留直接把逻辑简化掉了。解决办法是给延迟链所有关键信号加上KEEP和DONT_TOUCH属性同时在综合策略里关闭“相同寄存器合并”。综合完成后在报告里搜索CARRY4实例数量确认链的级数符合预期再继续布局布线。这一步是最容易被忽略、一旦出错后面全白做的环节。6.3 测量值随温度漂移的稳定化处理前面提过温度漂移这里讲排查顺序。先确认PCB电源稳定温度变化往往伴随电源负载变化电源纹波变大后TDC精度会明显劣化。再检查模拟前端比较器的失调电压随温度变化有些时间漂移问题根本不在FPGA内部。排除外部因素后用双通道方法定位FPGA内部问题两个TDC通道测同一个时间差如果两通道差值的漂移不大说明是公共路径漂移可在软件里做差分消除如果两通道漂移方向不一致就要回去检查布局是否跨了温度梯度不同的区域。最后再考虑在线校准闭环。这里还有一个长期稳定性的经验不要追求一次性把校准表做到极致而是让系统每次上电自动校准一次、运行中定期校准一次配合温度传感器做粗补偿。很多产品级TDC能稳定工作靠的都不是出厂校准精度而是这种闭环维护机制。最后再分享一点个人经验我这几年的习惯是每次调TDC都先写一个最小系统一路输入、一级采样时钟、128级延迟链、一个ILA。把所有噪声和时序问题在这个最小系统里看清了再加通道、加协议、加校准。这个方法帮我省下大量排查时间。另一个心得是不要一上来就追求几十皮秒的极限分辨率。先把码密度校准跑通把一个bin的统计噪声做到足够小再考虑提升分辨率或者压缩死时间。每一步都有可验证的中间结果最后系统联调时才不会崩溃。做硬件测量这行稳一点比快一点重要得多。
阅读完成 · 觉得有帮助?