Getting precise NTP synchronized microsecond timestamps using ESP-IDF and ESP32
Date: August 5, 2023
Sensor values are pretty much worthless without absolute timestamps.
The great thing: it’s easy to get them using ESP-IDF and their NTP implementation.
#include <stdio.h>
#include <time.h>
#include "esp_log.h"
#include "esp_sntp.h"
#define TIMER_INTERVAL_MS (10 * 60 * 1000)
static const char *TAG = "NTP";
void initialize_sntp()
{
esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
esp_sntp_setservername(0, "pool.ntp.org");
esp_sntp_init();
}
void wait_for_sntp_sync()
{
ESP_LOGI(TAG, "Waiting for SNTP synchronization...");
time_t now = 0;
struct tm timeinfo = {0};
int retry = 0;
const int retry_count = 10;
while (timeinfo.tm_year < (2020 - 1900) && ++retry < retry_count) {
ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
vTaskDelay(2000 / portTICK_PERIOD_MS);
time(&now);
localtime_r(&now, &timeinfo);
}
if (timeinfo.tm_year < (2020 - 1900)) {
ESP_LOGW(TAG, "SNTP synchronization failed");
} else {
ESP_LOGI(TAG, "SNTP synchronized. Timestamp: %04d-%02d-%02d %02d:%02d:%02d",
timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
}
}
void update_time_task(void *pvParameters) {
while (1) {
// Wait for sync with ntp server
while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET) {
vTaskDelay(100 / portTICK_PERIOD_MS);
}
// Give it some time to settle
vTaskDelay(100 / portTICK_PERIOD_MS);
// Pull time out of RTC
struct timeval now;
gettimeofday(&now, NULL);
// Show refreshed time
ESP_LOGI(TAG, "Refreshed time: %s", ctime(&now.tv_sec));
// Wait for next NTP sync
vTaskDelay(TIMER_INTERVAL_MS / portTICK_PERIOD_MS);
}
}
The update_time_task is getting called every 30 minutes to fix any clock shifts.
From the application site you then can convert the time into microseconds.
(...)
struct timeval now;
gettimeofday(&now, NULL);
uint64_t timestamp = (uint64_t)now.tv_sec * 1000000ULL + (uint64_t)now.tv_usec;
(...)
To verify this implementation I configured a Bosch BMP390L pressure sensor to a sampling rate of 12.5Hz and added a timestamp immediately after pulling the value out of the registers.
Pa Timestamp
98838.4393593062 2023-08-02T07:39:55.874285Z
98838.7389599497 2023-08-02T07:39:55.954506Z
Calculating at the time off a full sampling cycle (0.954506s - 0.87428s) = 0.080226s this results into a frequeny of 1/0.080226s = 12.46 Hz.
Looks Good! :-)