mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-04 13:14:32 +02:00
Merge branch 'feature/esp_timer_with_skip_unhandled_events_does_not_wake_up' into 'master'
esp_timer: A timer with skip_unhandled_events won't wake up in light sleep mode See merge request espressif/esp-idf!13219
This commit is contained in:
@@ -622,7 +622,7 @@ void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
|
|||||||
int core_id = xPortGetCoreID();
|
int core_id = xPortGetCoreID();
|
||||||
if (!should_skip_light_sleep(core_id)) {
|
if (!should_skip_light_sleep(core_id)) {
|
||||||
/* Calculate how much we can sleep */
|
/* Calculate how much we can sleep */
|
||||||
int64_t next_esp_timer_alarm = esp_timer_get_next_alarm();
|
int64_t next_esp_timer_alarm = esp_timer_get_next_alarm_for_wake_up();
|
||||||
int64_t now = esp_timer_get_time();
|
int64_t now = esp_timer_get_time();
|
||||||
int64_t time_until_next_alarm = next_esp_timer_alarm - now;
|
int64_t time_until_next_alarm = next_esp_timer_alarm - now;
|
||||||
int64_t wakeup_delay_us = portTICK_PERIOD_MS * 1000LL * xExpectedIdleTime;
|
int64_t wakeup_delay_us = portTICK_PERIOD_MS * 1000LL * xExpectedIdleTime;
|
||||||
|
@@ -360,6 +360,42 @@ TEST_CASE("esp_timer produces correct delays with light sleep", "[pm]")
|
|||||||
#undef NUM_INTERVALS
|
#undef NUM_INTERVALS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void timer_cb1(void *arg)
|
||||||
|
{
|
||||||
|
++*((int*) arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("esp_timer with SKIP_UNHANDLED_EVENTS does not wake up CPU from sleep", "[pm]")
|
||||||
|
{
|
||||||
|
int count_calls = 0;
|
||||||
|
int timer_interval_ms = 50;
|
||||||
|
|
||||||
|
const esp_timer_create_args_t timer_args = {
|
||||||
|
.name = "timer_cb1",
|
||||||
|
.arg = &count_calls,
|
||||||
|
.callback = &timer_cb1,
|
||||||
|
.skip_unhandled_events = true,
|
||||||
|
};
|
||||||
|
esp_timer_handle_t periodic_timer;
|
||||||
|
esp_timer_create(&timer_args, &periodic_timer);
|
||||||
|
TEST_ESP_OK(esp_timer_start_periodic(periodic_timer, timer_interval_ms * 1000));
|
||||||
|
|
||||||
|
light_sleep_enable();
|
||||||
|
|
||||||
|
const unsigned count_delays = 5;
|
||||||
|
unsigned i = count_delays;
|
||||||
|
while (i-- > 0) {
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
|
}
|
||||||
|
TEST_ASSERT_INT_WITHIN(1, count_delays, count_calls);
|
||||||
|
|
||||||
|
light_sleep_disable();
|
||||||
|
|
||||||
|
TEST_ESP_OK(esp_timer_stop(periodic_timer));
|
||||||
|
TEST_ESP_OK(esp_timer_dump(stdout));
|
||||||
|
TEST_ESP_OK(esp_timer_delete(periodic_timer));
|
||||||
|
}
|
||||||
|
|
||||||
#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
|
||||||
|
|
||||||
#endif // CONFIG_PM_ENABLE
|
#endif // CONFIG_PM_ENABLE
|
||||||
|
@@ -195,6 +195,13 @@ int64_t esp_timer_get_time(void);
|
|||||||
*/
|
*/
|
||||||
int64_t esp_timer_get_next_alarm(void);
|
int64_t esp_timer_get_next_alarm(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the timestamp when the next timeout is expected to occur skipping those which have skip_unhandled_events flag
|
||||||
|
* @return Timestamp of the nearest timer event, in microseconds.
|
||||||
|
* The timebase is the same as for the values returned by esp_timer_get_time.
|
||||||
|
*/
|
||||||
|
int64_t esp_timer_get_next_alarm_for_wake_up(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Dump the list of timers to a stream
|
* @brief Dump the list of timers to a stream
|
||||||
*
|
*
|
||||||
|
@@ -598,3 +598,26 @@ int64_t IRAM_ATTR esp_timer_get_next_alarm(void)
|
|||||||
}
|
}
|
||||||
return next_alarm;
|
return next_alarm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t IRAM_ATTR esp_timer_get_next_alarm_for_wake_up(void)
|
||||||
|
{
|
||||||
|
int64_t next_alarm = INT64_MAX;
|
||||||
|
for (esp_timer_dispatch_t dispatch_method = ESP_TIMER_TASK; dispatch_method < ESP_TIMER_MAX; ++dispatch_method) {
|
||||||
|
timer_list_lock(dispatch_method);
|
||||||
|
esp_timer_handle_t it;
|
||||||
|
LIST_FOREACH(it, &s_timers[dispatch_method], list_entry) {
|
||||||
|
if (it == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// timers with the SKIP_UNHANDLED_EVENTS flag do not want to wake up CPU from a sleep mode.
|
||||||
|
if ((it->flags & FL_SKIP_UNHANDLED_EVENTS) == 0) {
|
||||||
|
if (next_alarm > it->alarm) {
|
||||||
|
next_alarm = it->alarm;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timer_list_unlock(dispatch_method);
|
||||||
|
}
|
||||||
|
return next_alarm;
|
||||||
|
}
|
||||||
|
@@ -368,6 +368,7 @@ menu "FreeRTOS"
|
|||||||
|
|
||||||
Note that timers created using esp_timer APIs may prevent the system from
|
Note that timers created using esp_timer APIs may prevent the system from
|
||||||
entering sleep mode, even when no tasks need to run.
|
entering sleep mode, even when no tasks need to run.
|
||||||
|
To skip unnecessary wake-up initialize a timer with the "skip_unhandled_events" option as true.
|
||||||
|
|
||||||
If disabled, automatic light sleep support will be disabled.
|
If disabled, automatic light sleep support will be disabled.
|
||||||
|
|
||||||
|
@@ -82,6 +82,8 @@ you can use the `skip_unhandled_events` option during :cpp:func:`esp_timer_creat
|
|||||||
When the `skip_unhandled_events` is true, if a periodic timer expires one or more times during light sleep
|
When the `skip_unhandled_events` is true, if a periodic timer expires one or more times during light sleep
|
||||||
then only one callback is called on wake.
|
then only one callback is called on wake.
|
||||||
|
|
||||||
|
Using the `skip_unhandled_events` option with `automatic light sleep` (see :doc:`Power Management APIs <power_management>`) helps to reduce the consumption of the system when it is in light sleep. The duration of light sleep is also determined by esp_timers. Timers with `skip_unhandled_events` option will not wake up the system.
|
||||||
|
|
||||||
Handling callbacks
|
Handling callbacks
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
@@ -87,6 +87,8 @@ If none of the locks are acquired, and light sleep is enabled in a call to :cpp:
|
|||||||
|
|
||||||
Light sleep duration will be chosen to wake up the chip before the nearest event (task being unblocked, or timer elapses).
|
Light sleep duration will be chosen to wake up the chip before the nearest event (task being unblocked, or timer elapses).
|
||||||
|
|
||||||
|
To skip unnecessary wake-up you can consider initializing an esp_timer with the `skip_unhandled_events` option as true. Timers with this flag will not wake up the system and it helps to reduce consumption.
|
||||||
|
|
||||||
|
|
||||||
Dynamic Frequency Scaling and Peripheral Drivers
|
Dynamic Frequency Scaling and Peripheral Drivers
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
Reference in New Issue
Block a user