docs(esp_timer): Rewrite esp_timer api ref and related docs

This commit is contained in:
kirill.chalov 2023-11-09 18:46:05 +08:00
parent d556fee5c4
commit 8154150188
6 changed files with 428 additions and 296 deletions

View File

@ -1,4 +1,4 @@
menu "High resolution timer (esp_timer)"
menu "ESP Timer (High Resolution Timer)"
config ESP_TIMER_PROFILING
bool "Enable esp_timer profiling features"
@ -38,8 +38,8 @@ menu "High resolution timer (esp_timer)"
range 1 3 if IDF_TARGET_ESP32
range 1 1 if !IDF_TARGET_ESP32
help
It sets the interrupt level for esp_timer ISR in range 1..3.
A higher level (3) helps to decrease the ISR esp_timer latency.
This sets the interrupt priority level for esp_timer ISR.
A higher value reduces interrupt latency by minimizing the timer processing delay.
config ESP_TIMER_SHOW_EXPERIMENTAL
bool "show esp_timer's experimental features"

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -27,7 +27,9 @@
* used for simple callback functions, which do not take longer than a few
* microseconds to run.
*
* Timer callbacks are called from a task running on the PRO CPU.
* Timer callbacks are called from a task running on CPU0.
* On chips with multiple cores, CPU0 (default) can be changed using
* the Kconfig option CONFIG_ESP_TIMER_TASK_AFFINITY.
*/
#include <stdint.h>
@ -42,7 +44,7 @@ extern "C" {
#endif
/**
* @brief Opaque type representing a single esp_timer
* @brief Opaque type representing a single timer handle
*/
typedef struct esp_timer* esp_timer_handle_t;
@ -53,25 +55,27 @@ typedef struct esp_timer* esp_timer_handle_t;
typedef void (*esp_timer_cb_t)(void* arg);
/**
* @brief Method for dispatching timer callback
* @brief Method to dispatch timer callback
*/
typedef enum {
ESP_TIMER_TASK, //!< Callback is called from timer task
#ifdef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
ESP_TIMER_ISR, //!< Callback is called from timer ISR
ESP_TIMER_TASK, //!< Callback is dispatched from esp_timer task
#if CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD || __DOXYGEN__
ESP_TIMER_ISR, //!< Callback is dispatched from interrupt handler
#endif
ESP_TIMER_MAX, //!< Count of the methods for dispatching timer callback
ESP_TIMER_MAX, //!< Sentinel value for the number of callback dispatch methods
} esp_timer_dispatch_t;
/**
* @brief Timer configuration passed to esp_timer_create
* @brief Timer configuration passed to esp_timer_create()
*/
typedef struct {
esp_timer_cb_t callback; //!< Function to call when timer expires
void* arg; //!< Argument to pass to the callback
esp_timer_dispatch_t dispatch_method; //!< Call the callback from task or from ISR
const char* name; //!< Timer name, used in esp_timer_dump function
bool skip_unhandled_events; //!< Skip unhandled events for periodic timers
esp_timer_cb_t callback; //!< Callback function to execute when timer expires
void* arg; //!< Argument to pass to callback
esp_timer_dispatch_t dispatch_method; //!< Dispatch callback from task or ISR; if not specified, esp_timer task
// !< is used; for ISR to work, also set Kconfig option
// !< `CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD`
const char* name; //!< Timer name, used in esp_timer_dump() function
bool skip_unhandled_events; //!< Setting to skip unhandled events in light sleep for periodic timers
} esp_timer_create_args_t;
/**
@ -81,7 +85,7 @@ typedef struct {
* to call this function before using other esp_timer APIs.
*
* This function can be called very early in startup process, after this call
* only esp_timer_get_time function can be used.
* only esp_timer_get_time() function can be used.
*
* @return
* - ESP_OK on success
@ -93,12 +97,12 @@ esp_err_t esp_timer_early_init(void);
*
* @note This function is called from startup code. Applications do not need
* to call this function before using other esp_timer APIs.
* Before calling this function, esp_timer_early_init must be called by the
* Before calling this function, esp_timer_early_init() must be called by the
* startup code.
*
* This function will be called from startup code on every core
* if CONFIG_ESP_TIMER_ISR_AFFINITY_NO_AFFINITY is enabled,
* It allocates the timer ISR on MULTIPLE cores and
* This function will be called from startup code on every core.
* If Kconfig option `CONFIG_ESP_TIMER_ISR_AFFINITY` is set to `NO_AFFINITY`,
* it allocates the timer ISR on MULTIPLE cores and
* creates the timer task which can be run on any core.
*
* @return
@ -123,12 +127,12 @@ esp_err_t esp_timer_deinit(void);
/**
* @brief Create an esp_timer instance
*
* @note When done using the timer, delete it with esp_timer_delete function.
* @note When timer no longer needed, delete it using esp_timer_delete().
*
* @param create_args Pointer to a structure with timer creation arguments.
* Not saved by the library, can be allocated on the stack.
* @param[out] out_handle Output, pointer to esp_timer_handle_t variable which
* will hold the created timer handle.
* @param[out] out_handle Output, pointer to esp_timer_handle_t variable that
* holds the created timer handle.
*
* @return
* - ESP_OK on success
@ -140,11 +144,11 @@ esp_err_t esp_timer_create(const esp_timer_create_args_t* create_args,
esp_timer_handle_t* out_handle);
/**
* @brief Start one-shot timer
* @brief Start a one-shot timer
*
* Timer should not be running when this function is called.
* Timer represented by `timer` should not be running when this function is called.
*
* @param timer timer handle created using esp_timer_create
* @param timer timer handle created using esp_timer_create()
* @param timeout_us timer timeout, in microseconds relative to the current moment
* @return
* - ESP_OK on success
@ -156,10 +160,10 @@ esp_err_t esp_timer_start_once(esp_timer_handle_t timer, uint64_t timeout_us);
/**
* @brief Start a periodic timer
*
* Timer should not be running when this function is called. This function will
* start the timer which will trigger every 'period' microseconds.
* Timer represented by `timer` should not be running when this function is called.
* This function starts the timer which will trigger every `period` microseconds.
*
* @param timer timer handle created using esp_timer_create
* @param timer timer handle created using esp_timer_create()
* @param period timer period, in microseconds
* @return
* - ESP_OK on success
@ -171,11 +175,13 @@ esp_err_t esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period);
/**
* @brief Restart a currently running timer
*
* If the given timer is a one-shot timer, the timer is restarted immediately and will timeout once in `timeout_us` microseconds.
* If the given timer is a periodic timer, the timer is restarted immediately with a new period of `timeout_us` microseconds.
* Type of `timer` | Action
* --------------- | ------
* One-shot timer | Restarted immediately and times out once in `timeout_us` microseconds
* Periodic timer | Restarted immediately with a new period of `timeout_us` microseconds
*
* @param timer timer Handle created using esp_timer_create
* @param timeout_us Timeout, in microseconds relative to the current time.
* @param timer timer handle created using esp_timer_create()
* @param timeout_us Timeout in microseconds relative to the current time.
* In case of a periodic timer, also represents the new period.
* @return
* - ESP_OK on success
@ -185,12 +191,12 @@ esp_err_t esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period);
esp_err_t esp_timer_restart(esp_timer_handle_t timer, uint64_t timeout_us);
/**
* @brief Stop the timer
* @brief Stop a running timer
*
* This function stops the timer previously started using esp_timer_start_once
* or esp_timer_start_periodic.
* This function stops the timer previously started using esp_timer_start_once()
* or esp_timer_start_periodic().
*
* @param timer timer handle created using esp_timer_create
* @param timer timer handle created using esp_timer_create()
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if the timer is not running
@ -203,7 +209,7 @@ esp_err_t esp_timer_stop(esp_timer_handle_t timer);
* The timer must be stopped before deleting. A one-shot timer which has expired
* does not need to be stopped.
*
* @param timer timer handle allocated using esp_timer_create
* @param timer timer handle created using esp_timer_create()
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if the timer is running
@ -212,21 +218,23 @@ esp_err_t esp_timer_delete(esp_timer_handle_t timer);
/**
* @brief Get time in microseconds since boot
* @return number of microseconds since underlying timer has been started
* @return Number of microseconds since the initialization of ESP Timer
*/
int64_t esp_timer_get_time(void);
/**
* @brief Get the timestamp when the next timeout is expected to occur
* @brief Get the timestamp of the next expected timeout
* @return Timestamp of the nearest timer event, in microseconds.
* The timebase is the same as for the values returned by esp_timer_get_time.
* The timebase is the same as for the values returned by esp_timer_get_time().
*/
int64_t esp_timer_get_next_alarm(void);
/**
* @brief Get the timestamp when the next timeout is expected to occur skipping those which have skip_unhandled_events flag
* @brief Get the timestamp of the next expected timeout excluding those timers
* that should not interrupt light sleep (such timers have
* ::esp_timer_create_args_t::skip_unhandled_events enabled)
* @return Timestamp of the nearest timer event, in microseconds.
* The timebase is the same as for the values returned by esp_timer_get_time.
* The timebase is the same as for the values returned by esp_timer_get_time().
*/
int64_t esp_timer_get_next_alarm_for_wake_up(void);
@ -234,11 +242,9 @@ int64_t esp_timer_get_next_alarm_for_wake_up(void);
* @brief Get the period of a timer
*
* This function fetches the timeout period of a timer.
* For a one-shot timer, the timeout period will be 0.
*
* @note The timeout period is the time interval with which a timer restarts after expiry. For one-shot timers, the
* period is 0 as there is no periodicity associated with such timers.
*
* @param timer timer handle allocated using esp_timer_create
* @param timer timer handle created using esp_timer_create()
* @param period memory to store the timer period value in microseconds
* @return
* - ESP_OK on success
@ -251,10 +257,9 @@ esp_err_t esp_timer_get_period(esp_timer_handle_t timer, uint64_t *period);
*
* This function fetches the expiry time of a one-shot timer.
*
* @note This API returns a valid expiry time only for a one-shot timer. It returns an error if the timer handle passed
* to the function is for a periodic timer.
* @note Passing the timer handle of a periodic timer will result in an error.
*
* @param timer timer handle allocated using esp_timer_create
* @param timer timer handle created using esp_timer_create()
* @param expiry memory to store the timeout value in microseconds
* @return
* - ESP_OK on success
@ -266,27 +271,28 @@ esp_err_t esp_timer_get_expiry_time(esp_timer_handle_t timer, uint64_t *expiry);
/**
* @brief Dump the list of timers to a stream
*
* If CONFIG_ESP_TIMER_PROFILING option is enabled, this prints the list of all
* the existing timers. Otherwise, only the list active timers is printed.
* By default, this function prints the list of active (running) timers. The output format is:
*
* The format is:
* | Name | Period | Alarm |
*
* name period alarm times_armed times_triggered total_callback_run_time
* - Name timer pointer
* - Period period of timer in microseconds, or 0 for one-shot timer
* - Alarm - time of the next alarm in microseconds since boot, or 0 if the timer is not started
*
* where:
* To print the list of all created timers, enable Kconfig option `CONFIG_ESP_TIMER_PROFILING`.
* In this case, the output format is:
*
* name timer name (if CONFIG_ESP_TIMER_PROFILING is defined), or timer pointer
* period period of timer, in microseconds, or 0 for one-shot timer
* alarm - time of the next alarm, in microseconds since boot, or 0 if the timer
* is not started
* | Name | Period | Alarm | Times_armed | Times_trigg | Times_skip | Cb_exec_time |
*
* The following fields are printed if CONFIG_ESP_TIMER_PROFILING is defined:
* - Name timer name
* - Period same as above
* - Alarm same as above
* - Times_armed number of times the timer was armed via esp_timer_start_X
* - Times_triggered - number of times the callback was triggered
* - Times_skipped - number of times the callback was skipped
* - Callback_exec_time - total time taken by callback to execute, across all calls
*
* times_armed number of times the timer was armed via esp_timer_start_X
* times_triggered - number of times the callback was called
* total_callback_run_time - total time taken by callback to execute, across all calls
*
* @param stream stream (such as stdout) to dump the information to
* @param stream stream (such as stdout) to which to dump the information
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if can not allocate temporary buffer for the output
@ -306,21 +312,21 @@ void esp_timer_isr_dispatch_need_yield(void);
/**
* @brief Returns status of a timer, active or not
*
* This function is used to identify if the timer is still active or not.
* This function is used to identify if the timer is still active (running) or not.
*
* @param timer timer handle created using esp_timer_create
* @param timer timer handle created using esp_timer_create()
* @return
* - 1 if timer is still active
* - 0 if timer is not active.
* - 1 if timer is still active (running)
* - 0 if timer is not active
*/
bool esp_timer_is_active(esp_timer_handle_t timer);
/**
* @brief Get the ETM event handle of esp_timer underlying alarm event
*
* @note The created ETM event object can be deleted later by calling `esp_etm_del_event`
* @note The created ETM event object can be deleted later using esp_etm_del_event()
*
* @note The ETM event is generated by the underlying hardware -- systimer,
* @note The ETM event is generated by the underlying hardware - systimer;
* therefore, if the esp_timer is not clocked by systimer, then no ETM event will be generated.
*
* @param[out] out_event Returned ETM event handle

View File

@ -1,4 +1,4 @@
High Resolution Timer (ESP Timer)
ESP Timer (High Resolution Timer)
=================================
:link_to_translation:`zh_CN:[中文]`
@ -7,106 +7,317 @@ High Resolution Timer (ESP Timer)
{IDF_TARGET_HR_TIMER_Resolution:default = "Not updated", esp32 = "64", esp32s2 = "64", esp32c3 = "52", esp32s3 = "52", esp32c2 = "52", esp32c6 = "52", esp32h2 = "52", esp32p4 = "52"}
.. only:: html
This document covers the ESP-IDF feature called ESP Timer. The contents are as follows:
.. contents::
:local:
:depth: 2
Overview
--------
Although FreeRTOS provides software timers, FreeRTOS software timers have a few limitations:
The ESP Timer feature allows for creating software timers and invoking their callback functions (dispatching callbacks) on timeout. ESP Timer is useful when user software needs to perform delayed or periodic actions, such as delayed device start/stop or periodic sampling of sensor data.
- Maximum resolution is equal to the RTOS tick period
- Timer callbacks are dispatched from a low-priority timer service (i.e., daemon) task. This task can be preempted by other tasks, leading to decreased precision and accuracy.
ESP Timer hides the complexity associated with managing multiple timers, dispatching callbacks, accounting for clock frequency changes (if dynamic frequency scaling is enabled), and maintaining correct time after light sleep.
Although hardware timers are not subject to the limitations mentioned, they may not be as user-friendly. For instance, application components may require timer events to be triggered at specific future times, but hardware timers typically have only one "compare" value for interrupt generation. This necessitates the creation of an additional system on top of the hardware timer to keep track of pending events and ensure that callbacks are executed when the corresponding hardware interrupts occur.
For application scenarios that require better real-time performance (such as generating waveforms) or configurable timer resolution, it is recommended that :doc:`GPTimer </api-reference/peripherals/gptimer>` be used instead. Also, GPTimer has features not available in ESP Timer, such as event capture.
.. only:: esp32
The hardware timer interrupt's priority is configured via the :ref:`CONFIG_ESP_TIMER_INTERRUPT_LEVEL` option (possible priorities being 1, 2, or 3). Raising the timer interrupt's priority can reduce the timer processing delay caused by interrupt latency.
Finally, FreeRTOS has its own software timers. As explained in :ref:`FreeRTOS Timers`, they have much lower resolution compared to ESP Timer, but FreeRTOS timers are portable (non-dependent on ESP-IDF) which might be an advantage in some cases.
``esp_timer`` set of APIs provides one-shot and periodic timers, microsecond time resolution, and {IDF_TARGET_HR_TIMER_Resolution}-bit range.
Features and Concepts
---------------------
Internally, ``esp_timer`` uses a {IDF_TARGET_HR_TIMER_Resolution}-bit hardware timer. The exact hardware timer implementation used depends on the target, where {IDF_TARGET_HR_TIMER} is used for {IDF_TARGET_NAME}.
The ESP Timer API provides:
Timer callbacks can be dispatched by two methods:
- One-shot and periodic timers
- Multiple callback dispatch methods
- Handling overdue callbacks
- Bit range: {IDF_TARGET_HR_TIMER_Resolution} bits
- Time resolution: 1 microsecond
- ``ESP_TIMER_TASK``.
- ``ESP_TIMER_ISR``. Available only if :ref:`CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD` is enabled (by default disabled).
``ESP_TIMER_TASK``. Timer callbacks are dispatched from a high-priority ``esp_timer`` task. Because all the callbacks are dispatched from the same task, it is recommended to only do the minimal possible amount of work from the callback itself, posting an event to a lower-priority task using a queue instead.
One-Shot and Periodic Timers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If other tasks with a priority higher than ``esp_timer`` are running, callback dispatching will be delayed until the ``esp_timer`` task has a chance to run. For example, this will happen if an SPI Flash operation is in progress.
A one-shot timer invokes its callback function only once upon expiration and then stops operation. One-shot timers are useful for single delayed actions, such as turning off a device or reading a sensor after a specified time interval.
``ESP_TIMER_ISR``. Timer callbacks are dispatched directly from the timer interrupt handler. This method is useful for some simple callbacks which aim for lower latency.
A periodic timer invokes its callback function upon expiration and restarts itself automatically, resulting in the callback function being invoked at a defined interval until the periodic timer is manually stopped. Periodic timers are useful for repeated actions, such as sampling sensor data, updating display information, or generating a waveform.
Creating and starting a timer, and dispatching the callback takes some time. Therefore, there is a lower limit to the timeout value of one-shot ``esp_timer``. If :cpp:func:`esp_timer_start_once` is called with a timeout value of less than 20 us, the callback will be dispatched only after approximately 20 us.
Periodic ``esp_timer`` also imposes a 50 us restriction on the minimal timer period. Periodic software timers with a period of less than 50 us are not practical since they would consume most of the CPU time. Consider using dedicated hardware peripherals or DMA features if you find that a timer with a small period is required.
.. _Callback Methods:
Using ``esp_timer`` APIs
------------------------
Callback Dispatch Methods
^^^^^^^^^^^^^^^^^^^^^^^^^
A single timer is represented by :cpp:type:`esp_timer_handle_t` type. Each timer has a callback function associated with it. This callback function is called from the ``esp_timer`` task each time the timer elapses.
Timer callbacks can be dispatched using the following methods:
- To create a timer, call :cpp:func:`esp_timer_create`.
- To delete the timer when it is no longer needed, call :cpp:func:`esp_timer_delete`.
- Task Dispatch method (default):
The timer can be started in one-shot mode or in periodic mode.
- Dispatches timer callbacks from a single high-priority ESP Timer task (esp_timer task (notified by ISR) > callback)
- Suitable for handling timer callbacks that are not time-critical
- To start the timer in one-shot mode, call :cpp:func:`esp_timer_start_once`, passing the time interval after which the callback should be called. When the callback gets called, the timer is considered to be stopped.
- Interrupt Dispatch method (:cpp:enumerator:`ESP_TIMER_ISR <esp_timer_dispatch_t::ESP_TIMER_ISR>`):
- To start the timer in periodic mode, call :cpp:func:`esp_timer_start_periodic`, passing the period with which the callback should be called. The timer keeps running until :cpp:func:`esp_timer_stop` is called.
- Dispatches timer callbacks directly from an interrupt handler (ISR > callback)
- Suitable for simple, low-latency timer callbacks which take a few microseconds to run
- Ensures shorter delay between the event and the callback execution
- Not affected by other active tasks
Note that the timer must not be running when :cpp:func:`esp_timer_start_once` or :cpp:func:`esp_timer_start_periodic` is called. To restart a running timer, call :cpp:func:`esp_timer_stop` first, then call one of the start functions.
Callback Functions
Task Dispatch Specifics
~~~~~~~~~~~~~~~~~~~~~~~
The execution of callbacks in the ESP Timer task is serialized. Thus, when multiple timeouts occur simultaneously, the execution time of one callback will delay the execution of subsequent callbacks. For this reason, it is recommended to keep the callbacks short. If the callback needs to perform more work, the work should be deferred to a lower-priority task using FreeRTOS primitives, such as queues and semaphores.
If other FreeRTOS tasks with higher priority are running, such as an SPI Flash operation, callback dispatching will be delayed until the ESP Timer task has a chance to run.
To maintain predictable and timely execution of tasks, callbacks should never attempt block (waiting for resources) or yield (give up control) operations, because such operations disrupt the serialized execution of callbacks.
Interrupt Dispatch Specifics
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Timers using the Interrupt Dispatch method have their callbacks executed from an interrupt handler. As interrupts can preempt all tasks, the Interrupt Dispatch method offers lower latency. Interrupt dispatched timer callbacks should never attempt to block and should not attempt to trigger a context switch via ``portYIELD_FROM_ISR()``. Instead, the function :cpp:func:`esp_timer_isr_dispatch_need_yield` should be used. The context switch will happen after all ISR dispatch timers are processed.
While using interrupt dispatched timers, the standard logging or debugging methods, such as ``printf`` should be avoided. To debug an application or display certain information in the console, the ESP-IDF logging macros should be used, such as :c:macro:`ESP_DRAM_LOGI`, :c:macro:`ESP_EARLY_LOGI`, etc. These macros are specifically designed to work in various contexts, including interrupt service routines.
Obtaining Current Time
^^^^^^^^^^^^^^^^^^^^^^
The time passed since the initialization of ESP Timer can be obtained using the convenience function :cpp:func:`esp_timer_get_time`. The initialization happens shortly before the ``app_main`` function is called. This function is fast and has no locking mechanisms that could potentially introduce delays or conflicts. As a result, it can be useful for fine-grained timing, with the accuracy of 1 us, in tasks as well as in ISR routines.
Unlike the ``gettimeofday()`` function, :cpp:func:`esp_timer_get_time` has the following specifics:
- Upon wakeup from deep sleep, the initialization timer restarts from zero
- The returned value has no timezone settings or daylight saving time adjustments
System Integration
------------------
.. note:: Keep the callback functions as short as possible. Otherwise, it will affect all timers.
This section mainly covers some aspects of how to optimize the operation of ESP Timer and integrate it with other ESP-IDF features.
Timeout Value Limits
^^^^^^^^^^^^^^^^^^^^
As callback dispatching can never be instantaneous, the one-shot and periodic timers created with ESP Timer also have timeout value limits. These limits cannot be estimated precisely, because they depend on multiple factors.
For reference, the ESP32 running at 240 MHz and using the Task Dispatch method has the approximate minimum timeout values as follows:
* One-shot timers: ~20 us
* If :cpp:func:`esp_timer_start_once` is called, this is the earliest time after which the system will be able to dispatch a callback.
* Periodic timers: ~50 us
* Periodic software timers with a smaller timeout value would simply consume most of the CPU time, which is impractical.
The lower the CPU frequency, the higher the minimum timeout values will be. The general guideline is if the required timeout values are in the order of tens of microseconds, the user application needs to undergo thorough testing to ensure stable operation.
If the minimum timeout values slightly exceed the requirements, the Interrupt Dispatch method might offer an improvement.
.. only:: not SOC_PARLIO_SUPPORTED and SOC_RMT_SUPPORTED
For even smaller timeout values, for example, to generate or receive waveforms or do bit banging, the resolution of ESP Timer may be insufficient. In this case, it is recommended to use dedicated peripherals, such as :doc:`GPTimer </api-reference/peripherals/gptimer>` or :doc:`RMT </api-reference/peripherals/rmt>`, and their DMA features if available.
.. only:: SOC_PARLIO_SUPPORTED
For even smaller timeout values, for example, to generate or receive waveforms or do bit banging, the resolution of ESP Timer may be insufficient. In this case, it is recommended to use dedicated peripherals, such as :doc:`Parallel IO </api-reference/peripherals/parlio>`, and their DMA features if available.
Sleep Mode Considerations
^^^^^^^^^^^^^^^^^^^^^^^^^
If a timer is started, and there are no other tasks being executed during the wait time, the chip can be put into sleep to optimize power consumption.
Sleep can be induced in the following ways:
* **Automatic sleep** provided by :doc:`Power Management APIs <power_management>`: If no tasks are being executed, the chip can automatically enter light sleep and automatically wake up at the appropriate time for ESP Timer to dispatch a pending callback.
* **Manual sleep** provided by :doc:`Sleep Mode APIs <sleep_modes>`: The chip can be put into sleep regardless of whether other tasks are being executed.
For manually induced sleep, the following sleep modes exist:
* Deep-sleep mode: ESP Timer is deactivated
The user application restarts from scratch upon wakeup from deep sleep. This makes deep sleep unsuitable for continuous ESP Timer operation. However, deep sleep can be used if the running timers are not expected to persist across wakeups.
* Light-sleep mode: ESP Timer is suspended
While in light sleep, ESP Timer counter and callbacks are suspended. Timekeeping is done by the RTC timer. Once the chip is woken up, the counter of ESP Timer is automatically advanced by the amount of time spent in sleep, then timekeeping and callback execution is resumed.
At this point, ESP Timer will attempt to dispatch all unhandled callbacks if there are any. It can potentially lead to the overflow of ESP Timer callback execution queue. This behavior may be undesirable for certain applications, and the ways to avoid it are covered in :ref:`Handling Callbacks in Light Sleep`.
.. _FreeRTOS Timers:
FreeRTOS Timers
^^^^^^^^^^^^^^^
Although FreeRTOS provides `software timers <https://www.freertos.org/RTOS-software-timer.html>`_, they have limitations:
- FreeRTOS timer resolution is bound by the `tick frequency <https://www.freertos.org/a00110.html#configTICK_RATE_HZ>`_, which is typically in the range of 100 to 1000 Hz.
- Timer callbacks are dispatched from a low-priority timer task that can be preempted by other tasks, leading to decreased timer precision and accuracy.
However, FreeRTOS timers are portable (non-dependent on ESP-IDF) and are written to be deterministic as they do not dispatch callbacks from ISRs.
Timer callbacks that are processed by the ``ESP_TIMER_ISR`` method should not call the context switch call - ``portYIELD_FROM_ISR()``. Instead, use the :cpp:func:`esp_timer_isr_dispatch_need_yield` function. The context switch will be done after all ISR dispatch timers have been processed if required by the system.
.. only:: SOC_ETM_SUPPORTED and SOC_SYSTIMER_SUPPORT_ETM
ETM Event
---------
ETM Events
^^^^^^^^^^
The ``esp_timer`` is constructed based on a hardware timer called **systimer**, which is able to generate the alarm event and interact with the :doc:`ETM </api-reference/peripherals/etm>` module. You can call :cpp:func:`esp_timer_new_etm_alarm_event` to get the corresponding ETM event handle.
ESP Timer has connection to the :doc:`Event Task Matrix </api-reference/peripherals/etm>` (ETM) module. This module allows notifying a number of peripherals about events without involving CPU interrupts. Direct notifications reduce latency and decrease CPU workload. The function :cpp:func:`esp_timer_new_etm_alarm_event` can be called to get the corresponding ETM event handle.
To know more about how to connect the event to an ETM channel, please refer to the :doc:`ETM </api-reference/peripherals/etm>` documentation.
``esp_timer`` During Light-sleep
--------------------------------
Usage
-----
During Light-sleep, the ``esp_timer`` counter stops and no callback functions are called. Instead, the time is counted by the RTC counter. Upon waking up, the system gets the difference between the counters and calls a function that advances the ``esp_timer`` counter. Since the counter has been advanced, the system starts calling callbacks that were not called during sleep. The number of callbacks depends on the duration of the sleep and the period of the timers. It can lead to the overflow of some queues. This only applies to periodic timers, since one-shot timers are only called once.
While setting up your ESP-IDF project, make sure to:
This behavior can be changed by calling :cpp:func:`esp_timer_stop` before sleeping. In some cases, this can be inconvenient, and instead of the stop function, you can use the ``skip_unhandled_events`` option during :cpp:func:`esp_timer_create`. When the ``skip_unhandled_events`` is true, if a periodic timer expires one or more times during Light-sleep, then only one callback is called on wake.
- Add required component dependencies to your ``CMakeLists.txt``.
- Include required header files in your ``.c`` files.
- (Optional) Set Kconfig options. For this, see :ref:`Kconfig Options <component-config-esp-timer-high-resolution-timer->` > *ESP Timer (High Resolution Timer)*
Using the ``skip_unhandled_events`` option with automatic Light-sleep (see :doc:`Power Management APIs <power_management>`) helps to reduce the power consumption of the system when it is in Light-sleep. The duration of Light-sleep is also in part determined by the next event occurs. Timers with ``skip_unhandled_events`` option does not wake up the system.
Handling Callbacks
------------------
.. _General Procedure:
``esp_timer`` is designed to achieve a high-resolution and low-latency timer with the ability to handle delayed events. If the timer is late, then the callback will be called as soon as possible, and it will not be lost. In the worst case, when the timer has not been processed for more than one period (for periodic timers), the callbacks will be called one after the other without waiting for the set period. This can be bad for some applications, and the ``skip_unhandled_events`` option is introduced to eliminate this behavior. If ``skip_unhandled_events`` is set, then a periodic timer that has expired multiple times without being able to call the callback will still result in only one callback event once processing is possible.
General Procedure
^^^^^^^^^^^^^^^^^
Obtaining Current Time
----------------------
The general procedure to create, start, stop, and delete a timer is as follows:
``esp_timer`` also provides a convenience function to obtain the time passed since start-up, with microsecond precision: :cpp:func:`esp_timer_get_time`. This function returns the number of microseconds since ``esp_timer`` was initialized, which usually happens shortly before ``app_main`` function is called.
1. Create a timer
Unlike ``gettimeofday`` function, values returned by :cpp:func:`esp_timer_get_time`:
- Define a timer handle using the type :cpp:type:`esp_timer_handle_t`
- Set the timer configuration parameters by defining the structure :cpp:struct:`esp_timer_create_args_t` which also includes the callback function
- Start from zero after the chip wakes up from Deep-sleep
- Do not have timezone or DST adjustments applied
.. note::
Application Example
-------------------
It is recommended to keep callbacks as short as possible to avoid delaying other callbacks.
The following example illustrates the usage of ``esp_timer`` APIs: :example:`system/esp_timer`.
- To create a timer, call the function :cpp:func:`esp_timer_create`
2. Start the timer in one-shot mode or periodic mode depending on your requirements
- To start the timer in one-shot mode, call :cpp:func:`esp_timer_start_once`
- To start the timer in periodic mode, call :cpp:func:`esp_timer_start_periodic`; the timer will continue running until you explicitly stop it using :cpp:func:`esp_timer_stop`
.. note:: When executing a start function, ensure that the timer is not running. If a timer is running, either call :cpp:func:`esp_timer_restart` or stop it first using :cpp:func:`esp_timer_stop` and then call one of the start functions.
3. Stop the timer
- To stop the running timer, call the function :cpp:func:`esp_timer_stop`
4. Delete the timer
- When the timer is no longer needed, delete it to free up memory using the function :cpp:func:`esp_timer_delete`
.. _Using ESP_TIMER_ISR Callback Method:
Using the Interrupt Dispatch Method
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Out of the available :ref:`callback methods <Callback Methods>`, if you choose the Interrupt Dispatch method, follow these steps:
1. Set Kconfig options
- Enable :ref:`CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD`
2. Create a timer
- Set the timer configuration parameters by defining the structure :cpp:struct:`esp_timer_create_args_t`
.. code-block:: c
const esp_timer_create_args_t timer = {
... ,
.dispatch_method = ESP_TIMER_ISR,
...
};
- To create a timer, call the function :cpp:func:`esp_timer_create`
For further steps, refer to :ref:`General Procedure`.
.. _Handling Callbacks in Light Sleep:
Handling Callbacks in Light-sleep Mode
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Light sleep allows you to save power while maintaining the ability to quickly wake up for specific actions. To use ESP Timer in conjunction with Light-sleep mode, see :doc:`Sleep Mode APIs <sleep_modes>`.
During light sleep, to keep unhandled callbacks under control and avoid potential overflow of ESP Timer callback execution queue on wakeup, do one of the following:
- Prevent the invocation of callbacks in the first place: stop the timer before entering light sleep by using :cpp:func:`esp_timer_stop`.
- If calling the stop function is not desirable for any reason, use the option :cpp:member:`esp_timer_create_args_t::skip_unhandled_events`. In this case, if a periodic timer expires one or more times during light sleep, then only one callback is executed on wakeup.
Debugging Timers
^^^^^^^^^^^^^^^^
The function :cpp:func:`esp_timer_dump` allows dumping information about either all or only running timers: the parameters for timers, the number of times the timers were started, triggered, skipped, and time taken by timer callbacks to execute. This information can be helpful in debugging.
To debug timers, use the following procedure:
1. Set Kconfig options for more detailed output:
- Enable :ref:`CONFIG_ESP_TIMER_PROFILING`
Note that enabling this option increases code size and heap memory usage.
2. Wherever required in your code, call the function :cpp:func:`esp_timer_dump` to print the information and use it to debug your timers.
3. Once debugging is complete, consider disabling :ref:`CONFIG_ESP_TIMER_PROFILING`.
Troubleshooting
---------------
Unstable Callback Dispatch Time
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
While dispatching the same callback function repeatedly, if the response time varies considerably, try to stabilize it by doing the following:
.. list::
- Use the :ref:`ESP_TIMER_ISR callback method <Using ESP_TIMER_ISR Callback Method>`
:SOC_HP_CPU_HAS_MULTIPLE_CORES: - Use the Kconfig option :ref:`CONFIG_ESP_TIMER_TASK_AFFINITY` to run the ESP Timer task on both cores
Significant Delays Dispatching Callbacks
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If dispatching a callback function takes a considerable amount of time, the problem can lie in the callback function itself. More precisely, as all callback functions are processed one by one in a single esp_timer task, the delays might be caused by other callback functions earlier in the queue.
For this reason, make sure that all callback functions in your application can execute on their own quickly and without any blocking operations.
Repeated Callback Dispatches After Sleep
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If the callback functions are executed repeatedly upon wakeup from sleep, see :ref:`Handling Callbacks in Light Sleep`.
Stack Overflow While Dispatching Callbacks
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you see a stack overflow error when executing a callback function, consider reducing the stack usage within your callback function. Alternatively, try increasing the size of the ESP Timer task stack by adjusting :ref:`CONFIG_ESP_TIMER_TASK_STACK_SIZE`.
Application Examples
--------------------
* :example:`system/esp_timer` creates and starts one-shot and periodic software timers, shows how they work with Light-sleep mode, and then stops and deletes the timers
API Reference
-------------
.. include-build-file:: inc/esp_timer.inc

View File

@ -1,4 +1,4 @@
高分辨率定时器(ESP 定时器
ESP 定时器
=================================
:link_to_translation:`en:[English]`
@ -8,100 +8,7 @@
{IDF_TARGET_HR_TIMER_Resolution:default = "Not updated", esp32 = "64", esp32s2 = "64", esp32c3 = "52", esp32s3 = "52", esp32c2 = "52", esp32c6 = "52", esp32h2 = "52"}
概述
--------
尽管 FreeRTOS 提供软件定时器,但 FreeRTOS 软件定时器存在一定局限性:
- 最大分辨率等于 RTOS 滴答周期
- 定时器回调函数从低优先级的定时器服务(即守护进程)任务中分发。该任务可能会被其他任务抢占,导致精度和准确性下降。
硬件定时器虽不受上述限制但使用不便。例如应用组件可能需要在特定的未来时间触发计时器事件但硬件定时器通常只有一个“compare比较”值用于中断生成。为提升使用的便利性应在硬件定时器的基础上构建某种机制来管理待处理事件列表确保在相应的硬件中断发生时调度回调。
.. only:: esp32
配置 :ref:`CONFIG_ESP_TIMER_INTERRUPT_LEVEL` 选项,设置硬件定时器中断的优先级(可设置为 1、2 或 3 级),提高定时器中断的优先级可以减少由中断延迟引起的定时器处理延迟。
``esp_timer`` API 集支持单次定时器和周期定时器、微秒级的时间分辨率、以及 {IDF_TARGET_HR_TIMER_Resolution} 位范围。
``esp_timer`` 内部使用 {IDF_TARGET_HR_TIMER_Resolution} 位硬件定时器,具体硬件实现取决于芯片型号,如 {IDF_TARGET_NAME} 使用的是 {IDF_TARGET_HR_TIMER}。
定时器回调可通过以下两种方式调度:
- ``ESP_TIMER_TASK``
- ``ESP_TIMER_ISR``。仅当 :ref:`CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD` 被启用时可用(默认为禁用)。
使用 ``ESP_TIMER_TASK`` 这一途径时,定时器回调函数是从高优先级的 ``esp_timer`` 任务中调度的。由于所有回调函数都是从同一个任务中调度,因此建议在回调函数本身中仅执行最小化的工作,如使用队列向低优先级任务发布事件。
如果有优先级高于 ``esp_timer`` 的其他任务正在运行,则回调调度将延迟,直至 ``esp_timer`` 能够运行。例如,执行 SPI flash 操作时便会发生此类情况。
使用 ``ESP_TIMER_ISR`` 这一途径时,定时器回调由定时器中断处理程序直接调度。对旨在降低延迟的简单回调,建议使用此途径。
创建、启动定时器并调度回调需要一些时间。因此,单次 ``esp_timer`` 的超时值存在最小限制。若调用 :cpp:func:`esp_timer_start_once` 时设置的超时值小于 20 us回调函数仍会在大约 20 微秒后被调度。
周期 ``esp_timer`` 将最小周期限制为 50 us。周期小于 50 us 的软件定时器会占用大部分 CPU 时间,因此它们并不实用。如需使用小周期定时器,请考虑使用专用硬件外设或 DMA 功能。
使用 ``esp_timer`` API
------------------------
单个定时器由 :cpp:type:`esp_timer_handle_t` 类型表示。每个定时器都有与之关联的回调函数,定时器超时时便会从 ``esp_timer`` 任务中调用此函数。
- 要创建定时器,请调用函数 :cpp:func:`esp_timer_create`
- 要删除定时器,请调用函数 :cpp:func:`esp_timer_delete`
定时器可以以单次模式和周期模式启动。
- 要以单次模式启动定时器,请调用函数 :cpp:func:`esp_timer_start_once`,传递应在多久后调用回调的时间间隔。调用回调时,定时器被视为停止工作。
- 要以周期模式启动定时器,请调用函数 :cpp:func:`esp_timer_start_periodic`,传递应调用回调的周期。计时器持续运行,直到调用函数 :cpp:func:`esp_timer_stop`
注意,当调用函数 :cpp:func:`esp_timer_start_once`:cpp:func:`esp_timer_start_periodic` 时,应确保定时器处于非运行状态。因此,要重启运行中的定时器,需首先调用函数 :cpp:func:`esp_timer_stop` 停止定时器,然后调用 :cpp:func:`esp_timer_start_once`:cpp:func:`esp_timer_start_periodic` 来启动定时器。
回调函数
------------------
.. note:: 回调函数应尽可能简略,避免影响所有定时器。
若定时器回调由 ``ESP_TIMER_ISR`` 方式处理,则该回调不应调用切换上下文的 ``portYIELD_FROM_ISR()``,而应调用函数 :cpp:func:`esp_timer_isr_dispatch_need_yield`。如果系统有此需求,上下文切换将在所有 ISR 调度定时器处理完毕后进行。
.. only:: SOC_ETM_SUPPORTED and SOC_SYSTIMER_SUPPORT_ETM
ETM 事件
---------
``esp_timer`` 的构建基于 **systimer** 硬件定时器,能够产生报警事件并与 :doc:`ETM </api-reference/peripherals/etm>` 模块交互。调用函数 :cpp:func:`esp_timer_new_etm_alarm_event` 以获取相应的 ETM 事件句柄。
如需了解如何将 ETM 事件连接到相应 ETM 通道,请参阅 :doc:`ETM </api-reference/peripherals/etm>`
Light-sleep 模式下的 ``esp_timer``
-----------------------------------
在 Light-sleep 期间, ``esp_timer`` 计数器停止工作,并且不调用回调函数,而是由 RTC 计数器负责计算时间。唤醒后,系统得到两个计数器间的差值,并调用函数推进 ``esp_timer`` 计数器计数。计数器计数被推进后,系统开始调用 Light-sleep 期间未被调用的回调。回调数量取决于 Light-sleep 模式持续时长和定时器周期,这可能会导致某些队列溢出。以上情况仅适用于周期性定时器,单次定时器只会被调用一次。
通过在 Light-sleep 模式前调用函数 :cpp:func:`esp_timer_stop` 可以改变上述行为。但在某些情况下这可能并不方便。比起使用停止函数,在 :cpp:func:`esp_timer_create` 中使用 ``skip_unhandled_events`` 选项将更加便利。 当 ``skip_unhandled_events`` 为真时,如果一个周期性定时器在 Light-sleep 期间超时一次或多次,那么在唤醒时只有一个回调会被调用。
使用带有自动 Light-sleep 的 ``skip_unhandled_events`` 选项(请参阅 :doc:`电源管理 <power_management>`),有助于在系统处于 Light-sleep 状态时降低功耗。Light-sleep 的持续时间也在一定程度上由下一个事件发生的时间确定。具有 ``skip_unhandled_events``` 选项的定时器不会唤醒系统。
处理回调
------------------
设计 ``esp_timer`` 是为了使定时器实现高分辨率和低延迟,并具备处理延迟事件的能力。如果定时器延迟,回调将被尽快调用,不会丢失。在最糟的情况下,周期性定时器可能超过一个周期还没有被处理,此时回调将被陆续调用,而不会等待设定的周期。这会给某些应用带来负面影响,为避免此类情况发生,特引入 ``skip_unhandled_events`` 选项。设置该选项后,即使一个周期性定时器多次超时且无法调用回调,该定时器在恢复处理能力后,仍将只产生一个回调事件。
获取当前时间
----------------------
``esp_timer`` 还提供了一个便捷函数 :cpp:func:`esp_timer_get_time` 以获取自启动以来经过的时间,可精确到微秒。这个函数通常会在 ``app_main`` 函数即将被调用前,返回自 ``esp_timer`` 启动以来的微秒数。
不同于 ``gettimeofday`` 函数,:cpp:func:`esp_timer_get_time` 返回的值:
- 芯片从 Deep-sleep 中唤醒后,从零开始
- 没有应用时区或 DST 调整
应用示例
-------------------
``esp_timer`` API 的详细用法可参阅 :example:`system/esp_timer`
API 参考

View File

@ -1,50 +1,82 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
# High Resolution Timer Example (`esp_timer`)
# ESP Timer Example (High Resolution Timer)
(See the README.md file in the upper level 'examples' directory for more information about examples.)
The [High Resolution Timer (`esp_timer`)](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/esp_timer.html) APIs allow an application to create multiple timers using a single hardware timer, and hides complexity associated with managing multiple timers, invoking callbacks, accounting for APB frequency changes (if dynamic frequency scaling is enabled), and maintaining correct time after light sleep.
This example shows how to use the ESP Timer feature. For detailed information on the functions and procedures used in this example, see [ESP Timer API Reference](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/esp_timer.html).
This example illustrates the usage of the [`esp_timer` API](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/esp_timer.html#api-reference) to create one-shot and periodic software timers.
> **Note**: By default, all links to [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/index.html) refer to the documentation for the ESP32. After clicking such a link, please remember to select your Espressif chip in the dropdown menu in the top-left corner.
The `esp_timer` API also provides the `esp_timer_get_time()` function which returns the time since boot in microseconds. This can be useful for fine-grained timing in tasks and ISRs thus is also demonstrated in this example.
## How to use example
## Overview
### Hardware Required
The ESP Timer facilitates creation and handling of timers that invoke callback functions (dispatch callbacks) on timeout. ESP Timer is mainly used to perform delayed or periodic actions, such as delayed device start/stop or periodic sampling of sensor data.
This example should be able to run on any commonly available ESP development board.
ESP Timer hides the complexity associated with managing multiple timers, dispatching callbacks, accounting for clock frequency changes (if dynamic frequency scaling is enabled), and maintaining correct time after light sleep.
### Configure the project
## Usage
The subsections below give only absolutely necessary information. For full steps to configure ESP-IDF and use it to build and run projects, see [ESP-IDF Getting Started](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html#get-started).
### Required Hardware
* An Espressif development board
* USB A/micro USB B cable for power supply and serial communication
* Computer running Windows, Linux, or macOS
### Set Chip Target
In your example project directory, [set the chip target](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/tools/idf-py.html#select-the-target-chip-set-target):
```
idf.py set-target <target>
```
For example, to set esp32 as the chip target, run
```
idf.py set-target esp32
```
### Review Kconfig Options
This project has some Kconfig options set as default for this particular example in [sdkconfig.defaults](./sdkconfig.defaults). For more information about those and other Kconfig options, see [Project Configuration](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/kconfig.html).
To conveniently check or modify Kconfig options for this example, run:
```
idf.py menuconfig
```
Under `Component config > Common ESP-related` are the following `esp_timer` related configurations
* `High-resolution timer task stack size` can be increased if timer callbacks require a larger stack
* `Enable esp_timer profiling features` will cause `esp_timer_dump()` to include more information.
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
Build the project, flash it to your development board, then run the monitor tool to view serial output:
```
idf.py -p PORT flash monitor
idf.py build flash monitor
```
(Replace PORT with the name of the serial port to use.)
If the above command fails, try specifying your board's serial port name explicitly:
(To exit the serial monitor, type ``Ctrl-]``.)
```
# Replace PORT with your board's serial port name
idf.py -p PORT build flash monitor
```
### Exit the Serial Monitor
To exit the serial monitor, use `Ctrl` + `]`.
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
The example should have the following log output:
If you see the following output log, your example should be running correctly:
```
...
@ -81,79 +113,54 @@ I (10314) example: Woke up from light sleep, time since boot: 10525143 us
...
```
## Example Breakdown
### 1. Creating and starting timers
The subsections below walk you through the important parts of the application example.
The example starts by creating a periodic and a one shot timer using the `esp_timer_create()` function. Once created, the two timers are started using the `esp_timer_start_periodic()` and `esp_timer_start_once()` functions.
### Creating Callback Functions
```
I (265) example: Starting timers, time since boot: 2479 us
```
Timers are used to execute a callback function as a delayed action. So the callback functions `periodic_timer_callback()` and `oneshot_timer_callback()` are the most important parts of this application example. They are defined for the periodic and one-shot timers respectively.
### 2. Getting initial timer dump
These two repeating lines are the output of `esp_timer_dump()` function. There is one line for each of the timers created. This function can be useful for debugging purposes. Note that such debugging information is available because the example sets `CONFIG_ESP_TIMER_PROFILING` option in sdkconfig. Without this option, less information will be available. See documentation of `esp_timer_dump()` in ESP-IDF programming guide for more details.
### Setting Timer Configuration Parameters
```
timer period next time times times times callback
name to fire started fired skipped run time (us)
-------------------------------------------------------------------------------------------------
The struct `esp_timer_create_args_t` is used to initialize a timer. Its parameters are described in *ESP Timer API Reference* > [esp_timer_create_args_t](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/esp_timer.html#esp_timer_create_args_t).
periodic 500000 502455 1 0 0 0
one-shot 0 5002469 1 0 0 0
```
The defined struct instance is then used in the function `esp_timer_create()`.
### 3. Periodic timer keeps running at 500ms period:
```
I (765) example: Periodic timer called, time since boot: 502506 us
I (1265) example: Periodic timer called, time since boot: 1002478 us
I (1765) example: Periodic timer called, time since boot: 1502478 us
I (2265) example: Periodic timer called, time since boot: 2002478 us
periodic 500000 2502455 1 4 0 511
one-shot 0 5002469 1 0 0 0
I (2765) example: Periodic timer called, time since boot: 2502478 us
I (3265) example: Periodic timer called, time since boot: 3002478 us
I (3765) example: Periodic timer called, time since boot: 3502478 us
I (4265) example: Periodic timer called, time since boot: 4002478 us
periodic 500000 4502455 1 8 0 971
one-shot 0 5002469 1 0 0 0
I (4765) example: Periodic timer called, time since boot: 4502478 us
I (5265) example: Periodic timer called, time since boot: 5002476 us
```
### Creating and Starting Timers
### 4. One-shot timer runs
To run a timer, it needs to be created first using the function `esp_timer_create()` and then started using either `esp_timer_start_periodic()` or `esp_timer_start_once()` depending on the timer type.
The one-shot timer runs and changes the period of the periodic timer. Now the periodic timer runs with a period of 1 second:
```
I (5265) example: One-shot timer called, time since boot: 5002586 us
I (5265) example: Restarted periodic timer with 1s period, time since boot: 5005475 us
I (6265) example: Periodic timer called, time since boot: 6005492 us
periodic 1000000 7005469 2 11 0 1316
one-shot 0 0 1 1 0 11474
I (7265) example: Periodic timer called, time since boot: 7005492 us
I (8265) example: Periodic timer called, time since boot: 8005492 us
periodic 1000000 9005469 2 13 0 1550
one-shot 0 0 1 1 0 11474
I (9265) example: Periodic timer called, time since boot: 9005492 us
I (10265) example: Periodic timer called, time since boot: 10005492 us
```
### Printing Timer Dumps
### 5. Continuation through light sleep
The function `esp_timer_dump()` is used to print the timer dumps which can be useful for debugging purposes. For details, see *ESP Timer API Reference* > [Debugging Timers](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/esp_timer.html#debugging-timers).
To illustrate that timekeeping continues correctly after light sleep, the example enters light sleep for 0.5 seconds. This sleep does not impact timer period, and the timer is executed 1 second after the previous iteration. Note that the timers can not execute during light sleep, since the CPU is not running at that time. Such timers would execute immediately after light sleep, and then continue running with their normal period.
To make the output of the dump function more detailed, this example's file `sdkconfig.defaults` has the option `CONFIG_ESP_TIMER_PROFILING` set (see [Review Kconfig Options](#review-kconfig-options)).
```
I (10275) example: Entering light sleep for 0.5s, time since boot: 10011559 us
I (10275) example: Woke up from light sleep, time since boot: 10512007 us
I (10765) example: Periodic timer called, time since boot: 11005492 us
I (11765) example: Periodic timer called, time since boot: 12005492 us
```
### 6. Finally, timers are deleted.
### Entering and Waking Up from Light Sleep
```
I (12275) example: Stopped and deleted timers
```
To demonstrate that timekeeping continues correctly after light sleep, the example briefly enters light sleep using `esp_sleep_enable_timer_wakeup()` and `esp_light_sleep_start()`.
During light sleep, the CPU is not running, so callbacks cannot be dispatched. On wakeup, the system attempts to execute all unhandled callbacks if any, then ESP Timer resumes its normal operation.
### Stopping and Deleting Timers
Once the timers are not needed anymore, they are stopped and deleted to free up memory using `esp_timer_stop()` and `esp_timer_delete()`.
## Troubleshooting
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.
## Reference
- [ESP-IDF ESP Timer](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/esp_timer.html)
- [ESP-IDF Getting Started](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html#get-started)
- [Kconfig Options](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/kconfig.html)

View File

@ -1,3 +1,4 @@
# With this option enabled, esp_timer_dump() prints more data about timers in the output log
CONFIG_ESP_TIMER_PROFILING=y
# NEWLIB_NANO_FORMAT is enabled by default on ESP32-C2