1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #13416 from gschorcht/cpu/esp32/pm_layered

cpu/esp32: support for light/deep sleep and pm_layered
This commit is contained in:
benpicco 2020-03-23 14:11:05 +01:00 committed by GitHub
commit 45b635f4c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 1667 additions and 205 deletions

View File

@ -54,6 +54,13 @@
*/
#define BTN0_MODE GPIO_IN
/**
* @brief Default interrupt flank definition for the button GPIO
*/
#ifndef BTN0_INT_FLANK
#define BTN0_INT_FLANK GPIO_FALLING
#endif
/**
* @brief Definition for compatibility with previous versions
*/

View File

@ -60,6 +60,13 @@
#define BUTTON0_PIN BTN0_PIN
/** @} */
/**
* @brief Default interrupt flank definition for the button GPIO
*/
#ifndef BTN0_INT_FLANK
#define BTN0_INT_FLANK GPIO_FALLING
#endif
/**
* @name LED (on-board) configuration
*

View File

@ -56,6 +56,13 @@
*/
#define BTN0_MODE GPIO_IN
/**
* @brief Default interrupt flank definition for the button GPIO
*/
#ifndef BTN0_INT_FLANK
#define BTN0_INT_FLANK GPIO_FALLING
#endif
/**
* @brief Definition for compatibility with previous versions
*/

View File

@ -84,6 +84,10 @@ ifneq (,$(filter ndn-riot,$(USEPKG)))
USEMODULE += cipher_modes
endif
ifneq (,$(filter pm_layered,$(USEMODULE)))
USEMODULE += periph_rtc
endif
ifneq (,$(filter shell,$(USEMODULE)))
USEMODULE += ps
endif

View File

@ -50,6 +50,7 @@ USEMODULE += esp_idf_driver
USEMODULE += esp_idf_esp32
USEMODULE += esp_idf_soc
USEMODULE += periph_adc_ctrl
USEMODULE += pm_layered
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/
INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/include

View File

@ -41,7 +41,8 @@
8. [RTC Timer](#esp32_rtc_timer)
9. [UART Interfaces](#esp32_uart_interfaces)
10. [CAN Interfaces](#esp32_can_interfaces)
11. [Other Peripherals](#esp32_other_peripherals)
11. [Power Management](#esp32_power_management)
12. [Other Peripherals](#esp32_other_peripherals)
7. [Special On-board Peripherals](#esp32_special_on_board_peripherals)
1. [SPI RAM Modules](#esp32_spi_ram)
2. [SPIFFS Device](#esp32_spiffs_device)
@ -120,7 +121,7 @@ Module | Default | Short description
[esp_log_tagged](#esp32_esp_log_module) | not used | add additional information to the log output
[esp_now](#esp32_esp_now_network_interface) | not used | enable the ESP-NOW network device
[esp_rtc_timer](#esp32_rtc_timer) | not used | enable RTC hardware timer with internal 150 kHz RC oscillator
[esp_rtc_timer_32k](#esp32_rtc_timer) not used | enable RTC hardware timer with external 32.768 kHz crystal.
[esp_rtc_timer_32k](#esp32_rtc_timer) | not used | enable RTC hardware timer with external 32.768 kHz crystal.
[esp_spi_ram](#esp32_spi_ram) | not used | enable SPI RAM
[esp_spiffs](#esp32_spiffs_device) | not used | enable SPIFFS for on-board flash memory
[esp_wifi](#esp32_wifi_network_interface) | not used | enable the Wifi network device in WPA2 personal mode
@ -143,16 +144,16 @@ MCU | ESP32 | Supported by RIOT
------------|-----------|------------------
Vendor | Espressif | |
Cores | 1 or 2 x Tensilica Xtensa LX6 | 1 core
FPU | yes (ULP - Ultra low power co-processor) | no
RAM | 520 kByte SRAM <br> 16 kByte RTC SRAM | yes
FPU | ULP - Ultra low power co-processor | no
RAM | 520 kByte SRAM <br> 8 kByte slow RTC SRAM <br> 8 kByte fast RTC SRAM | yes <br> yes <br> yes
ROM | 448 kByte | yes
Flash | 512 kByte ... 16 MByte | yes
Frequency | 240 MHz, 160 MHz, 80 MHz | yes
Power Consumption | 68 mA @ 240 MHz <br> 44 mA @ 160 MHz <br> 31 mA @ 80 MHz <br> 5 uA in deep sleep mode | yes <br> yes <br> yes <br> no
Power Consumption | 68 mA @ 240 MHz <br> 44 mA @ 160 MHz (34 mA @ 160 MHz single core) <br> 31 mA @ 80 MHz (25 mA @ 80 MHz single core) <br> 800 uA in light sleep mode <br> 10 uA in deep sleep mode | yes <br> yes <br> yes <br> yes <br> yes
Timers | 4 x 64 bit | yes
ADCs | 2 x SAR-ADC with up to 18 x 12 bit channels total | yes
DACs | 2 x DAC with 8 bit | yes
GPIOs | 34 (6 of them are only inputs) | yes
GPIOs | 34 (6 are only inputs, 18 are RTC GPIOs) | yes
I2Cs | 2 | yes
SPIs | 4 | yes (2)
UARTs | 3 | yes
@ -189,6 +190,7 @@ The RIOT-OS for ESP32 SoCs supports the following features at the moment:
- PWM channels
- SPI RAM
- SPI Flash Drive (MTD with SPIFFS and VFS)
- Layered Power Management
- Hardware number generator
- Hardware timer devices
- ESP-NOW netdev interface
@ -509,12 +511,15 @@ ESP32 is an SoC and has a lot of peripherals that are not all supported by the R
\anchor esp32_gpio_pins
## <a name="esp32_gpio_pins"> GPIO pins </a> &nbsp;[[TOC](#esp32_toc)]
ESP32 has 34 GPIO pins, where only a subset can be used as output, as ADC channel, as DAC channel and in deep sleep mode. Some of them are used by special SoC components, e.g., as touch sensors. The following table gives a short overview.
ESP32 has 34 GPIO pins, where only a subset can be used as output, as
ADC channel, as DAC channel and as GPIOs in deep-sleep mode, the so-called
RTC GPIOs. Some of them are used by special SoC components, e.g., as touch
sensors. The following table gives a short overview.
<center>
Pin | Type | ADC | PU/PD | Special function | Remarks
-------|--------|:---:| ------ |------------------|--------
Pin | Type | ADC / RTC | PU / PD | Special function | Remarks
-------|:-------|:---:|:------:|------------------|--------
GPIO0 | In/Out | yes | yes | Touch sensor | Bootstrapping, pulled up
GPIO1 | In/Out | - | yes | UART0 TxD | Console
GPIO2 | In/Out | yes | yes | Touch sensor | Bootstrapping, pulled down
@ -548,11 +553,12 @@ GPIO35 | In | yes | - | VDET | -
GPIO36 | In | yes | - | SENSOR_VP | -
GPIO37 | In | yes | - | SENSOR_CAPP | usually not broken out
GPIO38 | In | yes | - | SENSOR_CAPN | usually not broken out
GPIO38 | In | yes | - | SENSOR_VN | -
GPIO39 | In | yes | - | SENSOR_VN | -
</center>
<b>ADC:</b> these pins can be used as ADC inputs<br>
<b>RTC:</b> these pins are RTC GPIOs and can be used in deep-sleep mode<br>
<b>PU/PD:</b> these pins have software configurable pull-up/pull-down functionality.<br>
@note GPIOs that can be used as ADC channels are also available as low power digital inputs/outputs in deep sleep mode.
@ -954,6 +960,139 @@ FEATURES_PROVIDED += periph_can # CAN peripheral interface
Otherwise, the application has to add the `periph_can` module in its makefile
when needed.
\anchor esp32_power_management
## <a name="esp32_power_management"> Power Management </a> &nbsp;[[TOC](#esp32_toc)]
### Power Modes
The RIOT port for the ESP32 implements RIOT's layered power management. It
supports the following operating modes:
- The **Modem-sleep** mode is the default operating mode when the WiFi
interface is disabled.
- The **Active** mode is the default operating mode when the WiFi interface
is used by either the `esp-wifi` or `esp-now` module.
- In **Light-sleep** mode, the CPUs including peripherals are stalled, but
the SRAM is retained. The system can continue when it returns from this mode.
- In **Deep-sleep** the CPU and the SRAM are powered down. The RTC memory can
be retained. The system must be restarted when it returns from this mode.
Since the peripherals are not working during _Light-sleep_/_Deep-sleep_, the
CPU cannot be woken up by internal interrupt sources such as timers. Therefore,
RIOT's layered power management can't select them as idle power mode. They are
therefore blocked for normal operation. The application has to select them
explicitly using the `pm_set` function. RIOT's layered power management
can only select either _Modem-sleep_ or _Active_ as the lowest unblocked mode.
But also in _Modem-sleep_ or _Active_ mode, the lowest possible power level
is used. For this purpose, the Xtensa ISA instruction `waiti` is used,
which saves power by setting the current interrupt level, turning off the
processor logic and waiting for an interrupt.
### Using Power Modes
_Modem-sleep_ mode and _Active_ mode are the default operating modes
dependent on whether the WiFi interface is used. They are selected
automatically by the system.
To enter the _Light-sleep_ or the _Deep-sleep_ mode, function `pm_set` has
to be used with the according mode `ESP_PM_LIGHT_SLEEP` or `ESP_PM_DEEP_SLEEP`
as parameter. To exit from these modes, several wake-up sources can be used.
#### Wake-up Sources in _Light-sleep_ Mode
Possible wake-up sources for the _Light-sleep_ mode are:
- RTC timer (set the RTC timer alarm using `rtc_set` before calling `pm_set`)
- GPIOs that are configured as input with enabled interrupt
- RxD signal of UART0 and/or UART1 (configured with `ESP_PM_WUP_UART0` and
`ESP_PM_WUP_UART1`)
@note Since the digital core (MCU) is stalled during _Light-sleep_, it
is not possible timers like `periph_timer` or `xtimer` as wake-up source.
@warning
Since only level interrupts are supported in _Light-sleep_ mode,
defined edge interrupts of type `GPIO_RISING` and `GPIO_FALLING` are
implicitly mapped to `GPIO_HIGH` and `GPIO_LOW`, respectively, when
entering _Light-sleep_ mode.
#### Wake-up Sources in _Light-sleep_ Mode
Possible Wake-up sources for the _Deep-sleep_ mode are:
- RTC timer (set the RTC timer alarm using `rtc_set` before calling `pm_set`)
- RTC GPIOs (configured by `ESP_PM_WUP_PINS` and `ESP_PM_WUP_LEVEL`)
@note RTC GPIOs are the GPIOs that are realized by the RTC unit and can also
be used as ADC channels. See section [GPIO pins](#esp32_gpio_pins) and
[ADC Channels](#esp32_adc_channels) for more information.
### Configuration
Several definitions can be used during compile time to configure the
_Light-sleep_ and the _Deep-sleep_ mode:
<center>
Parameter | Default | Mode | Description
:----------------|:-------------------------|:------|:------------
ESP_PM_GPIO_HOLD | not defined | Deep | Hold GPIO output level if defined
ESP_PM_WUP_PINS | none | Deep | GPIOs used as wake-up source
ESP_PM_WUP_LEVEL | ESP_PM_WUP_PINS_ANY_HIGH | Deep | Level for wake-up pins to wake-up
ESP_PM_WUP_UART0 | disabled | Light | Positive UART0 RxD signal edges to wake-up
ESP_PM_WUP_UART1 | disabled | Light | Positive UART1 RxD signal edges to wake-up
</center>
- If `ESP_PM_GPIO_HOLD` is defined, GPIOs hold their last output level
when entering _Deep-sleep_ mode. Please note that only RTC GPIOs
can hold their output value in _Deep-sleep_ mode.
- `ESP_PM_WUP_PINS` specifies either a single RTC GPIO or a comma separated
list of RTC GPIOs that are used as wake-up source in _Deep-sleep_ mode.
- `ESP_PM_WUP_LEVEL` specifies the level for the wake-up pins in _Deep-sleep_
mode:
- `ESP_PM_WUP_PINS_ANY_HIGH` (default) - The system is woken up when any of
the GPIOs specified in `ESP_PM_WUP_PINS` becomes HIGH.
- `ESP_PM_WUP_PINS_ALL_LOW` - The system is woken up when all GPIOs specified
in `ESP_PM_WUP_PINS` become LOW.
- `ESP_PM_WUP_UART0` and `ESP_PM_WUP_UART1` define the number of positive
edges of the RxD signal of the respective UART that are necessary to wake
up the system in the _Light-sleep_ mode. The value must be greater than 2,
otherwise UART is not activated as wake-up source. The specified value is
reduced by 2 so that `ESP_PM_WUP_UART0` or `ESP_PM_WUP_UART1` plus 2 is
the number of positive edges required to wake up.
In the following example the system shall be woken up from _Deep-sleep_ if
the pulled-up pin `GPIO25` (`ESP_PM_WUP_PINS=GPIO25`) goes LOW
(`ESP_PM_WUP_LEVEL=ESP_PM_WUP_PINS_ALL_LOW`). The last GPIO output values
are held (`ESP_PM_GPIO_HOLD`) in _Deep-sleep_ mode. From _Light-sleep_ the
system can be woken up by any of the GPIOs defined as input with enabled
interrupt or if the RxD signal of UART0 goes HIGH at least 4 times
(`ESP_PM_WUP_UART0=6`).
```
CFLAGS='-DESP_PM_WUP_PINS=GPIO25 -DESP_PM_WUP_LEVEL=ESP_PM_WUP_PINS_ALL_LOW \
-DESP_PM_WUP_UART0=6 -DESP_PM_GPIO_HOLD' \
make BOARD=esp32-wroom-32 -C tests/periph_pm
```
### Saving Data in _Deep-sleep_ Mode
In _Deep-sleep_ mode the SRAM is powered down. However, the slow RTC memory
can be retained. Therefore, data that must be retained during _Deep-sleep_ and
the subsequent system restart, must be stored in the slow RTC memory. For
that purpose, use
- `__attribute__((section(".rtc.bss")))` to place uninitialized
data in section `.rtc.bss`, and
- `__attribute__((section(".rtc.data")))` to
place initialized data in section `.rtc.data`.
For example:
```
static int _i_value __attribute__((section(".rtc.bss"))); /* set to 0 at power on */
static int _u_value __attribute__((section(".rtc.data"))) = 1; /* initialized */
```
## <a name="esp32_other_peripherals"> Other Peripherals </a> &nbsp;[[TOC](#esp32_toc)]
The ESP32 port of RIOT also supports:
@ -961,7 +1100,6 @@ The ESP32 port of RIOT also supports:
- hardware number generator with 32 bit
- CPU-ID function
- Vref measurement function
- power management functions
# <a name="esp32_special_on_board_peripherals"> Special On-board Peripherals </a> &nbsp;[[TOC](#esp32_toc)]

View File

@ -83,16 +83,6 @@ struct _adc_hw_t {
*/
extern const struct _adc_hw_t _adc_hw[];
/**
* @brief Configure sleep mode for an GPIO pin if the pin is a RTCIO pin
* @param pin GPIO pin
* @param mode active in sleep mode if true
* @param input as input if true, as output otherwise
* @return 0 success
* @return -1 on invalid pin
*/
int rtcio_config_sleep_mode (gpio_t pin, bool mode, bool input);
#ifdef __cplusplus
}
#endif

View File

@ -25,12 +25,21 @@
#include "soc/io_mux_reg.h"
#include "soc/gpio_sig_map.h"
#ifndef DOXYGEN
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Current an output pin can drive in active and sleep modes
*/
typedef enum {
GPIO_DRIVE_5 = 0, /**< 5 mA */
GPIO_DRIVE_10 = 1, /**< 10 mA */
GPIO_DRIVE_20 = 2, /**< 20 mA (default) */
GPIO_DRIVE_30 = 2, /**< 30 mA */
} gpio_drive_strength_t;
#ifndef DOXYGEN
/**
* @brief Table of GPIO to IOMUX register mappings
*/
@ -48,17 +57,7 @@ void gpio_pullup_dis (gpio_t pin);
int8_t gpio_is_rtcio (gpio_t pin);
/**
* @brief Configure sleep mode for an GPIO pin if the pin is an RTCIO pin
* @param pin GPIO pin
* @param mode active in sleep mode if true
* @param input as input if true, as output otherwise
* @return 0 on success
* @return -1 on invalid pin
*/
int gpio_config_sleep_mode (gpio_t pin, bool sleep_mode, bool input);
/**
* @brief GPIO set direction init the pin calling gpio_init
* @brief Set the direction of a pin (initializes the pin calling gpio_init)
* @param pin GPIO pin
* @param mode active in sleep mode if true
* @return 0 on success
@ -72,9 +71,41 @@ int gpio_set_direction(gpio_t pin, gpio_mode_t mode);
void gpio_matrix_in (uint32_t gpio, uint32_t signal_idx, bool inv);
void gpio_matrix_out(uint32_t gpio, uint32_t signal_idx, bool out_inv, bool oen_inv);
#endif /* DOXYGEN */
/**
* @brief Set the drive-strength of an output-capable pin
*
* Sets the drive-strength for an output-capable pin in active and sleep modes.
* The default drive-strength is GPIO_DRIVE_20 (20 mA).
*
* @param pin GPIO pin
* @param drive drive-strength
* GPIO_DRIVE_5 for 5 mA
* GPIO_DRIVE_10 for 10 mA
* GPIO_DRIVE_20 for 20 mA (default)
* GPIO_DRIVE_30 for 30 mA
* @pre pin is an output-capable pin
* @post an assertion blows up if the pin is not output-capable
* @return 0 on success
* -1 on error
*/
int gpio_set_drive_capability(gpio_t pin, gpio_drive_strength_t drive);
/**
* @brief Called before the power management enters a light or deep sleep mode
* @param mode sleep mode that is entered
*/
void gpio_pm_sleep_enter(unsigned mode);
/**
* @brief Called after the power management left light sleep mode
* @param cause wake-up cause
*/
void gpio_pm_sleep_exit(uint32_t cause);
#ifdef __cplusplus
}
#endif
#endif /* DOXYGEN */
#endif /* GPIO_ARCH_H */

View File

@ -32,6 +32,22 @@ extern "C" {
#define PROVIDES_PM_SET_LOWEST
#define PROVIDES_PM_RESTART
#define PROVIDES_PM_OFF
#define PROVIDES_PM_LAYERED_OFF
/**
* @brief Number of usable low power modes
*/
#define PM_NUM_MODES (2U)
/**
* @name Power modes
* @{
*/
#define ESP_PM_MODEM_SLEEP (2U)
#define ESP_PM_LIGHT_SLEEP (1U)
#define ESP_PM_DEEP_SLEEP (0U)
/** @} */
/** @} */
/**

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2020 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_esp32
* @{
*
* @file
* @brief Architecture specific RTC functions for ESP32
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#ifndef RTC_ARCH_H
#define RTC_ARCH_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Called before the power management enters a light or deep sleep mode
* @param mode sleep mode that is entered
* @return time to sleep in us
*/
uint64_t rtc_pm_sleep_enter(unsigned mode);
/**
* @brief Called after the power management left light sleep mode
* @param cause wake-up cause
*/
void rtc_pm_sleep_exit(uint32_t cause);
#ifdef __cplusplus
}
#endif
#endif /* RTC_ARCH_H */

View File

@ -90,6 +90,7 @@ extern "C" {
#define CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS 4
#define CONFIG_NEWLIB_NANO_FORMAT 0
#define CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY 2000
/**
* Bluetooth configuration (DO NOT CHANGE)

View File

@ -167,85 +167,3 @@ void _adc2_ctrl_init(void)
_adc2_ctrl_initialized = true;
}
int rtcio_config_sleep_mode (gpio_t pin, bool mode, bool input)
{
CHECK_PARAM_RET(pin < GPIO_PIN_NUMOF, -1);
uint8_t rtcio = _gpio_rtcio_map[pin];
uint8_t idx;
/* route pads to RTC and if possible, disable input, pull-up/pull-down */
switch (rtcio) {
case RTCIO_SENSOR_SENSE1: /* GPIO36, RTC0 */
RTCIO.sensor_pads.sense1_mux_sel = 1; /* route to RTC */
RTCIO.sensor_pads.sense1_fun_sel = 0; /* RTC mux function 0 */
RTCIO.sensor_pads.sense1_slp_sel = mode; /* sleep mode */
RTCIO.sensor_pads.sense1_slp_ie = input; /* input enabled */
break;
case RTCIO_SENSOR_SENSE2: /* GPIO37, RTC1 */
RTCIO.sensor_pads.sense2_mux_sel = 1; /* route to RTC */
RTCIO.sensor_pads.sense2_fun_sel = 0; /* RTC mux function 0 */
RTCIO.sensor_pads.sense2_slp_sel = mode; /* sleep mode */
RTCIO.sensor_pads.sense2_slp_ie = input; /* input enabled */
break;
case RTCIO_SENSOR_SENSE3: /* GPIO38, RTC2 */
RTCIO.sensor_pads.sense3_mux_sel = 1; /* route to RTC */
RTCIO.sensor_pads.sense3_fun_sel = 0; /* RTC mux function 0 */
RTCIO.sensor_pads.sense3_slp_sel = mode; /* sleep mode */
RTCIO.sensor_pads.sense3_slp_ie = input; /* input enabled */
break;
case RTCIO_SENSOR_SENSE4: /* GPIO39, RTC3 */
RTCIO.sensor_pads.sense4_mux_sel = 1; /* route to RTC */
RTCIO.sensor_pads.sense4_fun_sel = 0; /* RTC mux function 0 */
RTCIO.sensor_pads.sense4_slp_sel = mode; /* sleep mode */
RTCIO.sensor_pads.sense4_slp_ie = input; /* input enabled */
break;
case RTCIO_TOUCH0: /* GPIO4, RTC10 */
case RTCIO_TOUCH1: /* GPIO0, RTC11 */
case RTCIO_TOUCH2: /* GPIO2, RTC12 */
case RTCIO_TOUCH3: /* GPIO15, RTC13 */
case RTCIO_TOUCH4: /* GPIO13, RTC14 */
case RTCIO_TOUCH5: /* GPIO12, RTC15 */
case RTCIO_TOUCH6: /* GPIO14, RTC16 */
case RTCIO_TOUCH7: /* GPIO27, RTC17 */
case RTCIO_TOUCH8: /* GPIO33, RTC8 */
case RTCIO_TOUCH9: /* GPIO32, RTC9 */
idx = rtcio - RTCIO_TOUCH0;
RTCIO.touch_pad[idx].mux_sel = 1; /* route to RTC */
RTCIO.touch_pad[idx].fun_sel = 0; /* RTC mux function 0 */
RTCIO.touch_pad[idx].slp_sel = mode; /* sleep mode */
RTCIO.touch_pad[idx].slp_ie = input; /* input enabled */
RTCIO.touch_pad[idx].slp_oe = ~input; /* output enabled*/
break;
case RTCIO_ADC_ADC1: /* GPIO34, RTC4 */
RTCIO.adc_pad.adc1_mux_sel = 1; /* route to RTC */
RTCIO.adc_pad.adc1_fun_sel = 0; /* RTC mux function 0 */
RTCIO.adc_pad.adc1_slp_sel = mode; /* sleep mode */
RTCIO.adc_pad.adc1_slp_ie = input; /* input enabled */
break;
case RTCIO_ADC_ADC2: /* GPIO35, RTC5 */
RTCIO.adc_pad.adc2_mux_sel = 1; /* route to RTC */
RTCIO.adc_pad.adc2_fun_sel = 0; /* RTC mux function 0 */
RTCIO.adc_pad.adc2_slp_sel = mode; /* sleep mode */
RTCIO.adc_pad.adc2_slp_ie = input; /* input enabled */
break;
case RTCIO_DAC1: /* GPIO25, RTC6 */
case RTCIO_DAC2: /* GPIO26, RTC7 */
idx = rtcio - RTCIO_DAC1;
RTCIO.pad_dac[idx].mux_sel = 1; /* route to RTC */
RTCIO.pad_dac[idx].fun_sel = 0; /* RTC mux function 0 */
RTCIO.pad_dac[idx].slp_sel = mode; /* sleep mode */
RTCIO.pad_dac[idx].slp_ie = input; /* input enabled */
RTCIO.pad_dac[idx].slp_oe = ~input; /* output enabled*/
break;
default:
LOG_TAG_ERROR("gpio", "GPIO %d is not an RTCIO pin and "
"cannot be used in sleep mode\n", pin);
return -1;
}
return 0;
}

View File

@ -37,12 +37,20 @@
#include "xtensa/xtensa_api.h"
#include "esp_common.h"
#include "esp_sleep.h"
#include "adc_arch.h"
#include "adc_ctrl.h"
#include "gpio_arch.h"
#include "irq_arch.h"
#include "syscalls.h"
#define ESP_PM_WUP_PINS_ANY_HIGH ESP_EXT1_WAKEUP_ANY_HIGH
#define ESP_PM_WUP_PINS_ALL_LOW ESP_EXT1_WAKEUP_ALL_LOW
#ifndef ESP_PM_WUP_LEVEL
#define ESP_PM_WUP_LEVEL ESP_PM_WUP_PINS_ANY_HIGH
#endif
#define GPIO_PRO_CPU_INTR_ENA (BIT(2))
/* GPIO to IOMUX register mapping (see Technical Reference, Section 4.12 Register Summary)
@ -153,28 +161,29 @@ struct _rtc_gpio_t {
uint8_t mux; /**< mux io/rtc bit [0..31] in the register, 32 - no mux */
uint8_t pullup; /**< pullup bit [0..31] in the register, 32 - no pullup */
uint8_t pulldown; /**< pulldown bit [0..31] in the register, 32 - no pulldown */
uint8_t drive; /**< drive strength start bit [0..30] in the register */
};
/* Table of RTCIO GPIO pins information */
static const struct _rtc_gpio_t _rtc_gpios[] = {
{ 0, RTC_IO_SENSOR_PADS_REG, 27, 32, 32 }, /* rtc0 (gpio36) - no pullup/pulldown */
{ 1, RTC_IO_SENSOR_PADS_REG, 26, 32, 32 }, /* rtc1 (gpio37) - no pullup/pulldown */
{ 2, RTC_IO_SENSOR_PADS_REG, 25, 32, 32 }, /* rtc2 (gpio38) - no pullup/pulldown */
{ 3, RTC_IO_SENSOR_PADS_REG, 24, 32, 32 }, /* rtc3 (gpio39) - no pullup/pulldown */
{ 4, RTC_IO_ADC_PAD_REG, 29, 32, 32 }, /* rtc4 (gpio34) - no pullup/pulldown */
{ 5, RTC_IO_ADC_PAD_REG, 28, 32, 32 }, /* rtc5 (gpio35) - no pullup/pulldown */
{ 6, RTC_IO_PAD_DAC1_REG, 17, 27, 28 }, /* rtc6 (gpio25) */
{ 7, RTC_IO_PAD_DAC2_REG, 17, 27, 28 }, /* rtc7 (gpio26) */
{ 8, RTC_IO_XTAL_32K_PAD_REG, 18, 27, 28 },/* rtc8 (gpio33) */
{ 9, RTC_IO_XTAL_32K_PAD_REG, 17, 22, 23 },/* rtc9 (gpio32) */
{ 10, RTC_IO_TOUCH_PAD0_REG, 19, 27, 28 }, /* rtc10 (gpio4) */
{ 11, RTC_IO_TOUCH_PAD1_REG, 19, 27, 28 }, /* rtc11 (gpio0) */
{ 12, RTC_IO_TOUCH_PAD2_REG, 19, 27, 28 }, /* rtc12 (gpio2) */
{ 13, RTC_IO_TOUCH_PAD3_REG, 19, 27, 28 }, /* rtc13 (gpio15) */
{ 14, RTC_IO_TOUCH_PAD4_REG, 19, 27, 28 }, /* rtc14 (gpio13) */
{ 15, RTC_IO_TOUCH_PAD5_REG, 19, 27, 28 }, /* rtc15 (gpio12) */
{ 16, RTC_IO_TOUCH_PAD6_REG, 19, 27, 28 }, /* rtc16 (gpio14) */
{ 17, RTC_IO_TOUCH_PAD7_REG, 19, 27, 28 } /* rtc17 (gpio27) */
{ 0, RTC_IO_SENSOR_PADS_REG, 27, 32, 32, 32 }, /* rtc0 (gpio36) SENSOR_VP/SENSE 1 */
{ 1, RTC_IO_SENSOR_PADS_REG, 26, 32, 32, 32 }, /* rtc1 (gpio37) SENSOR_CAPP/SENSE 2 */
{ 2, RTC_IO_SENSOR_PADS_REG, 25, 32, 32, 32 }, /* rtc2 (gpio38) SENSOR_CAPN/SENSE 3 */
{ 3, RTC_IO_SENSOR_PADS_REG, 24, 32, 32, 32 }, /* rtc3 (gpio39) SENSOR_VN/SENSE 4*/
{ 4, RTC_IO_ADC_PAD_REG, 29, 32, 32, 32 }, /* rtc4 (gpio34) VDET_1/ADC1 */
{ 5, RTC_IO_ADC_PAD_REG, 28, 32, 32, 32 }, /* rtc5 (gpio35) VDET_2/ADC2 */
{ 6, RTC_IO_PAD_DAC1_REG, 17, 27, 28, 30 }, /* rtc6 (gpio25) DAC1 */
{ 7, RTC_IO_PAD_DAC2_REG, 17, 27, 28, 30 }, /* rtc7 (gpio26) DAC1 */
{ 8, RTC_IO_XTAL_32K_PAD_REG, 18, 27, 28, 30 },/* rtc8 (gpio33) XTAL_32K_N */
{ 9, RTC_IO_XTAL_32K_PAD_REG, 17, 22, 23, 25 },/* rtc9 (gpio32) XTAL_32K_P */
{ 10, RTC_IO_TOUCH_PAD0_REG, 19, 27, 28, 29 }, /* rtc10 (gpio4) TOUCH0 */
{ 11, RTC_IO_TOUCH_PAD1_REG, 19, 27, 28, 29 }, /* rtc11 (gpio0) TOUCH1 */
{ 12, RTC_IO_TOUCH_PAD2_REG, 19, 27, 28, 29 }, /* rtc12 (gpio2) TOUCH2 */
{ 13, RTC_IO_TOUCH_PAD3_REG, 19, 27, 28, 29 }, /* rtc13 (gpio15) TOUCH3 */
{ 14, RTC_IO_TOUCH_PAD4_REG, 19, 27, 28, 29 }, /* rtc14 (gpio13) TOUCH4 */
{ 15, RTC_IO_TOUCH_PAD5_REG, 19, 27, 28, 29 }, /* rtc15 (gpio12) TOUCH5 */
{ 16, RTC_IO_TOUCH_PAD6_REG, 19, 27, 28, 29 }, /* rtc16 (gpio14) TOUCH6 */
{ 17, RTC_IO_TOUCH_PAD7_REG, 19, 27, 28, 29 } /* rtc17 (gpio27) TOUCH7 */
};
/* Table of the usage type of each GPIO pin */
@ -425,6 +434,8 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
if (flank != GPIO_NONE) {
gpio_int_enabled_table [pin] = (gpio_isr_ctx_table[pin].cb != NULL);
GPIO.pin[pin].int_ena = GPIO_PRO_CPU_INTR_ENA;
GPIO.pin[pin].int_type = flank;
GPIO.pin[pin].wakeup_enable = 1;
intr_matrix_set(PRO_CPU_NUM, ETS_GPIO_INTR_SOURCE, CPU_INUM_GPIO);
xt_set_interrupt_handler(CPU_INUM_GPIO, gpio_int_handler, NULL);
@ -537,13 +548,106 @@ int8_t gpio_is_rtcio (gpio_t pin)
return _gpio_to_rtc[pin];
}
int gpio_config_sleep_mode (gpio_t pin, bool mode, bool input)
{
return rtcio_config_sleep_mode (pin, mode, input);
}
int gpio_set_direction(gpio_t pin, gpio_mode_t mode)
{
/* TODO implementation, for the moment we simply initialize the GPIO */
return gpio_init(pin, mode);
}
int gpio_set_drive_capability(gpio_t pin, gpio_drive_strength_t drive)
{
assert(pin < GPIO_PIN_NUMOF);
assert(pin < GPIO34);
const struct _rtc_gpio_t* rtc = (_gpio_to_rtc[pin] != -1) ?
&_rtc_gpios[_gpio_to_rtc[pin]] : NULL;
SET_PERI_REG_BITS(_gpio_to_iomux_reg, FUN_DRV_V, drive, FUN_DRV_S);
if (rtc) {
SET_PERI_REG_BITS(rtc->reg, 0x3, drive, rtc->drive);
}
return 0;
}
#if MODULE_PERIPH_GPIO_IRQ
static uint32_t gpio_int_saved_type[GPIO_PIN_NUMOF];
#endif
void gpio_pm_sleep_enter(unsigned mode)
{
/*
* Activate the power domain for RTC peripherals either when
* ESP_PM_GPIO_HOLD is defined or when light sleep mode is activated.
* As long as the RTC peripherals are active, the pad state of RTC GPIOs
* is held in deep sleep and the pad state of all GPIOs is held in light
* sleep.
*/
#ifdef ESP_PM_GPIO_HOLD
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
#else
if (mode == ESP_PM_LIGHT_SLEEP) {
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
}
#endif
if (mode == ESP_PM_DEEP_SLEEP) {
#ifdef ESP_PM_WUP_PINS
static const gpio_t wup_pins[] = { ESP_PM_WUP_PINS };
/*
* Prepare the wake-up pins if a single pin or a comma-separated list of
* pins is defined for wake-up.
*/
uint64_t wup_pin_mask = 0;
for (unsigned i = 0; i < ARRAY_SIZE(wup_pins); i++) {
wup_pin_mask |= 1ULL << wup_pins[i];
}
esp_sleep_enable_ext1_wakeup(wup_pin_mask, ESP_PM_WUP_LEVEL);
#endif /* ESP_PM_WUP_PINS */
}
else {
#if MODULE_PERIPH_GPIO_IRQ
esp_sleep_enable_gpio_wakeup();
for (unsigned i = 0; i < GPIO_PIN_NUMOF; i++) {
const struct _rtc_gpio_t* rtc =
(_gpio_to_rtc[i] != -1) ? &_rtc_gpios[_gpio_to_rtc[i]] : NULL;
if (gpio_int_enabled_table[i] && GPIO.pin[i].int_type) {
gpio_int_saved_type[i] = GPIO.pin[i].int_type;
switch (GPIO.pin[i].int_type) {
case GPIO_FALLING:
GPIO.pin[i].int_type = GPIO_LOW;
DEBUG("%s gpio=%u GPIO_LOW\n", __func__, i);
break;
case GPIO_RISING:
GPIO.pin[i].int_type = GPIO_HIGH;
DEBUG("%s gpio=%u GPIO_HIGH\n", __func__, i);
break;
case GPIO_BOTH:
DEBUG("%s gpio=%u GPIO_BOTH not supported\n",
__func__, i);
break;
default:
break;
}
if (rtc) {
RTCIO.pin[rtc->num].wakeup_enable = 1;
RTCIO.pin[rtc->num].int_type = GPIO.pin[i].int_type;
}
}
}
#endif
}
}
void gpio_pm_sleep_exit(uint32_t cause)
{
(void)cause;
#if MODULE_PERIPH_GPIO_IRQ
DEBUG("%s\n", __func__);
for (unsigned i = 0; i < GPIO_PIN_NUMOF; i++) {
if (gpio_int_enabled_table[i]) {
GPIO.pin[i].int_type = gpio_int_saved_type[i];
}
}
#endif
}

View File

@ -22,71 +22,58 @@
#include "debug.h"
#include "esp_attr.h"
#include "esp_sleep.h"
#include "gpio_arch.h"
#include "rtc_arch.h"
#include "syscalls.h"
#include "xtimer.h"
#include "periph/rtc.h"
#include "rom/rtc.h"
#include "rom/uart.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
void pm_set_lowest(void)
static inline esp_sleep_wakeup_cause_t pm_get_wakeup_cause(void)
{
DEBUG ("%s enter to sleep @%u\n", __func__, system_get_time());
return esp_sleep_get_wakeup_cause();
}
#if !defined(QEMU)
/* function that is required by pm_set if esp_now and esp_wifi are not used */
esp_err_t __attribute__((weak)) esp_wifi_start(void)
{
return ESP_OK;
}
/* function that is required by pm_set if esp_now and esp_wifi are not used */
esp_err_t __attribute__((weak)) esp_wifi_stop(void)
{
return ESP_OK;
}
static inline void pm_set_lowest_normal(void)
{
/* reset system watchdog timer */
system_wdt_feed();
#ifndef MODULE_ESP_QEMU
/* passive wait for interrupt to leave lowest power mode */
__asm__ volatile ("waiti 0");
/* reset system watchdog timer */
system_wdt_feed();
#endif
DEBUG ("%s exit from sleep @%u\n", __func__, system_get_time());
#endif
}
void IRAM_ATTR pm_off(void)
{
DEBUG ("%s\n", __func__);
/* disable remaining power domains */
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_OFF);
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_OFF);
/* suspend UARTs */
for (int i = 0; i < 3; ++i) {
REG_SET_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF);
uart_tx_wait_idle(i);
}
/* set all power down flags */
uint32_t pd_flags = RTC_SLEEP_PD_DIG |
RTC_SLEEP_PD_RTC_PERIPH |
RTC_SLEEP_PD_RTC_SLOW_MEM |
RTC_SLEEP_PD_RTC_FAST_MEM |
RTC_SLEEP_PD_RTC_MEM_FOLLOW_CPU |
RTC_SLEEP_PD_VDDSDIO;
rtc_sleep_config_t config = RTC_SLEEP_CONFIG_DEFAULT(pd_flags);
config.wifi_pd_en = 1;
config.rom_mem_pd_en = 1;
config.lslp_meminf_pd = 1;
/* Save current frequency and switch to XTAL */
rtc_cpu_freq_t cpu_freq = rtc_clk_cpu_freq_get();
rtc_clk_cpu_freq_set(RTC_CPU_FREQ_XTAL);
/* set deep sleep duration to forever */
rtc_sleep_set_wakeup_time(rtc_time_get() + ~0x0UL);
/* configure deep sleep */
rtc_sleep_init(config);
rtc_sleep_start(RTC_TIMER_TRIG_EN, 0);
/* Restore CPU frequency */
rtc_clk_cpu_freq_set(cpu_freq);
/* resume UARTs */
for (int i = 0; i < 3; ++i) {
REG_CLR_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF);
REG_SET_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XON);
REG_CLR_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XON);
}
/* enter hibernate mode without any enabled wake-up sources */
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
esp_deep_sleep_start();
}
extern void esp_restart_noos(void) __attribute__ ((noreturn));
@ -95,6 +82,11 @@ void pm_reboot(void)
{
DEBUG ("%s\n", __func__);
if (IS_USED(MODULE_ESP_WIFI_ANY)) {
/* stop WiFi if necessary */
esp_wifi_stop();
}
/* suspend and flush UARTs */
for (int i = 0; i < 3; ++i) {
REG_SET_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF);
@ -103,3 +95,73 @@ void pm_reboot(void)
software_reset();
}
#ifndef MODULE_PM_LAYERED
void pm_set_lowest(void)
{
pm_set_lowest_normal();
}
#else /* MODULE_PM_LAYERED */
void pm_set(unsigned mode)
{
if (mode == ESP_PM_MODEM_SLEEP) {
pm_set_lowest_normal();
return;
}
DEBUG ("%s enter to power mode %d @%u\n", __func__, mode, system_get_time());
/* flush stdout */
fflush(stdout);
/* Labels for RTC slow memory that are defined in the linker script */
extern int _rtc_bss_rtc_start;
extern int _rtc_bss_rtc_end;
/*
* Activate the Power Domain for slow RTC memory when the .rtc.bss
* section is used to retain uninitialized data. The Power Domain for
* slow RTC memory is automatically activated when the .rtc.data section
* is used to retain initialized data.
*/
if (&_rtc_bss_rtc_end > &_rtc_bss_rtc_start) {
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON);
}
/* Prepare the RTC timer if an RTC alarm is set to wake up. */
rtc_pm_sleep_enter(mode);
/* Prepare GPIOs as wakeup source */
gpio_pm_sleep_enter(mode);
if (mode == ESP_PM_DEEP_SLEEP) {
esp_deep_sleep_start();
/* waking up from deep-sleep leads to a DEEPSLEEP_RESET */
UNREACHABLE();
}
else if (mode == ESP_PM_LIGHT_SLEEP) {
if (IS_USED(MODULE_ESP_WIFI_ANY)) {
/* stop WiFi if necessary */
esp_wifi_stop();
}
esp_light_sleep_start();
esp_sleep_wakeup_cause_t wakeup_reason = pm_get_wakeup_cause();
gpio_pm_sleep_exit(wakeup_reason);
rtc_pm_sleep_exit(wakeup_reason);
DEBUG ("%s exit from power mode %d @%u with reason %d\n", __func__,
mode, system_get_time(), wakeup_reason);
/* restart WiFi if necessary */
if (IS_USED(MODULE_ESP_WIFI_ANY) && (esp_wifi_start() != ESP_OK)) {
LOG_ERROR("esp_wifi_start failed\n");
}
}
}
#endif /* MODULE_PM_LAYERED */

View File

@ -52,6 +52,7 @@
#include "cpu.h"
#include "esp_attr.h"
#include "esp_sleep.h"
#include "log.h"
#include "irq_arch.h"
#include "periph/rtc.h"
@ -99,23 +100,24 @@ static uint64_t _rtc_get_time_raw(void); /* RTC time in cycles */
static uint64_t _rtc_time_to_us(uint64_t raw); /* convert RTC cycles to us */
static void IRAM_ATTR _rtc_timer_handler(void* arg);
/* alias for compatibility with espressif/esp-idf */
int64_t esp_set_time_from_rtc(void) __attribute__((alias("rtc_init")));
void rtc_init(void)
{
uint64_t _rtc_time_us = _rtc_time_to_us(_rtc_get_time_raw());
uint64_t _rtc_time = _rtc_get_time_raw();
uint64_t _rtc_time_us = _rtc_time_to_us(_rtc_time);
if (_rtc_time_init == 0 && _rtc_time_init_us == 0) {
/* only set it new, if it was not set before */
_rtc_time_init = _rtc_get_time_raw();
_rtc_time_init = _rtc_time;
_rtc_time_init_us = _rtc_time_us;
_sys_time_off_us = 0;
DEBUG("%s saved rtc_init=%lld rtc_init_us=%lld\n",
__func__, _rtc_time_init, _rtc_time_init_us);
}
else {
_sys_time_off_us = _rtc_time_us - _rtc_time_set_us;
}
_sys_time_off_us = _rtc_time_us - _rtc_time_set_us - system_get_time_64();
_sys_time_set_us = 0;
}
@ -312,6 +314,7 @@ static void IRAM_ATTR _rtc_timer_handler(void* arg)
/* call back registered function */
if (_rtc_alarm_cb) {
_rtc_alarm_cb(_rtc_alarm_arg);
_rtc_alarm_cb = 0;
}
}
/* clear all interrupts */
@ -342,3 +345,23 @@ static void IRAM_ATTR _rtc_timer_handler(void* arg)
irq_isr_exit();
}
uint64_t rtc_pm_sleep_enter(unsigned mode)
{
(void)mode;
if (_rtc_alarm_cb) {
uint64_t sleep = (_sys_alarm_time - _sys_get_time()) * US_PER_SEC;
esp_sleep_enable_timer_wakeup(sleep);
return sleep;
}
return 0;
}
void rtc_pm_sleep_exit(uint32_t cause)
{
/* call the RTC time was the wakeup source and an RTC alarm was set */
if (cause == ESP_SLEEP_WAKEUP_TIMER && _rtc_alarm_cb) {
_rtc_alarm_cb(_rtc_alarm_arg);
_rtc_alarm_cb = 0;
}
}

View File

@ -43,6 +43,7 @@
#include "driver/periph_ctrl.h"
#include "esp/common_macros.h"
#include "esp32/esp_sleep.h"
#include "heap/esp_heap_caps_init.h"
#include "log/esp_log.h"
#include "rom/cache.h"
@ -153,6 +154,13 @@ NORETURN void IRAM call_start_cpu0 (void)
ets_printf("\n");
#endif
if (reset_reason == DEEPSLEEP_RESET) {
/* the cause has to be read to clear it */
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
(void)cause;
LOG_STARTUP("Restart after deep sleep, wake-up cause: %d\n", cause);
}
LOG_STARTUP("Current clocks in Hz: CPU=%d APB=%d XTAL=%d SLOW=%d\n",
rtc_clk_cpu_freq_value(rtc_clk_cpu_freq_get()),
rtc_clk_apb_freq_get(), rtc_clk_xtal_freq_get()*MHZ,

View File

@ -0,0 +1,739 @@
// Copyright 2015-2017 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.
#include <stddef.h>
#include <sys/lock.h>
#include <sys/param.h>
#include "esp_attr.h"
#include "esp_sleep.h"
#ifndef RIOT_VERSION
#include "esp_timer_impl.h"
#endif
#include "esp_log.h"
#include "esp_clk.h"
#ifndef RIOT_VERSION
#include "esp_newlib.h"
#endif
#include "driver/gpio.h"
#include "esp_spi_flash.h"
#include "rom/cache.h"
#include "rom/rtc.h"
#include "rom/uart.h"
#include "soc/cpu.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/spi_reg.h"
#include "soc/sens_reg.h"
#include "soc/dport_reg.h"
#include "driver/rtc_io.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"
// If light sleep time is less than that, don't power down flash
#define FLASH_PD_MIN_SLEEP_TIME_US 2000
// Time from VDD_SDIO power up to first flash read in ROM code
#define VDD_SDIO_POWERUP_TO_FLASH_READ_US 700
// Extra time it takes to enter and exit light sleep and deep sleep
// For deep sleep, this is until the wake stub runs (not the app).
#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
#define LIGHT_SLEEP_TIME_OVERHEAD_US (650 + 30 * 240 / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ)
#define DEEP_SLEEP_TIME_OVERHEAD_US (650 + 100 * 240 / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ)
#else
#define LIGHT_SLEEP_TIME_OVERHEAD_US (250 + 30 * 240 / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ)
#define DEEP_SLEEP_TIME_OVERHEAD_US (250 + 100 * 240 / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ)
#endif // CONFIG_ESP32_RTC_CLOCK_SOURCE
// Minimal amount of time we can sleep for
#define LIGHT_SLEEP_MIN_TIME_US 200
#define CHECK_SOURCE(source, value, mask) ((s_config.wakeup_triggers & mask) && \
(source == value))
/**
* Internal structure which holds all requested deep sleep parameters
*/
typedef struct {
esp_sleep_pd_option_t pd_options[ESP_PD_DOMAIN_MAX];
uint64_t sleep_duration;
uint32_t wakeup_triggers : 11;
uint32_t ext1_trigger_mode : 1;
uint32_t ext1_rtc_gpio_mask : 18;
uint32_t ext0_trigger_level : 1;
uint32_t ext0_rtc_gpio_num : 5;
uint32_t sleep_time_adjustment;
uint64_t rtc_ticks_at_sleep_start;
} sleep_config_t;
static sleep_config_t s_config = {
.pd_options = { ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO },
.wakeup_triggers = 0
};
bool s_light_sleep_wakeup = false;
/* Updating RTC_MEMORY_CRC_REG register via set_rtc_memory_crc()
is not thread-safe. */
static _lock_t lock_rtc_memory_crc;
static const char* TAG = "sleep";
static uint32_t get_power_down_flags(void);
static void ext0_wakeup_prepare(void);
static void ext1_wakeup_prepare(void);
static void timer_wakeup_prepare(void);
/* Wake from deep sleep stub
See esp_deepsleep.h esp_wake_deep_sleep() comments for details.
*/
esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void)
{
_lock_acquire(&lock_rtc_memory_crc);
uint32_t stored_crc = REG_READ(RTC_MEMORY_CRC_REG);
set_rtc_memory_crc();
uint32_t calc_crc = REG_READ(RTC_MEMORY_CRC_REG);
REG_WRITE(RTC_MEMORY_CRC_REG, stored_crc);
_lock_release(&lock_rtc_memory_crc);
if(stored_crc == calc_crc) {
return (esp_deep_sleep_wake_stub_fn_t)REG_READ(RTC_ENTRY_ADDR_REG);
} else {
return NULL;
}
}
void esp_set_deep_sleep_wake_stub(esp_deep_sleep_wake_stub_fn_t new_stub)
{
_lock_acquire(&lock_rtc_memory_crc);
REG_WRITE(RTC_ENTRY_ADDR_REG, (uint32_t)new_stub);
set_rtc_memory_crc();
_lock_release(&lock_rtc_memory_crc);
}
void RTC_IRAM_ATTR esp_default_wake_deep_sleep(void) {
/* Clear MMU for CPU 0 */
_DPORT_REG_WRITE(DPORT_PRO_CACHE_CTRL1_REG,
_DPORT_REG_READ(DPORT_PRO_CACHE_CTRL1_REG) | DPORT_PRO_CACHE_MMU_IA_CLR);
_DPORT_REG_WRITE(DPORT_PRO_CACHE_CTRL1_REG,
_DPORT_REG_READ(DPORT_PRO_CACHE_CTRL1_REG) & (~DPORT_PRO_CACHE_MMU_IA_CLR));
#if CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY > 0
// ROM code has not started yet, so we need to set delay factor
// used by ets_delay_us first.
ets_update_cpu_frequency_rom(ets_get_detected_xtal_freq() / 1000000);
// This delay is configured in menuconfig, it can be used to give
// the flash chip some time to become ready.
ets_delay_us(CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY);
#endif
}
void __attribute__((weak, alias("esp_default_wake_deep_sleep"))) esp_wake_deep_sleep(void);
void esp_deep_sleep(uint64_t time_in_us)
{
esp_sleep_enable_timer_wakeup(time_in_us);
esp_deep_sleep_start();
}
static void IRAM_ATTR flush_uarts(void)
{
for (int i = 0; i < 3; ++i) {
uart_tx_wait_idle(i);
}
}
static void IRAM_ATTR suspend_uarts(void)
{
for (int i = 0; i < 3; ++i) {
REG_SET_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF);
while (REG_GET_FIELD(UART_STATUS_REG(i), UART_ST_UTX_OUT) != 0) {
;
}
}
}
static void IRAM_ATTR resume_uarts(void)
{
for (int i = 0; i < 3; ++i) {
REG_CLR_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XOFF);
REG_SET_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XON);
REG_CLR_BIT(UART_FLOW_CONF_REG(i), UART_FORCE_XON);
}
}
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.
// For light sleep, suspend UART output — it will resume after wakeup.
// For deep sleep, wait for the contents of UART FIFO to be sent.
if (pd_flags & RTC_SLEEP_PD_DIG) {
flush_uarts();
} else {
suspend_uarts();
}
// Save current frequency and switch to XTAL
rtc_cpu_freq_t cpu_freq = rtc_clk_cpu_freq_get();
rtc_clk_cpu_freq_set(RTC_CPU_FREQ_XTAL);
// Configure pins for external wakeup
if (s_config.wakeup_triggers & RTC_EXT0_TRIG_EN) {
ext0_wakeup_prepare();
}
if (s_config.wakeup_triggers & RTC_EXT1_TRIG_EN) {
ext1_wakeup_prepare();
}
// Enable ULP wakeup
if (s_config.wakeup_triggers & RTC_ULP_TRIG_EN) {
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_WAKEUP_FORCE_EN);
}
// Enter sleep
rtc_sleep_config_t config = RTC_SLEEP_CONFIG_DEFAULT(pd_flags);
rtc_sleep_init(config);
// Configure timer wakeup
if ((s_config.wakeup_triggers & RTC_TIMER_TRIG_EN) &&
s_config.sleep_duration > 0) {
timer_wakeup_prepare();
}
uint32_t result = rtc_sleep_start(s_config.wakeup_triggers, 0);
// Restore CPU frequency
rtc_clk_cpu_freq_set(cpu_freq);
// re-enable UART output
resume_uarts();
return result;
}
void IRAM_ATTR esp_deep_sleep_start(void)
{
// record current RTC time
s_config.rtc_ticks_at_sleep_start = rtc_time_get();
#ifndef RIOT_VERSION
esp_sync_counters_rtc_and_frc();
#endif
// Configure wake stub
if (esp_get_deep_sleep_wake_stub() == NULL) {
esp_set_deep_sleep_wake_stub(esp_wake_deep_sleep);
}
// Decide which power domains can be powered down
uint32_t pd_flags = get_power_down_flags();
// Correct the sleep time
s_config.sleep_time_adjustment = DEEP_SLEEP_TIME_OVERHEAD_US;
// Enter sleep
esp_sleep_start(RTC_SLEEP_PD_DIG | RTC_SLEEP_PD_VDDSDIO | RTC_SLEEP_PD_XTAL | pd_flags);
// Because RTC is in a slower clock domain than the CPU, it
// can take several CPU cycles for the sleep mode to start.
while (1) {
;
}
}
static void rtc_wdt_enable(int time_ms)
{
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_SYS_RESET_LENGTH, 7);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_CPU_RESET_LENGTH, 7);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_RESET_RTC);
WRITE_PERI_REG(RTC_CNTL_WDTCONFIG1_REG, rtc_clk_slow_freq_get_hz() * time_ms / 1000);
SET_PERI_REG_MASK(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN | RTC_CNTL_WDT_PAUSE_IN_SLP);
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
}
static void rtc_wdt_disable(void)
{
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_OFF);
REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN);
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
}
/**
* Helper function which handles entry to and exit from light sleep
* Placed into IRAM as flash may need some time to be powered on.
*/
static esp_err_t esp_light_sleep_inner(uint32_t pd_flags,
uint32_t flash_enable_time_us,
rtc_vddsdio_config_t vddsdio_config) IRAM_ATTR __attribute__((noinline));
static esp_err_t esp_light_sleep_inner(uint32_t pd_flags,
uint32_t flash_enable_time_us,
rtc_vddsdio_config_t vddsdio_config)
{
// Enter sleep
esp_err_t err = esp_sleep_start(pd_flags);
// If VDDSDIO regulator was controlled by RTC registers before sleep,
// restore the configuration.
if (vddsdio_config.force) {
rtc_vddsdio_set_config(vddsdio_config);
}
// If SPI flash was powered down, wait for it to become ready
if (pd_flags & RTC_SLEEP_PD_VDDSDIO) {
// Wait for the flash chip to start up
ets_delay_us(flash_enable_time_us);
}
return err;
}
#ifdef RIOT_VERSION
extern void esp_set_time_from_rtc(void);
extern int64_t esp_timer_get_time(void);
#endif
esp_err_t esp_light_sleep_start(void)
{
static portMUX_TYPE light_sleep_lock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&light_sleep_lock);
#ifndef RIOT_VERSION
/* We will be calling esp_timer_impl_advance inside DPORT access critical
* section. Make sure the code on the other CPU is not holding esp_timer
* lock, otherwise there will be deadlock.
*/
esp_timer_impl_lock();
#else
#if (ESP_PM_WUP_UART0 > 2)
/* Enable UART0 wakeup if ESP_PM_WUP_UART0 > 0 */
REG_SET_FIELD(UART_SLEEP_CONF_REG(0), UART_ACTIVE_THRESHOLD, ESP_PM_WUP_UART0 - 2);
s_config.wakeup_triggers |= RTC_UART0_TRIG_EN;
#endif
#if (ESP_PM_WUP_UART1 > 2)
/* Enable UART1 wakeup if ESP_PM_WUP_UART1 > 0 */
REG_SET_FIELD(UART_SLEEP_CONF_REG(1), UART_ACTIVE_THRESHOLD, ESP_PM_WUP_UART1 - 2);
s_config.wakeup_triggers |= RTC_UART1_TRIG_EN;
#endif
#endif
s_config.rtc_ticks_at_sleep_start = rtc_time_get();
uint64_t frc_time_at_start = esp_timer_get_time();
DPORT_STALL_OTHER_CPU_START();
// Decide which power domains can be powered down
uint32_t pd_flags = get_power_down_flags();
// Amount of time to subtract from actual sleep time.
// This is spent on entering and leaving light sleep.
s_config.sleep_time_adjustment = LIGHT_SLEEP_TIME_OVERHEAD_US;
// Decide if VDD_SDIO needs to be powered down;
// If it needs to be powered down, adjust sleep time.
const uint32_t flash_enable_time_us = VDD_SDIO_POWERUP_TO_FLASH_READ_US
+ CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY;
#ifndef CONFIG_SPIRAM_SUPPORT
const uint32_t vddsdio_pd_sleep_duration = MAX(FLASH_PD_MIN_SLEEP_TIME_US,
flash_enable_time_us + LIGHT_SLEEP_TIME_OVERHEAD_US + LIGHT_SLEEP_MIN_TIME_US);
if (s_config.sleep_duration > vddsdio_pd_sleep_duration) {
pd_flags |= RTC_SLEEP_PD_VDDSDIO;
s_config.sleep_time_adjustment += flash_enable_time_us;
}
#endif //CONFIG_SPIRAM_SUPPORT
rtc_vddsdio_config_t vddsdio_config = rtc_vddsdio_get_config();
// Safety net: enable WDT in case exit from light sleep fails
rtc_wdt_enable(1000);
// Enter sleep, then wait for flash to be ready on wakeup
esp_err_t err = esp_light_sleep_inner(pd_flags,
flash_enable_time_us, vddsdio_config);
s_light_sleep_wakeup = true;
#ifndef RIOT_VERSION
/*
* We don't need to advance the system timer in RIOT. If module
* `esp_rtc_timer` is used, the system timer uses directly the RTC timer.
* Otherwise is updated automatically from the RTC timer when
* `esp_set_time_from_rtc` is called after.
*/
// FRC1 has been clock gated for the duration of the sleep, correct for that.
uint64_t rtc_ticks_at_end = rtc_time_get();
uint64_t frc_time_at_end = esp_timer_get_time();
uint64_t rtc_time_diff = rtc_time_slowclk_to_us(rtc_ticks_at_end - s_config.rtc_ticks_at_sleep_start,
esp_clk_slowclk_cal_get());
uint64_t frc_time_diff = frc_time_at_end - frc_time_at_start;
int64_t time_diff = rtc_time_diff - frc_time_diff;
/* Small negative values (up to 1 RTC_SLOW clock period) are possible,
* for very small values of sleep_duration. Ignore those to keep esp_timer
* monotonic.
*/
if (time_diff > 0) {
esp_timer_impl_advance(time_diff);
}
#else
(void)frc_time_at_start;
#endif
esp_set_time_from_rtc();
#ifndef RIOT_VERSION
esp_timer_impl_unlock();
#endif
DPORT_STALL_OTHER_CPU_END();
rtc_wdt_disable();
portEXIT_CRITICAL(&light_sleep_lock);
return err;
}
void system_deep_sleep(uint64_t) __attribute__((alias("esp_deep_sleep")));
esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source)
{
// For most of sources it is enough to set trigger mask in local
// configuration structure. The actual RTC wake up options
// will be updated by esp_sleep_start().
if (source == ESP_SLEEP_WAKEUP_ALL) {
s_config.wakeup_triggers = 0;
} else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_TIMER, RTC_TIMER_TRIG_EN)) {
s_config.wakeup_triggers &= ~RTC_TIMER_TRIG_EN;
s_config.sleep_duration = 0;
} else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_EXT0, RTC_EXT0_TRIG_EN)) {
s_config.ext0_rtc_gpio_num = 0;
s_config.ext0_trigger_level = 0;
s_config.wakeup_triggers &= ~RTC_EXT0_TRIG_EN;
} else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_EXT1, RTC_EXT1_TRIG_EN)) {
s_config.ext1_rtc_gpio_mask = 0;
s_config.ext1_trigger_mode = 0;
s_config.wakeup_triggers &= ~RTC_EXT1_TRIG_EN;
} else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_TOUCHPAD, RTC_TOUCH_TRIG_EN)) {
s_config.wakeup_triggers &= ~RTC_TOUCH_TRIG_EN;
} else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_GPIO, RTC_GPIO_TRIG_EN)) {
s_config.wakeup_triggers &= ~RTC_GPIO_TRIG_EN;
} else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_UART, (RTC_UART0_TRIG_EN | RTC_UART1_TRIG_EN))) {
s_config.wakeup_triggers &= ~(RTC_UART0_TRIG_EN | RTC_UART1_TRIG_EN);
}
#ifdef CONFIG_ULP_COPROC_ENABLED
else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_ULP, RTC_ULP_TRIG_EN)) {
s_config.wakeup_triggers &= ~RTC_ULP_TRIG_EN;
}
#endif
else {
ESP_LOGE(TAG, "Incorrect wakeup source (%d) to disable.", (int) source);
return ESP_ERR_INVALID_STATE;
}
return ESP_OK;
}
esp_err_t esp_sleep_enable_ulp_wakeup(void)
{
#ifdef CONFIG_ULP_COPROC_ENABLED
if(s_config.wakeup_triggers & RTC_EXT0_TRIG_EN) {
ESP_LOGE(TAG, "Conflicting wake-up trigger: ext0");
return ESP_ERR_INVALID_STATE;
}
s_config.wakeup_triggers |= RTC_ULP_TRIG_EN;
return ESP_OK;
#else
return ESP_ERR_INVALID_STATE;
#endif
}
esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us)
{
s_config.wakeup_triggers |= RTC_TIMER_TRIG_EN;
s_config.sleep_duration = time_in_us;
return ESP_OK;
}
static void timer_wakeup_prepare(void)
{
uint32_t period = esp_clk_slowclk_cal_get();
int64_t sleep_duration = (int64_t) s_config.sleep_duration - (int64_t) s_config.sleep_time_adjustment;
if (sleep_duration < 0) {
sleep_duration = 0;
}
int64_t rtc_count_delta = rtc_time_us_to_slowclk(sleep_duration, period);
rtc_sleep_set_wakeup_time(s_config.rtc_ticks_at_sleep_start + rtc_count_delta);
}
esp_err_t esp_sleep_enable_touchpad_wakeup(void)
{
if (s_config.wakeup_triggers & (RTC_EXT0_TRIG_EN)) {
ESP_LOGE(TAG, "Conflicting wake-up trigger: ext0");
return ESP_ERR_INVALID_STATE;
}
s_config.wakeup_triggers |= RTC_TOUCH_TRIG_EN;
return ESP_OK;
}
touch_pad_t esp_sleep_get_touchpad_wakeup_status(void)
{
if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_TOUCHPAD) {
return TOUCH_PAD_MAX;
}
uint32_t touch_mask = REG_GET_FIELD(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_EN);
assert(touch_mask != 0 && "wakeup reason is RTC_TOUCH_TRIG_EN but SENS_TOUCH_MEAS_EN is zero");
return (touch_pad_t) (__builtin_ffs(touch_mask) - 1);
}
esp_err_t esp_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level)
{
if (level < 0 || level > 1) {
return ESP_ERR_INVALID_ARG;
}
if (!RTC_GPIO_IS_VALID_GPIO(gpio_num)) {
return ESP_ERR_INVALID_ARG;
}
if (s_config.wakeup_triggers & (RTC_TOUCH_TRIG_EN | RTC_ULP_TRIG_EN)) {
ESP_LOGE(TAG, "Conflicting wake-up triggers: touch / ULP");
return ESP_ERR_INVALID_STATE;
}
s_config.ext0_rtc_gpio_num = rtc_gpio_desc[gpio_num].rtc_num;
s_config.ext0_trigger_level = level;
s_config.wakeup_triggers |= RTC_EXT0_TRIG_EN;
return ESP_OK;
}
static void ext0_wakeup_prepare(void)
{
int rtc_gpio_num = s_config.ext0_rtc_gpio_num;
// Set GPIO to be used for wakeup
REG_SET_FIELD(RTC_IO_EXT_WAKEUP0_REG, RTC_IO_EXT_WAKEUP0_SEL, rtc_gpio_num);
// Set level which will trigger wakeup
SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1,
s_config.ext0_trigger_level, RTC_CNTL_EXT_WAKEUP0_LV_S);
// Find GPIO descriptor in the rtc_gpio_desc table and configure the pad
for (size_t gpio_num = 0; gpio_num < GPIO_PIN_COUNT; ++gpio_num) {
const rtc_gpio_desc_t* desc = &rtc_gpio_desc[gpio_num];
if (desc->rtc_num == rtc_gpio_num) {
REG_SET_BIT(desc->reg, desc->mux);
SET_PERI_REG_BITS(desc->reg, 0x3, 0, desc->func);
REG_SET_BIT(desc->reg, desc->ie);
break;
}
}
}
esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode_t mode)
{
if (mode > ESP_EXT1_WAKEUP_ANY_HIGH) {
return ESP_ERR_INVALID_ARG;
}
// Translate bit map of GPIO numbers into the bit map of RTC IO numbers
uint32_t rtc_gpio_mask = 0;
for (int gpio = 0; mask; ++gpio, mask >>= 1) {
if ((mask & 1) == 0) {
continue;
}
if (!RTC_GPIO_IS_VALID_GPIO(gpio)) {
ESP_LOGE(TAG, "Not an RTC IO: GPIO%d", gpio);
return ESP_ERR_INVALID_ARG;
}
rtc_gpio_mask |= BIT(rtc_gpio_desc[gpio].rtc_num);
}
s_config.ext1_rtc_gpio_mask = rtc_gpio_mask;
s_config.ext1_trigger_mode = mode;
s_config.wakeup_triggers |= RTC_EXT1_TRIG_EN;
return ESP_OK;
}
static void ext1_wakeup_prepare(void)
{
// Configure all RTC IOs selected as ext1 wakeup inputs
uint32_t rtc_gpio_mask = s_config.ext1_rtc_gpio_mask;
for (int gpio = 0; gpio < GPIO_PIN_COUNT && rtc_gpio_mask != 0; ++gpio) {
int rtc_pin = rtc_gpio_desc[gpio].rtc_num;
if ((rtc_gpio_mask & BIT(rtc_pin)) == 0) {
continue;
}
const rtc_gpio_desc_t* desc = &rtc_gpio_desc[gpio];
// Route pad to RTC
REG_SET_BIT(desc->reg, desc->mux);
SET_PERI_REG_BITS(desc->reg, 0x3, 0, desc->func);
// set input enable in sleep mode
REG_SET_BIT(desc->reg, desc->ie);
// Pad configuration depends on RTC_PERIPH state in sleep mode
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] != ESP_PD_OPTION_ON) {
// RTC_PERIPH will be powered down, so RTC_IO_ registers will
// loose their state. Lock pad configuration.
// Pullups/pulldowns also need to be disabled.
REG_CLR_BIT(desc->reg, desc->pulldown);
REG_CLR_BIT(desc->reg, desc->pullup);
REG_SET_BIT(RTC_CNTL_HOLD_FORCE_REG, desc->hold_force);
}
// Keep track of pins which are processed to bail out early
rtc_gpio_mask &= ~BIT(rtc_pin);
}
// Clear state from previous wakeup
REG_SET_BIT(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_STATUS_CLR);
// Set pins to be used for wakeup
REG_SET_FIELD(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL, s_config.ext1_rtc_gpio_mask);
// Set logic function (any low, all high)
SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1,
s_config.ext1_trigger_mode, RTC_CNTL_EXT_WAKEUP1_LV_S);
}
uint64_t esp_sleep_get_ext1_wakeup_status(void)
{
if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_EXT1) {
return 0;
}
uint32_t status = REG_GET_FIELD(RTC_CNTL_EXT_WAKEUP1_STATUS_REG, RTC_CNTL_EXT_WAKEUP1_STATUS);
// Translate bit map of RTC IO numbers into the bit map of GPIO numbers
uint64_t gpio_mask = 0;
for (int gpio = 0; gpio < GPIO_PIN_COUNT; ++gpio) {
if (!RTC_GPIO_IS_VALID_GPIO(gpio)) {
continue;
}
int rtc_pin = rtc_gpio_desc[gpio].rtc_num;
if ((status & BIT(rtc_pin)) == 0) {
continue;
}
gpio_mask |= 1ULL << gpio;
}
return gpio_mask;
}
esp_err_t esp_sleep_enable_gpio_wakeup(void)
{
if (s_config.wakeup_triggers & (RTC_TOUCH_TRIG_EN | RTC_ULP_TRIG_EN)) {
ESP_LOGE(TAG, "Conflicting wake-up triggers: touch / ULP");
return ESP_ERR_INVALID_STATE;
}
s_config.wakeup_triggers |= RTC_GPIO_TRIG_EN;
return ESP_OK;
}
esp_err_t esp_sleep_enable_uart_wakeup(int uart_num)
{
if (uart_num == 0) {
s_config.wakeup_triggers |= RTC_UART0_TRIG_EN;
} else if (uart_num == 1) {
s_config.wakeup_triggers |= RTC_UART1_TRIG_EN;
} else {
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void)
{
if (rtc_get_reset_reason(0) != DEEPSLEEP_RESET && !s_light_sleep_wakeup) {
return ESP_SLEEP_WAKEUP_UNDEFINED;
}
uint32_t wakeup_cause = REG_GET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_CAUSE);
if (wakeup_cause & RTC_EXT0_TRIG_EN) {
return ESP_SLEEP_WAKEUP_EXT0;
} else if (wakeup_cause & RTC_EXT1_TRIG_EN) {
return ESP_SLEEP_WAKEUP_EXT1;
} else if (wakeup_cause & RTC_TIMER_TRIG_EN) {
return ESP_SLEEP_WAKEUP_TIMER;
} else if (wakeup_cause & RTC_TOUCH_TRIG_EN) {
return ESP_SLEEP_WAKEUP_TOUCHPAD;
} else if (wakeup_cause & RTC_ULP_TRIG_EN) {
return ESP_SLEEP_WAKEUP_ULP;
} else if (wakeup_cause & RTC_GPIO_TRIG_EN) {
return ESP_SLEEP_WAKEUP_GPIO;
} else if (wakeup_cause & (RTC_UART0_TRIG_EN | RTC_UART1_TRIG_EN)) {
return ESP_SLEEP_WAKEUP_UART;
} else {
return ESP_SLEEP_WAKEUP_UNDEFINED;
}
}
esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain,
esp_sleep_pd_option_t option)
{
if (domain >= ESP_PD_DOMAIN_MAX || option > ESP_PD_OPTION_AUTO) {
return ESP_ERR_INVALID_ARG;
}
s_config.pd_options[domain] = option;
return ESP_OK;
}
static uint32_t get_power_down_flags(void)
{
// Where needed, convert AUTO options to ON. Later interpret AUTO as OFF.
// RTC_SLOW_MEM is needed for the ULP, so keep RTC_SLOW_MEM powered up if ULP
// is used and RTC_SLOW_MEM is Auto.
// If there is any data placed into .rtc.data or .rtc.bss segments, and
// RTC_SLOW_MEM is Auto, keep it powered up as well.
// These labels are defined in the linker script:
extern int _rtc_data_start, _rtc_data_end, _rtc_bss_start, _rtc_bss_end;
if ((s_config.pd_options[ESP_PD_DOMAIN_RTC_SLOW_MEM] == ESP_PD_OPTION_AUTO) &&
(&_rtc_data_end > &_rtc_data_start || &_rtc_bss_end > &_rtc_bss_start ||
(s_config.wakeup_triggers & RTC_ULP_TRIG_EN))) {
s_config.pd_options[ESP_PD_DOMAIN_RTC_SLOW_MEM] = ESP_PD_OPTION_ON;
}
// RTC_FAST_MEM is needed for deep sleep stub.
// If RTC_FAST_MEM is Auto, keep it powered on, so that deep sleep stub
// can run.
// In the new chip revision, deep sleep stub will be optional,
// and this can be changed.
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_FAST_MEM] == ESP_PD_OPTION_AUTO) {
s_config.pd_options[ESP_PD_DOMAIN_RTC_FAST_MEM] = ESP_PD_OPTION_ON;
}
// RTC_PERIPH is needed for EXT0 wakeup and GPIO wakeup.
// If RTC_PERIPH is auto, and EXT0/GPIO aren't enabled, power down RTC_PERIPH.
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] == ESP_PD_OPTION_AUTO) {
if (s_config.wakeup_triggers & (RTC_EXT0_TRIG_EN | RTC_GPIO_TRIG_EN)) {
s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] = ESP_PD_OPTION_ON;
} else if (s_config.wakeup_triggers & (RTC_TOUCH_TRIG_EN | RTC_ULP_TRIG_EN)) {
// In both rev. 0 and rev. 1 of ESP32, forcing power up of RTC_PERIPH
// prevents ULP timer and touch FSMs from working correctly.
s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] = ESP_PD_OPTION_OFF;
}
}
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;
}
const char* option_str[] = {"OFF", "ON", "AUTO(OFF)" /* Auto works as OFF */};
#ifdef RIOT_VERSION
(void)option_str;
#endif
ESP_LOGD(TAG, "RTC_PERIPH: %s, RTC_SLOW_MEM: %s, RTC_FAST_MEM: %s",
option_str[s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH]],
option_str[s_config.pd_options[ESP_PD_DOMAIN_RTC_SLOW_MEM]],
option_str[s_config.pd_options[ESP_PD_DOMAIN_RTC_FAST_MEM]]);
// Prepare flags based on the selected options
uint32_t pd_flags = 0;
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_FAST_MEM] != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_RTC_FAST_MEM;
}
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_SLOW_MEM] != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_RTC_SLOW_MEM;
}
if (s_config.pd_options[ESP_PD_DOMAIN_RTC_PERIPH] != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_RTC_PERIPH;
}
if (s_config.pd_options[ESP_PD_DOMAIN_XTAL] != ESP_PD_OPTION_ON) {
pd_flags |= RTC_SLEEP_PD_XTAL;
}
return pd_flags;
}

View File

@ -25,6 +25,7 @@ extern "C" {
#define gpio_num_t gpio_t
#define gpio_pull_mode_t uint32_t
#define gpio_drive_cap_t gpio_drive_strength_t
#ifdef __cplusplus
}

View File

@ -0,0 +1,253 @@
// Copyright 2015-2016 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.
#ifndef DRIVER_RTC_GPIO_H
#define DRIVER_RTC_GPIO_H
#include <stdint.h>
#include "esp_err.h"
#include "driver/gpio.h"
#include "soc/rtc_gpio_channel.h"
#include "soc/rtc_periph.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
RTC_GPIO_MODE_INPUT_ONLY , /*!< Pad input */
RTC_GPIO_MODE_OUTPUT_ONLY, /*!< Pad output */
RTC_GPIO_MODE_INPUT_OUTPUT, /*!< Pad pull input + output */
RTC_GPIO_MODE_DISABLED, /*!< Pad (output + input) disable */
} rtc_gpio_mode_t;
/**
* @brief Determine if the specified GPIO is a valid RTC GPIO.
*
* @param gpio_num GPIO number
* @return true if GPIO is valid for RTC GPIO use. talse otherwise.
*/
inline static bool rtc_gpio_is_valid_gpio(gpio_num_t gpio_num)
{
return gpio_num < GPIO_PIN_COUNT
&& rtc_gpio_desc[gpio_num].reg != 0;
}
#define RTC_GPIO_IS_VALID_GPIO(gpio_num) rtc_gpio_is_valid_gpio(gpio_num) // Deprecated, use rtc_gpio_is_valid_gpio()
/**
* @brief Init a GPIO as RTC GPIO
*
* This function must be called when initializing a pad for an analog function.
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
*
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_init(gpio_num_t gpio_num);
/**
* @brief Init a GPIO as digital GPIO
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
*
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_deinit(gpio_num_t gpio_num);
/**
* @brief Get the RTC IO input level
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
*
* @return
* - 1 High level
* - 0 Low level
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
uint32_t rtc_gpio_get_level(gpio_num_t gpio_num);
/**
* @brief Set the RTC IO output level
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
* @param level output level
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_set_level(gpio_num_t gpio_num, uint32_t level);
/**
* @brief RTC GPIO set direction
*
* Configure RTC GPIO direction, such as output only, input only,
* output and input.
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
* @param mode GPIO direction
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_set_direction(gpio_num_t gpio_num, rtc_gpio_mode_t mode);
/**
* @brief RTC GPIO pullup enable
*
* This function only works for RTC IOs. In general, call gpio_pullup_en,
* which will work both for normal GPIOs and RTC IOs.
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_pullup_en(gpio_num_t gpio_num);
/**
* @brief RTC GPIO pulldown enable
*
* This function only works for RTC IOs. In general, call gpio_pulldown_en,
* which will work both for normal GPIOs and RTC IOs.
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_pulldown_en(gpio_num_t gpio_num);
/**
* @brief RTC GPIO pullup disable
*
* This function only works for RTC IOs. In general, call gpio_pullup_dis,
* which will work both for normal GPIOs and RTC IOs.
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_pullup_dis(gpio_num_t gpio_num);
/**
* @brief RTC GPIO pulldown disable
*
* This function only works for RTC IOs. In general, call gpio_pulldown_dis,
* which will work both for normal GPIOs and RTC IOs.
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_pulldown_dis(gpio_num_t gpio_num);
/**
* @brief Enable hold function on an RTC IO pad
*
* Enabling HOLD function will cause the pad to latch current values of
* input enable, output enable, output value, function, drive strength values.
* This function is useful when going into light or deep sleep mode to prevent
* the pin configuration from changing.
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_hold_en(gpio_num_t gpio_num);
/**
* @brief Disable hold function on an RTC IO pad
*
* Disabling hold function will allow the pad receive the values of
* input enable, output enable, output value, function, drive strength from
* RTC_IO peripheral.
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_hold_dis(gpio_num_t gpio_num);
/**
* @brief Helper function to disconnect internal circuits from an RTC IO
* This function disables input, output, pullup, pulldown, and enables
* hold feature for an RTC IO.
* Use this function if an RTC IO needs to be disconnected from internal
* circuits in deep sleep, to minimize leakage current.
*
* In particular, for ESP32-WROVER module, call
* rtc_gpio_isolate(GPIO_NUM_12) before entering deep sleep, to reduce
* deep sleep current.
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12).
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_isolate(gpio_num_t gpio_num);
/**
* @brief Disable force hold signal for all RTC IOs
*
* Each RTC pad has a "force hold" input signal from the RTC controller.
* If this signal is set, pad latches current values of input enable,
* function, output enable, and other signals which come from the RTC mux.
* Force hold signal is enabled before going into deep sleep for pins which
* are used for EXT1 wakeup.
*/
void rtc_gpio_force_hold_dis_all(void);
/**
* @brief Set RTC GPIO pad drive capability
*
* @param gpio_num GPIO number, only support output GPIOs
* @param strength Drive capability of the pad
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t rtc_gpio_set_drive_capability(gpio_num_t gpio_num, gpio_drive_cap_t strength);
/**
* @brief Get RTC GPIO pad drive capability
*
* @param gpio_num GPIO number, only support output GPIOs
* @param strength Pointer to accept drive capability of the pad
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t rtc_gpio_get_drive_capability(gpio_num_t gpio_num, gpio_drive_cap_t* strength);
#ifdef __cplusplus
}
#endif
#endif /* DRIVER_RTC_GPIO_H */

View File

@ -59,11 +59,14 @@ typedef enum {
*/
typedef enum {
ESP_SLEEP_WAKEUP_UNDEFINED, //!< In case of deep sleep, reset was not caused by exit from deep sleep
ESP_SLEEP_WAKEUP_ALL, //!< Not a wakeup cause, used to disable all wakeup sources
ESP_SLEEP_WAKEUP_EXT0, //!< Wakeup caused by external signal using RTC_IO
ESP_SLEEP_WAKEUP_EXT1, //!< Wakeup caused by external signal using RTC_CNTL
ESP_SLEEP_WAKEUP_TIMER, //!< Wakeup caused by timer
ESP_SLEEP_WAKEUP_TOUCHPAD, //!< Wakeup caused by touchpad
ESP_SLEEP_WAKEUP_ULP, //!< Wakeup caused by ULP program
ESP_SLEEP_WAKEUP_GPIO, //!< Wakeup caused by GPIO (light sleep only)
ESP_SLEEP_WAKEUP_UART, //!< Wakeup caused by UART (light sleep only)} esp_sleep_source_t;
} esp_sleep_source_t;
/* Leave this type define for compatibility */
@ -192,6 +195,43 @@ esp_err_t esp_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level);
*/
esp_err_t esp_sleep_enable_ext1_wakeup(uint64_t mask, esp_sleep_ext1_wakeup_mode_t mode);
/**
* @brief Enable wakeup from light sleep using GPIOs
*
* Each GPIO supports wakeup function, which can be triggered on either low level
* or high level. Unlike EXT0 and EXT1 wakeup sources, this method can be used
* both for all IOs: RTC IOs and digital IOs. It can only be used to wakeup from
* light sleep though.
*
* To enable wakeup, first call gpio_wakeup_enable, specifying gpio number and
* wakeup level, for each GPIO which is used for wakeup.
* Then call this function to enable wakeup feature.
*
* @note In revisions 0 and 1 of the ESP32, GPIO wakeup source
* can not be used together with touch or ULP wakeup sources.
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if wakeup triggers conflict
*/
esp_err_t esp_sleep_enable_gpio_wakeup(void);
/**
* @brief Enable wakeup from light sleep using UART
*
* Use uart_set_wakeup_threshold function to configure UART wakeup threshold.
*
* Wakeup from light sleep takes some time, so not every character sent
* to the UART can be received by the application.
*
* @note ESP32 does not support wakeup from UART2.
*
* @param uart_num UART port to wake up from
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if wakeup from given UART is not supported
*/
esp_err_t esp_sleep_enable_uart_wakeup(int uart_num);
/**
* @brief Get the bit mask of GPIOs which caused wakeup (ext1)

View File

@ -0,0 +1,59 @@
// Copyright 2018 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.
#include "soc/rtc_periph.h"
//Reg,Mux,Fun,IE,Up,Down,Rtc_number
const rtc_gpio_desc_t rtc_gpio_desc[GPIO_PIN_COUNT] = {
{RTC_IO_TOUCH_PAD1_REG, RTC_IO_TOUCH_PAD1_MUX_SEL_M, RTC_IO_TOUCH_PAD1_FUN_SEL_S, RTC_IO_TOUCH_PAD1_FUN_IE_M, RTC_IO_TOUCH_PAD1_RUE_M, RTC_IO_TOUCH_PAD1_RDE_M, RTC_IO_TOUCH_PAD1_SLP_SEL_M, RTC_IO_TOUCH_PAD1_SLP_IE_M, RTC_IO_TOUCH_PAD1_HOLD_M, RTC_CNTL_TOUCH_PAD1_HOLD_FORCE_M, RTC_IO_TOUCH_PAD1_DRV_V, RTC_IO_TOUCH_PAD1_DRV_S, RTCIO_GPIO0_CHANNEL}, //0
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //1
{RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_MUX_SEL_M, RTC_IO_TOUCH_PAD2_FUN_SEL_S, RTC_IO_TOUCH_PAD2_FUN_IE_M, RTC_IO_TOUCH_PAD2_RUE_M, RTC_IO_TOUCH_PAD2_RDE_M, RTC_IO_TOUCH_PAD2_SLP_SEL_M, RTC_IO_TOUCH_PAD2_SLP_IE_M, RTC_IO_TOUCH_PAD2_HOLD_M, RTC_CNTL_TOUCH_PAD2_HOLD_FORCE_M, RTC_IO_TOUCH_PAD2_DRV_V, RTC_IO_TOUCH_PAD2_DRV_S, RTCIO_GPIO2_CHANNEL}, //2
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //3
{RTC_IO_TOUCH_PAD0_REG, RTC_IO_TOUCH_PAD0_MUX_SEL_M, RTC_IO_TOUCH_PAD0_FUN_SEL_S, RTC_IO_TOUCH_PAD0_FUN_IE_M, RTC_IO_TOUCH_PAD0_RUE_M, RTC_IO_TOUCH_PAD0_RDE_M, RTC_IO_TOUCH_PAD0_SLP_SEL_M, RTC_IO_TOUCH_PAD0_SLP_IE_M, RTC_IO_TOUCH_PAD0_HOLD_M, RTC_CNTL_TOUCH_PAD0_HOLD_FORCE_M, RTC_IO_TOUCH_PAD0_DRV_V, RTC_IO_TOUCH_PAD0_DRV_S, RTCIO_GPIO4_CHANNEL}, //4
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //5
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //6
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //7
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //8
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //9
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //10
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //11
{RTC_IO_TOUCH_PAD5_REG, RTC_IO_TOUCH_PAD5_MUX_SEL_M, RTC_IO_TOUCH_PAD5_FUN_SEL_S, RTC_IO_TOUCH_PAD5_FUN_IE_M, RTC_IO_TOUCH_PAD5_RUE_M, RTC_IO_TOUCH_PAD5_RDE_M, RTC_IO_TOUCH_PAD5_SLP_SEL_M, RTC_IO_TOUCH_PAD5_SLP_IE_M, RTC_IO_TOUCH_PAD5_HOLD_M, RTC_CNTL_TOUCH_PAD5_HOLD_FORCE_M, RTC_IO_TOUCH_PAD5_DRV_V, RTC_IO_TOUCH_PAD5_DRV_S, RTCIO_GPIO12_CHANNEL}, //12
{RTC_IO_TOUCH_PAD4_REG, RTC_IO_TOUCH_PAD4_MUX_SEL_M, RTC_IO_TOUCH_PAD4_FUN_SEL_S, RTC_IO_TOUCH_PAD4_FUN_IE_M, RTC_IO_TOUCH_PAD4_RUE_M, RTC_IO_TOUCH_PAD4_RDE_M, RTC_IO_TOUCH_PAD4_SLP_SEL_M, RTC_IO_TOUCH_PAD4_SLP_IE_M, RTC_IO_TOUCH_PAD4_HOLD_M, RTC_CNTL_TOUCH_PAD4_HOLD_FORCE_M, RTC_IO_TOUCH_PAD4_DRV_V, RTC_IO_TOUCH_PAD4_DRV_S, RTCIO_GPIO13_CHANNEL}, //13
{RTC_IO_TOUCH_PAD6_REG, RTC_IO_TOUCH_PAD6_MUX_SEL_M, RTC_IO_TOUCH_PAD6_FUN_SEL_S, RTC_IO_TOUCH_PAD6_FUN_IE_M, RTC_IO_TOUCH_PAD6_RUE_M, RTC_IO_TOUCH_PAD6_RDE_M, RTC_IO_TOUCH_PAD6_SLP_SEL_M, RTC_IO_TOUCH_PAD6_SLP_IE_M, RTC_IO_TOUCH_PAD6_HOLD_M, RTC_CNTL_TOUCH_PAD6_HOLD_FORCE_M, RTC_IO_TOUCH_PAD6_DRV_V, RTC_IO_TOUCH_PAD6_DRV_S, RTCIO_GPIO14_CHANNEL}, //14
{RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_MUX_SEL_M, RTC_IO_TOUCH_PAD3_FUN_SEL_S, RTC_IO_TOUCH_PAD3_FUN_IE_M, RTC_IO_TOUCH_PAD3_RUE_M, RTC_IO_TOUCH_PAD3_RDE_M, RTC_IO_TOUCH_PAD3_SLP_SEL_M, RTC_IO_TOUCH_PAD3_SLP_IE_M, RTC_IO_TOUCH_PAD3_HOLD_M, RTC_CNTL_TOUCH_PAD3_HOLD_FORCE_M, RTC_IO_TOUCH_PAD3_DRV_V, RTC_IO_TOUCH_PAD3_DRV_S, RTCIO_GPIO15_CHANNEL}, //15
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //16
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //17
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //18
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //19
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //20
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //21
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //22
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //23
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //24
{RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_MUX_SEL_M, RTC_IO_PDAC1_FUN_SEL_S, RTC_IO_PDAC1_FUN_IE_M, RTC_IO_PDAC1_RUE_M, RTC_IO_PDAC1_RDE_M, RTC_IO_PDAC1_SLP_SEL_M, RTC_IO_PDAC1_SLP_IE_M, RTC_IO_PDAC1_HOLD_M, RTC_CNTL_PDAC1_HOLD_FORCE_M, RTC_IO_PDAC1_DRV_V, RTC_IO_PDAC1_DRV_S, RTCIO_GPIO25_CHANNEL}, //25
{RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_MUX_SEL_M, RTC_IO_PDAC2_FUN_SEL_S, RTC_IO_PDAC2_FUN_IE_M, RTC_IO_PDAC2_RUE_M, RTC_IO_PDAC2_RDE_M, RTC_IO_PDAC2_SLP_SEL_M, RTC_IO_PDAC2_SLP_IE_M, RTC_IO_PDAC2_HOLD_M, RTC_CNTL_PDAC2_HOLD_FORCE_M, RTC_IO_PDAC2_DRV_V, RTC_IO_PDAC2_DRV_S, RTCIO_GPIO26_CHANNEL}, //26
{RTC_IO_TOUCH_PAD7_REG, RTC_IO_TOUCH_PAD7_MUX_SEL_M, RTC_IO_TOUCH_PAD7_FUN_SEL_S, RTC_IO_TOUCH_PAD7_FUN_IE_M, RTC_IO_TOUCH_PAD7_RUE_M, RTC_IO_TOUCH_PAD7_RDE_M, RTC_IO_TOUCH_PAD7_SLP_SEL_M, RTC_IO_TOUCH_PAD7_SLP_IE_M, RTC_IO_TOUCH_PAD7_HOLD_M, RTC_CNTL_TOUCH_PAD7_HOLD_FORCE_M, RTC_IO_TOUCH_PAD7_DRV_V, RTC_IO_TOUCH_PAD7_DRV_S, RTCIO_GPIO27_CHANNEL}, //27
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //28
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //29
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //30
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //31
{RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_MUX_SEL_M, RTC_IO_X32P_FUN_SEL_S, RTC_IO_X32P_FUN_IE_M, RTC_IO_X32P_RUE_M, RTC_IO_X32P_RDE_M, RTC_IO_X32P_SLP_SEL_M, RTC_IO_X32P_SLP_IE_M, RTC_IO_X32P_HOLD_M, RTC_CNTL_X32P_HOLD_FORCE_M, RTC_IO_X32P_DRV_V, RTC_IO_X32P_DRV_S, RTCIO_GPIO32_CHANNEL}, //32
{RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL_M, RTC_IO_X32N_FUN_SEL_S, RTC_IO_X32N_FUN_IE_M, RTC_IO_X32N_RUE_M, RTC_IO_X32N_RDE_M, RTC_IO_X32N_SLP_SEL_M, RTC_IO_X32N_SLP_IE_M, RTC_IO_X32N_HOLD_M, RTC_CNTL_X32N_HOLD_FORCE_M, RTC_IO_X32N_DRV_V, RTC_IO_X32N_DRV_S, RTCIO_GPIO33_CHANNEL}, //33
{RTC_IO_ADC_PAD_REG, RTC_IO_ADC1_MUX_SEL_M, RTC_IO_ADC1_FUN_SEL_S, RTC_IO_ADC1_FUN_IE_M, 0, 0, RTC_IO_ADC1_SLP_SEL_M, RTC_IO_ADC1_SLP_IE_M, RTC_IO_ADC1_HOLD_M, RTC_CNTL_ADC1_HOLD_FORCE_M, 0, 0, RTCIO_GPIO34_CHANNEL}, //34
{RTC_IO_ADC_PAD_REG, RTC_IO_ADC2_MUX_SEL_M, RTC_IO_ADC2_FUN_SEL_S, RTC_IO_ADC2_FUN_IE_M, 0, 0, RTC_IO_ADC2_SLP_SEL_M, RTC_IO_ADC2_SLP_IE_M, RTC_IO_ADC1_HOLD_M, RTC_CNTL_ADC2_HOLD_FORCE_M, 0, 0, RTCIO_GPIO35_CHANNEL}, //35
{RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE1_MUX_SEL_M, RTC_IO_SENSE1_FUN_SEL_S, RTC_IO_SENSE1_FUN_IE_M, 0, 0, RTC_IO_SENSE1_SLP_SEL_M, RTC_IO_SENSE1_SLP_IE_M, RTC_IO_SENSE1_HOLD_M, RTC_CNTL_SENSE1_HOLD_FORCE_M, 0, 0, RTCIO_GPIO36_CHANNEL}, //36
{RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE2_MUX_SEL_M, RTC_IO_SENSE2_FUN_SEL_S, RTC_IO_SENSE2_FUN_IE_M, 0, 0, RTC_IO_SENSE2_SLP_SEL_M, RTC_IO_SENSE2_SLP_IE_M, RTC_IO_SENSE1_HOLD_M, RTC_CNTL_SENSE2_HOLD_FORCE_M, 0, 0, RTCIO_GPIO37_CHANNEL}, //37
{RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE3_MUX_SEL_M, RTC_IO_SENSE3_FUN_SEL_S, RTC_IO_SENSE3_FUN_IE_M, 0, 0, RTC_IO_SENSE3_SLP_SEL_M, RTC_IO_SENSE3_SLP_IE_M, RTC_IO_SENSE1_HOLD_M, RTC_CNTL_SENSE3_HOLD_FORCE_M, 0, 0, RTCIO_GPIO38_CHANNEL}, //38
{RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE4_MUX_SEL_M, RTC_IO_SENSE4_FUN_SEL_S, RTC_IO_SENSE4_FUN_IE_M, 0, 0, RTC_IO_SENSE4_SLP_SEL_M, RTC_IO_SENSE4_SLP_IE_M, RTC_IO_SENSE1_HOLD_M, RTC_CNTL_SENSE4_HOLD_FORCE_M, 0, 0, RTCIO_GPIO39_CHANNEL}, //39
};

View File

@ -402,6 +402,8 @@ static const char *_esp_wifi_disc_reasons [] = {
"HANDSHAKE_TIMEOUT" /* 204 */
};
static unsigned _esp_wifi_started = 0;
/*
* Event handler for esp system events.
*/
@ -416,6 +418,7 @@ static esp_err_t IRAM_ATTR _esp_system_event_handler(void *ctx, system_event_t *
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
_esp_wifi_started = 1;
ESP_WIFI_DEBUG("WiFi started");
result = esp_wifi_connect();
if (result != ESP_OK) {
@ -424,6 +427,11 @@ static esp_err_t IRAM_ATTR _esp_system_event_handler(void *ctx, system_event_t *
}
break;
case SYSTEM_EVENT_STA_STOP:
_esp_wifi_started = 0;
ESP_WIFI_DEBUG("WiFi stopped");
break;
case SYSTEM_EVENT_SCAN_DONE:
ESP_WIFI_DEBUG("WiFi scan done");
break;
@ -461,19 +469,20 @@ static esp_err_t IRAM_ATTR _esp_system_event_handler(void *ctx, system_event_t *
_esp_wifi_dev.event_disc++;
netdev_trigger_event_isr(&_esp_wifi_dev.netdev);
/* call disconnect to reset internal state */
result = esp_wifi_disconnect();
if (result != ESP_OK) {
ESP_WIFI_LOG_ERROR("esp_wifi_disconnect failed with "
"return value %d", result);
return result;
}
if (reason != WIFI_REASON_ASSOC_LEAVE) {
/* call disconnect to reset internal state */
result = esp_wifi_disconnect();
if (result != ESP_OK) {
ESP_WIFI_LOG_ERROR("esp_wifi_disconnect failed with "
"return value %d", result);
return result;
}
/* try to reconnect */
result = esp_wifi_connect();
if (result != ESP_OK) {
ESP_WIFI_LOG_ERROR("esp_wifi_connect failed with "
"return value %d", result);
/* try to reconnect */
if (_esp_wifi_started && ((result = esp_wifi_connect()) != ESP_OK)) {
ESP_WIFI_LOG_ERROR("esp_wifi_connect failed with "
"return value %d", result);
}
}
break;

View File

@ -131,7 +131,7 @@ TaskHandle_t xTaskGetCurrentTaskHandle(void)
void vTaskDelay( const TickType_t xTicksToDelay )
{
DEBUG("%s xTicksToDelay=%d\n", __func__, xTicksToDelay);
#if defined(MCU_ESP8266) && defined(MODULE_ESP_WIFI_ANY)
#if defined(MODULE_ESP_WIFI_ANY)
uint64_t us = xTicksToDelay * MHZ / xPortGetTickRateHz();
xtimer_usleep(us);
#endif