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]
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]
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:
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]
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:
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]
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
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]
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]
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]
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
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]
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