diff --git a/docs/en/api-reference/system/esp_timer.rst b/docs/en/api-reference/system/esp_timer.rst index 3984692dd4..ab8fc6e758 100644 --- a/docs/en/api-reference/system/esp_timer.rst +++ b/docs/en/api-reference/system/esp_timer.rst @@ -37,7 +37,7 @@ The ESP Timer API provides: - Multiple callback dispatch methods - Handling overdue callbacks - Bit range: {IDF_TARGET_HR_TIMER_Resolution} bits -- Time resolution: 1 microsecond +- Time resolution: one microsecond One-Shot and Periodic Timers @@ -57,15 +57,15 @@ Timer callbacks can be dispatched using the following methods: - Task Dispatch method (default): - - 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 + - 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. - Interrupt Dispatch method (:cpp:enumerator:`ESP_TIMER_ISR `): - - 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 + - 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. Task Dispatch Specifics @@ -73,7 +73,7 @@ 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. +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. @@ -81,7 +81,7 @@ To maintain predictable and timely execution of tasks, callbacks should never at 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. +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 timers using the ISR dispatch method 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. @@ -89,12 +89,12 @@ While using interrupt dispatched timers, the standard logging or debugging metho 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. +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 μs, 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 +- 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 @@ -110,11 +110,11 @@ As callback dispatching can never be instantaneous, the one-shot and periodic ti 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 +* One-shot timers: ~20 μs * 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 timers: ~50 μs * Periodic software timers with a smaller timeout value would simply consume most of the CPU time, which is impractical. @@ -145,13 +145,13 @@ 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. + 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. + 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`. + 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: @@ -194,29 +194,31 @@ The general procedure to create, start, stop, and delete a timer is as follows: 1. Create a timer - - 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 + - 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. - .. note:: + .. note:: - It is recommended to keep callbacks as short as possible to avoid delaying other callbacks. + It is recommended to keep callbacks as short as possible to avoid delaying other callbacks. - - To create a timer, call the function :cpp:func:`esp_timer_create` + - 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` + - 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. + .. 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` + - 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` + - 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: @@ -224,24 +226,25 @@ The general procedure to create, start, stop, and delete a timer is as follows: Using the Interrupt Dispatch Method ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Out of the available :ref:`callback methods `, if you choose the Interrupt Dispatch method, follow these steps: +Out of the available :ref:`callback dispatch methods `, if you choose the Interrupt Dispatch method, follow these steps: 1. Set Kconfig options - - Enable :ref:`CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD` + - 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` + - Set the timer configuration parameters by defining the structure :cpp:struct:`esp_timer_create_args_t`: - .. code-block:: c + .. code-block:: c - const esp_timer_create_args_t timer = { + const esp_timer_create_args_t timer = { ... , .dispatch_method = ESP_TIMER_ISR, ... - }; - - To create a timer, call the function :cpp:func:`esp_timer_create` + }; + + - To create a timer, call the function :cpp:func:`esp_timer_create`. For further steps, refer to :ref:`General Procedure`. @@ -268,9 +271,11 @@ To debug timers, use the following procedure: 1. Set Kconfig options for more detailed output: - - Enable :ref:`CONFIG_ESP_TIMER_PROFILING` + - Enable :ref:`CONFIG_ESP_TIMER_PROFILING`. - Note that enabling this option increases code size and heap memory usage. + .. note:: + + 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. @@ -287,12 +292,12 @@ While dispatching the same callback function repeatedly, if the response time va .. list:: - - Use the :ref:`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 + - Use the :ref:`Interrupt Dispatch method `. + :SOC_HP_CPU_HAS_MULTIPLE_CORES: - Use the Kconfig option :ref:`CONFIG_ESP_TIMER_TASK_AFFINITY` to run the ESP Timer task on any of the available cores. -Significant Delays Dispatching Callbacks -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Significant Delays while 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. diff --git a/docs/zh_CN/api-reference/system/esp_timer.rst b/docs/zh_CN/api-reference/system/esp_timer.rst index 8c85799098..6a9e51eb8c 100644 --- a/docs/zh_CN/api-reference/system/esp_timer.rst +++ b/docs/zh_CN/api-reference/system/esp_timer.rst @@ -1,19 +1,328 @@ -ESP 定时器 -================================= +ESP 定时器(高分辨率定时器) +============================ :link_to_translation:`en:[English]` {IDF_TARGET_HR_TIMER:default = "SYSTIMER", esp32 = "LAC 定时器"} -{IDF_TARGET_HR_TIMER_Resolution:default = "Not updated", esp32 = "64", esp32s2 = "64", esp32c3 = "52", esp32s3 = "52", esp32c2 = "52", esp32c5 = "52", esp32c6 = "52", esp32h2 = "52"} +{IDF_TARGET_HR_TIMER_Resolution:default = "未更新", esp32 = "64", esp32s2 = "64", esp32c3 = "52", esp32s3 = "52", esp32c2 = "52", esp32c5 = "52", esp32c6 = "52", esp32h2 = "52", esp32p4 = "52"} + +.. only:: html + + 本文介绍了 ESP-IDF 的 ESP 定时器功能,章节目录如下: + + .. contents:: + :local: + :depth: 2 +概述 +---- +使用 ESP 定时器可以创建软件定时器并在超时时调用其回调函数(分发回调函数)。尤其适用于当软件需要执行延迟操作或周期性操作的场景,例如:延迟启动设备或停止设备、周期性采样传感器数据等。 + +ESP 定时器可以简化一些操作,例如:管理多个定时器、分发回调函数、处理时钟频率变化(如果启用了动态调频),以及从浅睡眠中唤醒后保持准确的时间。 + +如果应用场景对实时性能要求较高(例如需要生成波形),或要求定时器分辨率可配置,建议使用 :doc:`GPTimer `。此外,GPTimer 还提供一些其他功能,例如事件捕获。 + +FreeRTOS 有其单独的软件定时器,但分辨率比 ESP 定时器低得多,优势在于 FreeRTOS 定时器有更好的移植性,因为它不依赖于 ESP-IDF。详情请参阅 :ref:`FreeRTOS Timers`。 + + +功能与概念 +---------- + +ESP 定时器 API 提供: + +- 一次性和周期性定时器 +- 多种分发回调函数的方法 +- 处理过期回调函数 +- 计数器位宽:{IDF_TARGET_HR_TIMER_Resolution} 位 +- 时间分辨率:1 us + + +一次性和周期性定时器 +^^^^^^^^^^^^^^^^^^^^ + +一次性定时器到期时仅调用一次回调函数便停止运行。一次性定时器适用于单次延迟操作,例如在指定时间间隔后关闭设备或读取传感器。 + +周期性定时器在到期时会调用回调函数并自动重启,回调函数会在指定时间间隔内被反复调用,直至手动暂停周期性定时器。周期性定时器适用于重复操作,例如采样传感器数据、更新显示信息或生成波形。 + + +.. _Callback Methods: + +分发回调函数的方法 +^^^^^^^^^^^^^^^^^^ + +定时器回调函数可以使用以下方法进行分发: + +- 任务分发法(默认): + + - 从单个高优先级 ESP 定时器任务中分发定时器回调函数(esp_timer 任务(由 ISR 通知)> 回调)。 + - 适用于对时序要求不高的定时器回调函数。 + +- 中断分发法 (:cpp:enumerator:`ESP_TIMER_ISR `): + + - 直接从中断处理程序分发定时器回调函数(ISR > 回调)。 + - 适合运行时间仅为几微秒的简单、低延迟定时器回调函数。 + - 能确保事件和执行回调之间的延迟较短。 + - 不受其他活动任务影响。 + + +任务分发细节 +~~~~~~~~~~~~ + +在 ESP 定时器任务中,回调函数是串行执行的,若多个超时同时发生,执行前一项回调函数会延迟后续回调函数的执行。因此,建议尽量保持回调函数简短。如果需要回调函数执行更多工作,应使用 FreeRTOS 原语(如队列和信号量)将工作推迟到低优先级任务中执行。 + +如果有其他更高优先级的 FreeRTOS 任务正在运行(例如 SPI flash 操作),则回调函数的分发将被延迟,直到 ESP 定时器任务有机会再次运行。 + +为了确保任务的可预测性和及时执行,回调函数不应进行阻塞(等待资源)或让步(放弃控制)操作,否则将中断回调函数的串行执行。 + + +中断分发细节 +~~~~~~~~~~~~ + +使用中断分发法的定时器,其回调由中断处理程序执行。由于中断可以抢占所有任务,中断分发法带来的延迟较低。中断分发的定时器回调函数不应尝试阻塞,也不应尝试通过 ``portYIELD_FROM_ISR()`` 触发上下文切换,而应使用 :cpp:func:`esp_timer_isr_dispatch_need_yield` 函数。上下文切换将在处理完所有使用 ISR 分发法的定时器后进行。 + +使用中断分发的定时器时,应避免使用标准的日志记录或调试方法(例如 ``printf``)。若想调试应用程序或在控制台中显示某些信息,应使用 ESP-IDF 日志宏,例如 :c:macro:`ESP_DRAM_LOGI` 和 :c:macro:`ESP_EARLY_LOGI` 等。这些宏专为在各种上下文(包括中断服务程序)中工作而设计。 + + +获取当前时间 +^^^^^^^^^^^^ + +可以使用便捷函数 :cpp:func:`esp_timer_get_time` 获取自 ESP 定时器初始化以来经过的时间。在调用 ``app_main`` 函数之前不久,ESP 定时器会开始初始化。该便捷函数速度极快,没有能引入延迟或冲突的锁机制,因此可用于细粒度定时,在任务和 ISR 例程中的精度为 1 μs。 + +与 ``gettimeofday()`` 函数不同,:cpp:func:`esp_timer_get_time` 具有以下特点: + +- 从深睡眠状态中唤醒后,初始化定时器将从零开始。 +- 返回值没有时区设置或夏令时调整。 + + +系统集成 +-------- + +本节主要介绍如何优化 ESP 定时器的操作并将其与其他 ESP-IDF 功能进行集成。 + + +超时值限制 +^^^^^^^^^^ + +分发回调不可能是瞬时的,使用 ESP 定时器创建的一次性和周期性定时器具有超时值限制。由于这些限制取决于多个因素,所以无法进行精确估计。 + +例如,ESP32 以 240 MHz 的频率运行并使用任务分发法,其最小超时值大约如下: + +* 一次性定时器:~20 μs + + * 如果调用 :cpp:func:`esp_timer_start_once`,这是系统能够分发回调函数的最小超时值。 + +* 周期性定时器:~50 μs + + * 具有较小超时值的周期性软件定时器将消耗大部分 CPU 时间,因此不实用。 + +CPU 频率越低,最小超时值就越高。一般来说,如果所需的超时值在几十微秒的范围内,则应用程序需要经过彻底测试才能确保稳定运行。 + +如果最小超时值稍稍超过要求,可以考虑使用中断分发法。 + +.. only:: not SOC_PARLIO_SUPPORTED and SOC_RMT_SUPPORTED + + 若需要更小的超时值,例如生成或接收波形、进行位操作时,ESP 定时器的分辨率可能不能满足要求。此时建议使用专用外设,例如 :doc:`GPTimer ` 或 :doc:`RMT `,以及使用它们的 DMA 功能(如果可用)。 + +.. only:: SOC_PARLIO_SUPPORTED + + 若需要更小的超时值,例如生成或接收波形、进行位操作时,ESP 定时器的分辨率可能不能满足要求。此时建议使用专用外设,例如 :doc:`并行 IO `,以及使用它们的 DMA 功能(如果可用)。 + + +睡眠模式注意事项 +^^^^^^^^^^^^^^^^ + +如果启动了定时器,并且在等待时间内没有执行其他任务,则可以将芯片置于睡眠状态以优化功耗。 + +可以通过以下方式进入不同睡眠模式: + +* **自动睡眠** 由 :doc:`电源管理 API ` 提供:如果没有正在执行的任务,芯片会自动进入浅睡眠状态,并在适当时间自动唤醒,以便 ESP 定时器分发待处理的回调函数。 +* **手动睡眠** 由 :doc:`睡眠模式 API ` 提供:无论是否正在执行其他任务,都可以将芯片置于睡眠状态。 + +若手动设置睡眠状态,则可以选择以下睡眠模式: + +* Deep-sleep 模式:ESP 定时器停用 + + 从深睡眠状态中唤醒时,应用程序即刻重新启动,因此该模式不适用于连续的 ESP 定时器操作。但如果不需要定时器在唤醒后持续运行,则可进入深睡眠状态。 + +* Light-sleep 模式:ESP 定时器暂停 + + 在浅睡眠状态下,ESP 定时器的计数器和回调函数会被暂停。RTC 定时器可保持系统时间。一旦芯片被唤醒,ESP 定时器的计数器会自动为系统增加睡眠期间的时长,之后时间保持和回调函数执行将恢复。 + + 此时,ESP 定时器将尝试分发所有未处理的回调函数(如果有的话),可能会导致 ESP 定时器回调执行队列的溢出。某些应用中不应出现此类行为,为避免这种情况,可参阅 :ref:`Handling Callbacks in Light Sleep`。 + + +.. _FreeRTOS Timers: + +FreeRTOS 定时器 +^^^^^^^^^^^^^^^ + +尽管 FreeRTOS 提供了 `软件定时器 `_,但它们有以下限制: + +- FreeRTOS 定时器的分辨率受 `tick 频率 `_ 的限制,该频率通常在 100 到 1000 Hz 之间。 +- 定时器回调函数由低优先级定时器任务分发,该任务可能会被其他任务抢占,导致定时器精度和准确度下降。 + +但 FreeRTOS 定时器是可移植的(不依赖于 ESP-IDF),且不会从 ISR 中分发,因此具有确定性。 + + +.. only:: SOC_ETM_SUPPORTED and SOC_SYSTIMER_SUPPORT_ETM + + ETM 事件 + ^^^^^^^^ + + ESP 定时器连接到 :doc:`事件任务矩阵 ` (ETM) 模块。该模块能够在不涉及 CPU 中断的情况下通知多个外设。直接通知可以减少延迟并降低 CPU 负载。可以调用函数 :cpp:func:`esp_timer_new_etm_alarm_event` 获取相应的 ETM 事件句柄。 + + +使用方法 +-------- + +在设置 ESP-IDF 项目时,请确保: + +- 在 ``CMakeLists.txt`` 中添加所需的组件依赖项 ``esp_timer``。 +- 在 ``.c`` 文件中包含所需的头文件 ``esp_timer.h``。 +- (可选)设置 Kconfig 选项。详见 :ref:`Kconfig 选项 ` > *ESP 定时器(高分辨率定时器)* + + +.. _General Procedure: + +一般程序 +^^^^^^^^ + +创建、启动、暂停和删除定时器的一般程序如下: + +1. 创建定时器 + + - 使用类型 :cpp:type:`esp_timer_handle_t` 定义定时器句柄 + - 通过定义结构体 :cpp:struct:`esp_timer_create_args_t` (包括回调函数)来设置定时器配置参数。 + + .. note:: + + 建议尽量使回调函数保持简短,避免延迟其他回调函数的执行。 + + - 调用函数 :cpp:func:`esp_timer_create` 来创建定时器。 + +2. 根据需求启动一次性或周期性的定时器 + + - 调用函数 :cpp:func:`esp_timer_start_once`,启动一次性定时器。 + - 调用函数 :cpp:func:`esp_timer_start_periodic`,启动周期性定时器。在调用函数 :cpp:func:`esp_timer_stop` 显式暂停定时器前,该周期性定时器将持续运行。 + + .. note:: + + 执行启动函数前,请确保定时器未在运行。如果定时器正在运行,请先调用 :cpp:func:`esp_timer_restart`,或是调用 :cpp:func:`esp_timer_stop` 暂停定时器,然后再使用上述启动函数。 + +3. 暂停定时器 + + - 调用函数 :cpp:func:`esp_timer_stop`,可暂停运行中的定时器。 + +4. 删除定时器 + + - 使用函数 :cpp:func:`esp_timer_delete`,可删除不需要的定时器以释放内存。 + + +.. _Using ESP_TIMER_ISR Callback Method: + +使用中断分发法 +^^^^^^^^^^^^^^ + +在可用的 :ref:`分发回调函数的方法 ` 中,如果选择中断分发法,请按以下步骤操作: + +1. 设置 Kconfig 选项 + + - 启用 :ref:`CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD`。 + +2. 创建定时器 + + - 通过定义结构体 :cpp:struct:`esp_timer_create_args_t` 来设置定时器配置参数: + + .. code-block:: c + + const esp_timer_create_args_t timer = { + ... , + .dispatch_method = ESP_TIMER_ISR, + ... + }; + + - 调用函数 :cpp:func:`esp_timer_create` 来创建定时器。 + +更多步骤请参阅 :ref:`General Procedure`。 + + +.. _Handling Callbacks in Light Sleep: + +在 Light-sleep 模式下处理回调函数 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +浅睡眠状态下,既能快速唤醒以执行特定操作,又能节省功耗。要想结合 Light-sleep 模式使用 ESP 定时器,请参阅 :doc:`睡眠模式 API `。 + +在浅睡眠状态下,为控制未处理的回调函数,并且避免唤醒时 ESP 定时器回调执行队列的溢出,请执行以下任一操作: + +- 首先要防止调用回调函数:在进入浅睡眠状态前,请使用函数 :cpp:func:`esp_timer_stop` 暂停定时器。 +- 若出于某种原因不希望调用停止函数,请使用选项 :cpp:member:`esp_timer_create_args_t::skip_unhandled_events`。此时,若周期性定时器在浅睡眠状态下到期一次或多次,则唤醒时只执行一次回调函数。 + + +调试定时器 +^^^^^^^^^^ + +使用函数 :cpp:func:`esp_timer_dump`,可转储所有定时器或仅运行中的定时器的相关信息:如定时器的参数、定时器启动次数、触发次数、跳过次数以及执行定时器回调函数所需的时间,这些信息能够帮助调试定时器。 + +请按照以下步骤调试定时器: + +1. 设置 Kconfig 选项以获取更详细的输出: + + - 启用 :ref:`CONFIG_ESP_TIMER_PROFILING`。 + + .. note:: + + 启用此选项会增加代码大小和堆内存使用量。 + +2. 调用函数 :cpp:func:`esp_timer_dump`,在代码中必要的位置打印信息并用于调试定时器。 + +3. 结束调试后,考虑禁用 :ref:`CONFIG_ESP_TIMER_PROFILING`。 + + +故障排除 +-------- + +回调函数分发时间不稳定 +^^^^^^^^^^^^^^^^^^^^^^ + +如果多次分发相同的回调函数时响应时间变化较大,请尝试下列方法,使分发时间趋于稳定: + +.. list:: + + - :ref:`使用中断分发法 `。 + :SOC_HP_CPU_HAS_MULTIPLE_CORES: - 使用 Kconfig 选项 :ref:`CONFIG_ESP_TIMER_TASK_AFFINITY`,将 esp_timer 安装到负载较轻的 CPU 核上运行。 + + +分发回调函数时延迟显著 +^^^^^^^^^^^^^^^^^^^^^^ + +若分发回调函数需要相当长的时间,问题可能出在回调函数本身。更准确地说,由于所有回调函数都在单个 esp_timer 任务中逐个处理,延迟可能是由队列中较早的其他回调函数引起的。 + +因此,要确保应用程序中的所有回调函数都能快速独立地执行,并且没有任何阻塞操作。 + + +唤醒后重复分发回调函数 +^^^^^^^^^^^^^^^^^^^^^^ + +从睡眠模式中唤醒后,若回调函数重复执行,请参阅 :ref:`Handling Callbacks in Light Sleep`。 + + +在分发回调函数时栈溢出 +^^^^^^^^^^^^^^^^^^^^^^ + +如果在执行回调函数时遇到栈溢出的错误,请考虑减少回调函数内的栈使用量;或者,尝试通过调整 :ref:`CONFIG_ESP_TIMER_TASK_STACK_SIZE` 来增加 ESP 定时器任务栈的大小。 + + +应用示例 +-------- + +* :example:`system/esp_timer` 创建并启动一次性及周期性的软件定时器,展示了如何结合 Light-sleep 模式使用定时器,然后停止并删除定时器。 API 参考 -------------- +-------- .. include-build-file:: inc/esp_timer.inc - -