freertos,esp32: automatic light sleep support

This commit is contained in:
Ivan Grokhotkov
2018-04-12 18:18:45 +08:00
committed by bot
parent 51aceaa030
commit 028fbb58e8
9 changed files with 404 additions and 8 deletions

View File

@@ -59,6 +59,10 @@ void esp_vApplicationIdleHook()
#ifdef CONFIG_PM_ENABLE #ifdef CONFIG_PM_ENABLE
esp_pm_impl_idle_hook(); esp_pm_impl_idle_hook();
#endif #endif
}
extern void esp_vApplicationWaitiHook( void )
{
asm("waiti 0"); asm("waiti 0");
} }

View File

@@ -22,10 +22,12 @@
#include "esp_pm.h" #include "esp_pm.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_crosscore_int.h" #include "esp_crosscore_int.h"
#include "esp_clk.h"
#include "soc/rtc.h" #include "soc/rtc.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/xtensa_timer.h" #include "freertos/xtensa_timer.h"
#include "xtensa/core-macros.h" #include "xtensa/core-macros.h"
@@ -39,6 +41,16 @@
*/ */
#define CCOMPARE_UPDATE_TIMEOUT 1000000 #define CCOMPARE_UPDATE_TIMEOUT 1000000
/* When changing CCOMPARE, don't allow changes if the difference is less
* than this. This is to prevent setting CCOMPARE below CCOUNT.
*/
#define CCOMPARE_MIN_CYCLES_IN_FUTURE 1000
/* When light sleep is used, wake this number of microseconds earlier than
* the next tick.
*/
#define LIGHT_SLEEP_EARLY_WAKEUP_US 100
#ifdef CONFIG_PM_PROFILING #ifdef CONFIG_PM_PROFILING
#define WITH_PROFILING #define WITH_PROFILING
#endif #endif
@@ -107,7 +119,7 @@ static const char* s_freq_names[] __attribute__((unused)) = {
[RTC_CPU_FREQ_2M] = "2" [RTC_CPU_FREQ_2M] = "2"
}; };
/* Whether automatic light sleep is enabled. Currently always false */ /* Whether automatic light sleep is enabled */
static bool s_light_sleep_en = false; static bool s_light_sleep_en = false;
/* When configuration is changed, current frequency may not match the /* When configuration is changed, current frequency may not match the
@@ -177,9 +189,11 @@ esp_err_t esp_pm_configure(const void* vconfig)
#endif #endif
const esp_pm_config_esp32_t* config = (const esp_pm_config_esp32_t*) vconfig; const esp_pm_config_esp32_t* config = (const esp_pm_config_esp32_t*) vconfig;
#ifndef CONFIG_FREERTOS_USE_TICKLESS_IDLE
if (config->light_sleep_enable) { if (config->light_sleep_enable) {
return ESP_ERR_NOT_SUPPORTED; return ESP_ERR_NOT_SUPPORTED;
} }
#endif
if (config->min_cpu_freq == RTC_CPU_FREQ_2M) { if (config->min_cpu_freq == RTC_CPU_FREQ_2M) {
/* Minimal APB frequency to achieve 1MHz REF_TICK frequency is 5 MHz */ /* Minimal APB frequency to achieve 1MHz REF_TICK frequency is 5 MHz */
@@ -401,10 +415,9 @@ static void IRAM_ATTR do_switch(pm_mode_t new_mode)
*/ */
static void IRAM_ATTR update_ccompare() static void IRAM_ATTR update_ccompare()
{ {
const uint32_t ccompare_min_cycles_in_future = 1000;
uint32_t ccount = XTHAL_GET_CCOUNT(); uint32_t ccount = XTHAL_GET_CCOUNT();
uint32_t ccompare = XTHAL_GET_CCOMPARE(XT_TIMER_INDEX); uint32_t ccompare = XTHAL_GET_CCOMPARE(XT_TIMER_INDEX);
if ((ccompare - ccompare_min_cycles_in_future) - ccount < UINT32_MAX / 2) { if ((ccompare - CCOMPARE_MIN_CYCLES_IN_FUTURE) - ccount < UINT32_MAX / 2) {
uint32_t diff = ccompare - ccount; uint32_t diff = ccompare - ccount;
uint32_t diff_scaled = (diff * s_ccount_mul + s_ccount_div - 1) / s_ccount_div; uint32_t diff_scaled = (diff * s_ccount_mul + s_ccount_div - 1) / s_ccount_div;
if (diff_scaled < _xt_tick_divisor) { if (diff_scaled < _xt_tick_divisor) {
@@ -453,6 +466,56 @@ void IRAM_ATTR esp_pm_impl_isr_hook()
ESP_PM_TRACE_EXIT(ISR_HOOK, core_id); ESP_PM_TRACE_EXIT(ISR_HOOK, core_id);
} }
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
bool IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
{
bool result = false;
portENTER_CRITICAL(&s_switch_lock);
if (s_mode == PM_MODE_LIGHT_SLEEP && !s_is_switching) {
/* Calculate how much we can sleep */
int64_t next_esp_timer_alarm = esp_timer_get_next_alarm();
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;
int64_t sleep_time_us = MIN(wakeup_delay_us, time_until_next_alarm);
if (sleep_time_us >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP * portTICK_PERIOD_MS * 1000LL) {
esp_sleep_enable_timer_wakeup(sleep_time_us - LIGHT_SLEEP_EARLY_WAKEUP_US);
#ifdef CONFIG_PM_TRACE
/* to force tracing GPIOs to keep state */
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
#endif
/* Enter sleep */
int core_id = xPortGetCoreID();
ESP_PM_TRACE_ENTER(SLEEP, core_id);
int64_t sleep_start = esp_timer_get_time();
esp_light_sleep_start();
int64_t slept_us = esp_timer_get_time() - sleep_start;
ESP_PM_TRACE_EXIT(SLEEP, core_id);
uint32_t slept_ticks = slept_us / (portTICK_PERIOD_MS * 1000LL);
if (slept_ticks > 0) {
/* Adjust RTOS tick count based on the amount of time spent in sleep */
vTaskStepTick(slept_ticks);
/* Trigger tick interrupt, since sleep time was longer
* than portTICK_PERIOD_MS. Note that setting INTSET does not
* work for timer interrupt, and changing CCOMPARE would clear
* the interrupt flag.
*/
XTHAL_SET_CCOUNT(XTHAL_GET_CCOMPARE(XT_TIMER_INDEX) - 16);
while (!(XTHAL_GET_INTERRUPT() & BIT(XT_TIMER_INTNUM))) {
;
}
}
result = true;
}
}
portEXIT_CRITICAL(&s_switch_lock);
return result;
}
#endif //CONFIG_FREERTOS_USE_TICKLESS_IDLE
#ifdef WITH_PROFILING #ifdef WITH_PROFILING
void esp_pm_impl_dump_stats(FILE* out) void esp_pm_impl_dump_stats(FILE* out)
{ {

View File

@@ -27,6 +27,7 @@ static const int DRAM_ATTR s_trace_io[] = {
BIT(18), BIT(18), // ESP_PM_TRACE_FREQ_SWITCH BIT(18), BIT(18), // ESP_PM_TRACE_FREQ_SWITCH
BIT(19), BIT(19), // ESP_PM_TRACE_CCOMPARE_UPDATE BIT(19), BIT(19), // ESP_PM_TRACE_CCOMPARE_UPDATE
BIT(25), BIT(26), // ESP_PM_TRACE_ISR_HOOK BIT(25), BIT(26), // ESP_PM_TRACE_ISR_HOOK
BIT(27), BIT(27), // ESP_PM_TRACE_SLEEP
}; };
void esp_pm_trace_init() void esp_pm_trace_init()

View File

@@ -22,6 +22,7 @@ typedef enum {
ESP_PM_TRACE_FREQ_SWITCH, ESP_PM_TRACE_FREQ_SWITCH,
ESP_PM_TRACE_CCOMPARE_UPDATE, ESP_PM_TRACE_CCOMPARE_UPDATE,
ESP_PM_TRACE_ISR_HOOK, ESP_PM_TRACE_ISR_HOOK,
ESP_PM_TRACE_SLEEP,
ESP_PM_TRACE_TYPE_MAX ESP_PM_TRACE_TYPE_MAX
} esp_pm_trace_event_t; } esp_pm_trace_event_t;

View File

@@ -7,7 +7,14 @@
#include "esp_clk.h" #include "esp_clk.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h" #include "esp_log.h"
#include "driver/timer.h"
#include "driver/rtc_io.h"
#include "esp32/ulp.h"
#include "soc/rtc_io_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_gpio_channel.h"
TEST_CASE("Can dump power management lock stats", "[pm]") TEST_CASE("Can dump power management lock stats", "[pm]")
{ {
@@ -48,4 +55,256 @@ TEST_CASE("Can switch frequency using esp_pm_configure", "[pm]")
switch_freq(orig_freq_mhz); switch_freq(orig_freq_mhz);
} }
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE
static void light_sleep_enable()
{
const esp_pm_config_esp32_t pm_config = {
.max_cpu_freq = rtc_clk_cpu_freq_get(),
.min_cpu_freq = RTC_CPU_FREQ_XTAL,
.light_sleep_enable = true
};
ESP_ERROR_CHECK( esp_pm_configure(&pm_config) );
}
static void light_sleep_disable()
{
const esp_pm_config_esp32_t pm_config = {
.max_cpu_freq = rtc_clk_cpu_freq_get(),
.min_cpu_freq = rtc_clk_cpu_freq_get(),
};
ESP_ERROR_CHECK( esp_pm_configure(&pm_config) );
}
TEST_CASE("Automatic light occurs when tasks are suspended", "[pm]")
{
/* To figure out if light sleep takes place, use Timer Group timer.
* It will stop working while in light sleep.
*/
timer_config_t config = {
.counter_dir = TIMER_COUNT_UP,
.divider = 80 /* 1 us per tick */
};
timer_init(TIMER_GROUP_0, TIMER_0, &config);
timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0);
timer_start(TIMER_GROUP_0, TIMER_0);
light_sleep_enable();
for (int ticks_to_delay = CONFIG_FREERTOS_IDLE_TIME_BEFORE_SLEEP;
ticks_to_delay < CONFIG_FREERTOS_IDLE_TIME_BEFORE_SLEEP * 10;
++ticks_to_delay) {
/* Wait until next tick */
vTaskDelay(1);
/* The following delay should cause light sleep to start */
uint64_t count_start;
timer_get_counter_value(TIMER_GROUP_0, TIMER_0, &count_start);
vTaskDelay(ticks_to_delay);
uint64_t count_end;
timer_get_counter_value(TIMER_GROUP_0, TIMER_0, &count_end);
int timer_diff_us = (int) (count_end - count_start);
const int us_per_tick = 1 * portTICK_PERIOD_MS * 1000;
printf("%d %d\n", ticks_to_delay * us_per_tick, timer_diff_us);
TEST_ASSERT(timer_diff_us < ticks_to_delay * us_per_tick);
}
light_sleep_disable();
}
TEST_CASE("Can wake up from automatic light sleep by GPIO", "[pm]")
{
assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 16 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig");
/* Set up GPIO used to wake up RTC */
const int ext1_wakeup_gpio = 25;
const int ext_rtc_io = RTCIO_GPIO25_CHANNEL;
TEST_ESP_OK(rtc_gpio_init(ext1_wakeup_gpio));
rtc_gpio_set_direction(ext1_wakeup_gpio, RTC_GPIO_MODE_INPUT_OUTPUT);
rtc_gpio_set_level(ext1_wakeup_gpio, 0);
/* Enable wakeup */
TEST_ESP_OK(esp_sleep_enable_ext1_wakeup(1ULL << ext1_wakeup_gpio, ESP_EXT1_WAKEUP_ANY_HIGH));
/* To simplify test environment, we'll use a ULP program to set GPIO high */
ulp_insn_t ulp_code[] = {
I_DELAY(65535), /* about 8ms, given 8MHz ULP clock */
I_WR_REG_BIT(RTC_CNTL_HOLD_FORCE_REG, RTC_CNTL_PDAC1_HOLD_FORCE_S, 0),
I_WR_REG_BIT(RTC_GPIO_OUT_REG, ext_rtc_io + RTC_GPIO_OUT_DATA_S, 1),
I_DELAY(1000),
I_WR_REG_BIT(RTC_GPIO_OUT_REG, ext_rtc_io + RTC_GPIO_OUT_DATA_S, 0),
I_WR_REG_BIT(RTC_CNTL_HOLD_FORCE_REG, RTC_CNTL_PDAC1_HOLD_FORCE_S, 1),
I_END(),
I_HALT()
};
TEST_ESP_OK(ulp_set_wakeup_period(0, 1000 /* us */));
size_t size = sizeof(ulp_code)/sizeof(ulp_insn_t);
TEST_ESP_OK(ulp_process_macros_and_load(0, ulp_code, &size));
light_sleep_enable();
for (int i = 0; i < 10; ++i) {
/* Set GPIO low */
REG_CLR_BIT(rtc_gpio_desc[ext1_wakeup_gpio].reg, rtc_gpio_desc[ext1_wakeup_gpio].hold_force);
rtc_gpio_set_level(ext1_wakeup_gpio, 0);
REG_SET_BIT(rtc_gpio_desc[ext1_wakeup_gpio].reg, rtc_gpio_desc[ext1_wakeup_gpio].hold_force);
/* Wait for the next tick */
vTaskDelay(1);
/* Start ULP program */
ulp_run(0);
const int delay_ms = 200;
const int delay_ticks = delay_ms / portTICK_PERIOD_MS;
int64_t start_rtc = esp_clk_rtc_time();
int64_t start_hs = esp_timer_get_time();
uint32_t start_tick = xTaskGetTickCount();
/* Will enter sleep here */
vTaskDelay(delay_ticks);
int64_t end_rtc = esp_clk_rtc_time();
int64_t end_hs = esp_timer_get_time();
uint32_t end_tick = xTaskGetTickCount();
printf("%lld %lld %u\n", end_rtc - start_rtc, end_hs - start_hs, end_tick - start_tick);
TEST_ASSERT_INT32_WITHIN(3, delay_ticks, end_tick - start_tick);
TEST_ASSERT_INT32_WITHIN(2 * portTICK_PERIOD_MS * 1000, delay_ms * 1000, end_hs - start_hs);
TEST_ASSERT_INT32_WITHIN(2 * portTICK_PERIOD_MS * 1000, delay_ms * 1000, end_rtc - start_rtc);
}
REG_CLR_BIT(rtc_gpio_desc[ext1_wakeup_gpio].reg, rtc_gpio_desc[ext1_wakeup_gpio].hold_force);
rtc_gpio_deinit(ext1_wakeup_gpio);
light_sleep_disable();
}
typedef struct {
int delay_us;
int result;
SemaphoreHandle_t done;
} delay_test_arg_t;
static void test_delay_task(void* p)
{
delay_test_arg_t* arg = (delay_test_arg_t*) p;
vTaskDelay(1);
uint64_t start = esp_clk_rtc_time();
vTaskDelay(arg->delay_us / portTICK_PERIOD_MS / 1000);
uint64_t stop = esp_clk_rtc_time();
arg->result = (int) (stop - start);
xSemaphoreGive(arg->done);
vTaskDelete(NULL);
}
TEST_CASE("vTaskDelay duration is correct with light sleep enabled", "[pm]")
{
light_sleep_enable();
delay_test_arg_t args = {
.done = xSemaphoreCreateBinary()
};
const int delays[] = { 10, 20, 50, 100, 150, 200, 250 };
const int delays_count = sizeof(delays) / sizeof(delays[0]);
for (int i = 0; i < delays_count; ++i) {
int delay_ms = delays[i];
args.delay_us = delay_ms * 1000;
xTaskCreatePinnedToCore(test_delay_task, "", 2048, (void*) &args, 3, NULL, 0);
TEST_ASSERT( xSemaphoreTake(args.done, delay_ms * 10 / portTICK_PERIOD_MS) );
printf("CPU0: %d %d\n", args.delay_us, args.result);
TEST_ASSERT_INT32_WITHIN(1000 * portTICK_PERIOD_MS * 2, args.delay_us, args.result);
#if portNUM_PROCESSORS == 2
xTaskCreatePinnedToCore(test_delay_task, "", 2048, (void*) &args, 3, NULL, 1);
TEST_ASSERT( xSemaphoreTake(args.done, delay_ms * 10 / portTICK_PERIOD_MS) );
printf("CPU1: %d %d\n", args.delay_us, args.result);
TEST_ASSERT_INT32_WITHIN(1000 * portTICK_PERIOD_MS * 2, args.delay_us, args.result);
#endif
}
vSemaphoreDelete(args.done);
light_sleep_disable();
}
/* This test is similar to the one in test_esp_timer.c, but since we can't use
* ref_clock, this test uses RTC clock for timing. Also enables automatic
* light sleep.
*/
TEST_CASE("esp_timer produces correct delays with light sleep", "[pm]")
{
// no, we can't make this a const size_t (§6.7.5.2)
#define NUM_INTERVALS 16
typedef struct {
esp_timer_handle_t timer;
size_t cur_interval;
int intervals[NUM_INTERVALS];
int64_t t_start;
SemaphoreHandle_t done;
} test_args_t;
void timer_func(void* arg)
{
test_args_t* p_args = (test_args_t*) arg;
int64_t t_end = esp_clk_rtc_time();
int32_t ms_diff = (t_end - p_args->t_start) / 1000;
printf("timer #%d %dms\n", p_args->cur_interval, ms_diff);
p_args->intervals[p_args->cur_interval++] = ms_diff;
// Deliberately make timer handler run longer.
// We check that this doesn't affect the result.
ets_delay_us(10*1000);
if (p_args->cur_interval == NUM_INTERVALS) {
printf("done\n");
TEST_ESP_OK(esp_timer_stop(p_args->timer));
xSemaphoreGive(p_args->done);
}
}
light_sleep_enable();
const int delay_ms = 100;
test_args_t args = {0};
esp_timer_handle_t timer1;
esp_timer_create_args_t create_args = {
.callback = &timer_func,
.arg = &args,
.name = "timer1",
};
TEST_ESP_OK(esp_timer_create(&create_args, &timer1));
args.timer = timer1;
args.t_start = esp_clk_rtc_time();
args.done = xSemaphoreCreateBinary();
TEST_ESP_OK(esp_timer_start_periodic(timer1, delay_ms * 1000));
TEST_ASSERT(xSemaphoreTake(args.done, delay_ms * NUM_INTERVALS * 2));
TEST_ASSERT_EQUAL_UINT32(NUM_INTERVALS, args.cur_interval);
for (size_t i = 0; i < NUM_INTERVALS; ++i) {
TEST_ASSERT_INT32_WITHIN(portTICK_PERIOD_MS, (i + 1) * delay_ms, args.intervals[i]);
}
TEST_ESP_OK( esp_timer_dump(stdout) );
TEST_ESP_OK( esp_timer_delete(timer1) );
vSemaphoreDelete(args.done);
light_sleep_disable();
#undef NUM_INTERVALS
}
#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
#endif // CONFIG_PM_ENABLE #endif // CONFIG_PM_ENABLE

View File

@@ -357,6 +357,31 @@ config FREERTOS_RUN_TIME_STATS_USING_CPU_CLK
endchoice endchoice
config FREERTOS_USE_TICKLESS_IDLE
bool "Tickless idle support"
depends on PM_ENABLE
default n
help
If power management support is enabled, FreeRTOS will be able to put
the system into light sleep mode when no tasks need to run for a number
of ticks. This number can be set using FREERTOS_IDLE_TIME_BEFORE_SLEEP option.
This feature is also known as "automatic light sleep".
Note that timers created using esp_timer APIs may prevent the system from
entering sleep mode, even when no tasks need to run.
If disabled, automatic light sleep support will be disabled.
config FREERTOS_IDLE_TIME_BEFORE_SLEEP
int "Minimum number of ticks to enter sleep mode for"
depends on FREERTOS_USE_TICKLESS_IDLE
default 3
range 2 4294967295
# Minimal value is 2 because of a check in FreeRTOS.h (search configEXPECTED_IDLE_TIME_BEFORE_SLEEP)
help
FreeRTOS will enter light sleep mode if no tasks need to run for this number
of ticks.
menuconfig FREERTOS_DEBUG_INTERNALS menuconfig FREERTOS_DEBUG_INTERNALS
bool "Debug FreeRTOS internals" bool "Debug FreeRTOS internals"
default n default n

View File

@@ -289,6 +289,10 @@ extern void vPortCleanUpTCB ( void *pxTCB );
#define INCLUDE_eTaskGetState 1 #define INCLUDE_eTaskGetState 1
#define configUSE_QUEUE_SETS 1 #define configUSE_QUEUE_SETS 1
#define configUSE_TICKLESS_IDLE CONFIG_FREERTOS_USE_TICKLESS_IDLE
#if configUSE_TICKLESS_IDLE
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP CONFIG_FREERTOS_IDLE_TIME_BEFORE_SLEEP
#endif //configUSE_TICKLESS_IDLE
#define configXT_BOARD 1 /* Board mode */ #define configXT_BOARD 1 /* Board mode */
#define configXT_SIMULATOR 0 #define configXT_SIMULATOR 0

View File

@@ -365,9 +365,13 @@ typedef struct {
#define PRIVILEGED_DATA #define PRIVILEGED_DATA
#endif #endif
extern void esp_vApplicationIdleHook( void );
extern void esp_vApplicationWaitiHook( void );
void _xt_coproc_release(volatile void * coproc_sa_base); void _xt_coproc_release(volatile void * coproc_sa_base);
bool vApplicationSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( idleTime ) vApplicationSleep( idleTime )
// porttrace // porttrace
#if configUSE_TRACE_FACILITY_2 #if configUSE_TRACE_FACILITY_2

View File

@@ -2151,6 +2151,23 @@ void vTaskSuspendAll( void )
#if ( configUSE_TICKLESS_IDLE != 0 ) #if ( configUSE_TICKLESS_IDLE != 0 )
static BaseType_t xHaveReadyTasks()
{
for (int i = tskIDLE_PRIORITY + 1; i < configMAX_PRIORITIES; ++i)
{
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ i ] ) ) > 0 )
{
return pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
return pdFALSE;
}
static TickType_t prvGetExpectedIdleTime( void ) static TickType_t prvGetExpectedIdleTime( void )
{ {
TickType_t xReturn; TickType_t xReturn;
@@ -2161,7 +2178,18 @@ void vTaskSuspendAll( void )
{ {
xReturn = 0; xReturn = 0;
} }
else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 ) #if portNUM_PROCESSORS > 1
/* This function is called from Idle task; in single core case this
* means that no higher priority tasks are ready to run, and we can
* enter sleep. In SMP case, there might be ready tasks waiting for
* the other CPU, so need to check all ready lists.
*/
else if( xHaveReadyTasks() )
{
xReturn = 0;
}
#endif // portNUM_PROCESSORS > 1
else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > portNUM_PROCESSORS )
{ {
/* There are other idle priority tasks in the ready state. If /* There are other idle priority tasks in the ready state. If
time slicing is used then the very next tick interrupt must be time slicing is used then the very next tick interrupt must be
@@ -3405,7 +3433,6 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
#endif /* configUSE_IDLE_HOOK */ #endif /* configUSE_IDLE_HOOK */
{ {
/* Call the esp-idf hook system */ /* Call the esp-idf hook system */
extern void esp_vApplicationIdleHook( void );
esp_vApplicationIdleHook(); esp_vApplicationIdleHook();
} }
@@ -3417,6 +3444,7 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
#if ( configUSE_TICKLESS_IDLE != 0 ) #if ( configUSE_TICKLESS_IDLE != 0 )
{ {
TickType_t xExpectedIdleTime; TickType_t xExpectedIdleTime;
BaseType_t xEnteredSleep = pdFALSE;
/* It is not desirable to suspend then resume the scheduler on /* It is not desirable to suspend then resume the scheduler on
each iteration of the idle task. Therefore, a preliminary each iteration of the idle task. Therefore, a preliminary
@@ -3427,7 +3455,6 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
{ {
// vTaskSuspendAll();
taskENTER_CRITICAL(&xTaskQueueMutex); taskENTER_CRITICAL(&xTaskQueueMutex);
{ {
/* Now the scheduler is suspended, the expected idle /* Now the scheduler is suspended, the expected idle
@@ -3439,7 +3466,7 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
{ {
traceLOW_POWER_IDLE_BEGIN(); traceLOW_POWER_IDLE_BEGIN();
portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ); xEnteredSleep = portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );
traceLOW_POWER_IDLE_END(); traceLOW_POWER_IDLE_END();
} }
else else
@@ -3448,13 +3475,21 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
} }
} }
taskEXIT_CRITICAL(&xTaskQueueMutex); taskEXIT_CRITICAL(&xTaskQueueMutex);
// ( void ) xTaskResumeAll();
} }
else else
{ {
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
/* It might be possible to enter tickless idle again, so skip
* the fallback sleep hook if tickless idle was successful
*/
if ( !xEnteredSleep )
{
esp_vApplicationWaitiHook();
}
} }
#else
esp_vApplicationWaitiHook();
#endif /* configUSE_TICKLESS_IDLE */ #endif /* configUSE_TICKLESS_IDLE */
} }
} }