light sleep: add cpu power down support for esp32c3

This commit is contained in:
Li Shuai
2020-12-24 21:02:32 +08:00
parent 63c4e5481f
commit f168ac3b39
12 changed files with 224 additions and 2 deletions

View File

@@ -72,3 +72,5 @@ entries:
gpio_hal_workaround:gpio_hal_sleep_pupd_config_unapply (noflash)
gpio_hal_workaround:gpio_hal_sleep_mode_setup_wrapper (noflash)
gpio_hal_workaround:gpio_hal_fun_pupd_restore (noflash)
if PM_SLP_IRAM_OPT = y && ESP_SYSTEM_PM_POWER_DOWN_CPU = y:
rtc_cntl_hal:rtc_cntl_hal_enable_cpu_retention (noflash)

View File

@@ -60,6 +60,7 @@
#include "esp32c3/clk.h"
#include "esp32c3/pm.h"
#include "driver/gpio.h"
#include "esp_private/sleep_modes.h"
#endif
#define MHZ (1000000)
@@ -303,6 +304,13 @@ esp_err_t esp_pm_configure(const void* vconfig)
esp_sleep_gpio_status_switch_configure(config->light_sleep_enable);
#endif
#if CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU && SOC_PM_SUPPORT_CPU_PD
esp_err_t ret = esp_sleep_cpu_pd_low_init(config->light_sleep_enable);
if (config->light_sleep_enable && ret != ESP_OK) {
ESP_LOGW(TAG, "Failed to enable CPU power down during light sleep.");
}
#endif
return ESP_OK;
}

View File

@@ -87,4 +87,12 @@ menu "ESP System Settings"
If enabled, chip will try to power down flash at light sleep, which costs more time when chip wakes up.
Only can be enabled if there is no SPIRAM configured.
config ESP_SYSTEM_PM_POWER_DOWN_CPU
bool "Power down CPU in light sleep"
depends on IDF_TARGET_ESP32C3
default y
help
If enabled, the CPU will be powered down in light sleep. Enabling this option will consume
1.68 KB of internal RAM and will reduce sleep current consumption by about 100 uA.
endmenu # ESP System Settings

View File

@@ -0,0 +1,40 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU
/**
* @brief CPU Power down low-level initialize
*
* @param enable enable or disable CPU power down during light sleep
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM not enough retention memory
*/
esp_err_t esp_sleep_cpu_pd_low_init(bool enable);
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -42,6 +42,7 @@ typedef enum {
ESP_PD_DOMAIN_RTC_SLOW_MEM, //!< RTC slow memory
ESP_PD_DOMAIN_RTC_FAST_MEM, //!< RTC fast memory
ESP_PD_DOMAIN_XTAL, //!< XTAL oscillator
ESP_PD_DOMAIN_CPU, //!< CPU core
ESP_PD_DOMAIN_MAX //!< Number of domains
} esp_sleep_pd_domain_t;

View File

@@ -70,6 +70,9 @@
#include "esp32s3/rom/cache.h"
#include "esp32c3/rom/rtc.h"
#include "soc/extmem_reg.h"
#include "esp_heap_caps.h"
#include "hal/rtc_hal.h"
#include "soc/rtc_caps.h"
#endif
// If light sleep time is less than that, don't power down flash
@@ -141,10 +144,13 @@ typedef struct {
uint32_t sleep_time_overhead_out;
uint32_t rtc_clk_cal_period;
uint64_t rtc_ticks_at_sleep_start;
#if SOC_PM_SUPPORT_CPU_PD
void *cpu_pd_mem;
#endif
} sleep_config_t;
static sleep_config_t s_config = {
.pd_options = { ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO },
.pd_options = { ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO },
.ccount_ticks_record = 0,
.sleep_time_overhead_out = DEFAULT_SLEEP_OUT_OVERHEAD_US,
.wakeup_triggers = 0
@@ -259,6 +265,32 @@ static void IRAM_ATTR resume_uarts(void)
inline static uint32_t IRAM_ATTR call_rtc_sleep_start(uint32_t reject_triggers);
#if SOC_PM_SUPPORT_CPU_PD
esp_err_t esp_sleep_cpu_pd_low_init(bool enable)
{
if (enable) {
if (s_config.cpu_pd_mem == NULL) {
void *buf = heap_caps_aligned_alloc(RTC_CNTL_CPU_PD_DMA_ADDR_ALIGN,
RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE + RTC_HAL_DMA_LINK_NODE_SIZE,
MALLOC_CAP_RETENTION|MALLOC_CAP_DEFAULT);
if (buf) {
memset(buf, 0, RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE + RTC_HAL_DMA_LINK_NODE_SIZE);
s_config.cpu_pd_mem = rtc_cntl_hal_dma_link_init(buf,
buf+RTC_HAL_DMA_LINK_NODE_SIZE, RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE, NULL);
} else {
return ESP_ERR_NO_MEM;
}
}
} else {
if (s_config.cpu_pd_mem) {
heap_caps_free(s_config.cpu_pd_mem);
s_config.cpu_pd_mem = NULL;
}
}
return ESP_OK;
}
#endif // SOC_PM_SUPPORT_CPU_PD
#if SOC_GPIO_SUPPORT_SLP_SWITCH
#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
static inline void gpio_sleep_mode_config_apply(void)
@@ -434,6 +466,10 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
s_config.ccount_ticks_record = cpu_ll_get_cycle_count();
}
#if SOC_PM_SUPPORT_CPU_PD
rtc_cntl_hal_disable_cpu_retention();
#endif
#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
gpio_sleep_mode_config_unapply();
#endif
@@ -591,6 +627,10 @@ esp_err_t esp_light_sleep_start(void)
periph_inform_out_light_sleep_overhead(s_config.sleep_time_adjustment - sleep_time_overhead_in);
#if SOC_PM_SUPPORT_CPU_PD
rtc_cntl_hal_enable_cpu_retention(s_config.cpu_pd_mem);
#endif
rtc_vddsdio_config_t vddsdio_config = rtc_vddsdio_get_config();
// Safety net: enable WDT in case exit from light sleep fails
@@ -1046,6 +1086,12 @@ static uint32_t get_power_down_flags(void)
#endif // SOC_TOUCH_PAD_WAKE_SUPPORTED
}
#if !SOC_PM_SUPPORT_CPU_PD
if (s_config.pd_options[ESP_PD_DOMAIN_CPU] == ESP_PD_OPTION_AUTO) {
s_config.pd_options[ESP_PD_DOMAIN_CPU] = ESP_PD_OPTION_ON;
}
#endif
if (s_config.pd_options[ESP_PD_DOMAIN_XTAL] == ESP_PD_OPTION_AUTO) {
s_config.pd_options[ESP_PD_DOMAIN_XTAL] = ESP_PD_OPTION_OFF;
}
@@ -1071,6 +1117,12 @@ static uint32_t get_power_down_flags(void)
pd_flags |= RTC_SLEEP_PD_RTC_PERIPH;
}
#if SOC_PM_SUPPORT_CPU_PD
if (s_config.pd_options[ESP_PD_DOMAIN_CPU] != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_CPU;
}
#endif
#ifdef CONFIG_IDF_TARGET_ESP32
pd_flags |= RTC_SLEEP_PD_XTAL;
#endif

View File

@@ -92,7 +92,8 @@ if(NOT BOOTLOADER_BUILD)
"esp32c3/systimer_hal.c"
"esp32c3/hmac_hal.c"
"spi_flash_hal_gpspi.c"
"spi_slave_hd_hal.c")
"spi_slave_hd_hal.c"
"esp32c3/rtc_cntl_hal.c")
endif()
endif()

View File

@@ -17,6 +17,7 @@
#include "soc/soc.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/apb_ctrl_reg.h"
#ifdef __cplusplus
extern "C" {
@@ -47,6 +48,21 @@ static inline void rtc_cntl_ll_ext1_clear_wakeup_pins(void)
REG_SET_BIT(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_WAKEUP_STATUS_CLR);
}
static inline void rtc_cntl_ll_enable_cpu_retention(uint32_t addr)
{
/* write memory address to register */
REG_SET_FIELD(APB_CTRL_RETENTION_CTRL_REG, APB_CTRL_RETENTION_LINK_ADDR, (uint32_t)addr);
/* Enable clock */
REG_SET_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN);
/* Enable retention when cpu sleep enable */
REG_SET_BIT(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_EN);
}
static inline void rtc_cntl_ll_disable_cpu_retention(void)
{
REG_CLR_BIT(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_EN);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,61 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The HAL layer for RTC CNTL (common part)
#include "hal/rtc_hal.h"
#include "soc/soc_caps.h"
#include "esp32c3/rom/lldesc.h"
#include "esp_attr.h"
#define RTC_CNTL_HAL_LINK_BUF_SIZE_MIN (RTC_CNTL_CPU_PD_DMA_BLOCK_SIZE) /* The minimum size of dma link buffer */
typedef struct rtc_cntl_link_buf_conf {
uint32_t cfg[4]; /* 4 word for dma link buffer configuration */
} rtc_cntl_link_buf_conf_t;
void * rtc_cntl_hal_dma_link_init(void *elem, void *buff, int size, void *next)
{
assert(elem != NULL);
assert(buff != NULL);
assert(size >= RTC_CNTL_HAL_LINK_BUF_SIZE_MIN);
lldesc_t *plink = (lldesc_t *)elem;
plink->eof = next ? 0 : 1;
plink->owner = 1;
plink->size = size >> 4; /* in unit of 16 bytes */
plink->length = size >> 4;
plink->buf = buff;
plink->offset = 0;
plink->sosf = 0;
STAILQ_NEXT(plink, qe) = next;
return (void *)plink;
}
void rtc_cntl_hal_enable_cpu_retention(void *addr)
{
if (addr) {
lldesc_t *plink = (lldesc_t *)addr;
/* dma link buffer configure */
rtc_cntl_link_buf_conf_t *pbuf = (rtc_cntl_link_buf_conf_t *)plink->buf;
pbuf->cfg[0] = 0;
pbuf->cfg[1] = 0;
pbuf->cfg[2] = 0;
pbuf->cfg[3] = (uint32_t)-1;
rtc_cntl_ll_enable_cpu_retention((uint32_t)addr);
}
}

View File

@@ -18,6 +18,8 @@
#include "hal/rtc_io_ll.h"
#include "hal/rtc_cntl_ll.h"
#define RTC_HAL_DMA_LINK_NODE_SIZE (16)
#define rtc_hal_ext1_get_wakeup_pins() rtc_cntl_ll_ext1_get_wakeup_pins()
#define rtc_hal_ext1_set_wakeup_pins(mask, mode) rtc_cntl_ll_ext1_set_wakeup_pins(mask, mode)
@@ -26,6 +28,12 @@
#define rtc_hal_set_wakeup_timer(ticks) rtc_cntl_ll_set_wakeup_timer(ticks)
void * rtc_cntl_hal_dma_link_init(void *elem, void *buff, int size, void *next);
void rtc_cntl_hal_enable_cpu_retention(void *addr);
#define rtc_cntl_hal_disable_cpu_retention() rtc_cntl_ll_disable_cpu_retention()
/*
* Enable wakeup from ULP coprocessor.
*/

View File

@@ -0,0 +1,22 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#define RTC_CNTL_CPU_PD_DMA_BUS_WIDTH (128)
#define RTC_CNTL_CPU_PD_REG_FILE_NUM (108)
#define RTC_CNTL_CPU_PD_DMA_ADDR_ALIGN (RTC_CNTL_CPU_PD_DMA_BUS_WIDTH >> 3)
#define RTC_CNTL_CPU_PD_DMA_BLOCK_SIZE (RTC_CNTL_CPU_PD_DMA_BUS_WIDTH >> 3)
#define RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE (RTC_CNTL_CPU_PD_REG_FILE_NUM * (RTC_CNTL_CPU_PD_DMA_BUS_WIDTH >> 3))

View File

@@ -44,6 +44,7 @@
#include "rmt_caps.h"
#include "spi_caps.h"
#include "uart_caps.h"
#include "rtc_caps.h"
/*-------------------------- TOUCH SENSOR CAPS -------------------------------*/
#define SOC_TOUCH_SENSOR_NUM (0) /*! No touch sensors on ESP32-C3 */
@@ -126,3 +127,5 @@
#define SOC_PM_SUPPORT_WIFI_WAKEUP (1)
#define SOC_PM_SUPPORT_BT_WAKEUP (1)
#define SOC_PM_SUPPORT_CPU_PD (1)