time-nuts@lists.febo.com

Discussion of precise time and frequency measurement

View all threads

time syncing on a microcontroller

FV
Folkert van Heusden
Tue, May 6, 2025 9:36 AM

Hi,

Does anyone know of a program for micro controllers like the ESP32 to
sync their clock like NTP does? (which then apparently does not show up
in my google searches)

Most implementations just do an SNTP request and step the clock.
TheESP32 SDK has an NTP implementation which also slews the clock which
is cool, but sofar none I could find also disciplines the clock.

I'm trying to reach 0.2 ms accuracy.

--
www.vanheusden.com [1]

Links:

[1] http://www.vanheusden.com

Hi, Does anyone know of a program for micro controllers like the ESP32 to sync their clock like NTP does? (which then apparently does not show up in my google searches) Most implementations just do an SNTP request and step the clock. TheESP32 SDK has an NTP implementation which also slews the clock which is cool, but sofar none I could find also disciplines the clock. I'm trying to reach 0.2 ms accuracy. -- www.vanheusden.com [1] Links: ------ [1] http://www.vanheusden.com
JE
Jeremy Elson
Wed, May 7, 2025 7:44 PM

It's not quite what you're asking for, but I wrote an ESP32 NTP client a
couple years ago: https://www.lectrobox.com/projects/esp32-ntp/

The architectural difference between it and classic NTP implementations is
that it makes no attempt to create a frequency-accurate or even monotonic
UTC timescale. It does not set the ESP32's clock, so the local clock can
still be used as a monotonic and frequency-stable timescale. My library
gives you an API to ask "what UTC timestamp corresponds to local timestamp
X?". Every time you ask it for such a conversion, it gives you its best
estimate, but each of these estimates is independent based on the most
recent observations received.

While the clock is not disciplined, the library does estimate the frequency
error of the local oscillator and use that estimate for the conversion.

These design choices work well for my uses, but not for everyone's, and
perhaps not yours.

-Jeremy

On Wed, May 7, 2025 at 12:33 PM Folkert van Heusden via time-nuts <
time-nuts@lists.febo.com> wrote:

Hi,

Does anyone know of a program for micro controllers like the ESP32 to
sync their clock like NTP does? (which then apparently does not show up
in my google searches)

Most implementations just do an SNTP request and step the clock.
TheESP32 SDK has an NTP implementation which also slews the clock which
is cool, but sofar none I could find also disciplines the clock.

I'm trying to reach 0.2 ms accuracy.

--
www.vanheusden.com [1]

Links:

[1] http://www.vanheusden.com


time-nuts mailing list -- time-nuts@lists.febo.com
To unsubscribe send an email to time-nuts-leave@lists.febo.com

It's not quite what you're asking for, but I wrote an ESP32 NTP client a couple years ago: https://www.lectrobox.com/projects/esp32-ntp/ The architectural difference between it and classic NTP implementations is that it makes no attempt to create a frequency-accurate or even monotonic UTC timescale. It does not set the ESP32's clock, so the local clock can still be used as a monotonic and frequency-stable timescale. My library gives you an API to ask "what UTC timestamp corresponds to local timestamp X?". Every time you ask it for such a conversion, it gives you its best estimate, but each of these estimates is independent based on the most recent observations received. While the clock is not disciplined, the library does estimate the frequency error of the local oscillator and use that estimate for the conversion. These design choices work well for my uses, but not for everyone's, and perhaps not yours. -Jeremy On Wed, May 7, 2025 at 12:33 PM Folkert van Heusden via time-nuts < time-nuts@lists.febo.com> wrote: > Hi, > > Does anyone know of a program for micro controllers like the ESP32 to > sync their clock like NTP does? (which then apparently does not show up > in my google searches) > > Most implementations just do an SNTP request and step the clock. > TheESP32 SDK has an NTP implementation which also slews the clock which > is cool, but sofar none I could find also disciplines the clock. > > I'm trying to reach 0.2 ms accuracy. > > -- > www.vanheusden.com [1] > > Links: > ------ > [1] http://www.vanheusden.com > _______________________________________________ > time-nuts mailing list -- time-nuts@lists.febo.com > To unsubscribe send an email to time-nuts-leave@lists.febo.com >
BD
Bill Dailey
Wed, May 7, 2025 7:45 PM

Micropython can do it with trim registers.

No, the code I shared isn't directly accessing the ESP32's trim registers. It's implementing a higher-level approach by:

  1. Detecting time drift by comparing local time with NTP time
  2. Manually adjusting the time in small increments using the RTC's datetime function

For a more precise implementation that uses the ESP32's trim registers, you would need to access the hardware-specific registers that control the RTC's oscillator frequency. Here's how you could modify the code to use trim registers in MicroPython:

import network
import ntptime
import time
import utime
import esp32
from machine import RTC

# Constants
NTP_SYNC_INTERVAL = 3600  # Sync every hour (in seconds)
CALIBRATION_CYCLES = 10   # Number of cycles to measure drift

def connect_wifi(ssid, password):
    """Connect to WiFi network"""
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if not wlan.isconnected():
        print('Connecting to WiFi...')
        wlan.connect(ssid, password)
        while not wlan.isconnected():
            pass
    print('WiFi connected:', wlan.ifconfig())

def measure_rtc_drift():
    """Measure RTC drift against NTP to calculate trim value"""
    # Get initial NTP time
    ntptime.settime()
    start_time = utime.time()
    
    # Wait for several hours to measure drift accurately
    print("Measuring RTC drift...")
    utime.sleep(CALIBRATION_CYCLES * 3600)  # Multiple hours for accuracy
    
    # Get NTP time again without setting it
    local_time = utime.time()
    ntptime.settime()
    ntp_time = utime.time()
    
    # Restore original time
    rtc = RTC()
    tm = utime.localtime(local_time)
    rtc.datetime((tm[0], tm[1], tm[2], tm[6], tm[3], tm[4], tm[5], 0))
    
    # Calculate drift in ppm (parts per million)
    elapsed_seconds = local_time - start_time
    time_drift = ntp_time - local_time
    drift_ppm = (time_drift * 1000000) / elapsed_seconds
    
    print(f"Measured drift: {drift_ppm} ppm over {elapsed_seconds} seconds")
    return drift_ppm

def adjust_rtc_trim(drift_ppm):
    """Adjust RTC trim register based on measured drift"""
    # Get current trim value
    current_trim = esp32.RTC().get_rtc_clk_cal_proc()
    
    # ESP32 RTC trim register works differently depending on hardware
    # This is a simplified example - you'll need to adapt it to your specific ESP32
    # The calculation below is an approximation
    
    # Calculate new trim value (specific formula depends on ESP32 variant)
    # A negative drift means RTC is running too fast
    adjustment = int(drift_ppm / 5)  # Approximate conversion factor
    new_trim = current_trim - adjustment
    
    # Apply new trim value
    # Note: In actual implementation, you'd use esp32 module to access RTC control registers
    # This is a placeholder as direct register access varies by MicroPython implementation
    try:
        esp32.RTC().set_rtc_clk_cal_proc(new_trim)
        print(f"RTC trim adjusted from {current_trim} to {new_trim}")
        return True
    except Exception as e:
        print(f"Failed to adjust RTC trim: {e}")
        return False

def main():
    # Replace with your WiFi credentials
    connect_wifi("YOUR_SSID", "YOUR_PASSWORD")
    
    # Initial time set
    try:
        ntptime.settime()
        print("Initial time set:", utime.localtime())
    except:
        print("Initial NTP sync failed")
    
    # Measure drift and calibrate RTC
    drift_ppm = measure_rtc_drift()
    adjust_rtc_trim(drift_ppm)
    
    # Main loop - periodically check and adjust if needed
    while True:
        utime.sleep(NTP_SYNC_INTERVAL)
        
        # Check current drift
        local_time = utime.time()
        ntptime.settime()  
        ntp_time = utime.time()
        
        # Restore local time
        rtc = RTC()
        tm = utime.localtime(local_time)
        rtc.datetime((tm[0], tm[1], tm[2], tm[6], tm[3], tm[4], tm[5], 0))
        
        # If drift is significant, recalibrate
        if abs(ntp_time - local_time) > 5:  # More than 5 seconds drift
            print("Significant drift detected, recalibrating...")
            drift_ppm = measure_rtc_drift()
            adjust_rtc_trim(drift_ppm)

if __name__ == "__main__":
    main()

On May 7, 2025, at 2:32 PM, Folkert van Heusden via time-nuts time-nuts@lists.febo.com wrote:

Hi,

Does anyone know of a program for micro controllers like the ESP32 to sync their clock like NTP does? (which then apparently does not show up in my google searches)

Most implementations just do an SNTP request and step the clock. TheESP32 SDK has an NTP implementation which also slews the clock which is cool, but sofar none I could find also disciplines the clock.

I'm trying to reach 0.2 ms accuracy.

--
www.vanheusden.com [1]

Links:

[1] http://www.vanheusden.com


time-nuts mailing list -- time-nuts@lists.febo.com
To unsubscribe send an email to time-nuts-leave@lists.febo.com

Micropython can do it with trim registers. No, the code I shared isn't directly accessing the ESP32's trim registers. It's implementing a higher-level approach by: 1. Detecting time drift by comparing local time with NTP time 2. Manually adjusting the time in small increments using the RTC's datetime function For a more precise implementation that uses the ESP32's trim registers, you would need to access the hardware-specific registers that control the RTC's oscillator frequency. Here's how you could modify the code to use trim registers in MicroPython: ```python import network import ntptime import time import utime import esp32 from machine import RTC # Constants NTP_SYNC_INTERVAL = 3600 # Sync every hour (in seconds) CALIBRATION_CYCLES = 10 # Number of cycles to measure drift def connect_wifi(ssid, password): """Connect to WiFi network""" wlan = network.WLAN(network.STA_IF) wlan.active(True) if not wlan.isconnected(): print('Connecting to WiFi...') wlan.connect(ssid, password) while not wlan.isconnected(): pass print('WiFi connected:', wlan.ifconfig()) def measure_rtc_drift(): """Measure RTC drift against NTP to calculate trim value""" # Get initial NTP time ntptime.settime() start_time = utime.time() # Wait for several hours to measure drift accurately print("Measuring RTC drift...") utime.sleep(CALIBRATION_CYCLES * 3600) # Multiple hours for accuracy # Get NTP time again without setting it local_time = utime.time() ntptime.settime() ntp_time = utime.time() # Restore original time rtc = RTC() tm = utime.localtime(local_time) rtc.datetime((tm[0], tm[1], tm[2], tm[6], tm[3], tm[4], tm[5], 0)) # Calculate drift in ppm (parts per million) elapsed_seconds = local_time - start_time time_drift = ntp_time - local_time drift_ppm = (time_drift * 1000000) / elapsed_seconds print(f"Measured drift: {drift_ppm} ppm over {elapsed_seconds} seconds") return drift_ppm def adjust_rtc_trim(drift_ppm): """Adjust RTC trim register based on measured drift""" # Get current trim value current_trim = esp32.RTC().get_rtc_clk_cal_proc() # ESP32 RTC trim register works differently depending on hardware # This is a simplified example - you'll need to adapt it to your specific ESP32 # The calculation below is an approximation # Calculate new trim value (specific formula depends on ESP32 variant) # A negative drift means RTC is running too fast adjustment = int(drift_ppm / 5) # Approximate conversion factor new_trim = current_trim - adjustment # Apply new trim value # Note: In actual implementation, you'd use esp32 module to access RTC control registers # This is a placeholder as direct register access varies by MicroPython implementation try: esp32.RTC().set_rtc_clk_cal_proc(new_trim) print(f"RTC trim adjusted from {current_trim} to {new_trim}") return True except Exception as e: print(f"Failed to adjust RTC trim: {e}") return False def main(): # Replace with your WiFi credentials connect_wifi("YOUR_SSID", "YOUR_PASSWORD") # Initial time set try: ntptime.settime() print("Initial time set:", utime.localtime()) except: print("Initial NTP sync failed") # Measure drift and calibrate RTC drift_ppm = measure_rtc_drift() adjust_rtc_trim(drift_ppm) # Main loop - periodically check and adjust if needed while True: utime.sleep(NTP_SYNC_INTERVAL) # Check current drift local_time = utime.time() ntptime.settime() ntp_time = utime.time() # Restore local time rtc = RTC() tm = utime.localtime(local_time) rtc.datetime((tm[0], tm[1], tm[2], tm[6], tm[3], tm[4], tm[5], 0)) # If drift is significant, recalibrate if abs(ntp_time - local_time) > 5: # More than 5 seconds drift print("Significant drift detected, recalibrating...") drift_ppm = measure_rtc_drift() adjust_rtc_trim(drift_ppm) if __name__ == "__main__": main() ``` > On May 7, 2025, at 2:32 PM, Folkert van Heusden via time-nuts <time-nuts@lists.febo.com> wrote: > > Hi, > > Does anyone know of a program for micro controllers like the ESP32 to sync their clock like NTP does? (which then apparently does not show up in my google searches) > > Most implementations just do an SNTP request and step the clock. TheESP32 SDK has an NTP implementation which also slews the clock which is cool, but sofar none I could find also disciplines the clock. > > I'm trying to reach 0.2 ms accuracy. > > -- > www.vanheusden.com [1] > > Links: > ------ > [1] http://www.vanheusden.com > _______________________________________________ > time-nuts mailing list -- time-nuts@lists.febo.com > To unsubscribe send an email to time-nuts-leave@lists.febo.com
PG
Philip Gladstone
Wed, May 7, 2025 8:20 PM

The nodemcu-firmware (which runs Lua on an esp32 & esp8266) has ntp
clock disciplining for the ESP8266 -- I haven't gotten around to porting it
forward to the ESP32. This is a graph of the last 7 days of one such
ESP8266 board. I suspect that the big excursions are when I'm either
uploading a lot of stuff, or downloading a lot of stuff. My internet
connection is not great so it becomes saturated fairly easily. Also, I
think that the other stuff is clock frequency drift due to temperature
changes in the house.

Philip

[image: image.png]

On Wed, May 7, 2025 at 3:52 PM Bill Dailey via time-nuts <
time-nuts@lists.febo.com> wrote:

Micropython can do it with trim registers.

No, the code I shared isn't directly accessing the ESP32's trim registers.
It's implementing a higher-level approach by:

  1. Detecting time drift by comparing local time with NTP time
  2. Manually adjusting the time in small increments using the RTC's
    datetime function

For a more precise implementation that uses the ESP32's trim registers,
you would need to access the hardware-specific registers that control the
RTC's oscillator frequency. Here's how you could modify the code to use
trim registers in MicroPython:

import network
import ntptime
import time
import utime
import esp32
from machine import RTC

# Constants
NTP_SYNC_INTERVAL = 3600  # Sync every hour (in seconds)
CALIBRATION_CYCLES = 10   # Number of cycles to measure drift

def connect_wifi(ssid, password):
    """Connect to WiFi network"""
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if not wlan.isconnected():
        print('Connecting to WiFi...')
        wlan.connect(ssid, password)
        while not wlan.isconnected():
            pass
    print('WiFi connected:', wlan.ifconfig())

def measure_rtc_drift():
    """Measure RTC drift against NTP to calculate trim value"""
    # Get initial NTP time
    ntptime.settime()
    start_time = utime.time()

    # Wait for several hours to measure drift accurately
    print("Measuring RTC drift...")
    utime.sleep(CALIBRATION_CYCLES * 3600)  # Multiple hours for accuracy

    # Get NTP time again without setting it
    local_time = utime.time()
    ntptime.settime()
    ntp_time = utime.time()

    # Restore original time
    rtc = RTC()
    tm = utime.localtime(local_time)
    rtc.datetime((tm[0], tm[1], tm[2], tm[6], tm[3], tm[4], tm[5], 0))

    # Calculate drift in ppm (parts per million)
    elapsed_seconds = local_time - start_time
    time_drift = ntp_time - local_time
    drift_ppm = (time_drift * 1000000) / elapsed_seconds

    print(f"Measured drift: {drift_ppm} ppm over {elapsed_seconds}
seconds")
    return drift_ppm

def adjust_rtc_trim(drift_ppm):
    """Adjust RTC trim register based on measured drift"""
    # Get current trim value
    current_trim = esp32.RTC().get_rtc_clk_cal_proc()

    # ESP32 RTC trim register works differently depending on hardware
    # This is a simplified example - you'll need to adapt it to your
specific ESP32
    # The calculation below is an approximation

    # Calculate new trim value (specific formula depends on ESP32 variant)
    # A negative drift means RTC is running too fast
    adjustment = int(drift_ppm / 5)  # Approximate conversion factor
    new_trim = current_trim - adjustment

    # Apply new trim value
    # Note: In actual implementation, you'd use esp32 module to access RTC
control registers
    # This is a placeholder as direct register access varies by
MicroPython implementation
    try:
        esp32.RTC().set_rtc_clk_cal_proc(new_trim)
        print(f"RTC trim adjusted from {current_trim} to {new_trim}")
        return True
    except Exception as e:
        print(f"Failed to adjust RTC trim: {e}")
        return False

def main():
    # Replace with your WiFi credentials
    connect_wifi("YOUR_SSID", "YOUR_PASSWORD")

    # Initial time set
    try:
        ntptime.settime()
        print("Initial time set:", utime.localtime())
    except:
        print("Initial NTP sync failed")

    # Measure drift and calibrate RTC
    drift_ppm = measure_rtc_drift()
    adjust_rtc_trim(drift_ppm)

    # Main loop - periodically check and adjust if needed
    while True:
        utime.sleep(NTP_SYNC_INTERVAL)

        # Check current drift
        local_time = utime.time()
        ntptime.settime()
        ntp_time = utime.time()

        # Restore local time
        rtc = RTC()
        tm = utime.localtime(local_time)
        rtc.datetime((tm[0], tm[1], tm[2], tm[6], tm[3], tm[4], tm[5], 0))

        # If drift is significant, recalibrate
        if abs(ntp_time - local_time) > 5:  # More than 5 seconds drift
            print("Significant drift detected, recalibrating...")
            drift_ppm = measure_rtc_drift()
            adjust_rtc_trim(drift_ppm)

if __name__ == "__main__":
    main()

On May 7, 2025, at 2:32 PM, Folkert van Heusden via time-nuts <

Hi,

Does anyone know of a program for micro controllers like the ESP32 to

sync their clock like NTP does? (which then apparently does not show up in
my google searches)

Most implementations just do an SNTP request and step the clock.

TheESP32 SDK has an NTP implementation which also slews the clock which is
cool, but sofar none I could find also disciplines the clock.

I'm trying to reach 0.2 ms accuracy.

--
www.vanheusden.com [1]

Links:

[1] http://www.vanheusden.com


time-nuts mailing list -- time-nuts@lists.febo.com
To unsubscribe send an email to time-nuts-leave@lists.febo.com


time-nuts mailing list -- time-nuts@lists.febo.com
To unsubscribe send an email to time-nuts-leave@lists.febo.com

The nodemcu-firmware (which runs Lua on an esp32 & esp8266) has ntp clock disciplining for the ESP8266 -- I haven't gotten around to porting it forward to the ESP32. This is a graph of the last 7 days of one such ESP8266 board. I suspect that the big excursions are when I'm either uploading a lot of stuff, or downloading a lot of stuff. My internet connection is not great so it becomes saturated fairly easily. Also, I think that the other stuff is clock frequency drift due to temperature changes in the house. Philip [image: image.png] On Wed, May 7, 2025 at 3:52 PM Bill Dailey via time-nuts < time-nuts@lists.febo.com> wrote: > Micropython can do it with trim registers. > > No, the code I shared isn't directly accessing the ESP32's trim registers. > It's implementing a higher-level approach by: > > 1. Detecting time drift by comparing local time with NTP time > 2. Manually adjusting the time in small increments using the RTC's > datetime function > > For a more precise implementation that uses the ESP32's trim registers, > you would need to access the hardware-specific registers that control the > RTC's oscillator frequency. Here's how you could modify the code to use > trim registers in MicroPython: > > ```python > import network > import ntptime > import time > import utime > import esp32 > from machine import RTC > > # Constants > NTP_SYNC_INTERVAL = 3600 # Sync every hour (in seconds) > CALIBRATION_CYCLES = 10 # Number of cycles to measure drift > > def connect_wifi(ssid, password): > """Connect to WiFi network""" > wlan = network.WLAN(network.STA_IF) > wlan.active(True) > if not wlan.isconnected(): > print('Connecting to WiFi...') > wlan.connect(ssid, password) > while not wlan.isconnected(): > pass > print('WiFi connected:', wlan.ifconfig()) > > def measure_rtc_drift(): > """Measure RTC drift against NTP to calculate trim value""" > # Get initial NTP time > ntptime.settime() > start_time = utime.time() > > # Wait for several hours to measure drift accurately > print("Measuring RTC drift...") > utime.sleep(CALIBRATION_CYCLES * 3600) # Multiple hours for accuracy > > # Get NTP time again without setting it > local_time = utime.time() > ntptime.settime() > ntp_time = utime.time() > > # Restore original time > rtc = RTC() > tm = utime.localtime(local_time) > rtc.datetime((tm[0], tm[1], tm[2], tm[6], tm[3], tm[4], tm[5], 0)) > > # Calculate drift in ppm (parts per million) > elapsed_seconds = local_time - start_time > time_drift = ntp_time - local_time > drift_ppm = (time_drift * 1000000) / elapsed_seconds > > print(f"Measured drift: {drift_ppm} ppm over {elapsed_seconds} > seconds") > return drift_ppm > > def adjust_rtc_trim(drift_ppm): > """Adjust RTC trim register based on measured drift""" > # Get current trim value > current_trim = esp32.RTC().get_rtc_clk_cal_proc() > > # ESP32 RTC trim register works differently depending on hardware > # This is a simplified example - you'll need to adapt it to your > specific ESP32 > # The calculation below is an approximation > > # Calculate new trim value (specific formula depends on ESP32 variant) > # A negative drift means RTC is running too fast > adjustment = int(drift_ppm / 5) # Approximate conversion factor > new_trim = current_trim - adjustment > > # Apply new trim value > # Note: In actual implementation, you'd use esp32 module to access RTC > control registers > # This is a placeholder as direct register access varies by > MicroPython implementation > try: > esp32.RTC().set_rtc_clk_cal_proc(new_trim) > print(f"RTC trim adjusted from {current_trim} to {new_trim}") > return True > except Exception as e: > print(f"Failed to adjust RTC trim: {e}") > return False > > def main(): > # Replace with your WiFi credentials > connect_wifi("YOUR_SSID", "YOUR_PASSWORD") > > # Initial time set > try: > ntptime.settime() > print("Initial time set:", utime.localtime()) > except: > print("Initial NTP sync failed") > > # Measure drift and calibrate RTC > drift_ppm = measure_rtc_drift() > adjust_rtc_trim(drift_ppm) > > # Main loop - periodically check and adjust if needed > while True: > utime.sleep(NTP_SYNC_INTERVAL) > > # Check current drift > local_time = utime.time() > ntptime.settime() > ntp_time = utime.time() > > # Restore local time > rtc = RTC() > tm = utime.localtime(local_time) > rtc.datetime((tm[0], tm[1], tm[2], tm[6], tm[3], tm[4], tm[5], 0)) > > # If drift is significant, recalibrate > if abs(ntp_time - local_time) > 5: # More than 5 seconds drift > print("Significant drift detected, recalibrating...") > drift_ppm = measure_rtc_drift() > adjust_rtc_trim(drift_ppm) > > if __name__ == "__main__": > main() > ``` > > > On May 7, 2025, at 2:32 PM, Folkert van Heusden via time-nuts < > time-nuts@lists.febo.com> wrote: > > > > Hi, > > > > Does anyone know of a program for micro controllers like the ESP32 to > sync their clock like NTP does? (which then apparently does not show up in > my google searches) > > > > Most implementations just do an SNTP request and step the clock. > TheESP32 SDK has an NTP implementation which also slews the clock which is > cool, but sofar none I could find also disciplines the clock. > > > > I'm trying to reach 0.2 ms accuracy. > > > > -- > > www.vanheusden.com [1] > > > > Links: > > ------ > > [1] http://www.vanheusden.com > > _______________________________________________ > > time-nuts mailing list -- time-nuts@lists.febo.com > > To unsubscribe send an email to time-nuts-leave@lists.febo.com > _______________________________________________ > time-nuts mailing list -- time-nuts@lists.febo.com > To unsubscribe send an email to time-nuts-leave@lists.febo.com
TA
Thomas Abbott
Wed, May 7, 2025 8:22 PM

I have two (pendulum) clock monitoring devices, micropython, one ESP32 and
one Pico W.
I use simple NTP to set the clock once on startup, and then measure the
clock offset every 15 minutes (subtracting half the round-trip), which I
store in the logs.
It looks like this.
[image: image.png]
This could be considered accurate to 10 ms with careful processing. There
are a few percent outliers. I think the network stack and wifi connection
are a big limitation, for example, some sort of sleep means that pinging
the Pico locally, is 2 ms when flooded, but 50 ms when pinging every 3
seconds. I also log the NTP round trip times, they vary from 10 ms to 80 ms
(I discard and retry if it's too long). It's hard to compensate for this,
maybe it can be turned off.

Thomas

On Wed, 7 May 2025 at 12:32, Folkert van Heusden via time-nuts <
time-nuts@lists.febo.com> wrote:

Hi,

Does anyone know of a program for micro controllers like the ESP32 to
sync their clock like NTP does? (which then apparently does not show up
in my google searches)

Most implementations just do an SNTP request and step the clock.
TheESP32 SDK has an NTP implementation which also slews the clock which
is cool, but sofar none I could find also disciplines the clock.

I'm trying to reach 0.2 ms accuracy.

--
www.vanheusden.com [1]

Links:

[1] http://www.vanheusden.com


time-nuts mailing list -- time-nuts@lists.febo.com
To unsubscribe send an email to time-nuts-leave@lists.febo.com

I have two (pendulum) clock monitoring devices, micropython, one ESP32 and one Pico W. I use simple NTP to set the clock once on startup, and then measure the clock offset every 15 minutes (subtracting half the round-trip), which I store in the logs. It looks like this. [image: image.png] This could be considered accurate to 10 ms with careful processing. There are a few percent outliers. I think the network stack and wifi connection are a big limitation, for example, some sort of sleep means that pinging the Pico locally, is 2 ms when flooded, but 50 ms when pinging every 3 seconds. I also log the NTP round trip times, they vary from 10 ms to 80 ms (I discard and retry if it's too long). It's hard to compensate for this, maybe it can be turned off. Thomas On Wed, 7 May 2025 at 12:32, Folkert van Heusden via time-nuts < time-nuts@lists.febo.com> wrote: > Hi, > > Does anyone know of a program for micro controllers like the ESP32 to > sync their clock like NTP does? (which then apparently does not show up > in my google searches) > > Most implementations just do an SNTP request and step the clock. > TheESP32 SDK has an NTP implementation which also slews the clock which > is cool, but sofar none I could find also disciplines the clock. > > I'm trying to reach 0.2 ms accuracy. > > -- > www.vanheusden.com [1] > > Links: > ------ > [1] http://www.vanheusden.com > _______________________________________________ > time-nuts mailing list -- time-nuts@lists.febo.com > To unsubscribe send an email to time-nuts-leave@lists.febo.com >
JP
James Perkins
Wed, May 7, 2025 9:41 PM

I have that beat on an electronics project I developed... source code at
https://gitlab.com/opalmirror/esp32-sntp-clock ... I developed these clocks
because I wanted a 7-segment x4 digit clock display which would self adjust
for DST (using a time zone spec) and accurately track SNTP time. Being a
time nut, a time step alone wasnt enough for me and I wanted it to be rate
controlled.

These clocks use wifi to talk (via SNTP) to a raspberry pi 4 with a GPS hat
which serves NTP on my home network. The rate/offset smoothing algorithm is
a weighted robust linear regression which uses double precision floating
point for simplicity.

I admit I haven't used an oscilloscope to actually measure the top of the
second as compared to the GPS output pin attached to the Pi Hat, but I do
believe it has a phase offset of less than a msec and is rate accurate to
~50 ppm or less, using the stock ESP32 crystal (which shows clear rate
vagaries partly temperature related but also due to nonlinear
characteristics).

This is a bespoke implementation and my first foray into FreeRTOS and LwIP,
so its not portable... but feel free to leverage code and ideas respecting
the BSD licensing.

Cheers,
James

James Perkins james@loowit.net  KN1X  www.loowit.net/~james
2030 W 28th Ave, Eugene OR 97405      +1.971.344.3969 mobile
Alternate email: opalmirror@gmail.com

On Wed, May 7, 2025, 12:32 Folkert van Heusden via time-nuts <
time-nuts@lists.febo.com> wrote:

Hi,

Does anyone know of a program for micro controllers like the ESP32 to
sync their clock like NTP does? (which then apparently does not show up
in my google searches)

Most implementations just do an SNTP request and step the clock.
TheESP32 SDK has an NTP implementation which also slews the clock which
is cool, but sofar none I could find also disciplines the clock.

I'm trying to reach 0.2 ms accuracy.

--
www.vanheusden.com [1]

Links:

[1] http://www.vanheusden.com


time-nuts mailing list -- time-nuts@lists.febo.com
To unsubscribe send an email to time-nuts-leave@lists.febo.com

I have that beat on an electronics project I developed... source code at https://gitlab.com/opalmirror/esp32-sntp-clock ... I developed these clocks because I wanted a 7-segment x4 digit clock display which would self adjust for DST (using a time zone spec) and accurately track SNTP time. Being a time nut, a time step alone wasnt enough for me and I wanted it to be rate controlled. These clocks use wifi to talk (via SNTP) to a raspberry pi 4 with a GPS hat which serves NTP on my home network. The rate/offset smoothing algorithm is a weighted robust linear regression which uses double precision floating point for simplicity. I admit I haven't used an oscilloscope to actually measure the top of the second as compared to the GPS output pin attached to the Pi Hat, but I do believe it has a phase offset of less than a msec and is rate accurate to ~50 ppm or less, using the stock ESP32 crystal (which shows clear rate vagaries partly temperature related but also due to nonlinear characteristics). This is a bespoke implementation and my first foray into FreeRTOS and LwIP, so its not portable... but feel free to leverage code and ideas respecting the BSD licensing. Cheers, James James Perkins <james@loowit.net> KN1X www.loowit.net/~james 2030 W 28th Ave, Eugene OR 97405 +1.971.344.3969 mobile Alternate email: <opalmirror@gmail.com> On Wed, May 7, 2025, 12:32 Folkert van Heusden via time-nuts < time-nuts@lists.febo.com> wrote: > Hi, > > Does anyone know of a program for micro controllers like the ESP32 to > sync their clock like NTP does? (which then apparently does not show up > in my google searches) > > Most implementations just do an SNTP request and step the clock. > TheESP32 SDK has an NTP implementation which also slews the clock which > is cool, but sofar none I could find also disciplines the clock. > > I'm trying to reach 0.2 ms accuracy. > > -- > www.vanheusden.com [1] > > Links: > ------ > [1] http://www.vanheusden.com > _______________________________________________ > time-nuts mailing list -- time-nuts@lists.febo.com > To unsubscribe send an email to time-nuts-leave@lists.febo.com > >
JG
Jeff Geerling
Thu, May 8, 2025 2:31 AM

I know much of the focus is on ESP devices but I've been looking into this on the Raspberry Pi Pico side (RP2040 and RP2350), and there are a few resources I've had bookmarked as I go down this road...

C implementation: https://github.com/raspberrypi/pico-examples/tree/master/pico_w/wifi/ntp_client
Micropython: https://github.com/micropython/micropython-lib/blob/f6723531802661e5a1fd3d63d3b7b68c38f40cd2/micropython/net/ntptime/ntptime.py

I haven't looked too much into a full RTC setup, but there was a good Pi forum thread on this a couple years back: https://forums.raspberrypi.com/viewtopic.php?t=337259

-Jeff Geerling

On May 7, 2025, at 3:22 PM, Thomas Abbott via time-nuts time-nuts@lists.febo.com wrote:

I have two (pendulum) clock monitoring devices, micropython, one ESP32 and
one Pico W.
I use simple NTP to set the clock once on startup, and then measure the
clock offset every 15 minutes (subtracting half the round-trip), which I
store in the logs.
It looks like this.
[image: image.png]
This could be considered accurate to 10 ms with careful processing. There
are a few percent outliers. I think the network stack and wifi connection
are a big limitation, for example, some sort of sleep means that pinging
the Pico locally, is 2 ms when flooded, but 50 ms when pinging every 3
seconds. I also log the NTP round trip times, they vary from 10 ms to 80 ms
(I discard and retry if it's too long). It's hard to compensate for this,
maybe it can be turned off.

Thomas

On Wed, 7 May 2025 at 12:32, Folkert van Heusden via time-nuts <
time-nuts@lists.febo.com> wrote:

Hi,

Does anyone know of a program for micro controllers like the ESP32 to
sync their clock like NTP does? (which then apparently does not show up
in my google searches)

Most implementations just do an SNTP request and step the clock.
TheESP32 SDK has an NTP implementation which also slews the clock which
is cool, but sofar none I could find also disciplines the clock.

I'm trying to reach 0.2 ms accuracy.

--
www.vanheusden.com [1]

Links:

[1] http://www.vanheusden.com


time-nuts mailing list -- time-nuts@lists.febo.com
To unsubscribe send an email to time-nuts-leave@lists.febo.com

<image.png>_______________________________________________
time-nuts mailing list -- time-nuts@lists.febo.com
To unsubscribe send an email to time-nuts-leave@lists.febo.com

I know much of the focus is on ESP devices but I've been looking into this on the Raspberry Pi Pico side (RP2040 and RP2350), and there are a few resources I've had bookmarked as I go down this road... C implementation: https://github.com/raspberrypi/pico-examples/tree/master/pico_w/wifi/ntp_client Micropython: https://github.com/micropython/micropython-lib/blob/f6723531802661e5a1fd3d63d3b7b68c38f40cd2/micropython/net/ntptime/ntptime.py I haven't looked too much into a full RTC setup, but there was a good Pi forum thread on this a couple years back: https://forums.raspberrypi.com/viewtopic.php?t=337259 -Jeff Geerling > On May 7, 2025, at 3:22 PM, Thomas Abbott via time-nuts <time-nuts@lists.febo.com> wrote: > > I have two (pendulum) clock monitoring devices, micropython, one ESP32 and > one Pico W. > I use simple NTP to set the clock once on startup, and then measure the > clock offset every 15 minutes (subtracting half the round-trip), which I > store in the logs. > It looks like this. > [image: image.png] > This could be considered accurate to 10 ms with careful processing. There > are a few percent outliers. I think the network stack and wifi connection > are a big limitation, for example, some sort of sleep means that pinging > the Pico locally, is 2 ms when flooded, but 50 ms when pinging every 3 > seconds. I also log the NTP round trip times, they vary from 10 ms to 80 ms > (I discard and retry if it's too long). It's hard to compensate for this, > maybe it can be turned off. > > Thomas > > > On Wed, 7 May 2025 at 12:32, Folkert van Heusden via time-nuts < > time-nuts@lists.febo.com> wrote: > >> Hi, >> >> Does anyone know of a program for micro controllers like the ESP32 to >> sync their clock like NTP does? (which then apparently does not show up >> in my google searches) >> >> Most implementations just do an SNTP request and step the clock. >> TheESP32 SDK has an NTP implementation which also slews the clock which >> is cool, but sofar none I could find also disciplines the clock. >> >> I'm trying to reach 0.2 ms accuracy. >> >> -- >> www.vanheusden.com [1] >> >> Links: >> ------ >> [1] http://www.vanheusden.com >> _______________________________________________ >> time-nuts mailing list -- time-nuts@lists.febo.com >> To unsubscribe send an email to time-nuts-leave@lists.febo.com >> > <image.png>_______________________________________________ > time-nuts mailing list -- time-nuts@lists.febo.com > To unsubscribe send an email to time-nuts-leave@lists.febo.com
BS
benedikt seeger
Thu, May 8, 2025 7:18 AM

Hello Guys,

I experimented in a research project a lot with stm32 MCUs. With cube mx
there comes and FreeRTOS+LWIP base networkstack that supports NTPD where we
achieved <2ms uncer but we didn't evaluate any further since we directly
switched to hardware timer/counter base GNSS clock synchronisation for
input capture timestamping.
https://github.com/Met4FoF/Met4FoF-SmartUpUnit
this are the most interesting code sections:
https://github.com/Met4FoF/Met4FoF-SmartUpUnit/blob/SSU_V3/Src/NMEAPraser.c
https://github.com/Met4FoF/Met4FoF-SmartUpUnit/blob/e962d144274572389a746ffff44b31e4ee28330f/Src/freertos.cpp#L287
https://github.com/Met4FoF/Met4FoF-SmartUpUnit/blob/e962d144274572389a746ffff44b31e4ee28330f/Src/freertos.cpp#L911
https://github.com/Met4FoF/Met4FoF-SmartUpUnit/blob/SSU_V3/Src/tim64extender.c

From a hardware point of view we just wracked an UBlox-LEA-NEO7 Module onto
the STM 32 with UART7 and the PPS output directly into TIM2 CH4 and had
TIM2 counting up with 108 MHz at max clock rate.

There we achieved <50 ns input capture time stamping uncertainty and 99.3%
of the time stamped values where with in the calculated uncer from the
GNSS-PPS timestamps and the MCUS clockspeed estimation since they are
correlated (i time stamp GNSS with the MCU clock) we overestimate uncer in
GUM conforme error estimation.
If there is interest I can share more information about this :)
The STM32F4 and newer cpus also support IEEE1588 compliant ptp time
distribution, which als outputs pps pulse into TIM2/5 32 bit counters.
I can link a paper for colleagues from RWTH AAchen  this on interest
that looks super promising.
I have the equipment here to test ptp with STM32F767zi cpus but I also have
an CS-beam-clock to repair :/

Best regards from Brunswick Bene

Am Do., 8. Mai 2025 um 07:55 Uhr schrieb Jeff Geerling via time-nuts <
time-nuts@lists.febo.com>:

I know much of the focus is on ESP devices but I've been looking into this
on the Raspberry Pi Pico side (RP2040 and RP2350), and there are a few
resources I've had bookmarked as I go down this road...

C implementation:
https://github.com/raspberrypi/pico-examples/tree/master/pico_w/wifi/ntp_client
Micropython:
https://github.com/micropython/micropython-lib/blob/f6723531802661e5a1fd3d63d3b7b68c38f40cd2/micropython/net/ntptime/ntptime.py

I haven't looked too much into a full RTC setup, but there was a good Pi
forum thread on this a couple years back:
https://forums.raspberrypi.com/viewtopic.php?t=337259

-Jeff Geerling

On May 7, 2025, at 3:22 PM, Thomas Abbott via time-nuts <

I have two (pendulum) clock monitoring devices, micropython, one ESP32

and

one Pico W.
I use simple NTP to set the clock once on startup, and then measure the
clock offset every 15 minutes (subtracting half the round-trip), which I
store in the logs.
It looks like this.
[image: image.png]
This could be considered accurate to 10 ms with careful processing. There
are a few percent outliers. I think the network stack and wifi connection
are a big limitation, for example, some sort of sleep means that pinging
the Pico locally, is 2 ms when flooded, but 50 ms when pinging every 3
seconds. I also log the NTP round trip times, they vary from 10 ms to 80

ms

(I discard and retry if it's too long). It's hard to compensate for this,
maybe it can be turned off.

Thomas

On Wed, 7 May 2025 at 12:32, Folkert van Heusden via time-nuts <
time-nuts@lists.febo.com> wrote:

Hi,

Does anyone know of a program for micro controllers like the ESP32 to
sync their clock like NTP does? (which then apparently does not show up
in my google searches)

Most implementations just do an SNTP request and step the clock.
TheESP32 SDK has an NTP implementation which also slews the clock which
is cool, but sofar none I could find also disciplines the clock.

I'm trying to reach 0.2 ms accuracy.

--
www.vanheusden.com [1]

Links:

[1] http://www.vanheusden.com


time-nuts mailing list -- time-nuts@lists.febo.com
To unsubscribe send an email to time-nuts-leave@lists.febo.com

<image.png>_______________________________________________
time-nuts mailing list -- time-nuts@lists.febo.com
To unsubscribe send an email to time-nuts-leave@lists.febo.com


time-nuts mailing list -- time-nuts@lists.febo.com
To unsubscribe send an email to time-nuts-leave@lists.febo.com

Hello Guys, I experimented in a research project a lot with stm32 MCUs. With cube mx there comes and FreeRTOS+LWIP base networkstack that supports NTPD where we achieved <2ms uncer but we didn't evaluate any further since we directly switched to hardware timer/counter base GNSS clock synchronisation for input capture timestamping. https://github.com/Met4FoF/Met4FoF-SmartUpUnit this are the most interesting code sections: https://github.com/Met4FoF/Met4FoF-SmartUpUnit/blob/SSU_V3/Src/NMEAPraser.c https://github.com/Met4FoF/Met4FoF-SmartUpUnit/blob/e962d144274572389a746ffff44b31e4ee28330f/Src/freertos.cpp#L287 https://github.com/Met4FoF/Met4FoF-SmartUpUnit/blob/e962d144274572389a746ffff44b31e4ee28330f/Src/freertos.cpp#L911 https://github.com/Met4FoF/Met4FoF-SmartUpUnit/blob/SSU_V3/Src/tim64extender.c From a hardware point of view we just wracked an UBlox-LEA-NEO7 Module onto the STM 32 with UART7 and the PPS output directly into TIM2 CH4 and had TIM2 counting up with 108 MHz at max clock rate. There we achieved <50 ns input capture time stamping uncertainty and 99.3% of the time stamped values where with in the calculated uncer from the GNSS-PPS timestamps and the MCUS clockspeed estimation since they are correlated (i time stamp GNSS with the MCU clock) we overestimate uncer in GUM conforme error estimation. If there is interest I can share more information about this :) The STM32F4 and newer cpus also support IEEE1588 compliant ptp time distribution, which als outputs pps pulse into TIM2/5 32 bit counters. I can link a paper for colleagues from RWTH AAchen this on interest that looks super promising. I have the equipment here to test ptp with STM32F767zi cpus but I also have an CS-beam-clock to repair :/ Best regards from Brunswick Bene Am Do., 8. Mai 2025 um 07:55 Uhr schrieb Jeff Geerling via time-nuts < time-nuts@lists.febo.com>: > I know much of the focus is on ESP devices but I've been looking into this > on the Raspberry Pi Pico side (RP2040 and RP2350), and there are a few > resources I've had bookmarked as I go down this road... > > C implementation: > https://github.com/raspberrypi/pico-examples/tree/master/pico_w/wifi/ntp_client > Micropython: > https://github.com/micropython/micropython-lib/blob/f6723531802661e5a1fd3d63d3b7b68c38f40cd2/micropython/net/ntptime/ntptime.py > > I haven't looked too much into a full RTC setup, but there was a good Pi > forum thread on this a couple years back: > https://forums.raspberrypi.com/viewtopic.php?t=337259 > > -Jeff Geerling > > > On May 7, 2025, at 3:22 PM, Thomas Abbott via time-nuts < > time-nuts@lists.febo.com> wrote: > > > > I have two (pendulum) clock monitoring devices, micropython, one ESP32 > and > > one Pico W. > > I use simple NTP to set the clock once on startup, and then measure the > > clock offset every 15 minutes (subtracting half the round-trip), which I > > store in the logs. > > It looks like this. > > [image: image.png] > > This could be considered accurate to 10 ms with careful processing. There > > are a few percent outliers. I think the network stack and wifi connection > > are a big limitation, for example, some sort of sleep means that pinging > > the Pico locally, is 2 ms when flooded, but 50 ms when pinging every 3 > > seconds. I also log the NTP round trip times, they vary from 10 ms to 80 > ms > > (I discard and retry if it's too long). It's hard to compensate for this, > > maybe it can be turned off. > > > > Thomas > > > > > > On Wed, 7 May 2025 at 12:32, Folkert van Heusden via time-nuts < > > time-nuts@lists.febo.com> wrote: > > > >> Hi, > >> > >> Does anyone know of a program for micro controllers like the ESP32 to > >> sync their clock like NTP does? (which then apparently does not show up > >> in my google searches) > >> > >> Most implementations just do an SNTP request and step the clock. > >> TheESP32 SDK has an NTP implementation which also slews the clock which > >> is cool, but sofar none I could find also disciplines the clock. > >> > >> I'm trying to reach 0.2 ms accuracy. > >> > >> -- > >> www.vanheusden.com [1] > >> > >> Links: > >> ------ > >> [1] http://www.vanheusden.com > >> _______________________________________________ > >> time-nuts mailing list -- time-nuts@lists.febo.com > >> To unsubscribe send an email to time-nuts-leave@lists.febo.com > >> > > <image.png>_______________________________________________ > > time-nuts mailing list -- time-nuts@lists.febo.com > > To unsubscribe send an email to time-nuts-leave@lists.febo.com > > _______________________________________________ > time-nuts mailing list -- time-nuts@lists.febo.com > To unsubscribe send an email to time-nuts-leave@lists.febo.com