18c2ecf20Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci====================== 48c2ecf20Sopenharmony_ciPPS - Pulse Per Second 58c2ecf20Sopenharmony_ci====================== 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ciCopyright (C) 2007 Rodolfo Giometti <giometti@enneenne.com> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ciThis program is free software; you can redistribute it and/or modify 108c2ecf20Sopenharmony_ciit under the terms of the GNU General Public License as published by 118c2ecf20Sopenharmony_cithe Free Software Foundation; either version 2 of the License, or 128c2ecf20Sopenharmony_ci(at your option) any later version. 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ciThis program is distributed in the hope that it will be useful, 158c2ecf20Sopenharmony_cibut WITHOUT ANY WARRANTY; without even the implied warranty of 168c2ecf20Sopenharmony_ciMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 178c2ecf20Sopenharmony_ciGNU General Public License for more details. 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ciOverview 228c2ecf20Sopenharmony_ci-------- 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ciLinuxPPS provides a programming interface (API) to define in the 258c2ecf20Sopenharmony_cisystem several PPS sources. 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ciPPS means "pulse per second" and a PPS source is just a device which 288c2ecf20Sopenharmony_ciprovides a high precision signal each second so that an application 298c2ecf20Sopenharmony_cican use it to adjust system clock time. 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ciA PPS source can be connected to a serial port (usually to the Data 328c2ecf20Sopenharmony_ciCarrier Detect pin) or to a parallel port (ACK-pin) or to a special 338c2ecf20Sopenharmony_ciCPU's GPIOs (this is the common case in embedded systems) but in each 348c2ecf20Sopenharmony_cicase when a new pulse arrives the system must apply to it a timestamp 358c2ecf20Sopenharmony_ciand record it for userland. 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ciCommon use is the combination of the NTPD as userland program, with a 388c2ecf20Sopenharmony_ciGPS receiver as PPS source, to obtain a wallclock-time with 398c2ecf20Sopenharmony_cisub-millisecond synchronisation to UTC. 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ciRFC considerations 438c2ecf20Sopenharmony_ci------------------ 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciWhile implementing a PPS API as RFC 2783 defines and using an embedded 468c2ecf20Sopenharmony_ciCPU GPIO-Pin as physical link to the signal, I encountered a deeper 478c2ecf20Sopenharmony_ciproblem: 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci At startup it needs a file descriptor as argument for the function 508c2ecf20Sopenharmony_ci time_pps_create(). 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ciThis implies that the source has a /dev/... entry. This assumption is 538c2ecf20Sopenharmony_ciOK for the serial and parallel port, where you can do something 548c2ecf20Sopenharmony_ciuseful besides(!) the gathering of timestamps as it is the central 558c2ecf20Sopenharmony_citask for a PPS API. But this assumption does not work for a single 568c2ecf20Sopenharmony_cipurpose GPIO line. In this case even basic file-related functionality 578c2ecf20Sopenharmony_ci(like read() and write()) makes no sense at all and should not be a 588c2ecf20Sopenharmony_ciprecondition for the use of a PPS API. 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ciThe problem can be simply solved if you consider that a PPS source is 618c2ecf20Sopenharmony_cinot always connected with a GPS data source. 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ciSo your programs should check if the GPS data source (the serial port 648c2ecf20Sopenharmony_cifor instance) is a PPS source too, and if not they should provide the 658c2ecf20Sopenharmony_cipossibility to open another device as PPS source. 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ciIn LinuxPPS the PPS sources are simply char devices usually mapped 688c2ecf20Sopenharmony_ciinto files /dev/pps0, /dev/pps1, etc. 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ciPPS with USB to serial devices 728c2ecf20Sopenharmony_ci------------------------------ 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ciIt is possible to grab the PPS from an USB to serial device. However, 758c2ecf20Sopenharmony_ciyou should take into account the latencies and jitter introduced by 768c2ecf20Sopenharmony_cithe USB stack. Users have reported clock instability around +-1ms when 778c2ecf20Sopenharmony_cisynchronized with PPS through USB. With USB 2.0, jitter may decrease 788c2ecf20Sopenharmony_cidown to the order of 125 microseconds. 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ciThis may be suitable for time server synchronization with NTP because 818c2ecf20Sopenharmony_ciof its undersampling and algorithms. 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ciIf your device doesn't report PPS, you can check that the feature is 848c2ecf20Sopenharmony_cisupported by its driver. Most of the time, you only need to add a call 858c2ecf20Sopenharmony_cito usb_serial_handle_dcd_change after checking the DCD status (see 868c2ecf20Sopenharmony_cich341 and pl2303 examples). 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ciCoding example 908c2ecf20Sopenharmony_ci-------------- 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ciTo register a PPS source into the kernel you should define a struct 938c2ecf20Sopenharmony_cipps_source_info as follows:: 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci static struct pps_source_info pps_ktimer_info = { 968c2ecf20Sopenharmony_ci .name = "ktimer", 978c2ecf20Sopenharmony_ci .path = "", 988c2ecf20Sopenharmony_ci .mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT | 998c2ecf20Sopenharmony_ci PPS_ECHOASSERT | 1008c2ecf20Sopenharmony_ci PPS_CANWAIT | PPS_TSFMT_TSPEC, 1018c2ecf20Sopenharmony_ci .echo = pps_ktimer_echo, 1028c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1038c2ecf20Sopenharmony_ci }; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ciand then calling the function pps_register_source() in your 1068c2ecf20Sopenharmony_ciinitialization routine as follows:: 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci source = pps_register_source(&pps_ktimer_info, 1098c2ecf20Sopenharmony_ci PPS_CAPTUREASSERT | PPS_OFFSETASSERT); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ciThe pps_register_source() prototype is:: 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci int pps_register_source(struct pps_source_info *info, int default_params) 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ciwhere "info" is a pointer to a structure that describes a particular 1168c2ecf20Sopenharmony_ciPPS source, "default_params" tells the system what the initial default 1178c2ecf20Sopenharmony_ciparameters for the device should be (it is obvious that these parameters 1188c2ecf20Sopenharmony_cimust be a subset of ones defined in the struct 1198c2ecf20Sopenharmony_cipps_source_info which describe the capabilities of the driver). 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ciOnce you have registered a new PPS source into the system you can 1228c2ecf20Sopenharmony_cisignal an assert event (for example in the interrupt handler routine) 1238c2ecf20Sopenharmony_cijust using:: 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci pps_event(source, &ts, PPS_CAPTUREASSERT, ptr) 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ciwhere "ts" is the event's timestamp. 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ciThe same function may also run the defined echo function 1308c2ecf20Sopenharmony_ci(pps_ktimer_echo(), passing to it the "ptr" pointer) if the user 1318c2ecf20Sopenharmony_ciasked for that... etc.. 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ciPlease see the file drivers/pps/clients/pps-ktimer.c for example code. 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ciSYSFS support 1378c2ecf20Sopenharmony_ci------------- 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ciIf the SYSFS filesystem is enabled in the kernel it provides a new class:: 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci $ ls /sys/class/pps/ 1428c2ecf20Sopenharmony_ci pps0/ pps1/ pps2/ 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ciEvery directory is the ID of a PPS sources defined in the system and 1458c2ecf20Sopenharmony_ciinside you find several files:: 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci $ ls -F /sys/class/pps/pps0/ 1488c2ecf20Sopenharmony_ci assert dev mode path subsystem@ 1498c2ecf20Sopenharmony_ci clear echo name power/ uevent 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ciInside each "assert" and "clear" file you can find the timestamp and a 1538c2ecf20Sopenharmony_cisequence number:: 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci $ cat /sys/class/pps/pps0/assert 1568c2ecf20Sopenharmony_ci 1170026870.983207967#8 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ciWhere before the "#" is the timestamp in seconds; after it is the 1598c2ecf20Sopenharmony_cisequence number. Other files are: 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci * echo: reports if the PPS source has an echo function or not; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci * mode: reports available PPS functioning modes; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci * name: reports the PPS source's name; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci * path: reports the PPS source's device path, that is the device the 1688c2ecf20Sopenharmony_ci PPS source is connected to (if it exists). 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ciTesting the PPS support 1728c2ecf20Sopenharmony_ci----------------------- 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ciIn order to test the PPS support even without specific hardware you can use 1758c2ecf20Sopenharmony_cithe pps-ktimer driver (see the client subsection in the PPS configuration menu) 1768c2ecf20Sopenharmony_ciand the userland tools available in your distribution's pps-tools package, 1778c2ecf20Sopenharmony_cihttp://linuxpps.org , or https://github.com/redlab-i/pps-tools. 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ciOnce you have enabled the compilation of pps-ktimer just modprobe it (if 1808c2ecf20Sopenharmony_cinot statically compiled):: 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci # modprobe pps-ktimer 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ciand the run ppstest as follow:: 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci $ ./ppstest /dev/pps1 1878c2ecf20Sopenharmony_ci trying PPS source "/dev/pps1" 1888c2ecf20Sopenharmony_ci found PPS source "/dev/pps1" 1898c2ecf20Sopenharmony_ci ok, found 1 source(s), now start fetching data... 1908c2ecf20Sopenharmony_ci source 0 - assert 1186592699.388832443, sequence: 364 - clear 0.000000000, sequence: 0 1918c2ecf20Sopenharmony_ci source 0 - assert 1186592700.388931295, sequence: 365 - clear 0.000000000, sequence: 0 1928c2ecf20Sopenharmony_ci source 0 - assert 1186592701.389032765, sequence: 366 - clear 0.000000000, sequence: 0 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ciPlease note that to compile userland programs, you need the file timepps.h. 1958c2ecf20Sopenharmony_ciThis is available in the pps-tools repository mentioned above. 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ciGenerators 1998c2ecf20Sopenharmony_ci---------- 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ciSometimes one needs to be able not only to catch PPS signals but to produce 2028c2ecf20Sopenharmony_cithem also. For example, running a distributed simulation, which requires 2038c2ecf20Sopenharmony_cicomputers' clock to be synchronized very tightly. One way to do this is to 2048c2ecf20Sopenharmony_ciinvent some complicated hardware solutions but it may be neither necessary 2058c2ecf20Sopenharmony_cinor affordable. The cheap way is to load a PPS generator on one of the 2068c2ecf20Sopenharmony_cicomputers (master) and PPS clients on others (slaves), and use very simple 2078c2ecf20Sopenharmony_cicables to deliver signals using parallel ports, for example. 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ciParallel port cable pinout:: 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci pin name master slave 2128c2ecf20Sopenharmony_ci 1 STROBE *------ * 2138c2ecf20Sopenharmony_ci 2 D0 * | * 2148c2ecf20Sopenharmony_ci 3 D1 * | * 2158c2ecf20Sopenharmony_ci 4 D2 * | * 2168c2ecf20Sopenharmony_ci 5 D3 * | * 2178c2ecf20Sopenharmony_ci 6 D4 * | * 2188c2ecf20Sopenharmony_ci 7 D5 * | * 2198c2ecf20Sopenharmony_ci 8 D6 * | * 2208c2ecf20Sopenharmony_ci 9 D7 * | * 2218c2ecf20Sopenharmony_ci 10 ACK * ------* 2228c2ecf20Sopenharmony_ci 11 BUSY * * 2238c2ecf20Sopenharmony_ci 12 PE * * 2248c2ecf20Sopenharmony_ci 13 SEL * * 2258c2ecf20Sopenharmony_ci 14 AUTOFD * * 2268c2ecf20Sopenharmony_ci 15 ERROR * * 2278c2ecf20Sopenharmony_ci 16 INIT * * 2288c2ecf20Sopenharmony_ci 17 SELIN * * 2298c2ecf20Sopenharmony_ci 18-25 GND *-----------* 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ciPlease note that parallel port interrupt occurs only on high->low transition, 2328c2ecf20Sopenharmony_ciso it is used for PPS assert edge. PPS clear edge can be determined only 2338c2ecf20Sopenharmony_ciusing polling in the interrupt handler which actually can be done way more 2348c2ecf20Sopenharmony_ciprecisely because interrupt handling delays can be quite big and random. So 2358c2ecf20Sopenharmony_cicurrent parport PPS generator implementation (pps_gen_parport module) is 2368c2ecf20Sopenharmony_cigeared towards using the clear edge for time synchronization. 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ciClear edge polling is done with disabled interrupts so it's better to select 2398c2ecf20Sopenharmony_cidelay between assert and clear edge as small as possible to reduce system 2408c2ecf20Sopenharmony_cilatencies. But if it is too small slave won't be able to capture clear edge 2418c2ecf20Sopenharmony_citransition. The default of 30us should be good enough in most situations. 2428c2ecf20Sopenharmony_ciThe delay can be selected using 'delay' pps_gen_parport module parameter. 243