Skip to content

Commit

Permalink
Merge pull request #13416 from gschorcht/cpu/esp32/pm_layered
Browse files Browse the repository at this point in the history
cpu/esp32: support for light/deep sleep and pm_layered
  • Loading branch information
benpicco authored Mar 23, 2020
2 parents 08afe95 + 4f97731 commit 45b635f
Show file tree
Hide file tree
Showing 23 changed files with 1,665 additions and 203 deletions.
7 changes: 7 additions & 0 deletions boards/esp32-olimex-evb/include/board.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
7 changes: 7 additions & 0 deletions boards/esp32-ttgo-t-beam/include/board.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down
7 changes: 7 additions & 0 deletions boards/esp32-wroom-32/include/board.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
4 changes: 4 additions & 0 deletions cpu/esp32/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions cpu/esp32/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
160 changes: 149 additions & 11 deletions cpu/esp32/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -954,14 +960,146 @@ 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:

- 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)]

Expand Down
10 changes: 0 additions & 10 deletions cpu/esp32/include/adc_ctrl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
59 changes: 45 additions & 14 deletions cpu/esp32/include/gpio_arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand All @@ -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
Expand All @@ -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 */
Loading

0 comments on commit 45b635f

Please sign in to comment.