diff --git a/components/esp_timer/include/esp_timer.h b/components/esp_timer/include/esp_timer.h index b02adf865806..6c0eed4c69e5 100644 --- a/components/esp_timer/include/esp_timer.h +++ b/components/esp_timer/include/esp_timer.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -157,6 +157,22 @@ esp_err_t esp_timer_create(const esp_timer_create_args_t* create_args, */ esp_err_t esp_timer_start_once(esp_timer_handle_t timer, uint64_t timeout_us); +/** + * @brief Start a one-shot timer + * + * Timer represented by `timer` should not be running when this function is + * called. + * + * @param timer timer handle created using esp_timer_create() + * @param alarm_us timer alarm time, in absolute microseconds (as returned by + * esp_timer_get_time()) + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if the handle is invalid + * - ESP_ERR_INVALID_STATE if the timer is already running or `alarm_us` is zero or in the past + */ +esp_err_t esp_timer_start_once_at(esp_timer_handle_t timer, uint64_t alarm_us); + /** * @brief Start a periodic timer * @@ -172,6 +188,26 @@ esp_err_t esp_timer_start_once(esp_timer_handle_t timer, uint64_t timeout_us); */ esp_err_t esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period); +/** + * @brief Start a periodic timer + * + * Timer represented by `timer` should not be running when this function is called. + * This function starts the timer which will trigger every `period` microseconds. + * The first alarm will be triggered at `first_alarm_us` time. + * + * @param timer timer handle created using esp_timer_create() + * @param period_us timer period, in microseconds + * @param first_alarm_us timer first alarm time, in absolute microseconds (as + * returned by esp_timer_get_time()) + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if the handle is invalid + * - ESP_ERR_INVALID_STATE if the timer is already running or `first_alarm_us` is zero or in the past + */ +esp_err_t esp_timer_start_periodic_at(esp_timer_handle_t timer, + uint64_t period_us, + uint64_t first_alarm_us); + /** * @brief Restart a currently running timer * @@ -190,6 +226,26 @@ 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 Restart a currently running timer + * + * Type of `timer` | Action + * --------------- | ------ + * One-shot timer | Restarted immediately and times out once at `alarm_us` microseconds + * Periodic timer | Restarted immediately with a new period of `timeout_us` microseconds. Next alarm is at `alarm_us` microseconds + * + * @param timer timer handle created using esp_timer_create() + * @param period_us In case of a periodic timer, represents the new period. + * @param alarm_us timer alarm time, in absolute microseconds (as returned by + * esp_timer_get_time()) + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if the handle is invalid + * - ESP_ERR_INVALID_STATE if the timer is not running or `alarm_us` is zero or in the past + */ +esp_err_t esp_timer_restart_at(esp_timer_handle_t timer, uint64_t period_us, + uint64_t alarm_us); + /** * @brief Stop a running timer * diff --git a/components/esp_timer/src/esp_timer.c b/components/esp_timer/src/esp_timer.c index 3c21f995dd67..df588fab715c 100644 --- a/components/esp_timer/src/esp_timer.c +++ b/components/esp_timer/src/esp_timer.c @@ -66,6 +66,13 @@ static bool timer_armed(esp_timer_handle_t timer); static void timer_list_lock(esp_timer_dispatch_t timer_type); static void timer_list_unlock(esp_timer_dispatch_t timer_type); +static esp_err_t esp_timer_start_once_at_impl(esp_timer_handle_t timer, + uint64_t alarm_us); +static esp_err_t esp_timer_start_periodic_at_impl(esp_timer_handle_t timer, + uint64_t period_us, + uint64_t first_alarm_us); +static esp_err_t esp_timer_restart_at_impl(esp_timer_handle_t timer, uint64_t timeout_us, uint64_t alarm_us); + #if WITH_PROFILING static void timer_insert_inactive(esp_timer_handle_t timer); static void timer_remove_inactive(esp_timer_handle_t timer); @@ -134,8 +141,6 @@ esp_err_t esp_timer_create(const esp_timer_create_args_t* args, */ esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_restart(esp_timer_handle_t timer, uint64_t timeout_us) { - esp_err_t ret = ESP_OK; - if (timer == NULL) { return ESP_ERR_INVALID_ARG; } @@ -144,6 +149,27 @@ esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_restart(esp_timer_handle_t timer, uint64 return ESP_ERR_INVALID_STATE; } + return esp_timer_restart_at_impl(timer, timeout_us, 0); +} + +esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_restart_at(esp_timer_handle_t timer, uint64_t period_us, uint64_t alarm_us) +{ + if (timer == NULL || alarm_us <= esp_timer_impl_get_time() || alarm_us == 0) { + return ESP_ERR_INVALID_ARG; + } + + if (!is_initialized() || !timer_armed(timer)) { + return ESP_ERR_INVALID_STATE; + } + + return esp_timer_restart_at_impl(timer, period_us, alarm_us); +} + +static esp_err_t ESP_TIMER_IRAM_ATTR +esp_timer_restart_at_impl(esp_timer_handle_t timer, uint64_t timeout_us, uint64_t alarm_us) +{ + esp_err_t ret = ESP_OK; + esp_timer_dispatch_t dispatch_method = timer->flags & FL_ISR_DISPATCH_METHOD; timer_list_lock(dispatch_method); @@ -169,6 +195,12 @@ esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_restart(esp_timer_handle_t timer, uint64 timer->alarm = now + timeout_us; timer->period = 0; } + + /* If the alarm time is explicitly specified, override the calculated one */ + if (alarm_us != 0) { + timer->alarm = alarm_us; + } + ret = timer_insert(timer, false); } @@ -185,7 +217,23 @@ esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_start_once(esp_timer_handle_t timer, uin if (!is_initialized()) { return ESP_ERR_INVALID_STATE; } - int64_t alarm = esp_timer_get_time() + timeout_us; + return esp_timer_start_once_at_impl(timer, esp_timer_get_time() + timeout_us); +} + +esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_start_once_at(esp_timer_handle_t timer, uint64_t alarm_us) +{ + if (timer == NULL || alarm_us <= esp_timer_impl_get_time() || alarm_us == 0) { + return ESP_ERR_INVALID_ARG; + } + if (!is_initialized()) { + return ESP_ERR_INVALID_STATE; + } + return esp_timer_start_once_at_impl(timer, alarm_us); +} + +static ESP_TIMER_IRAM_ATTR esp_err_t +esp_timer_start_once_at_impl(esp_timer_handle_t timer, uint64_t alarm_us) +{ esp_timer_dispatch_t dispatch_method = timer->flags & FL_ISR_DISPATCH_METHOD; esp_err_t err; @@ -199,7 +247,7 @@ esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_start_once(esp_timer_handle_t timer, uin if (timer_armed(timer)) { err = ESP_ERR_INVALID_STATE; } else { - timer->alarm = alarm; + timer->alarm = alarm_us; timer->period = 0; #if WITH_PROFILING timer->times_armed++; @@ -210,7 +258,22 @@ esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_start_once(esp_timer_handle_t timer, uin return err; } -esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period_us) +esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_start_periodic_at( + esp_timer_handle_t timer, uint64_t period_us, uint64_t first_alarm_us) +{ + if (timer == NULL || first_alarm_us <= esp_timer_impl_get_time() || first_alarm_us == 0) { + return ESP_ERR_INVALID_ARG; + } + if (!is_initialized()) { + return ESP_ERR_INVALID_STATE; + } + + period_us = MAX(period_us, esp_timer_impl_get_min_period_us()); + return esp_timer_start_periodic_at_impl(timer, period_us, first_alarm_us); +} + +esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_start_periodic(esp_timer_handle_t timer, + uint64_t period_us) { if (timer == NULL) { return ESP_ERR_INVALID_ARG; @@ -219,7 +282,13 @@ esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_start_periodic(esp_timer_handle_t timer, return ESP_ERR_INVALID_STATE; } period_us = MAX(period_us, esp_timer_impl_get_min_period_us()); - int64_t alarm = esp_timer_get_time() + period_us; + return esp_timer_start_periodic_at_impl(timer, period_us, + esp_timer_get_time() + period_us); +} + +static ESP_TIMER_IRAM_ATTR esp_err_t esp_timer_start_periodic_at_impl( + esp_timer_handle_t timer, uint64_t period_us, uint64_t first_alarm_us) +{ esp_timer_dispatch_t dispatch_method = timer->flags & FL_ISR_DISPATCH_METHOD; esp_err_t err; timer_list_lock(dispatch_method); @@ -228,7 +297,7 @@ esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_start_periodic(esp_timer_handle_t timer, if (timer_armed(timer)) { err = ESP_ERR_INVALID_STATE; } else { - timer->alarm = alarm; + timer->alarm = first_alarm_us; timer->period = period_us; #if WITH_PROFILING timer->times_armed++; diff --git a/components/ieee802154/lib b/components/ieee802154/lib new file mode 160000 index 000000000000..5d03fb64207e --- /dev/null +++ b/components/ieee802154/lib @@ -0,0 +1 @@ +Subproject commit 5d03fb64207e7769319891fe99292c9c471db7ba diff --git a/components/json/cJSON b/components/json/cJSON new file mode 160000 index 000000000000..d348621ca935 --- /dev/null +++ b/components/json/cJSON @@ -0,0 +1 @@ +Subproject commit d348621ca93571343a56862df7de4ff3bc9b5667 diff --git a/docs/en/api-reference/system/esp_timer.rst b/docs/en/api-reference/system/esp_timer.rst index 1be2f98d948a..e8bcba9a39ad 100644 --- a/docs/en/api-reference/system/esp_timer.rst +++ b/docs/en/api-reference/system/esp_timer.rst @@ -34,6 +34,7 @@ Features and Concepts The ESP Timer API provides: - One-shot and periodic timers +- Relative and absolute timing - Multiple callback dispatch methods - Handling overdue callbacks - Bit range: {IDF_TARGET_HR_TIMER_Resolution} bits @@ -43,7 +44,7 @@ The ESP Timer API provides: One-Shot and Periodic Timers ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -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. +A one-shot timer invokes its callback function only once upon expiration and then stops operation. One-shot timers are useful for single delayed or timed actions, such as turning off a device or reading a sensor after a specified time interval or at a specified time point. 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. @@ -205,12 +206,12 @@ The general procedure to create, start, stop, and delete a timer is as follows: 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` for delayed execution or :cpp:func:`esp_timer_start_once_at` for timed execution. + - To start the timer in periodic mode, call :cpp:func:`esp_timer_start_periodic` for delayed first execution or :cpp:func:`esp_timer_start_periodic_at` for timed first execution; 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. + When executing a start function, ensure that the timer is not running. If a timer is running, either call :cpp:func:`esp_timer_restart` / :cpp:func:`esp_timer_restart_at` or stop it first using :cpp:func:`esp_timer_stop` and then call one of the start functions. 3. Stop the timer diff --git a/examples/system/esp_timer/README.md b/examples/system/esp_timer/README.md index 6e498b101d86..5dd5b5f33ddd 100644 --- a/examples/system/esp_timer/README.md +++ b/examples/system/esp_timer/README.md @@ -86,36 +86,73 @@ If you see the following console output, your example should be running correctl ``` ... -I (294) example: Started timers, time since boot: 9662 us -periodic 500000 509644 1 0 0 0 -one-shot 0 5009654 1 0 0 0 -I (794) example: Periodic timer called, time since boot: 509694 us -I (1294) example: Periodic timer called, time since boot: 1009671 us -I (1794) example: Periodic timer called, time since boot: 1509671 us -I (2294) example: Periodic timer called, time since boot: 2009671 us -periodic 500000 2509644 1 4 0 542 -one-shot 0 5009654 1 0 0 0 -I (2794) example: Periodic timer called, time since boot: 2509671 us -I (3294) example: Periodic timer called, time since boot: 3009671 us -I (3794) example: Periodic timer called, time since boot: 3509671 us -I (4294) example: Periodic timer called, time since boot: 4009671 us -periodic 500000 4509644 1 8 0 1026 -one-shot 0 5009654 1 0 0 0 -I (4794) example: Periodic timer called, time since boot: 4509671 us -I (5294) example: Periodic timer called, time since boot: 5009669 us -I (5294) example: One-shot timer called, time since boot: 5009788 us -I (5294) example: Restarted periodic timer with 1s period, time since boot: 5012675 us -I (6294) example: Periodic timer called, time since boot: 6012692 us -periodic 1000000 7012666 2 11 0 1391 -one-shot 0 0 1 1 0 11472 -I (7294) example: Periodic timer called, time since boot: 7012692 us -I (8294) example: Periodic timer called, time since boot: 8012692 us -periodic 1000000 9012666 2 13 0 1639 -one-shot 0 0 1 1 0 11472 -I (9294) example: Periodic timer called, time since boot: 9012692 us -I (10294) example: Periodic timer called, time since boot: 10012692 us -I (10314) example: Entering light sleep for 0.5s, time since boot: 10024351 us -I (10314) example: Woke up from light sleep, time since boot: 10525143 us +I (266) example: Started timers, time since boot: 30808 us +Timer stats: +Name Period Alarm Times_armed Times_trigg Times_skip Cb_exec_time +periodic 500000 530773 1 0 0 0 +timed periodic 500000 3000000 1 0 0 0 +one-shot 0 5030792 1 0 0 0 +timed one-shot 0 6000000 1 0 0 0 +I (766) example: Periodic timer called, time since boot: 530850 us +I (1266) example: Periodic timer called, time since boot: 1030802 us +I (1766) example: Periodic timer called, time since boot: 1530802 us +I (2266) example: Periodic timer called, time since boot: 2030802 us +Timer stats: +Name Period Alarm Times_armed Times_trigg Times_skip Cb_exec_time +periodic 500000 2530773 1 4 0 999 +timed periodic 500000 3000000 1 0 0 0 +one-shot 0 5030792 1 0 0 0 +timed one-shot 0 6000000 1 0 0 0 +I (2766) example: Periodic timer called, time since boot: 2530826 us +I (3236) example: Timed periodic timer called, time since boot: 3000029 us +I (3266) example: Periodic timer called, time since boot: 3030802 us +I (3736) example: Timed periodic timer called, time since boot: 3500029 us +I (3766) example: Periodic timer called, time since boot: 3530802 us +I (4236) example: Timed periodic timer called, time since boot: 4000029 us +I (4266) example: Periodic timer called, time since boot: 4030802 us +Timer stats: +Name Period Alarm Times_armed Times_trigg Times_skip Cb_exec_time +timed periodic 500000 4500000 1 3 0 709 +periodic 500000 4530773 1 8 0 1947 +one-shot 0 5030792 1 0 0 0 +timed one-shot 0 6000000 1 0 0 0 +I (4736) example: Timed periodic timer called, time since boot: 4500053 us +I (4766) example: Periodic timer called, time since boot: 4530802 us +I (5236) example: Timed periodic timer called, time since boot: 5000030 us +I (5266) example: Periodic timer called, time since boot: 5030803 us +I (5266) example: One-shot timer called, time since boot: 5031025 us +I (5266) example: Restarted periodic timer with 1s period, time since boot: 5031920 us +I (5736) example: Timed periodic timer called, time since boot: 5500029 us +I (6236) example: Timed one-shot timer called, time since boot: 6000028 us +I (6236) example: Restarted timed periodic timer with 1s period, time since boot: 6000268 us +I (6266) example: Periodic timer called, time since boot: 6031945 us +Timer stats: +Name Period Alarm Times_armed Times_trigg Times_skip Cb_exec_time +timed periodic 1000000 7000000 1 6 0 1438 +periodic 1000000 7031916 2 11 0 2644 +timed one-shot 0 0 1 1 0 3722 +one-shot 0 0 1 1 0 8517 +I (7236) example: Timed periodic timer called, time since boot: 7000053 us +I (7266) example: Periodic timer called, time since boot: 7031945 us +I (8236) example: Timed periodic timer called, time since boot: 8000029 us +I (8266) example: Periodic timer called, time since boot: 8031945 us +Timer stats: +Name Period Alarm Times_armed Times_trigg Times_skip Cb_exec_time +timed periodic 1000000 9000000 1 8 0 1940 +periodic 1000000 9031916 2 13 0 3106 +timed one-shot 0 0 1 1 0 3722 +one-shot 0 0 1 1 0 8517 +I (9236) example: Timed periodic timer called, time since boot: 9000053 us +I (9266) example: Periodic timer called, time since boot: 9031945 us +I (10236) example: Timed periodic timer called, time since boot: 10000029 us +I (10266) example: Periodic timer called, time since boot: 10031945 us +I (10476) example: Entering light sleep for 0.5s, time since boot: 10239360 us +I (10476) example: Woke up from light sleep, time since boot: 10739673 us +I (10736) example: Timed periodic timer called, time since boot: 11000033 us +I (10766) example: Periodic timer called, time since boot: 11031945 us +I (11736) example: Timed periodic timer called, time since boot: 12000029 us +I (11766) example: Periodic timer called, time since boot: 12031945 us +I (12486) example: Stopped and deleted timers ... ``` @@ -127,7 +164,7 @@ The subsections below walk you through the important parts of the application ex ### Creating Callback Functions -Timers are used to execute a callback function as a delayed action. So the callback functions `periodic_timer_callback()` and `oneshot_timer_callback()` are crucial parts of this application example. +Timers are used to execute a callback function as a delayed action. So the callback functions `periodic_timer_callback()`, `timed_periodic_timer_callback()`, `oneshot_timer_callback()` and `timed_oneshot_timer_callback()`, are crucial parts of this application example. ### Printing Timer Dumps diff --git a/examples/system/esp_timer/main/esp_timer_example_main.c b/examples/system/esp_timer/main/esp_timer_example_main.c index 54183cb8a3e6..2c1df9973d4c 100644 --- a/examples/system/esp_timer/main/esp_timer_example_main.c +++ b/examples/system/esp_timer/main/esp_timer_example_main.c @@ -16,16 +16,23 @@ #include "sdkconfig.h" static void periodic_timer_callback(void* arg); +static void timed_periodic_timer_callback(void* arg); static void oneshot_timer_callback(void* arg); +static void timed_oneshot_timer_callback(void* arg); static const char* TAG = "example"; void app_main(void) { - /* Create two timers: + /* Create four timers: * 1. a periodic timer which will run every 0.5s, and print a message - * 2. a one-shot timer which will fire after 5s, and re-start periodic - * timer with period of 1s. + * 2. a periodic timer which will run every 0.5s, starting at time 3s from + * boot, and print a message + * 3. a one-shot timer which will fire after 5s, and re-start periodic + * timer 1 with period of 1s. + * 4. a one-shot timer which will fire at time 6s from boot, and re-start + * periodic timer 2 with period of 1s, firing for the first time at 7s + * after boot. */ const esp_timer_create_args_t periodic_timer_args = { @@ -33,11 +40,18 @@ void app_main(void) /* name is optional, but may help identify the timer when debugging */ .name = "periodic" }; - esp_timer_handle_t periodic_timer; ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer)); /* The timer has been created but is not running yet */ + const esp_timer_create_args_t timed_periodic_timer_args = { + .callback = &timed_periodic_timer_callback, + .name = "timed_periodic" + }; + esp_timer_handle_t timed_periodic_timer; + ESP_ERROR_CHECK(esp_timer_create(&timed_periodic_timer_args, &timed_periodic_timer)); + + const esp_timer_create_args_t oneshot_timer_args = { .callback = &oneshot_timer_callback, /* argument specified here will be passed to timer callback function */ @@ -47,9 +61,21 @@ void app_main(void) esp_timer_handle_t oneshot_timer; ESP_ERROR_CHECK(esp_timer_create(&oneshot_timer_args, &oneshot_timer)); + const esp_timer_create_args_t timed_oneshot_timer_args = { + .callback = &timed_oneshot_timer_callback, + .arg = (void*) timed_periodic_timer, + .name = "timed_one-shot" + }; + esp_timer_handle_t timed_oneshot_timer; + ESP_ERROR_CHECK(esp_timer_create(&timed_oneshot_timer_args, &timed_oneshot_timer)); + + + /* Start the timers */ ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, 500000)); + ESP_ERROR_CHECK(esp_timer_start_periodic_at(timed_periodic_timer, 500000, 3000000)); ESP_ERROR_CHECK(esp_timer_start_once(oneshot_timer, 5000000)); + ESP_ERROR_CHECK(esp_timer_start_once_at(timed_oneshot_timer, 6000000)); ESP_LOGI(TAG, "Started timers, time since boot: %lld us", esp_timer_get_time()); /* Print debugging information about timers to console every 2 seconds */ @@ -80,8 +106,11 @@ void app_main(void) /* Clean up and finish the example */ ESP_ERROR_CHECK(esp_timer_stop(periodic_timer)); + ESP_ERROR_CHECK(esp_timer_stop(timed_periodic_timer)); ESP_ERROR_CHECK(esp_timer_delete(periodic_timer)); + ESP_ERROR_CHECK(esp_timer_delete(timed_periodic_timer)); ESP_ERROR_CHECK(esp_timer_delete(oneshot_timer)); + ESP_ERROR_CHECK(esp_timer_delete(timed_oneshot_timer)); ESP_LOGI(TAG, "Stopped and deleted timers"); } @@ -91,6 +120,12 @@ static void periodic_timer_callback(void* arg) ESP_LOGI(TAG, "Periodic timer called, time since boot: %lld us", time_since_boot); } +static void timed_periodic_timer_callback(void* arg) +{ + int64_t time_since_boot = esp_timer_get_time(); + ESP_LOGI(TAG, "Timed periodic timer called, time since boot: %lld us", time_since_boot); +} + static void oneshot_timer_callback(void* arg) { int64_t time_since_boot = esp_timer_get_time(); @@ -103,3 +138,15 @@ static void oneshot_timer_callback(void* arg) ESP_LOGI(TAG, "Restarted periodic timer with 1s period, time since boot: %lld us", time_since_boot); } + +static void timed_oneshot_timer_callback(void* arg) +{ + int64_t time_since_boot = esp_timer_get_time(); + ESP_LOGI(TAG, "Timed one-shot timer called, time since boot: %lld us", time_since_boot); + esp_timer_handle_t timed_periodic_timer_handle = (esp_timer_handle_t) arg; + /* To start the timer which is running, need to stop it first */ + ESP_ERROR_CHECK(esp_timer_restart_at(timed_periodic_timer_handle, 1000000, 7000000)); + time_since_boot = esp_timer_get_time(); + ESP_LOGI(TAG, "Restarted timed periodic timer with 1s period, time since boot: %lld us", + time_since_boot); +} diff --git a/examples/system/esp_timer/pytest_esp_timer.py b/examples/system/esp_timer/pytest_esp_timer.py index cc6fa7bd41f6..a20b8f120d04 100644 --- a/examples/system/esp_timer/pytest_esp_timer.py +++ b/examples/system/esp_timer/pytest_esp_timer.py @@ -12,13 +12,16 @@ TIMER_DUMP_LINE_REGEX = r'([\w-]+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)' PERIODIC_TIMER_REGEX = r'Periodic timer called, time since boot: (\d+) us' +TIMED_PERIODIC_TIMER_REGEX = r'Timed periodic timer called, time since boot: (\d+) us' LIGHT_SLEEP_ENTER_REGEX = r'Entering light sleep for 0\.5s, time since boot: (\d+) us' LIGHT_SLEEP_EXIT_REGEX = r'Woke up from light sleep, time since boot: (\d+) us' ONE_SHOT_REGEX = r'One\-shot timer called, time since boot: (\d+) us' +TIMED_ONE_SHOT_REGEX = r'Timed one-shot timer called, time since boot: (\d+) us' RESTART_REGEX = r'Restarted periodic timer with 1s period, time since boot: (\d+) us' +TIMED_RESTART_REGEX = r'Restarted timed periodic timer with 1s period, time since boot: (\d+) us' STOP_REGEX = r'Stopped and deleted timers' @@ -26,6 +29,9 @@ FINAL_TIMER_PERIOD = 1000000 LIGHT_SLEEP_TIME = 500000 ONE_SHOT_TIMER_PERIOD = 5000000 +TIMED_PERIODIC_START_TIME = 3000000 +TIMED_ONE_SHOT_TIME = 6000000 +TIMED_RESTART_TIME = 7000000 @pytest.mark.generic @@ -40,35 +46,69 @@ def test_esp_timer(dut: Dut) -> None: match = dut.expect(STARTING_TIMERS_REGEX) start_time = int(match.group(1)) - logging.info('Start time: {} us'.format(start_time)) + logging.info(f'Start time: {start_time} us') match = dut.expect(TIMER_DUMP_LINE_REGEX, timeout=2) assert match.group(1).decode('utf8') == 'periodic' and int(match.group(2)) == INITIAL_TIMER_PERIOD match = dut.expect(TIMER_DUMP_LINE_REGEX, timeout=2) + assert match.group(1).decode('utf8') == 'timed_periodic' and int(match.group(2)) == INITIAL_TIMER_PERIOD + match = dut.expect(TIMER_DUMP_LINE_REGEX, timeout=2) assert match.group(1).decode('utf8') == 'one-shot' and int(match.group(2)) == 0 + match = dut.expect(TIMER_DUMP_LINE_REGEX, timeout=2) + assert match.group(1).decode('utf8') == 'timed_one-shot' and int(match.group(2)) == 0 for i in range(0, 5): match = dut.expect(PERIODIC_TIMER_REGEX, timeout=2) cur_time = int(match.group(1)) diff = start_time + (i + 1) * INITIAL_TIMER_PERIOD - cur_time - logging.info('Callback #{}, time: {} us, diff: {} us'.format(i, cur_time, diff)) + logging.info(f'Callback #{i}, time: {cur_time} us, diff: {diff} us') + assert abs(diff) < 100 + + for i in range(0, 5): + match = dut.expect(TIMED_PERIODIC_TIMER_REGEX, timeout=2) + cur_time = int(match.group(1)) + diff = TIMED_PERIODIC_START_TIME + i * INITIAL_TIMER_PERIOD - cur_time + logging.info(f'Callback #{i}, time: {cur_time} us, diff: {diff} us') assert abs(diff) < 100 match = dut.expect(ONE_SHOT_REGEX, timeout=3) one_shot_timer_time = int(match.group(1)) diff = start_time + ONE_SHOT_TIMER_PERIOD - one_shot_timer_time - logging.info('One-shot timer, time: {} us, diff: {}'.format(one_shot_timer_time, diff)) + logging.info(f'One-shot timer, time: {one_shot_timer_time} us, diff: {diff}') assert abs(diff) < 400 match = dut.expect(RESTART_REGEX, timeout=3) start_time = int(match.group(1)) - logging.info('Timer restarted, time: {} us'.format(start_time)) + logging.info(f'Timer restarted, time: {start_time} us') + + match = dut.expect(TIMED_ONE_SHOT_REGEX, timeout=3) + timed_one_shot_timer_time = int(match.group(1)) + diff = TIMED_ONE_SHOT_TIME - timed_one_shot_timer_time + logging.info(f'Timed one-shot timer, time: {timed_one_shot_timer_time} us, diff: {diff}') + + match = dut.expect(TIMED_RESTART_REGEX, timeout=3) + timed_start_time = int(match.group(1)) + logging.info(f'Timed timer restarted, time: {timed_start_time} us') + + # First callback after restart + match = dut.expect(PERIODIC_TIMER_REGEX, timeout=2) + cur_time = int(match.group(1)) + diff = start_time + FINAL_TIMER_PERIOD - cur_time + logging.info(f'Callback #{0}, time: {cur_time} us, diff: {diff} us') + assert abs(diff) < 100 + + # Callbacks 2 to 5 after restart (now both timers are running) + for i in range(1, 5): + timed_match = dut.expect(TIMED_PERIODIC_TIMER_REGEX, timeout=2) + timed_cur_time = int(timed_match.group(1)) + timed_diff = TIMED_RESTART_TIME + (i - 1) * FINAL_TIMER_PERIOD - timed_cur_time + logging.info(f'Timed Callback #{i}, time: {timed_cur_time} us, diff: {timed_diff} us') + assert abs(timed_diff) < 100 - for i in range(0, 5): match = dut.expect(PERIODIC_TIMER_REGEX, timeout=2) cur_time = int(match.group(1)) diff = start_time + (i + 1) * FINAL_TIMER_PERIOD - cur_time - logging.info('Callback #{}, time: {} us, diff: {} us'.format(i, cur_time, diff)) + logging.info(f'Callback #{i}, time: {cur_time} us, diff: {diff} us') assert abs(diff) < 100 if dut.app.sdkconfig.get('SOC_LIGHT_SLEEP_SUPPORTED'): @@ -78,15 +118,21 @@ def test_esp_timer(dut: Dut) -> None: sleep_exit_time = int(match.group(1)) sleep_time = sleep_exit_time - sleep_enter_time - logging.info('Enter sleep: {}, exit sleep: {}, slept: {}'.format(sleep_enter_time, sleep_exit_time, sleep_time)) + logging.info(f'Enter sleep: {sleep_enter_time}, exit sleep: {sleep_exit_time}, slept: {sleep_time}') assert -2000 < sleep_time - LIGHT_SLEEP_TIME < 1000 for i in range(5, 7): + timed_match = dut.expect(TIMED_PERIODIC_TIMER_REGEX, timeout=2) + timed_cur_time = int(timed_match.group(1)) + timed_diff = TIMED_RESTART_TIME + (i - 1) * FINAL_TIMER_PERIOD - timed_cur_time + logging.info(f'Timed Callback #{i}, time: {timed_cur_time} us, diff: {timed_diff} us') + assert abs(timed_diff) < 100 + match = dut.expect(PERIODIC_TIMER_REGEX, timeout=2) cur_time = int(match.group(1)) diff = abs(start_time + (i + 1) * FINAL_TIMER_PERIOD - cur_time) - logging.info('Callback #{}, time: {} us, diff: {} us'.format(i, cur_time, diff)) + logging.info(f'Callback #{i}, time: {cur_time} us, diff: {diff} us') assert diff < 100 dut.expect(STOP_REGEX, timeout=2)