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:
Angus Gratton
2021-06-29 08:10:51 +00:00
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();
if (!should_skip_light_sleep(core_id)) {
/* 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 time_until_next_alarm = next_esp_timer_alarm - now;
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
}
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_PM_ENABLE

View File

@@ -195,6 +195,13 @@ int64_t esp_timer_get_time(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
*

View File

@@ -598,3 +598,26 @@ int64_t IRAM_ATTR esp_timer_get_next_alarm(void)
}
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
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.

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

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