esp-idf/docs/en/api-reference/system/system_time.rst
Wang Zi Yan 72d9b9d94f
docs: remove outdated section on custom toolchain for 64-bit time_t
Co-authored-by: Ivan Grokhotkov <ivan@espressif.com>
2023-04-20 17:42:32 +02:00

166 lines
9.9 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-clock-source-choice:
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
esp_sntp_setoperatingmode(ESP_SNTP_OPMODE_POLL);
esp_sntp_setservername(0, "pool.ntp.org");
esp_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.
Year 2036 and 2038 Overflow Issues
----------------------------------
SNTP/NTP 2036 Overflow
^^^^^^^^^^^^^^^^^^^^^^
SNTP/NTP timestamps are represented as 64-bit unsigned fixed point numbers, where the first 32 bits represent the integer part, and the last 32 bits represent the fractional part. The 64-bit unsigned fixed point number represents the number of seconds since 00:00 on 1st of January 1900, thus SNTP/NTP times will overflow in the year 2036.
To address this issue, lifetime of the SNTP/NTP timestamps has been extended by convention by using the MSB (bit 0 by convention) of the integer part to indicate time ranges between years 1968 to 2104 (see `RFC2030 <https://www.rfc-editor.org/rfc/rfc2030>`_ for more details). This convention is implemented in lwIP library SNTP module. Therefore SNTP-related functions in ESP-IDF are future-proof until year 2104.
Unix Time 2038 Overflow
^^^^^^^^^^^^^^^^^^^^^^^
Unix time (type ``time_t``) was previously represented as a 32-bit signed integer, leading to an overflow in year 2038 (i.e., `Y2K38 issue <https://en.wikipedia.org/wiki/Year_2038_problem>`_). To address the Y2K38 issue, ESP-IDF uses a 64-bit signed integer to represent ``time_t`` starting from release v5.0, thus deferring ``time_t`` overflow for another 292 billion years.
API Reference
-------------
.. include-build-file:: inc/esp_sntp.inc