From b4131c6ac598ee78b77e23e4d5b08f7d7e712a4f Mon Sep 17 00:00:00 2001 From: Scramble Tools <162384439+scrambletools@users.noreply.github.com> Date: Mon, 25 May 2026 23:30:48 -0700 Subject: [PATCH] fix(esp_eth): use stored base_increment when computing PTP addend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The addend in `emac_hal_ptp_start()` was derived from the floating-point `config->ptp_req_accuracy_ns` instead of the integer `base_increment` register that actually drives the sub-second update. The cast to `uint8_t` loses the fractional part, so the un-corrected addend leaves the PTP clock running off-rate. Example: with a 40 MHz XTAL and the default `req_accuracy_ns = 40`, `base_increment` rounds 85.899 up to 86, leaving the clock +1170 ppm fast — well outside the IEEE 802.1AS neighborRateRatio limit (~±200 ppm), so strict-1AS bridges refuse asCapable. Compute the addend from the stored `base_increment` for both rollover modes: `addend = 2^32 * clk_period_ns / increment_ns`. Measured on ESP32-P4: neighborRateRatio drops from +1147.5 ppm to +4.2 ppm, and asCapable is granted. Co-authored-by: Ondrej Kosta --- components/esp_hal_emac/emac_hal.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/components/esp_hal_emac/emac_hal.c b/components/esp_hal_emac/emac_hal.c index 1ef1ab373d0..e8be3015b1c 100644 --- a/components/esp_hal_emac/emac_hal.c +++ b/components/esp_hal_emac/emac_hal.c @@ -431,12 +431,25 @@ esp_err_t emac_hal_ptp_start(emac_hal_context_t *hal, const emac_hal_ptp_config_ int32_t to = 0; /* If you are using the Fine correction method */ if (config->upd_method == ETH_PTP_UPDATE_METHOD_FINE) { - /** - * 2^32 2^32 TsysClk(ns) - * Addend = ——————— = —————————————————————————— = 2^32 * —————————————— - * ratio SysClk(MHz)/PTPaccur(MHz) Taccur(ns) + /* + * Compute the addend from the actual integer base_increment written + * to hardware, not from the ideal ptp_req_accuracy_ns. Because + * base_increment is a uint8_t, the cast truncates the fractional + * part, making the real sub-second step differ from the requested + * accuracy. This is especially required for IEEE 802.1AS where the + * uncorrected rate must already be within 200 ppm (neighborRateRatio) + * before Sync messages arrive, so we derive the addend from + * the truncated value directly. */ - uint32_t base_addend = (1ll << 32) * config->ptp_clk_src_period_ns / config->ptp_req_accuracy_ns; + double increment_ns; + if (emac_ll_is_ts_digital_roll_set(hal->ptp_regs)) { + increment_ns = (double)base_increment; + } else { + increment_ns = (double)base_increment * 1.0e9 / (double)(1ULL << 31); + } + uint32_t base_addend = (uint32_t)((double)(1ULL << 32) * + config->ptp_clk_src_period_ns / + increment_ns); emac_ll_set_ts_addend_val(hal->ptp_regs, base_addend); emac_ll_ts_addend_do_update(hal->ptp_regs); while (!emac_ll_is_ts_addend_update_done(hal->ptp_regs) && to < EMAC_PTP_INIT_TIMEOUT_US) {