|
ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
|
This example makes the ESP32 a PTP slave: it listens for a Precision Time Protocol master on the LAN and measures how far its own clock is from the master's, plus the network path delay. PTP (IEEE 1588) is how professional audio, industrial automation, telecom, and test gear keep many devices on the same clock - far tighter than plain NTP.
The master and slave trade four timestamped messages each cycle:
From those four numbers:
((t2 - t1) - (t4 - t3)) / 2((t2 - t1) + (t4 - t3)) / 2pc_ptp_compute() does that arithmetic; the codec builds and parses every message.
linuxptp provides ptp4l.On a Linux box on the same network (replace eth0 with your interface):
-S uses software timestamping (no special NIC needed); --masterOnly=1 makes it the grandmaster so your ESP32 always plays slave.
Put your Wi-Fi name/password in SSID / PASSWORD at the top of Ptp.ino, upload, and open the Serial Monitor at 115200. You will see the master's Announce, then per-cycle offset and delay:
Timestamps here are taken in software, inside the UDP receive callback, so jitter is millisecond-class. That is enough to prove the exchange and to measure LAN path delay, but it is not the sub-microsecond accuracy PTP is famous for. That requires hardware timestamping at the MAC - which this chip's Ethernet MAC supports (see the Ethernet examples) but Wi-Fi does not. Over Wi-Fi, treat this as "NTP-class accuracy using the PTP protocol."
Pair the offset with the Time Source feature to serve corrected time, or feed it to the NTP server example so the whole LAN can sync to a PTP grandmaster through this device. For a GPS- disciplined grandmaster, combine with the UbloxGnss example.
PTP master: line. The master is not reachable: check both devices are on the same subnet, multicast/IGMP is not blocked by the AP, and ptp4l is running with -m (so you can see it work).event bind=0.** Another process holds UDP 319, or the Wi-Fi did not come up.(The Arduino IDE reads the flag from build_opt.h beside the sketch automatically.)
Every PTP message starts with the same 34-octet header (message type, a version, length, domain, a 64-bit correction field, the sender's 8-octet clock identity + port, a sequence id, and a control byte), all big-endian. Timestamps are 10 octets: 6 for seconds, 4 for nanoseconds. pc_ptp_parse_header decodes the header; pc_ptp_parse_timestamp_msg / _parse_delay_resp / _parse_announce decode the bodies; the pc_ptp_build_* functions do the reverse and stamp the right message-type and control values for you. It is fixed-size with no heap, unit-tested on a PC (test/test_ptp) against the IEEE 1588-2008 wire format. Only the UDP send/receive and the timestamping run on the ESP32. See src/services/timing_position/ptp/ptp.h.