Merge branch 'contrib/github_pr_17807' into 'master'

Support absolute timings for ESP Timer (High Resolution Timer) (GitHub PR)

Closes IDFGH-16718

See merge request espressif/esp-idf!43231
This commit is contained in:
Konstantin Kondrashov
2025-12-10 23:36:25 +08:00
6 changed files with 280 additions and 83 deletions
+54 -1
View File
@@ -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,23 @@ 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 with absolute alarm time
*
* This function starts a one-shot timer that will trigger once at the specified absolute time.
* To start a timer relative to the current time, see esp_timer_start_once().
* 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 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 +189,24 @@ 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 with absolute alarm time
*
* 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.
* To start a periodic timer relative to the current time, see esp_timer_start_periodic().
*
* @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 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 +225,24 @@ 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 with absolute alarm time
*
* 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 `period_us` microseconds. Next alarm is at `first_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 first_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 in the past
*/
esp_err_t esp_timer_restart_at(esp_timer_handle_t timer, uint64_t period_us, uint64_t first_alarm_us);
/**
* @brief Stop a running timer
*
+51 -35
View File
@@ -65,6 +65,7 @@ static esp_err_t timer_remove(esp_timer_handle_t timer);
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 timer_restart(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);
@@ -133,6 +134,20 @@ esp_err_t esp_timer_create(const esp_timer_create_args_t* args,
* in IRAM when PM_SLP_IRAM_OPT = y and ESP_TASK_WDT USE ESP_TIMER = y.
*/
esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_restart(esp_timer_handle_t timer, uint64_t timeout_us)
{
return timer_restart(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 first_alarm_us)
{
const uint64_t min_overhead_us = esp_timer_impl_get_min_period_us();
if (first_alarm_us + min_overhead_us < esp_timer_impl_get_time()) {
return ESP_ERR_INVALID_ARG;
}
return timer_restart(timer, period_us, first_alarm_us);
}
static esp_err_t ESP_TIMER_IRAM_ATTR timer_restart(esp_timer_handle_t timer, uint64_t timeout_us, uint64_t first_alarm_us)
{
esp_err_t ret = ESP_OK;
@@ -163,11 +178,11 @@ esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_restart(esp_timer_handle_t timer, uint64
/* Remove function got rid of the alarm and period fields, restore them */
const uint64_t min_period = esp_timer_impl_get_min_period_us();
const uint64_t new_period = MAX(timeout_us, min_period);
timer->alarm = now + new_period;
timer->alarm = (first_alarm_us != 0) ? first_alarm_us : now + new_period;
timer->period = new_period;
} else {
/* The new one-shot alarm shall be triggered timeout_us after the current time */
timer->alarm = now + timeout_us;
timer->alarm = (first_alarm_us != 0) ? first_alarm_us : now + timeout_us;
timer->period = 0;
}
ret = timer_insert(timer, false);
@@ -178,7 +193,7 @@ esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_restart(esp_timer_handle_t timer, uint64
return ret;
}
esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_start_once(esp_timer_handle_t timer, uint64_t timeout_us)
static esp_err_t ESP_TIMER_IRAM_ATTR timer_init(esp_timer_handle_t timer, uint64_t period_us, uint64_t first_alarm_us)
{
if (timer == NULL) {
return ESP_ERR_INVALID_ARG;
@@ -186,7 +201,7 @@ 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;
esp_timer_dispatch_t dispatch_method = timer->flags & FL_ISR_DISPATCH_METHOD;
esp_err_t err;
@@ -200,37 +215,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->period = 0;
#if WITH_PROFILING
timer->times_armed++;
#endif
err = timer_insert(timer, false);
}
timer_list_unlock(dispatch_method);
return err;
}
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;
}
if (!is_initialized()) {
return ESP_ERR_INVALID_STATE;
}
uint64_t min_period = esp_timer_impl_get_min_period_us();
period_us = MAX(period_us, min_period);
int64_t alarm = esp_timer_get_time() + period_us;
esp_timer_dispatch_t dispatch_method = timer->flags & FL_ISR_DISPATCH_METHOD;
esp_err_t err;
timer_list_lock(dispatch_method);
/* Check if the timer is armed once the list is locked to avoid a data race */
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++;
@@ -242,6 +227,37 @@ esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_start_periodic(esp_timer_handle_t timer,
return err;
}
esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_start_once(esp_timer_handle_t timer, uint64_t timeout_us)
{
return timer_init(timer, 0, 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)
{
const uint64_t min_overhead_us = esp_timer_impl_get_min_period_us();
if (alarm_us + min_overhead_us < esp_timer_impl_get_time()) {
return ESP_ERR_INVALID_ARG;
}
return timer_init(timer, 0, alarm_us);
}
esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period_us)
{
uint64_t min_period = esp_timer_impl_get_min_period_us();
period_us = MAX(period_us, min_period);
return timer_init(timer, period_us, esp_timer_get_time() + 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)
{
const uint64_t min_overhead_us = esp_timer_impl_get_min_period_us();
if (first_alarm_us + min_overhead_us < esp_timer_impl_get_time()) {
return ESP_ERR_INVALID_ARG;
}
period_us = MAX(period_us, min_overhead_us);
return timer_init(timer, period_us, first_alarm_us);
}
esp_err_t ESP_TIMER_IRAM_ATTR esp_timer_stop(esp_timer_handle_t timer)
{
if (timer == NULL) {
+5 -4
View File
@@ -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` to invoke the callback after a specified timeout duration, or :cpp:func:`esp_timer_start_once_at` to invoke it at a specific absolute time.
- To start the timer in periodic mode, call :cpp:func:`esp_timer_start_periodic` to invoke the callback repeatedly at regular intervals, or :cpp:func:`esp_timer_start_periodic_at` to start the first invocation at a specific absolute time and then repeat at regular intervals; 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
+68 -31
View File
@@ -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
@@ -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,17 @@ 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 +60,19 @@ 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 +103,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 +117,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 +135,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);
}
+54 -8
View File
@@ -12,13 +12,16 @@ STARTING_TIMERS_REGEX = r'Started timers, time since boot: (\d+) us'
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 @@ INITIAL_TIMER_PERIOD = 500000
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 @@ ONE_SHOT_TIMER_PERIOD = 5000000
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)