mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 19:13:21 +00:00
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:
@@ -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
|
||||
*
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user