Merge branch 'feature/gpio_slp_leakage_current_opt' into 'master'

components/pm: Add gpio configure workaround at slept status

Closes IDF-2637

See merge request espressif/esp-idf!11292
This commit is contained in:
Jiang Jiang Jian 2021-01-15 18:07:54 +08:00
commit 46b29f8c6b
18 changed files with 913 additions and 1 deletions

View File

@ -114,4 +114,18 @@ menu "Driver configurations"
endmenu # RTCIO Configuration
menu "GPIO Configuration"
visible if IDF_TARGET_ESP32
config GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
bool "Support light sleep GPIO pullup/pulldown configuration for ESP32"
depends on IDF_TARGET_ESP32
help
This option is intended to fix the bug that ESP32 is not able to switch to configured
pullup/pulldown mode in sleep.
If this option is selected, chip will automatically emulate the behaviour of switching,
and about 450B of source codes would be placed into IRAM.
endmenu # GPIO Configuration
endmenu # Driver configurations

View File

@ -704,3 +704,177 @@ void gpio_iomux_out(uint8_t gpio_num, int func, bool oen_inv)
{
gpio_hal_iomux_out(gpio_context.gpio_hal, gpio_num, func, (uint32_t)oen_inv);
}
#if SOC_GPIO_SUPPORT_SLP_SWITCH
static esp_err_t gpio_sleep_pullup_en(gpio_num_t gpio_num)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&gpio_context.gpio_spinlock);
gpio_hal_sleep_pullup_en(gpio_context.gpio_hal, gpio_num);
portEXIT_CRITICAL(&gpio_context.gpio_spinlock);
return ESP_OK;
}
static esp_err_t gpio_sleep_pullup_dis(gpio_num_t gpio_num)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&gpio_context.gpio_spinlock);
gpio_hal_sleep_pullup_dis(gpio_context.gpio_hal, gpio_num);
portEXIT_CRITICAL(&gpio_context.gpio_spinlock);
return ESP_OK;
}
static esp_err_t gpio_sleep_pulldown_en(gpio_num_t gpio_num)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&gpio_context.gpio_spinlock);
gpio_hal_sleep_pulldown_en(gpio_context.gpio_hal, gpio_num);
portEXIT_CRITICAL(&gpio_context.gpio_spinlock);
return ESP_OK;
}
static esp_err_t gpio_sleep_pulldown_dis(gpio_num_t gpio_num)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&gpio_context.gpio_spinlock);
gpio_hal_sleep_pulldown_dis(gpio_context.gpio_hal, gpio_num);
portEXIT_CRITICAL(&gpio_context.gpio_spinlock);
return ESP_OK;
}
static esp_err_t gpio_sleep_input_disable(gpio_num_t gpio_num)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
gpio_hal_sleep_input_disable(gpio_context.gpio_hal, gpio_num);
return ESP_OK;
}
static esp_err_t gpio_sleep_input_enable(gpio_num_t gpio_num)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
gpio_hal_sleep_input_enable(gpio_context.gpio_hal, gpio_num);
return ESP_OK;
}
static esp_err_t gpio_sleep_output_disable(gpio_num_t gpio_num)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
gpio_hal_sleep_output_disable(gpio_context.gpio_hal, gpio_num);
return ESP_OK;
}
static esp_err_t gpio_sleep_output_enable(gpio_num_t gpio_num)
{
GPIO_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "GPIO output gpio_num error", ESP_ERR_INVALID_ARG);
gpio_hal_sleep_output_enable(gpio_context.gpio_hal, gpio_num);
return ESP_OK;
}
esp_err_t gpio_sleep_set_direction(gpio_num_t gpio_num, gpio_mode_t mode)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
if ((GPIO_IS_VALID_OUTPUT_GPIO(gpio_num) != true) && (mode & GPIO_MODE_DEF_OUTPUT)) {
ESP_LOGE(GPIO_TAG, "io_num=%d can only be input", gpio_num);
return ESP_ERR_INVALID_ARG;
}
esp_err_t ret = ESP_OK;
if (mode & GPIO_MODE_DEF_INPUT) {
gpio_sleep_input_enable(gpio_num);
} else {
gpio_sleep_input_disable(gpio_num);
}
if (mode & GPIO_MODE_DEF_OUTPUT) {
gpio_sleep_output_enable(gpio_num);
} else {
gpio_sleep_output_disable(gpio_num);
}
return ret;
}
esp_err_t gpio_sleep_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
GPIO_CHECK(pull <= GPIO_FLOATING, "GPIO pull mode error", ESP_ERR_INVALID_ARG);
esp_err_t ret = ESP_OK;
switch (pull) {
case GPIO_PULLUP_ONLY:
gpio_sleep_pulldown_dis(gpio_num);
gpio_sleep_pullup_en(gpio_num);
break;
case GPIO_PULLDOWN_ONLY:
gpio_sleep_pulldown_en(gpio_num);
gpio_sleep_pullup_dis(gpio_num);
break;
case GPIO_PULLUP_PULLDOWN:
gpio_sleep_pulldown_en(gpio_num);
gpio_sleep_pullup_en(gpio_num);
break;
case GPIO_FLOATING:
gpio_sleep_pulldown_dis(gpio_num);
gpio_sleep_pullup_dis(gpio_num);
break;
default:
ESP_LOGE(GPIO_TAG, "Unknown pull up/down mode,gpio_num=%u,pull=%u", gpio_num, pull);
ret = ESP_ERR_INVALID_ARG;
break;
}
return ret;
}
esp_err_t gpio_sleep_sel_en(gpio_num_t gpio_num)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&gpio_context.gpio_spinlock);
gpio_hal_sleep_sel_en(gpio_context.gpio_hal, gpio_num);
portEXIT_CRITICAL(&gpio_context.gpio_spinlock);
return ESP_OK;
}
esp_err_t gpio_sleep_sel_dis(gpio_num_t gpio_num)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
portENTER_CRITICAL(&gpio_context.gpio_spinlock);
gpio_hal_sleep_sel_dis(gpio_context.gpio_hal, gpio_num);
portEXIT_CRITICAL(&gpio_context.gpio_spinlock);
return ESP_OK;
}
#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
esp_err_t gpio_sleep_pupd_config_apply(gpio_num_t gpio_num)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
gpio_hal_sleep_pupd_config_apply(gpio_context.gpio_hal, gpio_num);
return ESP_OK;
}
esp_err_t gpio_sleep_pupd_config_unapply(gpio_num_t gpio_num)
{
GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
gpio_hal_sleep_pupd_config_unapply(gpio_context.gpio_hal, gpio_num);
return ESP_OK;
}
#endif
#endif

View File

@ -445,6 +445,82 @@ esp_err_t gpio_force_hold_all(void);
esp_err_t gpio_force_unhold_all(void);
#endif
#if SOC_GPIO_SUPPORT_SLP_SWITCH
/**
* @brief Enable SLP_SEL to change GPIO status automantically in lightsleep.
* @param gpio_num GPIO number of the pad.
*
* @return
* - ESP_OK Success
*
*/
esp_err_t gpio_sleep_sel_en(gpio_num_t gpio_num);
/**
* @brief Disable SLP_SEL to change GPIO status automantically in lightsleep.
* @param gpio_num GPIO number of the pad.
*
* @return
* - ESP_OK Success
*
*/
esp_err_t gpio_sleep_sel_dis(gpio_num_t gpio_num);
/**
* @brief GPIO set direction at sleep
*
* Configure GPIO direction,such as output_only,input_only,output_and_input
*
* @param gpio_num Configure GPIO pins number, it should be GPIO number. If you want to set direction of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
* @param mode GPIO direction
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO error
*
*/
esp_err_t gpio_sleep_set_direction(gpio_num_t gpio_num, gpio_mode_t mode);
/**
* @brief Configure GPIO pull-up/pull-down resistors at sleep
*
* Only pins that support both input & output have integrated pull-up and pull-down resistors. Input-only GPIOs 34-39 do not.
*
* @param gpio_num GPIO number. If you want to set pull up or down mode for e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
* @param pull GPIO pull up/down mode.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG : Parameter error
*
*/
esp_err_t gpio_sleep_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull);
#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
/**
* @brief Emulate ESP32S2 behaviour to backup FUN_PU, FUN_PD information
*
* @note Need to be called before sleep.
*
* @return
* - ESP_OK Success
*
* */
esp_err_t gpio_sleep_pupd_config_apply(gpio_num_t gpio_num);
/**
* @brief Emulate ESP32S2 behaviour to restore FUN_PU, FUN_PD information
*
* @note Need to be called after sleep.
*
* @return
* - ESP_OK Success
*
* */
esp_err_t gpio_sleep_pupd_config_unapply(gpio_num_t gpio_num);
#endif
#endif
#ifdef __cplusplus
}
#endif

View File

@ -77,4 +77,17 @@ menu "Power Management"
This feature is intended to be used when lower power consumption is needed
while there is enough place in IRAM to place source code.
config PM_SLP_DISABLE_GPIO
bool "Disable all GPIO when chip at sleep"
depends on FREERTOS_USE_TICKLESS_IDLE
help
This feature is intended to disable all GPIO pins at automantic sleep to get a lower power mode.
If enabled, chips will disable all GPIO pins at automantic sleep to reduce about 200~300 uA current.
If you want to specifically use some pins normally as chip wakes when chip sleeps,
you can call 'gpio_sleep_sel_dis' to disable this feature on those pins.
You can also keep this feature on and call 'gpio_sleep_set_direction' and 'gpio_sleep_set_pull_mode'
to have a different GPIO configuration at sleep.
Waring: If you want to enable this option on ESP32, you should enable `GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL`
at first, otherwise you will not be able to switch pullup/pulldown mode.
endmenu # "Power Management"

View File

@ -51,3 +51,22 @@ entries:
esp_time_impl:esp_rtc_get_time_us (noflash)
esp_time_impl:esp_clk_slowclk_cal_set (noflash)
esp_time_impl:esp_set_time_from_rtc (noflash)
[mapping:driver_pm]
archive: libdriver.a
entries:
if GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL = y:
gpio:gpio_sleep_pupd_config_unapply (noflash)
if PM_SLP_IRAM_OPT = y:
gpio:gpio_sleep_pupd_config_apply (noflash)
[mapping:hal_pm]
archive: libhal.a
entries:
if GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL = y:
if PM_SLP_IRAM_OPT = y:
gpio_hal_workaround (noflash)
else:
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)

View File

@ -46,9 +46,11 @@
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/clk.h"
#include "esp32/pm.h"
#include "driver/gpio.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/clk.h"
#include "esp32s2/pm.h"
#include "driver/gpio.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/clk.h"
#include "esp32s3/pm.h"
@ -283,6 +285,10 @@ esp_err_t esp_pm_configure(const void* vconfig)
s_config_changed = true;
portEXIT_CRITICAL(&s_switch_lock);
#if CONFIG_PM_SLP_DISABLE_GPIO && SOC_GPIO_SUPPORT_SLP_SWITCH
esp_sleep_gpio_status_switch_configure(config->light_sleep_enable);
#endif
return ESP_OK;
}
@ -697,6 +703,9 @@ void esp_pm_impl_init(void)
esp_pm_trace_init();
#endif
#if CONFIG_PM_SLP_DISABLE_GPIO && SOC_GPIO_SUPPORT_SLP_SWITCH
esp_sleep_gpio_status_init();
#endif
ESP_ERROR_CHECK(esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "rtos0",
&s_rtos_lock_handle[0]));
ESP_ERROR_CHECK(esp_pm_lock_acquire(s_rtos_lock_handle[0]));

View File

@ -20,6 +20,8 @@
#include "hal/touch_sensor_types.h"
#include "hal/gpio_types.h"
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -382,6 +384,19 @@ void esp_default_wake_deep_sleep(void);
*/
void esp_deep_sleep_disable_rom_logging(void);
#if SOC_GPIO_SUPPORT_SLP_SWITCH
/**
* @brief Disable all GPIO pins at slept status.
*
*/
void esp_sleep_gpio_status_init(void);
/**
* @brief Configure GPIO pins status switching between slept status and waked status.
* @param enable decide whether to switch status or not
*/
void esp_sleep_gpio_status_switch_configure(bool enable);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -53,11 +53,13 @@
#include "esp32/rom/cache.h"
#include "esp32/clk.h"
#include "esp32/rom/rtc.h"
#include "driver/gpio.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/clk.h"
#include "esp32s2/rom/cache.h"
#include "esp32s2/rom/rtc.h"
#include "soc/extmem_reg.h"
#include "driver/gpio.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/clk.h"
#include "esp32s3/rom/cache.h"
@ -273,6 +275,58 @@ static void IRAM_ATTR resume_uarts(void)
inline static uint32_t IRAM_ATTR call_rtc_sleep_start(uint32_t reject_triggers);
#if SOC_GPIO_SUPPORT_SLP_SWITCH
#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
static inline void gpio_sleep_mode_config_apply(void)
{
for (gpio_num_t gpio_num = GPIO_NUM_0; gpio_num < GPIO_NUM_MAX; gpio_num++) {
if (GPIO_IS_VALID_GPIO(gpio_num)) {
gpio_sleep_pupd_config_apply(gpio_num);
}
}
}
static inline void gpio_sleep_mode_config_unapply(void)
{
for (gpio_num_t gpio_num = GPIO_NUM_0; gpio_num < GPIO_NUM_MAX; gpio_num++) {
if (GPIO_IS_VALID_GPIO(gpio_num)) {
gpio_sleep_pupd_config_unapply(gpio_num);
}
}
}
#endif
void esp_sleep_gpio_status_init(void)
{
ESP_LOGI(TAG, "Init to disable all pins at light sleep");
for (gpio_num_t gpio_num = GPIO_NUM_0; gpio_num < GPIO_NUM_MAX; gpio_num++) {
if (GPIO_IS_VALID_GPIO(gpio_num)) {
gpio_sleep_set_direction(gpio_num, GPIO_MODE_DISABLE);
gpio_sleep_set_pull_mode(gpio_num, GPIO_FLOATING);
}
}
}
void esp_sleep_gpio_status_switch_configure(bool enable)
{
if (enable) {
ESP_LOGI(TAG, "Light sleep enabled, start GPIO status switching");
} else {
ESP_LOGI(TAG, "Light sleep disabled, stop GPIO status switching");
}
for (gpio_num_t gpio_num = GPIO_NUM_0; gpio_num < GPIO_NUM_MAX; gpio_num++) {
if (GPIO_IS_VALID_GPIO(gpio_num)) {
if (enable) {
gpio_sleep_sel_en(gpio_num);
} else {
gpio_sleep_sel_dis(gpio_num);
}
}
}
}
#endif
static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
{
// Stop UART output so that output is not lost due to APB frequency change.
@ -313,6 +367,9 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
if (s_config.wakeup_triggers & RTC_ULP_TRIG_EN) {
rtc_hal_ulp_wakeup_enable();
}
#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
gpio_sleep_mode_config_apply();
#endif
#endif
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
@ -391,6 +448,9 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
s_config.ccount_ticks_record = cpu_ll_get_cycle_count();
}
#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
gpio_sleep_mode_config_unapply();
#endif
// re-enable UART output
resume_uarts();

View File

@ -43,7 +43,8 @@ if(NOT BOOTLOADER_BUILD)
"esp32/adc_hal.c"
"esp32/brownout_hal.c"
"esp32/interrupt_descriptor_table.c"
"esp32/touch_sensor_hal.c")
"esp32/touch_sensor_hal.c"
"esp32/gpio_hal_workaround.c")
if(NOT BOOTLOADER_BUILD AND CONFIG_ETH_USE_ESP32_EMAC)
list(APPEND srcs "esp32/emac_hal.c")
endif()

View File

@ -0,0 +1,119 @@
// 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 GPIO (common part)
//
#include "esp_attr.h"
#include "soc/soc.h"
#include "hal/gpio_hal.h"
#include "soc/soc_caps.h"
#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
typedef struct gpio_slp_mode_cfg {
volatile uint16_t fun_pu[((SOC_GPIO_PIN_COUNT-1) >> 4) + 1];
volatile uint16_t fun_pd[((SOC_GPIO_PIN_COUNT-1) >> 4) + 1];
} gpio_slp_mode_cfg_t;
static void gpio_hal_sleep_mode_setup_wrapper(
gpio_hal_context_t *hal,
gpio_num_t gpio_num,
void (*opt)(gpio_hal_context_t *, gpio_num_t, void *)
)
{
static DRAM_ATTR gpio_slp_mode_cfg_t gpio_cfg;
if (opt) {
(*opt)(hal, gpio_num, (void *)&gpio_cfg);
}
}
/**
* @brief GPIO pu/pd information backup function
* @param hal gpio hal
* @param gpio_num gpio num
* @param args pointer for bitmap to backup GPIO pu/pd information
*/
static void gpio_hal_fun_pupd_backup(gpio_hal_context_t *hal, gpio_num_t gpio_num, void *args)
{
/* On ESP32, setting SLP_PU, SLP_PD couldn`t change GPIO status
* from FUN_PU, FUN_PD to SLP_PU, SLP_PD at sleep.
* On the ESP32S2, it does.
* The following code emulates ESP32S2`s behavior:
*/
gpio_slp_mode_cfg_t *pcfg = (gpio_slp_mode_cfg_t *)args;
if (gpio_ll_sleep_sel_is_enabled(hal->dev, gpio_num)) {
/* Record fun_pu and fun_pd state in bitmap */
if (gpio_ll_pullup_is_enabled(hal->dev, gpio_num)) {
pcfg->fun_pu[gpio_num >> 4] |= BIT(gpio_num & 0xf);
} else {
pcfg->fun_pu[gpio_num >> 4] &= ~BIT(gpio_num & 0xf);
}
if (gpio_ll_pulldown_is_enabled(hal->dev, gpio_num)) {
pcfg->fun_pd[gpio_num >> 4] |= BIT(gpio_num & 0xf);
} else {
pcfg->fun_pd[gpio_num >> 4] &= ~BIT(gpio_num & 0xf);
}
if (gpio_ll_sleep_pullup_is_enabled(hal->dev, gpio_num)) {
gpio_ll_pullup_en(hal->dev, gpio_num);
} else {
gpio_ll_pullup_dis(hal->dev, gpio_num);
}
if (gpio_ll_sleep_pulldown_is_enabled(hal->dev, gpio_num)) {
gpio_ll_pulldown_en(hal->dev, gpio_num);
} else {
gpio_ll_pulldown_dis(hal->dev, gpio_num);
}
}
}
/**
* @brief GPIO pu/pd information backup function
* @param hal gpio hal
* @param gpio_num gpio num
* @param args pointer for bitmap to restore GPIO pu/pd information
*/
static void gpio_hal_fun_pupd_restore(gpio_hal_context_t *hal, gpio_num_t gpio_num, void *args)
{
/* On ESP32, setting SLP_PU, SLP_PD couldn`t change GPIO status
* from SLP_PU, SLP_PD to FUN_PU, FUN_PD when it wakes up.
* On the ESP32S2, it does.
* The following code emulates ESP32S2`s behavior:
*/
gpio_slp_mode_cfg_t *pcfg = (gpio_slp_mode_cfg_t *)args;
if (gpio_ll_sleep_sel_is_enabled(hal->dev, gpio_num)) {
if (pcfg->fun_pu[gpio_num >> 4] & BIT(gpio_num & 0xf)) {
gpio_ll_pullup_en(hal->dev, gpio_num);
} else {
gpio_ll_pullup_dis(hal->dev, gpio_num);
}
if (pcfg->fun_pd[gpio_num >> 4] & BIT(gpio_num & 0xf)) {
gpio_ll_pulldown_en(hal->dev, gpio_num);
} else {
gpio_ll_pulldown_dis(hal->dev, gpio_num);
}
}
}
void gpio_hal_sleep_pupd_config_apply(gpio_hal_context_t *hal, gpio_num_t gpio_num)
{
gpio_hal_sleep_mode_setup_wrapper(hal, gpio_num, gpio_hal_fun_pupd_backup);
}
void gpio_hal_sleep_pupd_config_unapply(gpio_hal_context_t *hal, gpio_num_t gpio_num)
{
gpio_hal_sleep_mode_setup_wrapper(hal, gpio_num, gpio_hal_fun_pupd_restore);
}
#endif

View File

@ -22,6 +22,7 @@
#pragma once
#include <stdbool.h>
#include "soc/soc.h"
#include "soc/gpio_periph.h"
#include "soc/rtc_cntl_reg.h"
@ -63,6 +64,18 @@ static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU);
}
/**
* @brief Return pull-up status on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
* @return if GPIO gpio_num`s FUN_PU is true
*/
static inline bool gpio_ll_pullup_is_enabled(gpio_dev_t *hw, gpio_num_t gpio_num)
{
return REG_GET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU) ? true : false;
}
/**
* @brief Enable pull-down on GPIO.
*
@ -85,6 +98,120 @@ static inline void gpio_ll_pulldown_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD);
}
/**
* @brief Return pull-down status on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
* @return if GPIO gpio_num`s FUN_PD is true
*/
static inline bool gpio_ll_pulldown_is_enabled(gpio_dev_t *hw, gpio_num_t gpio_num)
{
return REG_GET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD) ? true : false;
}
/**
* @brief Enable GPIO pin used for wakeup from sleep.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_sel_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_SEL_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable GPIO pin used for wakeup from sleep.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_sel_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_SEL_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Return slp-sel status on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
* @return if GPIO gpio_num`s SLP_SEL is true
*/
static inline bool gpio_ll_sleep_sel_is_enabled(gpio_dev_t *hw, gpio_num_t gpio_num)
{
return REG_GET_BIT(GPIO_PIN_MUX_REG[gpio_num], SLP_SEL) ? true : false;
}
/**
* @brief Disable GPIO pull-up in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLUP_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Enable GPIO pull-up in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_pullup_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLUP_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Return slp-pull-up status on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
* @return if GPIO gpio_num`s SLP_PU is true
*/
static inline bool gpio_ll_sleep_pullup_is_enabled(gpio_dev_t *hw, gpio_num_t gpio_num)
{
return REG_GET_BIT(GPIO_PIN_MUX_REG[gpio_num], SLP_PU) ? true : false;
}
/**
* @brief Enable GPIO pull-down in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_pulldown_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLDOWN_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable GPIO pull-down in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_pulldown_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLDOWN_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Return slp-pull-down status on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
* @return if GPIO gpio_num`s SLP_PD is true
*/
static inline bool gpio_ll_sleep_pulldown_is_enabled(gpio_dev_t *hw, gpio_num_t gpio_num)
{
return REG_GET_BIT(GPIO_PIN_MUX_REG[gpio_num], SLP_PD) ? true : false;
}
/**
* @brief GPIO set interrupt trigger type
*
@ -226,6 +353,50 @@ static inline void gpio_ll_output_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
}
}
/**
* @brief Disable GPIO input in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_input_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_INPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Enable GPIO input in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_input_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable GPIO output in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_output_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_OUTPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Enable GPIO output in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_output_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_OUTPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable open-drain mode on GPIO.
*

View File

@ -420,6 +420,117 @@ static inline void gpio_ll_force_unhold_all(gpio_dev_t *hw)
SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_CLR_DG_PAD_AUTOHOLD);
}
/**
* @brief Enable GPIO pin used for wakeup from sleep.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_sel_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_SEL_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable GPIO pin used for wakeup from sleep.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_sel_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_SEL_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable GPIO pull-up in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLUP_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Enable GPIO pull-up in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_pullup_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLUP_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Enable GPIO pull-down in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_pulldown_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLDOWN_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable GPIO pull-down in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_pulldown_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLDOWN_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable GPIO input in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_input_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_INPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Enable GPIO input in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_input_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable GPIO output in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_output_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_OUTPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Enable GPIO output in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_output_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_OUTPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
#ifdef __cplusplus
}
#endif

View File

@ -338,6 +338,105 @@ void gpio_hal_intr_disable(gpio_hal_context_t *hal, gpio_num_t gpio_num);
#define gpio_hal_force_unhold_all(hal) gpio_ll_force_unhold_all((hal)->dev)
#endif
#if SOC_GPIO_SUPPORT_SLP_SWITCH
/**
* @brief Enable pull-up on GPIO when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_pullup_en(hal, gpio_num) gpio_ll_sleep_pullup_en((hal)->dev, gpio_num)
/**
* @brief Disable pull-up on GPIO when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_pullup_dis(hal, gpio_num) gpio_ll_sleep_pullup_dis((hal)->dev, gpio_num)
/**
* @brief Enable pull-down on GPIO when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_pulldown_en(hal, gpio_num) gpio_ll_sleep_pulldown_en((hal)->dev, gpio_num)
/**
* @brief Disable pull-down on GPIO when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_pulldown_dis(hal, gpio_num) gpio_ll_sleep_pulldown_dis((hal)->dev, gpio_num)
/**
* @brief Enable sleep select on GPIO.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_sel_en(hal, gpio_num) gpio_ll_sleep_sel_en((hal)->dev, gpio_num)
/**
* @brief Disable sleep select on GPIO.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_sel_dis(hal, gpio_num) gpio_ll_sleep_sel_dis((hal)->dev, gpio_num)
/**
* @brief Disable input mode on GPIO when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_input_disable(hal, gpio_num) gpio_ll_sleep_input_disable((hal)->dev, gpio_num)
/**
* @brief Enable input mode on GPIO when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_input_enable(hal, gpio_num) gpio_ll_sleep_input_enable((hal)->dev, gpio_num)
/**
* @brief Disable output mode on GPIO when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_output_disable(hal, gpio_num) gpio_ll_sleep_output_disable((hal)->dev, gpio_num)
/**
* @brief Enable output mode on GPIO when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_output_enable(hal, gpio_num) gpio_ll_sleep_output_enable((hal)->dev, gpio_num)
#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
/**
* @brief Apply slp_pu/slp_pd configuration to fun_pu/fun_pd when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number.
*/
void gpio_hal_sleep_pupd_config_apply(gpio_hal_context_t *hal, gpio_num_t gpio_num);
/**
* @brief Restore fun_pu/fun_pd configuration when system wakeup.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number.
*/
void gpio_hal_sleep_pupd_config_unapply(gpio_hal_context_t *hal, gpio_num_t gpio_num);
#endif
#endif
#ifdef __cplusplus
}
#endif

View File

@ -73,6 +73,17 @@
#define MCU_SEL_V 0x7
#define MCU_SEL_S 12
#define PIN_SLP_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_IE)
#define PIN_SLP_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_IE)
#define PIN_SLP_OUTPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_OE)
#define PIN_SLP_OUTPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_OE)
#define PIN_SLP_PULLUP_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_PU)
#define PIN_SLP_PULLUP_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_PU)
#define PIN_SLP_PULLDOWN_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_PD)
#define PIN_SLP_PULLDOWN_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_PD)
#define PIN_SLP_SEL_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_SEL)
#define PIN_SLP_SEL_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_SEL)
#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE)
#define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE)
#define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv));

View File

@ -116,6 +116,9 @@
// GPIO >= 34 are input only
#define SOC_GPIO_VALID_OUTPUT_GPIO_MASK (SOC_GPIO_VALID_GPIO_MASK & ~(0ULL | BIT34 | BIT35 | BIT36 | BIT37 | BIT38 | BIT39))
// Support to configure slept status
#define SOC_GPIO_SUPPORT_SLP_SWITCH (1)
/*-------------------------- I2C CAPS ----------------------------------------*/
// ESP32 have 2 I2C.
#define SOC_I2C_NUM (2)

View File

@ -73,6 +73,17 @@
#define MCU_SEL_V 0x7
#define MCU_SEL_S 12
#define PIN_SLP_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_IE)
#define PIN_SLP_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_IE)
#define PIN_SLP_OUTPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_OE)
#define PIN_SLP_OUTPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_OE)
#define PIN_SLP_PULLUP_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_PU)
#define PIN_SLP_PULLUP_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_PU)
#define PIN_SLP_PULLDOWN_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_PD)
#define PIN_SLP_PULLDOWN_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_PD)
#define PIN_SLP_SEL_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,SLP_SEL)
#define PIN_SLP_SEL_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,SLP_SEL)
#define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE)
#define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE)
#define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv));

View File

@ -99,6 +99,9 @@
// GPIO 46, 47 are input only
#define SOC_GPIO_VALID_OUTPUT_GPIO_MASK (SOC_GPIO_VALID_GPIO_MASK & ~(0ULL | BIT46 | BIT47))
// Support to configure slept status
#define SOC_GPIO_SUPPORT_SLP_SWITCH (1)
/*-------------------------- Dedicated GPIO CAPS ---------------------------------------*/
#define SOC_DEDIC_GPIO_OUT_CHANNELS_NUM (8) /*!< 8 outward channels on each CPU core */
#define SOC_DEDIC_GPIO_IN_CHANNELS_NUM (8) /*!< 8 inward channels on each CPU core */

View File

@ -9,3 +9,6 @@ CONFIG_PM_USE_RTC_TIMER_REF=y
# Put related source code in IRAM
CONFIG_PM_SLP_IRAM_OPT=y
CONFIG_PM_RTOS_IDLE_OPT=y
# Disable all GPIO at light sleep
CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL=y
CONFIG_PM_SLP_DISABLE_GPIO=y