Timestamp counter with PPS synchronization

This module can be used to keep track of time inside the FPGA logic, allowing other modules to read the current time in nanoseconds at any moment. Internally, this is achieved by incrementing two counters, one for the seconds and one for the nanoseconds within the second. The former is synchronized with a PPS signal, while the latter is updated by the system clock of the FPGA and it is reset at PPS arrival.

The uncertainty of the timestamp increases with time within each second, but it is reset to a single period of the system clock whenever a PPS pulse arrives. To compute the uncertainty as a function of time within the second, use the following equation:

\[\Delta t = \textnormal{period} + \frac{\textnormal{ppm}}{1\,000\,000} t\]

where period is the period of the system clock and ppm is its frequency uncertainty in parts per million. Note that this uncertainty calculation assumes perfect accuracy of the PPS.

The period of the system clock shall be specified as an integer number of nanoseconds in the clk_period_g generic. If the real period of the clock is non-integer in ns, the nanoseconds within the second will be tracked wrongly by a factor of (clk_period_g / real_period), while the seconds will be counted correctly. This situation should be avoided, but if unavoidable the timestamps may be corrected by software in the receiver via the following procedure:

  1. seconds = timestamp / 1_000_000_000

  2. nanos = timestamp - seconds

  3. real_nanos = nanos * real_period / clk_period_g

  4. real_timestamp = seconds + real_nanos

The internal “seconds” counter can also be synchronized with an externally provided starting time in nanoseconds, overwriting the current value of the counter at the next PPS pulse. To request such synchronization, provide the desired time on time_i and raise sync_i for one clock cycle. Note that synchronization does not happen immediately when doing this and time_i shall be maintained constant until the arrival of the next PPS pulse.

The current time kept by the module is available at any moment on time_o. Finally, sync_o can be used to check if the internal time is coherent with the one provided externally: if it is low, no synchronization has happened yet since last reset and the internal time is relative to the moment of reset deassertion, while if it is high the count has been synchronized at least once with time_i and thus it is coherent with the external reference.

VHDL interface description

timestamp_counterclk_istd_logicrstn_istd_logicpps_istd_logicsync_istd_logictime_istd_logic_vector(63downto 0)sync_ostd_logictime_ostd_logic_vector(63downto 0)

Generics

Name

Description

Type

Default

clk_period_g

period of `clk_i` in ns. if the real period is non-integer, follow the steps described above to correct the timstamps on software

positive

Unspecified

Input signals


IN ports

Name

Description

Type

clk_i

system clock of the fpga

std_logic

rstn_i

active-low synchronous reset for all internal logic of the module

std_logic

pps_i

pps signal used to synchronize the internal counter. frequency must be 1 hz, high time and low time must be longer than the period of `clk_i`

std_logic

sync_i

counter synchronization request. whenever this signal goes high, `time_i` will replace the content of the internal counter at the next `pps_i` rising edge

std_logic

time_i

at pps rising edge, this timestamp will overwrite the internal counter if a `sync_i` pulse has been received in the current second

std_logic_vector(63 downto 0)

Output signals


OUT ports

Name

Description

Type

sync_o

synchronization status flag. set when the counter is synchronized with `time_i`, reset when `rstn_i` is asserted

std_logic

time_o

current time in nanoseconds

std_logic_vector(63 downto 0)