FPGA designs
for
reconfigurable converters

Basic FPGA TDC design

This page contains the basics for simple Time to Digital Converters implemented in a FPGA.
The main purpose of a conversion is to accurately measure the time between a START and STOP signal.

Time Measurement
The principle of time measuring.

Time to Digital Converters

TDC basics

Several ways of implementing Time to Digital Converters exists. Especially in ASIC various ways can be easily implemented, such as time counters, oscillators, pulse shrinkers, delay lines and Vernier lines.
For FPGAs on the contrary the design is limited to the FPGA slice structure. Although it is possible to implement reconfigurable versions of TDC oscillators and time counters, they are limited in use due to low resolution or demanding calibration requirements.

As of today the most used structure implemented in a FPGA for TDC purposes is that of the carrychain, i.e. a delay line TDC. The START signal is propagated through a delay line, in ASIC implemented with either buffers or inverters (minimum propagation delay). On the arrival of the STOP signal, the propagated START signal is latched. This directly gives a thermometer time code. The number of stages flipped to one gives the timing information. The resolution of the TDC is given by the buffer or inverter propagation time τ.

Delay line based TDC
A delay line based TDC can be implemented in a FPGA employing the carry structure.

In the FPGA the carrychain is used instead of inverters or buffers, as it is the only structure with a dedicated routing path, i.e. the signal is not routed through the switch boxes, it is the structure with the smallest delay. Furthermore the routing is independent of the compiler making the delay stable with each compile run.
The main limitations are those coming with the FPGA slice structure: the clock domains, clock slew and slack, the carry-look-ahead and the non-uniform delay inter and intra carry slices.

Basic TDC in a FPGA

TDC basics

The requirement for the first and most basic TDC is a synchronous STOP signal. E.g. this can be the clock of a pulsed laser or any other reference clock. Ideally the clock should have a high frequency, which can make the delay line short and increase the linearities of the system as the number of clock domain crossings can be reduced.
In the case of a low frequency reference clock or an asynchronous STOP signal, check the page on Advanced FPGA TDC design.

The carry is propagated through the carrychain. In order to achieve a carry that propagates, the sum of the carry should be 1 on the arrival of a carry input of 1. Therefore the carry A and B inputs are respectively 0 and 1. The carry propagates with the speed of the carry elements. This speed is in the order of 15 - 25 ps, dependent on the FPGA platform.

Delay line based TDC
TDC implementation in the FPGA with the carrychain as delay line.

Keeping the carry propagation delay in mind, the length of the delay line can be estimated. The delay line should cover (dependent on the application) the clock period. The line length N can be calculated with:

Calc. delay line length

where resolution is the carry propagation delay.
E.g. In the case of a 200 MHz clock frequency acting as STOP signal and a resolution of 20 ps, the line length is 250 carries. The line can thus be implemented in 63 slices, each containing a Carry4 primitive.

Implementing the TDC - Delay line

TDC basics

The first step is the generation of the delay line. This generation can be automated and be placed on the desired location. Manually specifying a starting X, Y location for the delay line ensures best linearity and resolution and the behaviour will be the same each compile run.
The VHDL files can be found below under downloads.

The delay line is generated in fine_tdc, with the following entity:

Code. fine TDC entity

The trigger is the START signal, i.e. the propagating carry. clock is the STOP signal, i.e. the synchronous time stop signal to latch the carry chain output into the flip flops.
The line has a defined length STAGES, which defines the number of carry stages (not the number of Carry4 elements, which is STAGES/4. The first carry stage will be placed on the specified X,Y coordinate. Therefore specify a valid X, Y coordinate for the targeted FPGA.

The carrychain is placed with the generate statement, while using the ATTRIBUTE LOC for the X, Y placement:

Code. fine TDC line generation

The first block is taken apart as the trigger is the carry input, for the other blocks, the carry in is the carry out of the previous block. As the blocks are placed as Carry4 entities, STAGES has to be an integer multiple of 4. Each block is locked to the same X and increasing Y coordinate.

In a similar way, the double flip flops are placed. In most cases, the compiler will automatically place the flip flops in the desired slices along the Carry4 blocks, in the case it doesn't uncomment the two LOC attributes for the flip flops in the fine_tdc file. In that case they are placed in the same slices as the corresponding Carry4 blocks X and the adjacent slices X+1. This ensures the compiler places the entire delay line in the same way independent of the remainder of the design.

Implementing the TDC - Thermometer decoder

TDC basics

The resulting thermometer time code has to be converted to binary to be practically usable, the thermometer decoder is in the therm2bin_count VHDL file. With the b generic, the number of fine bits can be set. Normally this would be equal to √STAGES or 2b=STAGES. It is a standard mux based encoder, except for the final stage, which is the bit counter. The counter counts the remaining high bits, which in practice overcomes the bubble problem, which either gives an over- or underestimate. The structure of the decoder is shown in the following drawing:

Thermometer decoder with bit counter in final stages.
Example of a pipelined thermometer to binary decoder with a bit counter in the final stages.

Obviously the bit counter in this small example makes not so much sense. In practice the bit counter is implemented on the last remaining 15 bits, in which the probability of having a bubble is highest.

As the decoder is being pipelined, the latency of a conversion is in the order of 10 clock cycles (dependent on the size of the TDC and therefore the number of pipeline stages required).
Combining this thermometer decoder and the delay line gives a complete and basic synchronous STOP TDC, the accompanying file fine_tdc_with_encoder is the main entity that can be used in a custom design. It is extended with an input filter as described below.

Implementing the TDC - Input filter

TDC basics

In the case of input pulses being longer than the clock period it is useful to shrink them to the end of the clock cycle (especially if the TDC will be shared), also for the sake of getting one conversion value per input pulse. The input filter is implemented as shown in the following figure. It consists of basically two latches that reset itself so as to be able to fire directly after the clock edge.

Input filter with self reset.
Input filter with self reset as used to shrink the pulses till the end of the clock cycle and making the encoder only give one output for one input pulse.

The input filter is implemented in the fine_tdc_with_encoder VHDL file.

Download VHDL

VHDL icon

tdc_library.vhd
fine_tdc_with_encoder.vhd
fine_tdc.vhd
therm2bin_count.vhd
GPL license

VHDL files for the basic FPGA TDC.
fine_tdc incorporates the carrychain delay line and the double output buffering;
therm2bin_count is the thermometer decoder with a bit counter in the final stages;
fine_tdc_with_encoder is the bundling of the above combined with the input filter.

GNU GPL License Copyright 2015 Harald Homulle / Edoardo Charbon
This software is released under The GNU General Public License 3. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.