mirror of
https://github.com/espressif/esp-idf.git
synced 2026-05-28 16:46:31 +03:00
feat(esp_timer): Support absolute timing APIs
Merges https://github.com/espressif/esp-idf/pull/17807
This commit is contained in:
committed by
Konstantin Kondrashov
parent
d18019de5b
commit
b3ccc1316d
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user