Merge branch 'bugfix/tickless_idle_single_core' into 'master'

freertos, pm: fix tickless idle not entered in single core mode

See merge request idf/esp-idf!3584
This commit is contained in:
Ivan Grokhotkov 2018-11-06 12:15:03 +08:00
commit 28f1e1597b
2 changed files with 48 additions and 8 deletions

View file

@ -81,11 +81,20 @@ static uint32_t s_ccount_div;
static uint32_t s_ccount_mul; static uint32_t s_ccount_mul;
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE #if CONFIG_FREERTOS_USE_TICKLESS_IDLE
/* Indicates if light sleep entry was successful for given CPU. /* Indicates if light sleep entry was skipped in vApplicationSleep for given CPU.
* This in turn gets used in IDLE hook to decide if `waiti` needs * This in turn gets used in IDLE hook to decide if `waiti` needs
* to be invoked or not. * to be invoked or not.
*/ */
static bool s_entered_light_sleep[portNUM_PROCESSORS]; static bool s_skipped_light_sleep[portNUM_PROCESSORS];
#if portNUM_PROCESSORS == 2
/* When light sleep is finished on one CPU, it is possible that the other CPU
* will enter light sleep again very soon, before interrupts on the first CPU
* get a chance to run. To avoid such situation, set a flag for the other CPU to
* skip light sleep attempt.
*/
static bool s_skip_light_sleep[portNUM_PROCESSORS];
#endif // portNUM_PROCESSORS == 2
#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE #endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE
/* Indicates to the ISR hook that CCOMPARE needs to be updated on the given CPU. /* Indicates to the ISR hook that CCOMPARE needs to be updated on the given CPU.
@ -465,10 +474,14 @@ void esp_pm_impl_waiti()
{ {
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE #if CONFIG_FREERTOS_USE_TICKLESS_IDLE
int core_id = xPortGetCoreID(); int core_id = xPortGetCoreID();
if (!s_entered_light_sleep[core_id]) { if (s_skipped_light_sleep[core_id]) {
asm("waiti 0"); asm("waiti 0");
} else { /* Interrupt took the CPU out of waiti and s_rtos_lock_handle[core_id]
s_entered_light_sleep[core_id] = false; * is now taken. However since we are back to idle task, we can release
* the lock so that vApplicationSleep can attempt to enter light sleep.
*/
esp_pm_impl_idle_hook();
s_skipped_light_sleep[core_id] = false;
} }
#else #else
asm("waiti 0"); asm("waiti 0");
@ -477,10 +490,35 @@ void esp_pm_impl_waiti()
#if CONFIG_FREERTOS_USE_TICKLESS_IDLE #if CONFIG_FREERTOS_USE_TICKLESS_IDLE
static inline bool IRAM_ATTR should_skip_light_sleep(int core_id)
{
#if portNUM_PROCESSORS == 2
if (s_skip_light_sleep[core_id]) {
s_skip_light_sleep[core_id] = false;
s_skipped_light_sleep[core_id] = true;
return true;
}
#endif // portNUM_PROCESSORS == 2
if (s_mode != PM_MODE_LIGHT_SLEEP || s_is_switching) {
s_skipped_light_sleep[core_id] = true;
} else {
s_skipped_light_sleep[core_id] = false;
}
return s_skipped_light_sleep[core_id];
}
static inline void IRAM_ATTR other_core_should_skip_light_sleep(int core_id)
{
#if portNUM_PROCESSORS == 2
s_skip_light_sleep[!core_id] = true;
#endif
}
void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime ) void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
{ {
portENTER_CRITICAL(&s_switch_lock); portENTER_CRITICAL(&s_switch_lock);
if (s_mode == PM_MODE_LIGHT_SLEEP && !s_is_switching) { int core_id = xPortGetCoreID();
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();
int64_t now = esp_timer_get_time(); int64_t now = esp_timer_get_time();
@ -494,7 +532,6 @@ void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
#endif #endif
/* Enter sleep */ /* Enter sleep */
int core_id = xPortGetCoreID();
ESP_PM_TRACE_ENTER(SLEEP, core_id); ESP_PM_TRACE_ENTER(SLEEP, core_id);
int64_t sleep_start = esp_timer_get_time(); int64_t sleep_start = esp_timer_get_time();
esp_light_sleep_start(); esp_light_sleep_start();
@ -516,7 +553,7 @@ void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
; ;
} }
} }
s_entered_light_sleep[core_id] = true; other_core_should_skip_light_sleep(core_id);
} }
} }
portEXIT_CRITICAL(&s_switch_lock); portEXIT_CRITICAL(&s_switch_lock);

View file

@ -2147,6 +2147,8 @@ void vTaskSuspendAll( void )
#if ( configUSE_TICKLESS_IDLE != 0 ) #if ( configUSE_TICKLESS_IDLE != 0 )
#if ( portNUM_PROCESSORS > 1 )
static BaseType_t xHaveReadyTasks() static BaseType_t xHaveReadyTasks()
{ {
for (int i = tskIDLE_PRIORITY + 1; i < configMAX_PRIORITIES; ++i) for (int i = tskIDLE_PRIORITY + 1; i < configMAX_PRIORITIES; ++i)
@ -2163,6 +2165,7 @@ void vTaskSuspendAll( void )
return pdFALSE; return pdFALSE;
} }
#endif // portNUM_PROCESSORS > 1
static TickType_t prvGetExpectedIdleTime( void ) static TickType_t prvGetExpectedIdleTime( void )
{ {