Skip to content

arch/arm/stm32: implement PTP hardware clock driver (/dev/ptp0) - #20180

Open
daniel-p-carvalho wants to merge 6 commits into
apache:masterfrom
daniel-p-carvalho:feat/stm32-ptp-posix
Open

daniel-p-carvalho wants to merge 6 commits into
apache:masterfrom
daniel-p-carvalho:feat/stm32-ptp-posix

Conversation

@daniel-p-carvalho

Copy link
Copy Markdown
Contributor

Summary

This PR implements lower-half PTP hardware clock operations (struct ptp_lowerhalf_s and struct ptp_ops_s) in the STM32 Ethernet driver (arch/arm/src/common/stm32/stm32_eth_m3m4_v1.c) and registers it with the generic PTP clock framework (drivers/timers/ptp_clock.c) to expose the standard POSIX character driver /dev/ptp0.

Supported operations:

  • adjfine: adjust PTP clock frequency in parts per billion (ppb) via the addend register (PTPTSAR)
  • adjphase: adjust PTP clock phase via hardware TSSTU
  • adjtime: shift PTP clock time by signed delta in nanoseconds
  • gettime: atomic double-read of hardware timestamp counter with second rollover handling
  • settime: initialize/jump hardware timestamp counter via TSSTI
  • getres: report 1 ns clock resolution

It also includes necessary fixes to support hardware PTP clock operation:

  • Deliver direct raw hardware counter timestamps in d_rxtimestamp so the PTP servo can close the feedback loop against the master clock.
  • Fix RX timestamp conversion order so stm32_eth_ptp_convert_rxtime() runs before pkt_input().
  • Fix sign bug in stm32_eth_ptp_adjust() where uint64_t addend promoted negative ppb adjustments to unsigned, corrupting frequency trim for crystals running fast.
  • Add TMRDEPPATH/TMRVPATH for PTP clock drivers in drivers/timers/Make.defs.
  • Set ETH_MACCR_ROD to disable reception of self-transmitted frames.

Follow-up to #20148 per @xiaoxiang781216's review suggestion to replace custom socket ioctls (SIOCS_PTP_ADJFREQ, SIOCS_PTP_ADJPHASE) with the standard POSIX character driver /dev/ptp0. Hardware transmit timestamping will follow in a separate PR aligned with #20161 (SO_TIMESTAMPING).

Impact

Enables standard POSIX hardware clock disciplining via clock_adjtime() on /dev/ptp0 on STM32 Ethernet interfaces. Fully compatible with ptpd -p /dev/ptp0.

Testing

Tested on real hardware (stm32f4discovery-ext:ethraw / STM32F407) connected via L2 Ethernet P2P to a GNSS-referenced PTP Grandmaster (IEC/IEEE 61850-9-3 profile):

Running ptpd -2 -s -p /dev/ptp0 -B -H -P -i eth0:

nsh> ptpd -t 5
PTPD (PID 5) status:
- clock_source_valid: 1
|- id: 00 14 2d ff fe 61 2b b5
|- utcoffset: 37
|- priority1: 128
|- class: 6
|- accuracy: 34
|- variance: 20061
|- priority2: 128
|- gm_id: 00 14 2d ff fe 61 2b b5
|- stepsremoved: 0
'- timesource: 160
- last_clock_update: 2026-09-17T20:25:40.759091596
- last_delta_ns: -383
- last_adjtime_ns: -80539
- drift_ppb: -82636
- path_delay_ns: 0

Phase locked to -383 ns residual error with crystal drift disciplined at -82636 ppb.

@github-actions github-actions Bot added Arch: arm Issues related to ARM (32-bit) architecture Area: Drivers Drivers issues Size: M The size of the change in this PR is medium labels Sep 17, 2026
@github-actions

github-actions Bot commented Sep 17, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

acassis
acassis previously approved these changes Sep 17, 2026
Comment thread arch/arm/src/common/stm32/stm32_eth_m3m4_v1.c Outdated
Comment thread arch/arm/src/common/stm32/stm32_eth_m3m4_v1.c Outdated
Comment thread arch/arm/src/common/stm32/stm32_eth_m3m4_v1.c Outdated
Comment thread arch/arm/src/common/stm32/stm32_eth_m3m4_v1.c Outdated
Comment thread arch/arm/src/common/stm32/stm32_eth_m3m4_v1.c Outdated
Comment thread arch/arm/src/common/stm32/stm32_eth_m3m4_v1.c Outdated
Comment thread arch/arm/src/common/stm32/stm32_eth_m3m4_v1.c Outdated
jerpelea
jerpelea previously approved these changes Sep 18, 2026
@xiaoxiang781216

Copy link
Copy Markdown
Contributor

please fix:

Error: ./common/stm32/stm32_eth_m3m4_v1.c:4666:2: error: #endif without #if
 4666 | #endif /* CONFIG_NET && CONFIG_STM32_ETHMAC */

Every other timer driver block in this Make.defs sets TMRDEPPATH and
TMRVPATH so DEPPATH/VPATH include this directory. CONFIG_PTP_CLOCK
and CONFIG_PTP_CLOCK_DUMMY were the only two missing it, leaving
ptp_clock.c/ptp_clock_dummy.c unreachable via VPATH and without a
generated dependency file when no other timer driver in this file is
also selected.

Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
(cherry picked from commit 6d38122)
stm32_receive() called pkt_input() before
stm32_eth_ptp_convert_rxtime(), so every packet handed to a packet
socket carried the previous frame's RX timestamp instead of its own
in dev->d_rxtime. Reorder so the timestamp is converted first.

Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
(cherry picked from commit 9bfa20d)
Set ETH_MACCR_ROD unconditionally when configuring the MAC. In
half-duplex mode the MAC otherwise reflects every frame it transmits
back to its own receiver, flooding the receive path with our own
traffic right as a genuine reply arrives. The bit has no effect in
full-duplex (confirmed on our hardware: fduplex=1), so setting it
unconditionally is safe and changes nothing observable for boards
already running full-duplex.

The sibling stm32f7 driver has the same gap (ETH_MACCR_ROD cleared
but never set) and stm32h7's equivalent ETH_MACCR_DO bit has the same
issue; both are left out of scope here since only m3m4_v1 hardware
was available to validate against.

Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
(cherry picked from commit 41536cb)
The MAC hardware counter is the PTP clock reference. Delivering its
raw timestamp directly (instead of synthesizing one against
CLOCK_REALTIME, which starts at an arbitrary boot-time phase) lets the
PTP daemon close the feedback loop and phase-lock the MAC counter -
and therefore the physical PPS output - to the master.

Assisted-by: Gemini:gemini-3.8-flash-medium
Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
Implement lower-half PTP hardware clock operations (struct ptp_lowerhalf_s
and struct ptp_ops_s) in the STM32 Ethernet driver and register it with the
generic PTP clock framework (drivers/timers/ptp_clock.c) to expose /dev/ptp0.

Supported operations:
- adjfine: adjust PTP clock frequency in parts per billion (ppb)
- adjphase: adjust PTP clock phase via hardware TSSTU
- adjtime: shift PTP clock time by signed delta in nanoseconds
- gettime: atomic double-read of hardware timestamp registers
- settime: initialize hardware timestamp counter via TSSTI
- getres: return 1 ns clock resolution

Also fix a sign bug in stm32_eth_ptp_adjust() where uint64_t addend
promoted negative ppb adjustments to unsigned, corrupting frequency trim
for crystals running faster than nominal.

Follow-up to apache#20148 per review recommendation to use the standard POSIX
/dev/ptp0 character driver instead of custom socket ioctls.

Assisted-by: Gemini:gemini-3.8-pro
Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
Variable conn is declared and initialized in append_timestamping()
but never referenced, triggering -Wunused-variable compiler warning.

Assisted-by: Gemini:gemini-3.8-pro
Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: arm Issues related to ARM (32-bit) architecture Area: Drivers Drivers issues Size: M The size of the change in this PR is medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants