esp_timer: Timers with skip_unhandled_events option won't wake up system from light sleep

This commit is contained in:
KonstantinKondrashov
2021-04-19 20:48:16 +08:00
committed by bot
parent cdad1eaa9c
commit f9ad16bb66
7 changed files with 72 additions and 1 deletions

View File

@@ -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;

View File

@@ -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

View File

@@ -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
* *

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -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
------------------ ------------------

View File

@@ -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
------------------------------------------------ ------------------------------------------------