mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
c2c2cc8592
Since https://github.com/RIOT-OS/RIOT/pull/20935 gpio_write() uses a `bool` instead of an `int`. This does the same treatment for `gpio_read()`. This does indeed add an instruction to `gpio_read()` implementations. However, users caring about an instruction more are better served with `gpio_ll_read()` anyway. And `gpio_read() == 1` is often seen in newcomer's code, which would now work as expected.
574 lines
15 KiB
C
574 lines
15 KiB
C
/*
|
|
* Copyright (C) 2022 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
|
|
* @ingroup drivers_periph_gpio
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief GPIO driver implementation for ESP32
|
|
*
|
|
* @author Gunar Schorcht <gunar@schorcht.net>
|
|
* @}
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <stdbool.h>
|
|
|
|
#include "log.h"
|
|
#include "periph/gpio.h" /* RIOT gpio.h */
|
|
#if IS_USED(MODULE_GPIO_LL)
|
|
#include "periph/gpio_ll_arch.h"
|
|
#endif
|
|
|
|
#include "esp/common_macros.h"
|
|
#include "esp_intr_alloc.h"
|
|
#include "hal/gpio_hal.h"
|
|
#include "hal/gpio_types.h"
|
|
#include "hal/rtc_io_types.h"
|
|
#include "rom/ets_sys.h"
|
|
#include "soc/gpio_reg.h"
|
|
#include "soc/gpio_sig_map.h"
|
|
#include "soc/gpio_struct.h"
|
|
#include "soc/io_mux_reg.h"
|
|
#include "soc/rtc_cntl_reg.h"
|
|
#include "soc/rtc_io_periph.h"
|
|
|
|
#if __xtensa__
|
|
#include "xtensa/xtensa_api.h"
|
|
#endif
|
|
|
|
#include "esp_idf_api/gpio.h"
|
|
|
|
#include "adc_arch.h"
|
|
#include "bitfield.h"
|
|
#include "esp_common.h"
|
|
#include "esp_sleep.h"
|
|
#include "gpio_arch.h"
|
|
#include "irq_arch.h"
|
|
#include "syscalls.h"
|
|
|
|
#define ENABLE_DEBUG 0
|
|
#include "debug.h"
|
|
|
|
#if SOC_PM_SUPPORT_EXT_WAKEUP
|
|
#define ESP_PM_WUP_PINS_ANY_HIGH ESP_EXT1_WAKEUP_ANY_HIGH
|
|
#define ESP_PM_WUP_PINS_ALL_LOW ESP_EXT1_WAKEUP_ALL_LOW
|
|
#define ESP_PM_WUP_PINS_ANY_LOW -1
|
|
#endif
|
|
|
|
#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
|
|
#define ESP_PM_WUP_PINS_ANY_HIGH ESP_GPIO_WAKEUP_GPIO_HIGH
|
|
#define ESP_PM_WUP_PINS_ANY_LOW ESP_GPIO_WAKEUP_GPIO_LOW
|
|
#define ESP_PM_WUP_PINS_ALL_LOW -1
|
|
#endif
|
|
|
|
#ifndef ESP_PM_WUP_LEVEL
|
|
#define ESP_PM_WUP_LEVEL ESP_PM_WUP_PINS_ANY_HIGH
|
|
#endif
|
|
|
|
#if ESP_PM_WUP_LEVEL == -1
|
|
#error "ESP32x SoC does not support this ESP_PM_WUP_LEVEL"
|
|
#endif
|
|
|
|
#define GPIO_PRO_CPU_INTR_ENA (BIT(2))
|
|
|
|
/* architecture specific tables */
|
|
extern gpio_pin_usage_t _gpio_pin_usage[GPIO_PIN_NUMOF];
|
|
|
|
_Static_assert(ARRAY_SIZE(_gpio_pin_usage) == SOC_GPIO_PIN_COUNT,
|
|
"size of _gpio_pin_usage does not match SOC_GPIO_PIN_COUNT");
|
|
|
|
#if !IS_USED(MODULE_ESP_IDF_GPIO_HAL)
|
|
extern const uint32_t _gpio_to_iomux_reg[GPIO_PIN_NUMOF];
|
|
|
|
_Static_assert(ARRAY_SIZE(_gpio_to_iomux_reg) == SOC_GPIO_PIN_COUNT,
|
|
"size of _gpio_to_iomux_reg does not match SOC_GPIO_PIN_COUNT");
|
|
#endif
|
|
|
|
/* String representation of usage types */
|
|
const char* _gpio_pin_usage_str[] =
|
|
{
|
|
"GPIO", "ADC", "CAN", "DAC", "EMAC", "I2C", "PWM", "SPI", "SPI Flash", "UART", "N/A"
|
|
};
|
|
|
|
#ifdef ESP_PM_WUP_PINS
|
|
/* for saving the pullup/pulldown settings of wakeup pins in deep sleep mode */
|
|
bool _gpio_pin_pu[GPIO_PIN_NUMOF] = { };
|
|
bool _gpio_pin_pd[GPIO_PIN_NUMOF] = { };
|
|
#endif
|
|
|
|
#if SOC_GPIO_PIN_COUNT > 32
|
|
|
|
static inline int _gpio_reg_in_get(gpio_t pin)
|
|
{
|
|
return (pin < 32) ? (GPIO.in >> pin) & 1 : (GPIO.in1.val >> (pin - 32)) & 1;
|
|
}
|
|
|
|
static inline int _gpio_reg_out_get(gpio_t pin)
|
|
{
|
|
return (pin < 32) ? (GPIO.out >> pin) & 1 : (GPIO.out1.val >> (pin - 32)) & 1;
|
|
}
|
|
|
|
static inline void _gpio_reg_out_set(gpio_t pin)
|
|
{
|
|
if (pin < 32) {
|
|
GPIO.out_w1ts = BIT(pin);
|
|
}
|
|
else {
|
|
GPIO.out1_w1ts.val = BIT(pin - 32);
|
|
}
|
|
}
|
|
|
|
static inline void _gpio_reg_out_clr(gpio_t pin)
|
|
{
|
|
if (pin < 32) {
|
|
GPIO.out_w1tc = BIT(pin);
|
|
}
|
|
else {
|
|
GPIO.out1_w1tc.val = BIT(pin - 32);
|
|
}
|
|
}
|
|
|
|
static inline void _gpio_reg_out_xor(gpio_t pin)
|
|
{
|
|
if (pin < 32) {
|
|
GPIO.out ^= BIT(pin);
|
|
}
|
|
else {
|
|
GPIO.out1.val ^= BIT(pin - 32);
|
|
}
|
|
}
|
|
|
|
#elif SOC_GPIO_PIN_COUNT < 32
|
|
|
|
static inline int _gpio_reg_in_get(gpio_t pin)
|
|
{
|
|
return (GPIO.in.val >> pin) & 1;
|
|
}
|
|
|
|
static inline int _gpio_reg_out_get(gpio_t pin)
|
|
{
|
|
return (GPIO.out.val >> pin) & 1;
|
|
}
|
|
|
|
static inline void _gpio_reg_out_set(gpio_t pin)
|
|
{
|
|
GPIO.out_w1ts.val = BIT(pin);
|
|
}
|
|
|
|
static inline void _gpio_reg_out_clr(gpio_t pin)
|
|
{
|
|
GPIO.out_w1tc.val = BIT(pin);
|
|
}
|
|
|
|
static inline void _gpio_reg_out_xor(gpio_t pin)
|
|
{
|
|
GPIO.out.val ^= BIT(pin);
|
|
}
|
|
|
|
#else
|
|
#error "Platform implementation is missing"
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
int _gpio_init_mode_check(gpio_t pin, gpio_mode_t mode)
|
|
{
|
|
assert(pin < GPIO_PIN_NUMOF);
|
|
|
|
/* check if the pin can be used as GPIO or if it is used for something else */
|
|
if (_gpio_pin_usage[pin] != _GPIO) {
|
|
LOG_TAG_ERROR("gpio", "GPIO%d is already used as %s signal\n", pin,
|
|
_gpio_pin_usage_str[_gpio_pin_usage[pin]]);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int gpio_init(gpio_t pin, gpio_mode_t mode)
|
|
{
|
|
DEBUG("%s: gpio=%d mode=%d\n", __func__, pin, mode);
|
|
assert(_gpio_init_mode_check(pin, mode) == 0);
|
|
assert(pin < GPIO_PIN_NUMOF);
|
|
|
|
gpio_config_t cfg = { };
|
|
|
|
cfg.pin_bit_mask = (1ULL << pin);
|
|
|
|
switch (mode) {
|
|
case GPIO_IN:
|
|
case GPIO_IN_PD:
|
|
case GPIO_IN_PU:
|
|
cfg.mode = GPIO_MODE_DEF_INPUT;
|
|
break;
|
|
case GPIO_IN_OD:
|
|
case GPIO_IN_OD_PU:
|
|
cfg.mode = GPIO_MODE_DEF_INPUT | GPIO_MODE_DEF_OUTPUT | GPIO_MODE_DEF_OD;
|
|
break;
|
|
case GPIO_IN_OUT:
|
|
cfg.mode = GPIO_MODE_DEF_INPUT | GPIO_MODE_DEF_OUTPUT;
|
|
break;
|
|
case GPIO_OUT:
|
|
cfg.mode = GPIO_MODE_DEF_OUTPUT;
|
|
break;
|
|
case GPIO_OD:
|
|
case GPIO_OD_PU:
|
|
cfg.mode = GPIO_MODE_DEF_OUTPUT | GPIO_MODE_DEF_OD;
|
|
break;
|
|
}
|
|
|
|
/* digital GPIO configuration */
|
|
cfg.pull_up_en = ((mode == GPIO_IN_PU) ||
|
|
(mode == GPIO_OD_PU) ||
|
|
(mode == GPIO_IN_OD_PU)) ? GPIO_PULLUP_ENABLE
|
|
: GPIO_PULLUP_DISABLE;
|
|
cfg.pull_down_en = (mode == GPIO_IN_PD) ? GPIO_PULLDOWN_ENABLE
|
|
: GPIO_PULLDOWN_DISABLE;
|
|
cfg.intr_type = GPIO_INTR_DISABLE;
|
|
|
|
#ifdef ESP_PM_WUP_PINS
|
|
/* for saving the pullup/pulldown settings of wakeup pins in deep sleep mode */
|
|
_gpio_pin_pu[pin] = cfg.pull_up_en;
|
|
_gpio_pin_pd[pin] = cfg.pull_down_en;
|
|
#endif
|
|
|
|
return (esp_idf_gpio_config(&cfg) == ESP_OK) ? 0 : -1;
|
|
}
|
|
|
|
#if MODULE_PERIPH_GPIO_IRQ
|
|
|
|
/* interrupt enabled state is required for sleep modes */
|
|
bool gpio_int_enabled_table[GPIO_PIN_NUMOF] = { };
|
|
bool gpio_isr_service_installed = false;
|
|
|
|
int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
|
|
gpio_cb_t cb, void *arg)
|
|
{
|
|
DEBUG("%s: gpio=%d mode=%d flank=%d\n", __func__, pin, mode, flank);
|
|
assert(_gpio_init_mode_check(pin, mode) == 0);
|
|
|
|
if (gpio_init(pin, mode) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
gpio_int_type_t type = GPIO_INTR_DISABLE;
|
|
|
|
switch (flank) {
|
|
case GPIO_NONE:
|
|
type = GPIO_INTR_DISABLE;
|
|
break;
|
|
case GPIO_RISING:
|
|
type = GPIO_INTR_POSEDGE;
|
|
break;
|
|
case GPIO_FALLING:
|
|
type = GPIO_INTR_NEGEDGE;
|
|
break;
|
|
case GPIO_BOTH:
|
|
type = GPIO_INTR_ANYEDGE;
|
|
break;
|
|
case GPIO_LOW:
|
|
type = GPIO_INTR_LOW_LEVEL;
|
|
break;
|
|
case GPIO_HIGH:
|
|
type = GPIO_INTR_HIGH_LEVEL;
|
|
break;
|
|
}
|
|
|
|
/* install GPIO ISR of ESP-IDF if not yet done */
|
|
if (!gpio_isr_service_installed &&
|
|
esp_idf_gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1) != ESP_OK) {
|
|
return -1;
|
|
}
|
|
gpio_isr_service_installed = true;
|
|
|
|
/* set the interrupt type for the pin */
|
|
if (esp_idf_gpio_set_intr_type(pin, type) != ESP_OK) {
|
|
return -1;
|
|
}
|
|
|
|
/* unmask and clear pending interrupts for the pin */
|
|
if (esp_idf_gpio_isr_handler_add(pin, cb, arg) != ESP_OK) {
|
|
return -1;
|
|
}
|
|
|
|
gpio_irq_enable(pin);
|
|
|
|
return (gpio_int_enabled_table[pin]) ? 0 : -1;
|
|
}
|
|
|
|
void gpio_irq_enable(gpio_t pin)
|
|
{
|
|
DEBUG("%s: gpio=%d\n", __func__, pin);
|
|
assert(pin < GPIO_PIN_NUMOF);
|
|
|
|
if (esp_idf_gpio_intr_enable(pin) == ESP_OK) {
|
|
gpio_int_enabled_table[pin] = true;
|
|
}
|
|
}
|
|
|
|
void gpio_irq_disable(gpio_t pin)
|
|
{
|
|
DEBUG("%s: gpio=%d\n", __func__, pin);
|
|
assert(pin < GPIO_PIN_NUMOF);
|
|
|
|
if (esp_idf_gpio_intr_disable(pin) == ESP_OK) {
|
|
gpio_int_enabled_table[pin] = false;
|
|
}
|
|
}
|
|
|
|
#endif /* MODULE_PERIPH_GPIO_IRQ */
|
|
|
|
#if IS_USED(MODULE_ESP_IDF_GPIO_HAL)
|
|
|
|
static gpio_hal_context_t _gpio_hal_ctx = {
|
|
.dev = GPIO_HAL_GET_HW(0)
|
|
};
|
|
|
|
/*
|
|
* Since `gpio_hal_get_level` returns the current pin level and not the value
|
|
* last written to the output, we have to handle the state of each pin in a
|
|
* separate static variable.
|
|
*/
|
|
static BITFIELD(_output, GPIO_PIN_NUMOF);
|
|
|
|
bool gpio_read(gpio_t pin)
|
|
{
|
|
assert(pin < GPIO_PIN_NUMOF);
|
|
|
|
/* if the pin is not an input, it alsways returns 0 */
|
|
/* TODO: not really clear whether it should return the last written value
|
|
* in this case. */
|
|
int value = gpio_hal_get_level(&_gpio_hal_ctx, pin);
|
|
|
|
DEBUG("%s gpio=%u val=%d\n", __func__, pin, value);
|
|
return value;
|
|
}
|
|
|
|
void gpio_write(gpio_t pin, bool value)
|
|
{
|
|
DEBUG("%s gpio=%u val=%d\n", __func__, pin, value);
|
|
assert(pin < GPIO_PIN_NUMOF);
|
|
|
|
if (value) {
|
|
bf_set(_output, pin);
|
|
}
|
|
else {
|
|
bf_unset(_output, pin);
|
|
}
|
|
gpio_hal_set_level(&_gpio_hal_ctx, pin, value);
|
|
}
|
|
|
|
void gpio_set(gpio_t pin)
|
|
{
|
|
DEBUG("%s gpio=%u\n", __func__, pin);
|
|
assert(pin < GPIO_PIN_NUMOF);
|
|
|
|
bf_set(_output, pin);
|
|
gpio_hal_set_level(&_gpio_hal_ctx, pin, 1);
|
|
}
|
|
|
|
void gpio_clear(gpio_t pin)
|
|
{
|
|
DEBUG("%s gpio=%u\n", __func__, pin);
|
|
assert(pin < GPIO_PIN_NUMOF);
|
|
|
|
bf_unset(_output, pin);
|
|
gpio_hal_set_level(&_gpio_hal_ctx, pin, 0);
|
|
}
|
|
|
|
void gpio_toggle(gpio_t pin)
|
|
{
|
|
DEBUG("%s gpio=%u\n", __func__, pin);
|
|
assert(pin < GPIO_PIN_NUMOF);
|
|
|
|
bf_toggle(_output, pin);
|
|
gpio_hal_set_level(&_gpio_hal_ctx, pin, bf_isset(_output, pin) ? 1 : 0);
|
|
}
|
|
|
|
#else /* IS_USED(MODULE_ESP_IDF_GPIO_HAL) */
|
|
|
|
bool gpio_read(gpio_t pin)
|
|
{
|
|
assert(pin < GPIO_PIN_NUMOF);
|
|
|
|
int value;
|
|
|
|
if (REG_GET_BIT(_gpio_to_iomux_reg[pin], FUN_IE)) {
|
|
/* in case the pin is any kind of input, read from input register */
|
|
value = _gpio_reg_in_get(pin);
|
|
}
|
|
else {
|
|
/* otherwise read the last value written to the output register */
|
|
value = _gpio_reg_out_get(pin);
|
|
}
|
|
DEBUG("%s gpio=%u val=%d\n", __func__, pin, value);
|
|
return value;
|
|
}
|
|
|
|
void gpio_write(gpio_t pin, bool value)
|
|
{
|
|
DEBUG("%s gpio=%u val=%d\n", __func__, pin, value);
|
|
assert(pin < GPIO_PIN_NUMOF);
|
|
if (value) {
|
|
_gpio_reg_out_set(pin);
|
|
}
|
|
else {
|
|
_gpio_reg_out_clr(pin);
|
|
}
|
|
}
|
|
|
|
void gpio_set(gpio_t pin)
|
|
{
|
|
DEBUG("%s gpio=%u\n", __func__, pin);
|
|
assert(pin < GPIO_PIN_NUMOF);
|
|
_gpio_reg_out_set(pin);
|
|
}
|
|
|
|
void gpio_clear(gpio_t pin)
|
|
{
|
|
DEBUG("%s gpio=%u\n", __func__, pin);
|
|
assert(pin < GPIO_PIN_NUMOF);
|
|
_gpio_reg_out_clr(pin);
|
|
|
|
}
|
|
|
|
void gpio_toggle(gpio_t pin)
|
|
{
|
|
DEBUG("%s gpio=%u\n", __func__, pin);
|
|
assert(pin < GPIO_PIN_NUMOF);
|
|
_gpio_reg_out_xor(pin);
|
|
}
|
|
|
|
#endif /* IS_USED(MODULE_ESP_IDF_GPIO_HAL) */
|
|
|
|
int gpio_set_pin_usage(gpio_t pin, gpio_pin_usage_t usage)
|
|
{
|
|
assert(pin < GPIO_PIN_NUMOF);
|
|
_gpio_pin_usage[pin] = usage;
|
|
return 0;
|
|
}
|
|
|
|
gpio_pin_usage_t gpio_get_pin_usage (gpio_t pin)
|
|
{
|
|
return (pin < GPIO_PIN_NUMOF) ? _gpio_pin_usage[pin] : _NOT_EXIST;
|
|
}
|
|
|
|
const char* gpio_get_pin_usage_str(gpio_t pin)
|
|
{
|
|
return _gpio_pin_usage_str[_gpio_pin_usage[((pin < GPIO_PIN_NUMOF) ? pin : _NOT_EXIST)]];
|
|
}
|
|
|
|
#if MODULE_PERIPH_GPIO_IRQ
|
|
static uint32_t gpio_int_saved_type[GPIO_PIN_NUMOF];
|
|
#endif
|
|
|
|
void gpio_pm_sleep_enter(unsigned mode)
|
|
{
|
|
if (mode == ESP_PM_DEEP_SLEEP) {
|
|
#ifdef ESP_PM_GPIO_HOLD
|
|
/*
|
|
* Activate the power domain for RTC peripherals when
|
|
* ESP_PM_GPIO_HOLD is defined for deep sleep mode.
|
|
*/
|
|
esp_idf_gpio_deep_sleep_hold();
|
|
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
|
#endif
|
|
|
|
#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];
|
|
|
|
#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
|
|
/* If internal pullups/pulldowns are used, they have to be
|
|
activated also in deep sleep mode in RTC power domain */
|
|
bool pu_pd_used = false;
|
|
|
|
assert(rtc_io_num_map[wup_pins[i]] >= 0);
|
|
if (_gpio_pin_pu[wup_pins[i]]) {
|
|
pu_pd_used = true;
|
|
esp_idf_rtc_gpio_pullup_en(wup_pins[i]);
|
|
}
|
|
else {
|
|
esp_idf_rtc_gpio_pullup_dis(wup_pins[i]);
|
|
}
|
|
if (_gpio_pin_pd[wup_pins[i]]) {
|
|
pu_pd_used = true;
|
|
esp_idf_rtc_gpio_pulldown_en(wup_pins[i]);
|
|
}
|
|
else {
|
|
esp_idf_rtc_gpio_pulldown_dis(wup_pins[i]);
|
|
}
|
|
if (pu_pd_used) {
|
|
/* If internal pullups/pulldowns are used, the RTC power domain
|
|
* must remain active in deep sleep mode */
|
|
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
|
}
|
|
#endif /* SOC_RTCIO_INPUT_OUTPUT_SUPPORTED */
|
|
}
|
|
#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
|
|
/* ESP_PM_WUP_PINS_ANY_LOW or ESP_PM_WUP_PINS_ANY_HIGH */
|
|
esp_deep_sleep_enable_gpio_wakeup(wup_pin_mask, ESP_PM_WUP_LEVEL);
|
|
#elif SOC_PM_SUPPORT_EXT_WAKEUP
|
|
/* ESP_PM_WUP_PINS_ALL_LOW or ESP_PM_WUP_PINS_ANY_HIGH */
|
|
esp_sleep_enable_ext1_wakeup(wup_pin_mask, ESP_PM_WUP_LEVEL);
|
|
#else
|
|
#error "ESP32x SoC variant doesn't allow to define GPIOs for wake-up from deep sleep"
|
|
#endif
|
|
#endif /* ESP_PM_WUP_PINS */
|
|
}
|
|
else {
|
|
#if MODULE_PERIPH_GPIO_IRQ
|
|
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] = GPIO.pin[i].int_type;
|
|
switch (gpio_int_saved_type[i]) {
|
|
case GPIO_LOW:
|
|
case GPIO_FALLING:
|
|
esp_idf_gpio_wakeup_enable(i, GPIO_INTR_LOW_LEVEL);
|
|
DEBUG("%s gpio=%u GPIO_LOW\n", __func__, i);
|
|
break;
|
|
case GPIO_HIGH:
|
|
case GPIO_RISING:
|
|
esp_idf_gpio_wakeup_enable(i, GPIO_INTR_HIGH_LEVEL);
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
esp_sleep_enable_gpio_wakeup();
|
|
#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
|
|
}
|