mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
162 lines
10 KiB
ReStructuredText
162 lines
10 KiB
ReStructuredText
System Time
|
|
===========
|
|
:link_to_translation:`zh_CN:[中文]`
|
|
|
|
{IDF_TARGET_RTC_CLK_FRE:default="Not updated", esp32="150 kHz", esp32s2="90 kHz", esp32s3="136 kHz", esp32c3="136 kHz", esp32c2="136 kHz"}
|
|
{IDF_TARGET_INT_OSC_FRE:default="Not updated", esp32="8.5 MHz", esp32s2="8.5 MHz", esp32s3="17.5 MHz", esp32c3="17.5 MHz", esp32c2="17.5 MHz"}
|
|
{IDF_TARGET_INT_OSC_FRE_DIVIDED:default="Not updated", esp32="~33 kHz", esp32s2="~33 kHz", esp32s3="~68 kHz", esp32c3="~68 kHz", esp32c2="~68 kHz"}
|
|
{IDF_TARGET_EXT_CRYSTAL_PIN:default="Not updated", esp32="32K_XP and 32K_XN", esp32s2="XTAL_32K_P and XTAL_32K_N", esp32s3="XTAL_32K_P and XTAL_32K_N", esp32c3="XTAL_32K_P and XTAL_32K_N"}
|
|
{IDF_TARGET_EXT_OSC_PIN:default="Not updated", esp32="32K_XN", esp32s2="XTAL_32K_P", esp32s3="XTAL_32K_P", esp32c3="XTAL_32K_P", esp32c2="GPIO0"}
|
|
{IDF_TARGET_HARDWARE_DESIGN_URL:default="Not updated",esp32="`ESP32 Hardware Design Guidelines <https://www.espressif.com/sites/default/files/documentation/esp32_hardware_design_guidelines_en.pdf#page=11>`_", esp32s2="`ESP32-S2 Hardware Design Guidelines <https://www.espressif.com/sites/default/files/documentation/esp32-s2_hardware_design_guidelines_en.pdf#page=10>`_", esp32s3="`ESP32-S3 Hardware Design Guidelines <https://www.espressif.com/sites/default/files/documentation/esp32-s3_hardware_design_guidelines_en.pdf#page=11>`_", esp32c3="`ESP32-C3 Hardware Design Guidelines <https://www.espressif.com/sites/default/files/documentation/esp32-c3_hardware_design_guidelines_en.pdf#page=9>`_"}
|
|
|
|
|
|
Overview
|
|
--------
|
|
|
|
{IDF_TARGET_NAME} uses two hardware timers for the purpose of keeping system time. System time can be kept by using either one or both of the hardware timers depending on the application's purpose and accuracy requirements for system time. The two hardware timers are:
|
|
|
|
- **RTC timer**: This timer allows time keeping in various sleep modes, and can also persist time keeping across any resets (with the exception of power-on resets which reset the RTC timer). The frequency deviation depends on the `RTC Timer Clock Sources`_ and affects the accuracy only in sleep modes, in which case the time will be measured at 6.6667 μs resolution.
|
|
|
|
- **High-resolution timer**: This timer is not available in sleep modes and will not persist over a reset, but has greater accuracy. The timer uses the APB_CLK clock source (typically 80 MHz), which has a frequency deviation of less than ±10 ppm. Time will be measured at 1 μs resolution.
|
|
|
|
The possible combinations of hardware timers used to keep system time are listed below:
|
|
|
|
- RTC and high-resolution timer (default)
|
|
- RTC
|
|
- High-resolution timer
|
|
- None
|
|
|
|
It is recommended that users stick to the default option as it provides the highest accuracy. However, users can also select a different setting via the :ref:`CONFIG_NEWLIB_TIME_SYSCALL` configuration option.
|
|
|
|
|
|
RTC Timer Clock Sources
|
|
------------------------
|
|
|
|
The RTC timer has the following clock sources:
|
|
|
|
.. list::
|
|
|
|
- ``Internal {IDF_TARGET_RTC_CLK_FRE} RC oscillator`` (default): Features the lowest Deep-sleep current consumption and no dependence on any external components. However, the frequency stability of this clock source is affected by temperature fluctuations, so time may drift in both Deep-sleep and Light-sleep modes.
|
|
|
|
:not esp32c2: - ``External 32 kHz crystal``: Requires a 32 kHz crystal to be connected to the {IDF_TARGET_EXT_CRYSTAL_PIN} pins. This source provides a better frequency stability at the expense of a slightly higher (by 1 μA) Deep-sleep current consumption.
|
|
|
|
- ``External 32 kHz oscillator at {IDF_TARGET_EXT_OSC_PIN} pin``: Allows using 32 kHz clock generated by an external circuit. The external clock signal must be connected to the {IDF_TARGET_EXT_OSC_PIN} pin. The amplitude should be less than 1.2 V for sine wave signal and less than 1 V for square wave signal. Common mode voltage should be in the range of 0.1 < Vcm < 0.5xVamp, where Vamp stands for signal amplitude. In this case, the {IDF_TARGET_EXT_OSC_PIN} pin cannot be used as a GPIO pin.
|
|
|
|
- ``Internal {IDF_TARGET_INT_OSC_FRE} oscillator, divided by 256 ({IDF_TARGET_INT_OSC_FRE_DIVIDED})``: Provides better frequency stability than the ``Internal {IDF_TARGET_RTC_CLK_FRE} RC oscillator`` at the expense of a higher (by 5 μA) Deep-sleep current consumption. It also does not require external components.
|
|
|
|
The choice depends on your requirements for system time accuracy and power consumption in sleep modes. To modify the RTC clock source, set :ref:`CONFIG_RTC_CLK_SRC` in project configuration.
|
|
|
|
.. Need to add esp32c2 hardware design guideline link after it is publsihed.
|
|
|
|
.. only:: not esp32c2
|
|
|
|
More details about the wiring requirements for the external crystal or external oscillator, please refer to {IDF_TARGET_HARDWARE_DESIGN_URL}.
|
|
|
|
|
|
Get Current Time
|
|
----------------
|
|
|
|
To get the current time, use the POSIX function ``gettimeofday()``. Additionally, you can use the following standard C library functions to obtain time and manipulate it:
|
|
|
|
.. code-block:: bash
|
|
|
|
gettimeofday
|
|
time
|
|
asctime
|
|
clock
|
|
ctime
|
|
difftime
|
|
gmtime
|
|
localtime
|
|
mktime
|
|
strftime
|
|
adjtime*
|
|
|
|
To stop smooth time adjustment and update the current time immediately, use the POSIX function ``settimeofday()``.
|
|
|
|
If you need to obtain time with one second resolution, use the following code snippet:
|
|
|
|
.. code-block:: c
|
|
|
|
time_t now;
|
|
char strftime_buf[64];
|
|
struct tm timeinfo;
|
|
|
|
time(&now);
|
|
// Set timezone to China Standard Time
|
|
setenv("TZ", "CST-8", 1);
|
|
tzset();
|
|
|
|
localtime_r(&now, &timeinfo);
|
|
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
|
|
ESP_LOGI(TAG, "The current date/time in Shanghai is: %s", strftime_buf);
|
|
|
|
If you need to obtain time with one microsecond resolution, use the code snippet below:
|
|
|
|
.. code-block:: c
|
|
|
|
struct timeval tv_now;
|
|
gettimeofday(&tv_now, NULL);
|
|
int64_t time_us = (int64_t)tv_now.tv_sec * 1000000L + (int64_t)tv_now.tv_usec;
|
|
|
|
.. _system-time-sntp-sync:
|
|
|
|
SNTP Time Synchronization
|
|
-------------------------
|
|
|
|
To set the current time, you can use the POSIX functions ``settimeofday()`` and ``adjtime()``. They are used internally in the lwIP SNTP library to set current time when a response from the NTP server is received. These functions can also be used separately from the lwIP SNTP library.
|
|
|
|
The function to use inside the lwIP SNTP library depends on the sync mode for system time. Use the function :cpp:func:`sntp_set_sync_mode` to set one of the following sync modes:
|
|
|
|
- :cpp:enumerator:`SNTP_SYNC_MODE_IMMED` (default): Updates system time immediately upon receiving a response from the SNTP server after using ``settimeofday()``.
|
|
- :cpp:enumerator:`SNTP_SYNC_MODE_SMOOTH`: Updates time smoothly by gradually reducing time error using the function ``adjtime()``. If the difference between the SNTP response time and system time is more than 35 minutes, update system time immediately by using ``settimeofday()``.
|
|
|
|
The lwIP SNTP library has API functions for setting a callback function for a certain event. You might need the following functions:
|
|
|
|
- :cpp:func:`sntp_set_time_sync_notification_cb()`: Can be used to set a callback function that will notify of the time synchronization process.
|
|
- :cpp:func:`sntp_get_sync_status()` and :cpp:func:`sntp_set_sync_status()`: Can be used to get/set time synchronization status.
|
|
|
|
To start synchronization via SNTP, just call the following three functions:
|
|
|
|
.. code-block:: c
|
|
|
|
sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
|
sntp_setservername(0, "pool.ntp.org");
|
|
sntp_init();
|
|
|
|
An application with this initialization code will periodically synchronize the time. The time synchronization period is determined by :ref:`CONFIG_LWIP_SNTP_UPDATE_DELAY` (the default value is one hour). To modify the variable, set :ref:`CONFIG_LWIP_SNTP_UPDATE_DELAY` in project configuration.
|
|
|
|
A code example that demonstrates the implementation of time synchronization based on the lwIP SNTP library is provided in the :example:`protocols/sntp` directory.
|
|
|
|
|
|
Timezones
|
|
---------
|
|
|
|
To set the local timezone, use the following POSIX functions:
|
|
|
|
1. Call ``setenv()`` to set the ``TZ`` environment variable to the correct value based on the device location. The format of the time string is the same as described in the `GNU libc documentation <https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html>`_ (although the implementation is different).
|
|
2. Call ``tzset()`` to update C library runtime data for the new timezone.
|
|
|
|
Once these steps are completed, call the standard C library function ``localtime()``, and it will return the correct local time taking into account the timezone offset and daylight saving time.
|
|
|
|
|
|
64-bit ``time_t``
|
|
-----------------
|
|
|
|
ESP-IDF uses 32-bit ``time_t`` type by default. To address the Y2K38 issue, you may need to use 64-bit ``time_t`` type when building the application.
|
|
|
|
Currently, this requires building the cross-compiler toolchain from scratch. See the instructions for building the toolchain in :doc:`/get-started/linux-macos-setup`. To enable 64-bit ``time_t`` support in the toolchain, you need to remove the ``--enable-newlib-long-time_t`` option from the ``crosstool-NG/samples/xtensa-esp32-elf/crosstool.config`` file before building the toolchain.
|
|
|
|
If you need to make the program compatible with both 32-bit and 64-bit ``time_t``, you may use the following methods:
|
|
|
|
- In C or C++ source files, ``_USE_LONG_TIME_T`` preprocessor macro will be defined if 32-bit ``time_t`` is used. You need to include ``<sys/types.h>`` to make this macro available.
|
|
- In CMake files, ``TIME_T_SIZE`` IDF build property will be set to the size of ``time_t`` in bytes. You may call ``idf_build_get_property(var TIME_T_SIZE)`` to get the value of this property into a CMake variable ``var``. See :ref:`ESP-IDF CMake Build System API <cmake_buildsystem_api>` for more information about ``idf_build_get_property``.
|
|
|
|
Note that the size of ``time_t`` type also affects the sizes of other types, for example, ``struct timeval``, ``struct stat``, and ``struct utimbuf``.
|
|
|
|
|
|
API Reference
|
|
-------------
|
|
|
|
.. include-build-file:: inc/esp_sntp.inc
|