Exploration and test of 1PPS time synchronization function of GPS

Posted by igorlopez on Thu, 11 Jun 2020 05:41:44 +0200

Recently, in the study of GPSD related information, it is found that GPSD can cooperate with NTPD to achieve high-precision time synchronization function, so this topic is involved.

At present, Ublox F9P module is in hand, UART outputs NEMA data, and another GPIO outputs 1PPS pulse

First, look at a sequence diagram:

1. NEMA contains time information, generally at the second level, and some with milliseconds

2. 1PPS is to output one pulse per second. In the figure, take high-level trigger as an example (no falling edge is drawn). The time to receive and process 1PPS pulse is also at ns level

3. Because NEMA is sent and received through the serial port, and the amount of NEMA data at a time is KB, the processing time is much longer than 1PPS

4. High precision time synchronization can be achieved by combining second level time and 1PPS pulse in NEMA (ns level: according to 1PPS response time)

Take Linux as an example, the common combination method is: kenel pps.ko , GPSD, chronyd or NTPD

First, Kernel pps.ko :

Currently, the kernel supports pps processing. Because the pps of my ublox is connected to gpio, I choose gpio mode

1. kernel timer client is the pps signal simulated by kernel software for testing

2. pps client using gpio uses gpio as pps signal source

pps-gpio.c source code is also relatively simple, mainly through the registration of GPIO interrupt, when the GPIO level changes, record the current system running time, and then post event to the user space.

Because external GPIO is used, before using this module, you need to specify the relevant GPIO pin in dts, and the compatible is "PPS GPIO"

static const struct of_device_id pps_gpio_dt_ids[] = {

{ .compatible = "pps-gpio", },

{ /* sentinel */ }

};

Compile and start after configuration, check dmesg

root@imx8qxpmek:~# dmesg |grep pps
[    0.708441] pps_core: LinuxPPS API ver. 1 registered
[    0.713357] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[    1.737515] pps pps0: new PPS source ktimer
[    1.741727] pps pps0: ktimer PPS source registered
[    1.747556] pps pps1: new PPS source pps.-1
[    1.751804] pps pps1: Registered IRQ 115 as PPS source
[  236.866057] pps pps1: unsupported capabilities (2)

Here, PPS0 is the PPS signal simulated by the kernel, and PPS signal of pps1 ublox module

In the application layer, ppstest tool can be used to view the time value of pps signal (system time point at the time of pps signal occurrence)

root@imx8qxpmek:~# ppstest /dev/pps0 
trying PPS source "/dev/pps0"
found PPS source "/dev/pps0"
ok, found 1 source(s), now start fetching data...
source 0 - assert 1591828917.828448156, sequence: 85791 - clear  0.000000000, sequence: 0
source 0 - assert 1591828918.852533634, sequence: 85792 - clear  0.000000000, sequence: 0
source 0 - assert 1591828919.876534727, sequence: 85793 - clear  0.000000000, sequence: 0
^C
root@imx8qxpmek:~# 
root@imx8qxpmek:~# ppstest /dev/pps1 
trying PPS source "/dev/pps1"
found PPS source "/dev/pps1"
ok, found 1 source(s), now start fetching data...
source 0 - assert 1591828923.065352191, sequence: 87742 - clear  0.000000000, sequence: 0
source 0 - assert 1591828924.065348846, sequence: 87743 - clear  0.000000000, sequence: 0
source 0 - assert 1591828925.065347127, sequence: 87744 - clear  0.000000000, sequence: 0
source 0 - assert 1591828926.065348783, sequence: 87745 - clear  0.000000000, sequence: 0
^C

View pps interrupt:

root@imx8qxpmek:~# date
Thu Jun 11 06:43:49 CST 2020
root@imx8qxpmek:~# cat /proc/interrupts |grep pps
115:      87851          0          0          0  gpio-mxc  16 Edge      pps.-1
root@imx8qxpmek:~# date
Thu Jun 11 06:43:53 CST 2020
root@imx8qxpmek:~# cat /proc/interrupts |grep pps
115:      87855          0          0          0  gpio-mxc  16 Edge      pps.-1

Through date time printing, you can see that 1s generates an interrupt.

At this point, the pps configuration is completed. Next, NEMA data is processed, and gpsd is used

gpsd is a special gps signal processing service that supports multiple devices, multiple protocols and provides a rich tool set. This part mainly introduces the use, no compilation and detailed function description.

Through gpsd-l, you can check the supported gps protocols or modules. I have cropped them and only kept NEMA and ublox, so only two of them are displayed

root@imx8qxpmek:~# ./gpsd -l
                                NMEA0183
n       b       c       *       u-blox
# n: mode switch, b: speed switch, c: rate switch, *: non-NMEA packet type.
# Socket export enabled.
# Shared memory export enabled.
# Time service features enabled.

In addition, it can also be seen that socket and shared memory are supported for communication. For example, the subsequent use of chronyd is to use shared memory, and time service is also enabled. Of course, it is not used here, but it is implemented separately with chrony.

After starting the gpsd service, you can obtain the gps status through various tool sets provided by it, such as gpsmon:

Next, configure the chrony as a dedicated time service program, similar to NTPD

It is configured as / etc/chrony.conf

leapsectz right/UTC
makestep 1.0 -1
rtcsync

refclock PPS /dev/pps1 lock GPSD prefer refid PPS
refclock SHM 0 offset 0.0 delay 0.2 refid GPSD

allow

Drivetfile - calculates the ratio of the increase and decrease of the computer's time according to the actual time. It is the most reasonable to record it in a file. It will make compensation for the system clock after restart, and even get a better estimate from the clock server if possible.

rtcsync - the instruction will enable a kernel mode in which system time is copied to the real-time clock (RTC) every 11 minutes.

allow / deny - here you can specify a host, subnet, or network to allow or deny NTP connections to the machine acting as the clock server.
makestep - generally, cronyd will slow down or speed up the clock according to the demand, so that the system gradually corrects all time deviations. In some specific cases, the system clock may drift too fast, causing the adjustment process to take a long time to correct the system clock. This instruction forces cronyd to step adjust the system clock when the adjustment period is greater than a certain threshold, but it only takes effect when there are no more clock updates because the startup time of cronyd exceeds the specified limit (negative value can be used to disable the limit)

refclock driver parameter[:option]...​ [option]...​

    The refclock directive specifies a hardware reference clock to be used as a time source. It has two mandatory parameters, a driver name and a driver-specific parameter. The two parameters are followed by zero or more refclock options. Some drivers have special options, which can be appended to the driver-specific parameter using the : character.

    There are four drivers included in chronyd:

    PPS

        Driver for the kernel PPS (pulse per second) API. The parameter is the path to the PPS device (typically /dev/pps?). As PPS refclocks do not supply full time, another time source (e.g. NTP server or non-PPS refclock) is needed to complete samples from the PPS refclock. An alternative is to enable the local directive to allow synchronisation with some unknown but constant offset. The driver supports the following option:

        clear

            By default, the PPS refclock uses assert events (rising edge) for synchronisation. With this option, it will use clear events (falling edge) instead.

        Examples:

        refclock PPS /dev/pps0 lock NMEA refid GPS
        refclock SHM 0 offset 0.5 delay 0.2 refid NMEA noselect
        refclock PPS /dev/pps1:clear refid GPS2

For detailed configurations, please refer to the official documents: https://chrony.tuxfamily.org/documentation.html

After running chronyd, you can see the time synchronization process:

root@imx8qxpmek:~# chronyd  -d -f /etc/chrony.conf  
2020-06-10T17:00:41Z chronyd version 3.2 starting (+CMDMON +NTP +REFCLOCK +RTC -PRIVDROP -SCFILTER -SECHASH -SIGND +ASYNCDNS +IPV6 -DEBUG)
2020-06-10T17:00:41Z Initial frequency -116.709 ppm
2020-06-10T17:00:41Z Timezone right/UTC failed leap second check, ignoring

2020-06-10T17:01:28Z Selected source PPS
2020-06-10T17:01:28Z System clock wrong by 34565.191649 seconds, adjustment started
2020-06-11T02:37:33Z System clock was stepped by 34565.191649 seconds

On the client side, use ntpd to test as follows:

root@OpenWrt:~# ntpd -d -n -p 192.168.3.1
ntpd: sending query to 192.168.3.1
ntpd: reply from 192.168.3.1: offset:+6152.992411 delay:0.008204 status:0x24 strat:1 refid:0x00535050 rootdelay:0.000015 reach:0x01
ntpd: sending query to 192.168.3.1
ntpd: reply from 192.168.3.1: offset:+6152.990378 delay:0.004154 status:0x24 strat:1 refid:0x00535050 rootdelay:0.000015 reach:0x03
ntpd: setting time to 2020-06-11 10:42:38.090639 (offset +6152.990378s)

So far, the time server built on the linux platform with NEMA, 1PPS, GPSD, and chromyd has been completed.

Topics: Linux socket network