Skip to content

Software-based TimeSync

Software-based TimeSync is supported through Linux PTP. The driver exposes a hardware derived intermediate clock device through the Linux PTP Hardware Clock Subsystem accessible to user-space via /dev/ptpX device nodes. This intermediate clock is disciplined to a reference clock source using, e.g., phc2sys. Drift correction is handled by phc2sys, the default servo update interval can typically be set to 1 second.

The software path is: Device free-running clock -> periodic disciplining (phc2sys) -> Hardware derived intermediate clock -> timestamp mapping -> Disciplined timestamps

The driver does not perform drift compensation on its own. Time alignment requires running LinuxPTP user-space tools.

Following is an example of using phc2sys to discipline the device's exposed hardware derived intermediate clock to the host system clock CLOCK_REALTIME.

Load the driver and verify that the PHC device exists:

  ls /dev/ptp*

Debug PHC access:

  sudo phc_ctl -l7 /dev/ptpN

Discipline one PHC to host system clock:

sudo phc2sys -mq -O0 -s CLOCK_REALTIME -c /dev/ptpN

Discipline multiple PHCs to host system clock:

sudo phc2sys -mq -O0 -s CLOCK_REALTIME -c /dev/ptpN -c /dev/ptpM

Use external PPS/EXTTS reference instead of CLOCK_REALTIME:

sudo ts2phc -mq -s /dev/ptp1 -c /dev/ptpM

Automatic startup configuration

For automatic start when a Kvaser PHC appears, create the following systemd service file:

/etc/systemd/system/[email protected]

[Unit]
Description=Synchronize Kvaser device clock %I to system clock
Documentation=man:phc2sys
BindsTo=dev-%i.device
After=dev-%i.device

[Service]
Type=simple
ExecStart=/usr/sbin/phc2sys -O0 -s CLOCK_REALTIME -c /dev/%I
Restart=on-failure

[Install]
WantedBy=multi-user.target

And create the udev rules in /etc/udev/rules.d/99-kvaser-ptp.rules:

ACTION=="add", SUBSYSTEM=="ptp", DRIVERS=="kvpciefd",
TAG+="systemd", ENV{SYSTEMD_WANTS}="kvaser-timesync@$kernel.service"

For SocketCAN, replace kvpciefd with kvaser_pciefd.

CANlib considerations

Disable automatic bus-on time zeroing before synchronization (canIOCTL_SET_BUSON_TIME_AUTO_RESET). If using CANlib time domains, apply offsets only after clocks are already synchronized.