요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
======================
PPS - Pulse Per Second
======================
Copyright (C) 2007 Rodolfo Giometti <giometti@enneenne.com>
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 2 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.
Overview
--------
LinuxPPS provides a programming interface (API) to define in the
system several PPS sources.
PPS means "pulse per second" and a PPS source is just a device which
provides a high precision signal each second so that an application
can use it to adjust system clock time.
A PPS source can be connected to a serial port (usually to the Data
Carrier Detect pin) or to a parallel port (ACK-pin) or to a special
CPU's GPIOs (this is the common case in embedded systems) but in each
case when a new pulse arrives the system must apply to it a timestamp
and record it for userland.
Common use is the combination of the NTPD as userland program, with a
GPS receiver as PPS source, to obtain a wallclock-time with
sub-millisecond synchronisation to UTC.
RFC considerations
------------------
While implementing a PPS API as RFC 2783 defines and using an embedded
CPU GPIO-Pin as physical link to the signal, I encountered a deeper
problem:
At startup it needs a file descriptor as argument for the function
time_pps_create().
This implies that the source has a /dev/... entry. This assumption is
OK for the serial and parallel port, where you can do something
useful besides(!) the gathering of timestamps as it is the central
task for a PPS API. But this assumption does not work for a single
purpose GPIO line. In this case even basic file-related functionality
(like read() and write()) makes no sense at all and should not be a
precondition for the use of a PPS API.
The problem can be simply solved if you consider that a PPS source is
not always connected with a GPS data source.
So your programs should check if the GPS data source (the serial port
for instance) is a PPS source too, and if not they should provide the
possibility to open another device as PPS source.
In LinuxPPS the PPS sources are simply char devices usually mapped
into files /dev/pps0, /dev/pps1, etc.
PPS with USB to serial devices
------------------------------
It is possible to grab the PPS from an USB to serial device. However,
you should take into account the latencies and jitter introduced by
the USB stack. Users have reported clock instability around +-1ms when
synchronized with PPS through USB. With USB 2.0, jitter may decrease
down to the order of 125 microseconds.
This may be suitable for time server synchronization with NTP because
of its undersampling and algorithms.
If your device doesn't report PPS, you can check that the feature is
supported by its driver. Most of the time, you only need to add a call
to usb_serial_handle_dcd_change after checking the DCD status (see
ch341 and pl2303 examples).
Coding example
--------------
To register a PPS source into the kernel you should define a struct
pps_source_info as follows::
static struct pps_source_info pps_ktimer_info = {
.name = "ktimer",
.path = "",
.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
PPS_ECHOASSERT |
PPS_CANWAIT | PPS_TSFMT_TSPEC,
.echo = pps_ktimer_echo,
.owner = THIS_MODULE,
};
and then calling the function pps_register_source() in your
initialization routine as follows::
source = pps_register_source(&pps_ktimer_info,
PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
The pps_register_source() prototype is::
int pps_register_source(struct pps_source_info *info, int default_params)
where "info" is a pointer to a structure that describes a particular
PPS source, "default_params" tells the system what the initial default
parameters for the device should be (it is obvious that these parameters
must be a subset of ones defined in the struct
pps_source_info which describe the capabilities of the driver).
Once you have registered a new PPS source into the system you can
signal an assert event (for example in the interrupt handler routine)
just using::
pps_event(source, &ts, PPS_CAPTUREASSERT, ptr)
where "ts" is the event's timestamp.
The same function may also run the defined echo function
(pps_ktimer_echo(), passing to it the "ptr" pointer) if the user
asked for that... etc..
Please see the file drivers/pps/clients/pps-ktimer.c for example code.
SYSFS support
-------------
If the SYSFS filesystem is enabled in the kernel it provides a new class::
$ ls /sys/class/pps/
pps0/ pps1/ pps2/
Every directory is the ID of a PPS sources defined in the system and
inside you find several files::
$ ls -F /sys/class/pps/pps0/
assert dev mode path subsystem@
clear echo name power/ uevent
Inside each "assert" and "clear" file you can find the timestamp and a
sequence number::
$ cat /sys/class/pps/pps0/assert
1170026870.983207967#8
Where before the "#" is the timestamp in seconds; after it is the
sequence number. Other files are:
* echo: reports if the PPS source has an echo function or not;
* mode: reports available PPS functioning modes;
* name: reports the PPS source's name;
* path: reports the PPS source's device path, that is the device the
PPS source is connected to (if it exists).
Testing the PPS support
-----------------------
In order to test the PPS support even without specific hardware you can use
the pps-ktimer driver (see the client subsection in the PPS configuration menu)
and the userland tools available in your distribution's pps-tools package,
http://linuxpps.org , or https://github.com/redlab-i/pps-tools.
Once you have enabled the compilation of pps-ktimer just modprobe it (if
not statically compiled)::
# modprobe pps-ktimer
and the run ppstest as follow::
$ ./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 1186592699.388832443, sequence: 364 - clear 0.000000000, sequence: 0
source 0 - assert 1186592700.388931295, sequence: 365 - clear 0.000000000, sequence: 0
source 0 - assert 1186592701.389032765, sequence: 366 - clear 0.000000000, sequence: 0
Please note that to compile userland programs, you need the file timepps.h.
This is available in the pps-tools repository mentioned above.
Generators
----------
Sometimes one needs to be able not only to catch PPS signals but to produce
them also. For example, running a distributed simulation, which requires
computers' clock to be synchronized very tightly.
To do so the class pps-gen has been added. PPS generators can be
registered in the kernel by defining a struct pps_gen_source_info as
follows::
static const struct pps_gen_source_info pps_gen_dummy_info = {
.use_system_clock = true,
.get_time = pps_gen_dummy_get_time,
.enable = pps_gen_dummy_enable,
};
Where the use_system_clock states if the generator uses the system
clock to generate its pulses, or they are from a peripheral device
clock. Method get_time() is used to query the time stored into the
generator clock, while the method enable() is used to enable or
disable the PPS pulse generation.
Then calling the function pps_gen_register_source() in your
initialization routine as follows creates a new generator in the
system::
pps_gen = pps_gen_register_source(&pps_gen_dummy_info);
Generators SYSFS support
------------------------
If the SYSFS filesystem is enabled in the kernel it provides a new class::
$ ls /sys/class/pps-gen/
pps-gen0/ pps-gen1/ pps-gen2/
Every directory is the ID of a PPS generator defined in the system and
inside of it you find several files::
$ ls -F /sys/class/pps-gen/pps-gen0/
dev enable name power/ subsystem@ system time uevent
To enable the PPS signal generation you can use the command below::
$ echo 1 > /sys/class/pps-gen/pps-gen0/enable
Parallel port generator
------------------------
One way to do this is to invent some complicated hardware solutions but it
may be neither necessary nor affordable. The cheap way is to load a PPS
generator on one of the computers (master) and PPS clients on others
(slaves), and use very simple cables to deliver signals using parallel
ports, for example.
Parallel port cable pinout::
pin name master slave
1 STROBE *------ *
2 D0 * | *
3 D1 * | *
4 D2 * | *
5 D3 * | *
6 D4 * | *
7 D5 * | *
8 D6 * | *
9 D7 * | *
10 ACK * ------*
11 BUSY * *
12 PE * *
13 SEL * *
14 AUTOFD * *
15 ERROR * *
16 INIT * *
17 SELIN * *
18-25 GND *-----------*
Please note that parallel port interrupt occurs only on high->low transition,
so it is used for PPS assert edge. PPS clear edge can be determined only
using polling in the interrupt handler which actually can be done way more
precisely because interrupt handling delays can be quite big and random. So
current parport PPS generator implementation (pps_gen_parport module) is
geared towards using the clear edge for time synchronization.
Clear edge polling is done with disabled interrupts so it's better to select
delay between assert and clear edge as small as possible to reduce system
latencies. But if it is too small slave won't be able to capture clear edge
transition. The default of 30us should be good enough in most situations.
The delay can be selected using 'delay' pps_gen_parport module parameter.
Intel Timed I/O PPS signal generator
------------------------------------
Intel Timed I/O is a high precision device, present on 2019 and newer Intel
CPUs, that can generate PPS signals.
Timed I/O and system time are both driven by same hardware clock. The signal
is generated with a precision of ~20 nanoseconds. The generated PPS signal
is used to synchronize an external device with system clock. For example,
it can be used to share your clock with a device that receives PPS signal,
generated by Timed I/O device. There are dedicated Timed I/O pins to deliver
the PPS signal to an external device.
Usage of Intel Timed I/O as PPS generator:
Start generating PPS signal::
$echo 1 > /sys/class/pps-gen/pps-genx/enable
Stop generating PPS signal::
$echo 0 > /sys/class/pps-gen/pps-genx/enable
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
LinuxPPS와 pulse-per-second source
1-41LinuxPPS는 system 안에 여러 PPS source를 정의하는 programming API입니다. PPS는 pulse per second를 뜻하며 source는 매초 high-precision signal을 제공해 application이 system clock을 보정할 수 있게 합니다.
PPS source는 보통 serial port의 Data Carrier Detect pin, parallel port의 ACK pin, 또는 embedded system의 CPU GPIO에 연결됩니다. 어느 연결이든 새 pulse가 도착하면 kernel이 즉시 timestamp를 붙이고 userland가 읽을 수 있도록 기록해야 합니다.
대표 구성은 GPS receiver를 PPS source로 사용하고 userland NTPD가 이를 처리해 wall-clock time을 UTC에 sub-millisecond 수준으로 동기화하는 방식입니다.
매초 발생한 hardware edge에 kernel timestamp를 붙여 user-space clock discipline에 제공합니다.
.. SPDX-License-Identifier: GPL-2.0
======================
PPS - Pulse Per Second
======================
Copyright (C) 2007 Rodolfo Giometti <giometti@enneenne.com>
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 2 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.
Overview
--------
LinuxPPS provides a programming interface (API) to define in the
system several PPS sources.
PPS means "pulse per second" and a PPS source is just a device which
provides a high precision signal each second so that an application
can use it to adjust system clock time.
A PPS source can be connected to a serial port (usually to the Data
Carrier Detect pin) or to a parallel port (ACK-pin) or to a special
CPU's GPIOs (this is the common case in embedded systems) but in each
case when a new pulse arrives the system must apply to it a timestamp
and record it for userland.
Common use is the combination of the NTPD as userland program, with a
GPS receiver as PPS source, to obtain a wallclock-time with
sub-millisecond synchronisation to UTC.
RFC 2783 file descriptor 가정과 Linux char device
42-70RFC 2783 PPS API의 `time_pps_create()`는 시작할 때 file descriptor를 요구하므로 source에 `/dev/...` entry가 있다고 가정합니다. serial·parallel port는 timestamp capture 외에도 read/write 기능이 있어 자연스럽지만, single-purpose GPIO line에는 file operation 자체가 의미 없으므로 이 가정이 맞지 않습니다.
PPS source가 GPS data source와 항상 같은 device는 아닙니다. application은 GPS serial port 자체가 PPS source인지 확인하고, 아니라면 별도 PPS device를 열 수 있게 해야 합니다.
LinuxPPS는 source를 `/dev/pps0`, `/dev/pps1` 같은 char device로 mapping해 RFC API가 요구하는 descriptor와 실제 signal source를 분리합니다.
RFC considerations
------------------
While implementing a PPS API as RFC 2783 defines and using an embedded
CPU GPIO-Pin as physical link to the signal, I encountered a deeper
problem:
At startup it needs a file descriptor as argument for the function
time_pps_create().
This implies that the source has a /dev/... entry. This assumption is
OK for the serial and parallel port, where you can do something
useful besides(!) the gathering of timestamps as it is the central
task for a PPS API. But this assumption does not work for a single
purpose GPIO line. In this case even basic file-related functionality
(like read() and write()) makes no sense at all and should not be a
precondition for the use of a PPS API.
The problem can be simply solved if you consider that a PPS source is
not always connected with a GPS data source.
So your programs should check if the GPS data source (the serial port
for instance) is a PPS source too, and if not they should provide the
possibility to open another device as PPS source.
In LinuxPPS the PPS sources are simply char devices usually mapped
into files /dev/pps0, /dev/pps1, etc.
USB-to-serial PPS의 latency와 driver 지원
71-88USB-to-serial device에서도 PPS를 capture할 수 있지만 USB stack이 latency와 jitter를 추가합니다. user report에서는 USB PPS 동기화의 clock instability가 약 ±1ms였고 USB 2.0에서는 jitter가 약 125 microseconds 수준까지 줄 수 있습니다.
NTP의 undersampling과 filtering algorithm을 사용한 time server에는 이 정확도가 충분할 수 있습니다. device가 PPS를 report하지 않으면 driver 지원 여부를 확인해야 하며, 많은 경우 DCD status 확인 뒤 `usb_serial_handle_dcd_change()` 호출을 추가하면 됩니다. `ch341`과 `pl2303` driver가 예입니다.
PPS with USB to serial devices
------------------------------
It is possible to grab the PPS from an USB to serial device. However,
you should take into account the latencies and jitter introduced by
the USB stack. Users have reported clock instability around +-1ms when
synchronized with PPS through USB. With USB 2.0, jitter may decrease
down to the order of 125 microseconds.
This may be suitable for time server synchronization with NTP because
of its undersampling and algorithms.
If your device doesn't report PPS, you can check that the feature is
supported by its driver. Most of the time, you only need to add a call
to usb_serial_handle_dcd_change after checking the DCD status (see
ch341 and pl2303 examples).
PPS source 등록과 event 전달
89-135kernel에 PPS source를 등록하려면 `struct pps_source_info`를 정의합니다. 예제 `pps_ktimer_info`는 name, path, 지원 mode, echo callback, owner를 지정하며 mode에는 `PPS_CAPTUREASSERT`, `PPS_OFFSETASSERT`, `PPS_ECHOASSERT`, `PPS_CANWAIT`, `PPS_TSFMT_TSPEC` capability가 포함됩니다.
initialization routine에서 `pps_register_source(&pps_ktimer_info, default_params)`를 호출합니다. `info`는 source capability를 설명하고 `default_params`는 초기 device parameter이므로 반드시 capability mode의 subset이어야 합니다.
등록 뒤 interrupt handler 같은 pulse 처리 지점에서 `pps_event(source, &ts, PPS_CAPTUREASSERT, ptr)`를 호출해 assert event와 timestamp를 기록합니다. user가 echo를 요청했다면 같은 함수가 `ptr`을 넘겨 `pps_ktimer_echo()`도 실행할 수 있습니다. 전체 예제는 `drivers/pps/clients/pps-ktimer.c`에 있습니다.
capability를 등록한 뒤 각 hardware edge를 timestamp event로 전달합니다.
Coding example
--------------
To register a PPS source into the kernel you should define a struct
pps_source_info as follows::
static struct pps_source_info pps_ktimer_info = {
.name = "ktimer",
.path = "",
.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
PPS_ECHOASSERT |
PPS_CANWAIT | PPS_TSFMT_TSPEC,
.echo = pps_ktimer_echo,
.owner = THIS_MODULE,
};
and then calling the function pps_register_source() in your
initialization routine as follows::
source = pps_register_source(&pps_ktimer_info,
PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
The pps_register_source() prototype is::
int pps_register_source(struct pps_source_info *info, int default_params)
where "info" is a pointer to a structure that describes a particular
PPS source, "default_params" tells the system what the initial default
parameters for the device should be (it is obvious that these parameters
must be a subset of ones defined in the struct
pps_source_info which describe the capabilities of the driver).
Once you have registered a new PPS source into the system you can
signal an assert event (for example in the interrupt handler routine)
just using::
pps_event(source, &ts, PPS_CAPTUREASSERT, ptr)
where "ts" is the event's timestamp.
The same function may also run the defined echo function
(pps_ktimer_echo(), passing to it the "ptr" pointer) if the user
asked for that... etc..
Please see the file drivers/pps/clients/pps-ktimer.c for example code.
PPS source sysfs interface
136-170SYSFS를 enable한 kernel은 `/sys/class/pps/` 아래에 `pps0`, `pps1`처럼 등록 source별 directory를 만듭니다. 각 directory에는 `assert`, `clear`, `dev`, `echo`, `mode`, `name`, `path`, `power`, `subsystem`, `uevent`가 나타납니다.
`assert`와 `clear` file은 `seconds.nanoseconds#sequence` 형식으로 timestamp와 sequence number를 제공합니다. `#` 앞은 seconds 단위 timestamp이고 뒤는 event sequence입니다.
`echo`는 source에 echo function이 있는지, `mode`는 사용 가능한 PPS mode, `name`은 source 이름, `path`는 존재하는 경우 source가 연결된 device path를 보여 줍니다.
SYSFS support
-------------
If the SYSFS filesystem is enabled in the kernel it provides a new class::
$ ls /sys/class/pps/
pps0/ pps1/ pps2/
Every directory is the ID of a PPS sources defined in the system and
inside you find several files::
$ ls -F /sys/class/pps/pps0/
assert dev mode path subsystem@
clear echo name power/ uevent
Inside each "assert" and "clear" file you can find the timestamp and a
sequence number::
$ cat /sys/class/pps/pps0/assert
1170026870.983207967#8
Where before the "#" is the timestamp in seconds; after it is the
sequence number. Other files are:
* echo: reports if the PPS source has an echo function or not;
* mode: reports available PPS functioning modes;
* name: reports the PPS source's name;
* path: reports the PPS source's device path, that is the device the
PPS source is connected to (if it exists).
pps-ktimer와 ppstest
171-197전용 PPS hardware가 없어도 kernel configuration의 PPS client 항목에서 `pps-ktimer`를 enable하고 distribution의 `pps-tools`, linuxpps.org 또는 redlab-i/pps-tools를 사용해 지원을 시험할 수 있습니다.
module이면 `modprobe pps-ktimer`로 load한 뒤 `ppstest /dev/pps1`을 실행합니다. output은 source 발견 여부와 연속 assert timestamp·sequence를 보여 주며 clear event가 없으면 zero timestamp와 sequence 0으로 표시될 수 있습니다.
userland program을 compile하려면 pps-tools repository의 `timepps.h`가 필요합니다.
software timer source로 char-device capture 경로를 검증합니다.
Testing the PPS support
-----------------------
In order to test the PPS support even without specific hardware you can use
the pps-ktimer driver (see the client subsection in the PPS configuration menu)
and the userland tools available in your distribution's pps-tools package,
http://linuxpps.org , or https://github.com/redlab-i/pps-tools.
Once you have enabled the compilation of pps-ktimer just modprobe it (if
not statically compiled)::
# modprobe pps-ktimer
and the run ppstest as follow::
$ ./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 1186592699.388832443, sequence: 364 - clear 0.000000000, sequence: 0
source 0 - assert 1186592700.388931295, sequence: 365 - clear 0.000000000, sequence: 0
source 0 - assert 1186592701.389032765, sequence: 366 - clear 0.000000000, sequence: 0
Please note that to compile userland programs, you need the file timepps.h.
This is available in the pps-tools repository mentioned above.
PPS generator 등록
198-226distributed simulation처럼 여러 computer clock을 매우 정밀하게 맞추려면 PPS를 capture할 뿐 아니라 생성해야 합니다. 이를 위해 kernel은 `pps-gen` class를 제공합니다.
generator는 `struct pps_gen_source_info`를 정의해 등록합니다. `use_system_clock`은 pulse timing이 system clock인지 peripheral device clock인지 나타냅니다. `get_time()`은 generator clock의 현재 시간을 조회하고 `enable()`은 pulse generation을 enable 또는 disable합니다.
initialization routine에서 `pps_gen_register_source(&pps_gen_dummy_info)`를 호출하면 새 PPS generator가 system에 생성됩니다.
clock source와 callback을 등록해 주기적 output pulse를 제공합니다.
Generators
----------
Sometimes one needs to be able not only to catch PPS signals but to produce
them also. For example, running a distributed simulation, which requires
computers' clock to be synchronized very tightly.
To do so the class pps-gen has been added. PPS generators can be
registered in the kernel by defining a struct pps_gen_source_info as
follows::
static const struct pps_gen_source_info pps_gen_dummy_info = {
.use_system_clock = true,
.get_time = pps_gen_dummy_get_time,
.enable = pps_gen_dummy_enable,
};
Where the use_system_clock states if the generator uses the system
clock to generate its pulses, or they are from a peripheral device
clock. Method get_time() is used to query the time stored into the
generator clock, while the method enable() is used to enable or
disable the PPS pulse generation.
Then calling the function pps_gen_register_source() in your
initialization routine as follows creates a new generator in the
system::
pps_gen = pps_gen_register_source(&pps_gen_dummy_info);
PPS generator sysfs
227-244SYSFS가 enable되면 `/sys/class/pps-gen/` 아래에 `pps-gen0`, `pps-gen1` 같은 generator directory가 생성됩니다. 각 directory에는 `dev`, `enable`, `name`, `power`, `subsystem`, `system`, `time`, `uevent`가 있습니다.
`enable`에 1을 쓰면 PPS signal generation을 시작합니다. 같은 file은 generator의 runtime output switch로 사용됩니다.
Generators SYSFS support
------------------------
If the SYSFS filesystem is enabled in the kernel it provides a new class::
$ ls /sys/class/pps-gen/
pps-gen0/ pps-gen1/ pps-gen2/
Every directory is the ID of a PPS generator defined in the system and
inside of it you find several files::
$ ls -F /sys/class/pps-gen/pps-gen0/
dev enable name power/ subsystem@ system time uevent
To enable the PPS signal generation you can use the command below::
$ echo 1 > /sys/class/pps-gen/pps-gen0/enable
parallel-port PPS generator와 cable timing
245-289저렴한 distributed clock 구성은 master computer에 PPS generator를 load하고 slave computer에는 PPS client를 두어 simple parallel-port cable로 signal을 전달합니다. cable은 master의 STROBE pin 1을 slave의 ACK pin 10에 연결하고 pin 18–25의 GND를 서로 연결합니다. 다른 data/status pin은 이 예에서 연결하지 않습니다.
parallel-port interrupt는 high→low transition에서만 발생하므로 이 edge를 PPS assert로 사용합니다. clear edge는 interrupt handler 안의 polling으로 결정하며 interrupt latency가 크고 random할 수 있어 오히려 이 방식이 더 정밀할 수 있습니다. 현재 `pps_gen_parport`는 clear edge를 time synchronization 기준으로 사용합니다.
clear polling은 interrupt를 disabled한 채 수행하므로 assert와 clear 사이 delay는 system latency를 줄이도록 작게 해야 합니다. 너무 작으면 slave가 clear transition을 capture하지 못합니다. 기본 30µs가 대체로 적절하며 `pps_gen_parport` module의 `delay` parameter로 조정합니다.
Parallel port generator
------------------------
One way to do this is to invent some complicated hardware solutions but it
may be neither necessary nor affordable. The cheap way is to load a PPS
generator on one of the computers (master) and PPS clients on others
(slaves), and use very simple cables to deliver signals using parallel
ports, for example.
Parallel port cable pinout::
pin name master slave
1 STROBE *------ *
2 D0 * | *
3 D1 * | *
4 D2 * | *
5 D3 * | *
6 D4 * | *
7 D5 * | *
8 D6 * | *
9 D7 * | *
10 ACK * ------*
11 BUSY * *
12 PE * *
13 SEL * *
14 AUTOFD * *
15 ERROR * *
16 INIT * *
17 SELIN * *
18-25 GND *-----------*
Please note that parallel port interrupt occurs only on high->low transition,
so it is used for PPS assert edge. PPS clear edge can be determined only
using polling in the interrupt handler which actually can be done way more
precisely because interrupt handling delays can be quite big and random. So
current parport PPS generator implementation (pps_gen_parport module) is
geared towards using the clear edge for time synchronization.
Clear edge polling is done with disabled interrupts so it's better to select
delay between assert and clear edge as small as possible to reduce system
latencies. But if it is too small slave won't be able to capture clear edge
transition. The default of 30us should be good enough in most situations.
The delay can be selected using 'delay' pps_gen_parport module parameter.
Intel Timed I/O PPS generator
290-311Intel Timed I/O는 2019년 이후 Intel CPU에 있는 high-precision device로 PPS signal을 생성할 수 있습니다. Timed I/O와 system time은 같은 hardware clock으로 구동되며 약 20 nanoseconds precision으로 signal을 만듭니다.
전용 Timed I/O pin으로 외부 device에 PPS를 전달해 external clock을 system clock과 동기화합니다. `/sys/class/pps-gen/pps-genx/enable`에 1을 쓰면 생성이 시작되고 0을 쓰면 중지됩니다.
system time과 같은 hardware clock을 사용해 외부 device로 정밀 PPS를 보냅니다.
Intel Timed I/O PPS signal generator
------------------------------------
Intel Timed I/O is a high precision device, present on 2019 and newer Intel
CPUs, that can generate PPS signals.
Timed I/O and system time are both driven by same hardware clock. The signal
is generated with a precision of ~20 nanoseconds. The generated PPS signal
is used to synchronize an external device with system clock. For example,
it can be used to share your clock with a device that receives PPS signal,
generated by Timed I/O device. There are dedicated Timed I/O pins to deliver
the PPS signal to an external device.
Usage of Intel Timed I/O as PPS generator:
Start generating PPS signal::
$echo 1 > /sys/class/pps-gen/pps-genx/enable
Stop generating PPS signal::
$echo 0 > /sys/class/pps-gen/pps-genx/enable
요약과 해설
pps.rst:1-311LinuxPPS는 serial DCD, parallel ACK, GPIO 등의 매초 edge에 kernel timestamp를 붙여 `/dev/ppsN`과 sysfs로 제공하고 NTP 같은 userland가 system clock을 discipline하게 합니다. 반대 방향의 pps-gen은 system 또는 peripheral clock으로 output pulse를 만들며 parallel port와 Intel Timed I/O 구현을 제공합니다.