mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 05:32:45 +01:00
Merge pull request #17442 from gschorcht/cpu/esp32/periph_gpio_ll
cpu/esp32: implement periph/gpio_ll and periph/gpio_ll_irq
This commit is contained in:
commit
44440caf68
@ -17,6 +17,10 @@ config CPU_FAM_ESP32
|
||||
select HAS_ESP_BLE_ESP32
|
||||
select HAS_ESP_HW_COUNTER
|
||||
select HAS_ESP_WIFI_ENTERPRISE
|
||||
select HAS_PERIPH_GPIO_LL
|
||||
select HAS_PERIPH_GPIO_LL_IRQ
|
||||
select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_HIGH
|
||||
select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_LOW
|
||||
select HAS_PUF_SRAM
|
||||
|
||||
select PACKAGE_ESP32_SDK if TEST_KCONFIG
|
||||
|
@ -18,6 +18,10 @@ config CPU_FAM_ESP32C3
|
||||
select HAS_ESP_BLE
|
||||
select HAS_ESP_BLE_ESP32C3
|
||||
select HAS_ESP_WIFI_ENTERPRISE
|
||||
select HAS_PERIPH_GPIO_LL
|
||||
select HAS_PERIPH_GPIO_LL_IRQ
|
||||
select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_HIGH
|
||||
select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_LOW
|
||||
select HAS_PUF_SRAM
|
||||
|
||||
select PACKAGE_ESP32_SDK if TEST_KCONFIG
|
||||
|
@ -13,6 +13,10 @@ config CPU_FAM_ESP32S2
|
||||
select HAS_CPU_ESP32
|
||||
select HAS_ESP_HW_COUNTER
|
||||
select HAS_ESP_WIFI_ENTERPRISE
|
||||
select HAS_PERIPH_GPIO_LL
|
||||
select HAS_PERIPH_GPIO_LL_IRQ
|
||||
select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_HIGH
|
||||
select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_LOW
|
||||
select HAS_PUF_SRAM
|
||||
|
||||
select PACKAGE_ESP32_SDK if TEST_KCONFIG
|
||||
|
@ -19,6 +19,10 @@ config CPU_FAM_ESP32S3
|
||||
select HAS_ESP_BLE_ESP32C3
|
||||
select HAS_ESP_HW_COUNTER
|
||||
select HAS_ESP_WIFI_ENTERPRISE
|
||||
select HAS_PERIPH_GPIO_LL
|
||||
select HAS_PERIPH_GPIO_LL_IRQ
|
||||
select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_HIGH
|
||||
select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_LOW
|
||||
select HAS_PUF_SRAM
|
||||
|
||||
select PACKAGE_ESP32_SDK if TEST_KCONFIG
|
||||
|
@ -17,6 +17,10 @@ include $(RIOTCPU)/esp_common/Makefile.features
|
||||
|
||||
FEATURES_PROVIDED += arch_esp32
|
||||
FEATURES_PROVIDED += esp_wifi_enterprise
|
||||
FEATURES_PROVIDED += periph_gpio_ll
|
||||
FEATURES_PROVIDED += periph_gpio_ll_irq
|
||||
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_high
|
||||
FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low
|
||||
FEATURES_PROVIDED += puf_sram
|
||||
|
||||
ifeq (xtensa,$(CPU_ARCH))
|
||||
|
@ -31,6 +31,11 @@ esp_err_t esp_idf_gpio_config(const gpio_config_t *cfg)
|
||||
return gpio_config(cfg);
|
||||
}
|
||||
|
||||
esp_err_t esp_idf_gpio_reset_pin(gpio_num_t gpio_num)
|
||||
{
|
||||
return gpio_reset_pin(gpio_num);
|
||||
}
|
||||
|
||||
esp_err_t esp_idf_gpio_intr_enable(gpio_num_t gpio_num)
|
||||
{
|
||||
return gpio_intr_enable(gpio_num);
|
||||
@ -88,6 +93,12 @@ esp_err_t esp_idf_gpio_deep_sleep_hold(void)
|
||||
}
|
||||
#endif /* ESP_PM_GPIO_HOLD */
|
||||
|
||||
esp_err_t esp_idf_gpio_set_drive_capability(gpio_num_t gpio_num,
|
||||
gpio_drive_cap_t strength)
|
||||
{
|
||||
return gpio_set_drive_capability(gpio_num, strength);
|
||||
}
|
||||
|
||||
#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
|
||||
esp_err_t esp_idf_rtc_gpio_deinit(gpio_num_t gpio_num)
|
||||
|
||||
|
@ -33,6 +33,7 @@ extern "C" {
|
||||
* @{
|
||||
*/
|
||||
esp_err_t esp_idf_gpio_config(const gpio_config_t *cfg);
|
||||
esp_err_t esp_idf_gpio_reset_pin(gpio_num_t gpio_num);
|
||||
|
||||
esp_err_t esp_idf_gpio_intr_enable(gpio_num_t gpio_num);
|
||||
esp_err_t esp_idf_gpio_intr_disable(gpio_num_t gpio_num);
|
||||
@ -45,6 +46,8 @@ esp_err_t esp_idf_gpio_isr_handler_add(gpio_num_t gpio_num,
|
||||
esp_err_t esp_idf_gpio_wakeup_enable(gpio_num_t gpio_num,
|
||||
gpio_int_type_t intr_type);
|
||||
esp_err_t esp_idf_gpio_deep_sleep_hold(void);
|
||||
esp_err_t esp_idf_gpio_set_drive_capability(gpio_num_t gpio_num,
|
||||
gpio_drive_cap_t strength);
|
||||
|
||||
esp_err_t esp_idf_rtc_gpio_deinit(gpio_num_t gpio_num);
|
||||
esp_err_t esp_idf_rtc_gpio_pullup_en(gpio_num_t gpio_num);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Gunar Schorcht
|
||||
* Copyright (C) 2021 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
|
||||
|
133
cpu/esp32/include/gpio_ll_arch.h
Normal file
133
cpu/esp32/include/gpio_ll_arch.h
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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_ll
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief CPU specific part of the Peripheral GPIO Low-Level API
|
||||
*
|
||||
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifndef GPIO_LL_ARCH_H
|
||||
#define GPIO_LL_ARCH_H
|
||||
|
||||
#include "gpio_arch.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/gpio_struct.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef DOXYGEN /* hide implementation specific details from Doxygen */
|
||||
|
||||
#define GPIO_PORT(num) ((gpio_port_t)(&_esp32_ports[num]))
|
||||
#define GPIO_PORT_NUM(port) (((_esp32_port_t*)port == _esp32_ports) ? 0 : 1)
|
||||
|
||||
/* GPIO port descriptor type */
|
||||
typedef struct {
|
||||
volatile uint32_t *out; /* address of GPIO_OUT/GPIO_OUT1 */
|
||||
volatile uint32_t *out_w1ts; /* address of GPIO_OUT_W1TS/GPIO_OUT1_W1TC */
|
||||
volatile uint32_t *out_w1tc; /* address of GPIO_OUT_W1TC/GPIO_OUT1_W1TC */
|
||||
volatile uint32_t *in; /* address of GPIO_IN/GPIO_IN1 */
|
||||
volatile uint32_t *enable; /* address of GPIO_ENABLE/GPIO_ENABLE1 */
|
||||
volatile uint32_t *enable_w1ts; /* address of GPIO_ENABLE_W1TS/GPIO_ENABLE1_W1TS */
|
||||
volatile uint32_t *enable_w1tc; /* address of GPIO_ENABLE_W1TC/GPIO_ENABLE1_W1TC */
|
||||
volatile uint32_t *status_w1tc; /* address of GPIO_STATUS_W1TC/GPIO_STATUS1_W1TC */
|
||||
} _esp32_port_t;
|
||||
|
||||
/* GPIO port table */
|
||||
extern const _esp32_port_t _esp32_ports[];
|
||||
|
||||
static inline uword_t gpio_ll_read(gpio_port_t port)
|
||||
{
|
||||
/* return 0 for unconfigured pins, the current level at the pin otherwise */
|
||||
const _esp32_port_t *p = (_esp32_port_t *)port;
|
||||
return *p->in;
|
||||
}
|
||||
|
||||
static inline uword_t gpio_ll_read_output(gpio_port_t port)
|
||||
{
|
||||
/* return output register bits */
|
||||
const _esp32_port_t *p = (_esp32_port_t *)port;
|
||||
return *p->out;
|
||||
}
|
||||
|
||||
static inline void gpio_ll_set(gpio_port_t port, uword_t mask)
|
||||
{
|
||||
/* set output register bits for configured pins in the mask */
|
||||
const _esp32_port_t *p = (_esp32_port_t *)port;
|
||||
*p->out_w1ts = mask;
|
||||
}
|
||||
|
||||
static inline void gpio_ll_clear(gpio_port_t port, uword_t mask)
|
||||
{
|
||||
/* clear output register bits for configured pins in the mask */
|
||||
const _esp32_port_t *p = (_esp32_port_t *)port;
|
||||
*p->out_w1tc = mask;
|
||||
}
|
||||
|
||||
static inline void gpio_ll_toggle(gpio_port_t port, uword_t mask)
|
||||
{
|
||||
/* toggle output register bits for configured pins in the mask */
|
||||
const _esp32_port_t *p = (_esp32_port_t *)port;
|
||||
*p->out ^= mask;
|
||||
}
|
||||
|
||||
static inline void gpio_ll_write(gpio_port_t port, uword_t value)
|
||||
{
|
||||
/* write output register bits for configured pins in the mask */
|
||||
const _esp32_port_t *p = (_esp32_port_t *)port;
|
||||
*p->out = value;
|
||||
}
|
||||
|
||||
static inline gpio_port_t gpio_get_port(gpio_t pin)
|
||||
{
|
||||
return GPIO_PORT(pin >> 5);
|
||||
}
|
||||
|
||||
static inline uint8_t gpio_get_pin_num(gpio_t pin)
|
||||
{
|
||||
return pin & 0x1f;
|
||||
}
|
||||
|
||||
static inline gpio_port_t gpio_port_pack_addr(void *addr)
|
||||
{
|
||||
return (gpio_port_t)addr;
|
||||
}
|
||||
|
||||
static inline void * gpio_port_unpack_addr(gpio_port_t port)
|
||||
{
|
||||
const _esp32_port_t *p = (_esp32_port_t *)port;
|
||||
|
||||
/* return NULL if port is one of the port descriptors in GPIO port table */
|
||||
#if GPIO_PORT_NUMOF > 1
|
||||
return ((p == &_esp32_ports[0]) ||
|
||||
(p == &_esp32_ports[1])) ? NULL : (void *)port;
|
||||
#else
|
||||
return (p == _esp32_ports) ? NULL : (void *)port;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool is_gpio_port_num_valid(uint_fast8_t num)
|
||||
{
|
||||
return (num < GPIO_PORT_NUMOF);
|
||||
}
|
||||
|
||||
#endif /* DOXYGEN */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GPIO_LL_ARCH_H */
|
@ -88,7 +88,7 @@ typedef unsigned int gpio_t;
|
||||
* @brief Define a CPU specific GPIO pin generator macro
|
||||
* @{
|
||||
*/
|
||||
#define GPIO_PIN(x, y) ((x & 0) | y)
|
||||
#define GPIO_PIN(x, y) ((x << 5) | y)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
@ -118,7 +118,7 @@ typedef enum {
|
||||
GPIO_FALLING, /**< emit interrupt on falling flank */
|
||||
GPIO_BOTH, /**< emit interrupt on both flanks */
|
||||
GPIO_LOW, /**< emit interrupt on low level */
|
||||
GPIO_HIGH /**< emit interrupt on low level */
|
||||
GPIO_HIGH /**< emit interrupt on high level */
|
||||
} gpio_flank_t;
|
||||
/** @} */
|
||||
|
||||
@ -141,6 +141,84 @@ typedef enum {
|
||||
} gpio_mode_t;
|
||||
/** @} */
|
||||
|
||||
/* BEGIN: GPIO LL overwrites */
|
||||
|
||||
#if SOC_GPIO_PIN_COUNT > 32
|
||||
|
||||
#define GPIO_PORT_NUMOF 2
|
||||
#define GPIO_PORT_0 GPIO_PORT(0)
|
||||
#define GPIO_PORT_1 GPIO_PORT(1)
|
||||
#define GPIO_PORT_0_PIN_NUMOF (32)
|
||||
#define GPIO_PORT_1_PIN_NUMOF (SOC_GPIO_PIN_COUNT - 32)
|
||||
#define GPIO_PORT_PIN_NUMOF(p) ((p == GPIO_PORT_0) ? GPIO_PORT_0_PIN_NUMOF \
|
||||
: GPIO_PORT_1_PIN_NUMOF)
|
||||
#else
|
||||
|
||||
#define GPIO_PORT_NUMOF 1
|
||||
#define GPIO_PORT_0 GPIO_PORT(0)
|
||||
#define GPIO_PORT_0_PIN_NUMOF (SOC_GPIO_PIN_COUNT)
|
||||
#define GPIO_PORT_PIN_NUMOF(p) ((p == GPIO_PORT_0) ? GPIO_PORT_0_PIN_NUMOF : 0)
|
||||
|
||||
#endif
|
||||
|
||||
#define HAVE_GPIO_PORT_T
|
||||
typedef uintptr_t gpio_port_t;
|
||||
|
||||
#define HAVE_GPIO_SLEW_T
|
||||
typedef enum {
|
||||
GPIO_SLEW_SLOWEST = 0,
|
||||
GPIO_SLEW_SLOW = 0,
|
||||
GPIO_SLEW_FAST = 0,
|
||||
GPIO_SLEW_FASTEST = 0,
|
||||
} gpio_slew_t;
|
||||
|
||||
#define HAVE_GPIO_PULL_STRENGTH_T
|
||||
typedef enum {
|
||||
GPIO_PULL_WEAKEST = 0,
|
||||
GPIO_PULL_WEAK = 0,
|
||||
GPIO_PULL_STRONG = 0,
|
||||
GPIO_PULL_STRONGEST = 0
|
||||
} gpio_pull_strength_t;
|
||||
|
||||
#define HAVE_GPIO_PULL_T
|
||||
typedef enum {
|
||||
GPIO_FLOATING = 0,
|
||||
GPIO_PULL_UP = 1,
|
||||
GPIO_PULL_DOWN = 2,
|
||||
GPIO_PULL_KEEP = 0xff /*< not supported */
|
||||
} gpio_pull_t;
|
||||
|
||||
/**
|
||||
* @brief Current an output pin can drive in active and sleep modes
|
||||
*/
|
||||
#define HAVE_GPIO_DRIVE_STRENGTH_T
|
||||
typedef enum {
|
||||
GPIO_DRIVE_WEAKEST = 0, /**< 5 mA */
|
||||
GPIO_DRIVE_WEAK = 1, /**< 10 mA */
|
||||
GPIO_DRIVE_STRONG = 2, /**< 20 mA (default) */
|
||||
GPIO_DRIVE_STRONGEST = 3, /**< 30 mA */
|
||||
} gpio_drive_strength_t;
|
||||
|
||||
/*
|
||||
* @brief Map former enumeration values the new enumeration values for compatibility.
|
||||
*/
|
||||
#define GPIO_DRIVE_5 GPIO_DRIVE_WEAKEST /**< 5 mA */
|
||||
#define GPIO_DRIVE_10 GPIO_DRIVE_WEAK /**< 10 mA */
|
||||
#define GPIO_DRIVE_20 GPIO_DRIVE_STRONG /**< 20 mA (default) */
|
||||
#define GPIO_DRIVE_30 GPIO_DRIVE_STRONGEST /**< 30 mA */
|
||||
|
||||
#define HAVE_GPIO_IRQ_TRIG_T
|
||||
typedef enum {
|
||||
GPIO_TRIGGER_NONE = 0,
|
||||
GPIO_TRIGGER_EDGE_RISING = 1,
|
||||
GPIO_TRIGGER_EDGE_FALLING = 2,
|
||||
GPIO_TRIGGER_EDGE_BOTH = 3,
|
||||
GPIO_TRIGGER_LEVEL_LOW = 4,
|
||||
GPIO_TRIGGER_LEVEL_HIGH = 5
|
||||
} gpio_irq_trig_t;
|
||||
|
||||
/* END: GPIO LL overwrites */
|
||||
|
||||
#endif /* ndef DOXYGEN */
|
||||
/** @} */
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Low-level GPIO driver implementation for ESP32
|
||||
* @brief GPIO driver implementation for ESP32
|
||||
*
|
||||
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||
* @}
|
||||
@ -23,12 +23,15 @@
|
||||
|
||||
#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 "esp/common_macros.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
@ -77,7 +80,7 @@
|
||||
#define GPIO_PRO_CPU_INTR_ENA (BIT(2))
|
||||
|
||||
/* architecture specific tables */
|
||||
extern gpio_pin_usage_t _gpio_pin_usage [GPIO_PIN_NUMOF];
|
||||
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");
|
||||
@ -97,25 +100,78 @@ const char* _gpio_pin_usage_str[] =
|
||||
|
||||
#ifdef ESP_PM_WUP_PINS
|
||||
/* for saving the pullup/pulldown settings of wakeup pins in deep sleep mode */
|
||||
static bool _gpio_pin_pu[GPIO_PIN_NUMOF] = { };
|
||||
static bool _gpio_pin_pd[GPIO_PIN_NUMOF] = { };
|
||||
bool _gpio_pin_pu[GPIO_PIN_NUMOF] = { };
|
||||
bool _gpio_pin_pd[GPIO_PIN_NUMOF] = { };
|
||||
#endif
|
||||
|
||||
#if defined(CPU_FAM_ESP32) || defined(CPU_FAM_ESP32S2) || defined(CPU_FAM_ESP32S3)
|
||||
#if SOC_GPIO_PIN_COUNT > 32
|
||||
|
||||
#define GPIO_IN_GET(b) (b < 32) ? GPIO.in & BIT(b) : GPIO.in1.val & BIT(b-32)
|
||||
#define GPIO_OUT_SET(b) if (b < 32) { GPIO.out_w1ts = BIT(b); } else { GPIO.out1_w1ts.val = BIT(b-32); }
|
||||
#define GPIO_OUT_CLR(b) if (b < 32) { GPIO.out_w1tc = BIT(b); } else { GPIO.out1_w1tc.val = BIT(b-32); }
|
||||
#define GPIO_OUT_XOR(b) if (b < 32) { GPIO.out ^= BIT(b); } else { GPIO.out1.val ^= BIT(b-32); }
|
||||
#define GPIO_OUT_GET(b) (b < 32) ? (GPIO.out >> b) & 1 : (GPIO.out1.val >> (b-32)) & 1
|
||||
static inline int _gpio_reg_in_get(gpio_t pin)
|
||||
{
|
||||
return (pin < 32) ? (GPIO.in >> pin) & 1 : (GPIO.in1.val >> (pin - 32)) & 1;
|
||||
}
|
||||
|
||||
#elif defined(CPU_FAM_ESP32C3)
|
||||
static inline int _gpio_reg_out_get(gpio_t pin)
|
||||
{
|
||||
return (pin < 32) ? (GPIO.out >> pin) & 1 : (GPIO.out1.val >> (pin - 32)) & 1;
|
||||
}
|
||||
|
||||
#define GPIO_IN_GET(b) GPIO.in.val & BIT(b)
|
||||
#define GPIO_OUT_SET(b) GPIO.out_w1ts.val = BIT(b)
|
||||
#define GPIO_OUT_CLR(b) GPIO.out_w1tc.val = BIT(b)
|
||||
#define GPIO_OUT_XOR(b) GPIO.out.val ^= BIT(b)
|
||||
#define GPIO_OUT_GET(b) (GPIO.out.val >> b) & 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"
|
||||
@ -144,11 +200,6 @@ int gpio_init(gpio_t pin, gpio_mode_t mode)
|
||||
|
||||
gpio_config_t cfg = { };
|
||||
|
||||
#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
|
||||
/* if we come from deep sleep, the GPIO is configured as RTC IO */
|
||||
esp_idf_rtc_gpio_deinit(pin);
|
||||
#endif
|
||||
|
||||
cfg.pin_bit_mask = (1ULL << pin);
|
||||
|
||||
switch (mode) {
|
||||
@ -159,17 +210,17 @@ int gpio_init(gpio_t pin, gpio_mode_t mode)
|
||||
break;
|
||||
case GPIO_IN_OD:
|
||||
case GPIO_IN_OD_PU:
|
||||
cfg.mode = (GPIO_MODE_DEF_INPUT) | (GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD);
|
||||
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);
|
||||
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);
|
||||
cfg.mode = GPIO_MODE_DEF_OUTPUT | GPIO_MODE_DEF_OD;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -194,9 +245,8 @@ int gpio_init(gpio_t pin, gpio_mode_t mode)
|
||||
#if MODULE_PERIPH_GPIO_IRQ
|
||||
|
||||
/* interrupt enabled state is required for sleep modes */
|
||||
static bool gpio_int_enabled_table[GPIO_PIN_NUMOF] = { };
|
||||
|
||||
static bool _isr_installed = false;
|
||||
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)
|
||||
@ -231,16 +281,19 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
|
||||
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;
|
||||
}
|
||||
|
||||
if (!_isr_installed &&
|
||||
esp_idf_gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1) != ESP_OK) {
|
||||
return -1;
|
||||
}
|
||||
_isr_installed = true;
|
||||
|
||||
/* unmask and clear pending interrupts for the pin */
|
||||
if (esp_idf_gpio_isr_handler_add(pin, cb, arg) != ESP_OK) {
|
||||
return -1;
|
||||
}
|
||||
@ -275,7 +328,7 @@ void gpio_irq_disable(gpio_t pin)
|
||||
#if IS_USED(MODULE_ESP_IDF_GPIO_HAL)
|
||||
|
||||
static gpio_hal_context_t _gpio_hal_ctx = {
|
||||
.dev = GPIO_HAL_GET_HW(GPIO_PORT_0)
|
||||
.dev = GPIO_HAL_GET_HW(0)
|
||||
};
|
||||
|
||||
/*
|
||||
@ -349,11 +402,11 @@ int gpio_read(gpio_t pin)
|
||||
|
||||
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_IN_GET(pin)) ? 1 : 0;
|
||||
value = _gpio_reg_in_get(pin);
|
||||
}
|
||||
else {
|
||||
/* otherwise read the last value written to the output register */
|
||||
value = GPIO_OUT_GET(pin);
|
||||
value = _gpio_reg_out_get(pin);
|
||||
}
|
||||
DEBUG("%s gpio=%u val=%d\n", __func__, pin, value);
|
||||
return value;
|
||||
@ -364,10 +417,10 @@ void gpio_write(gpio_t pin, int value)
|
||||
DEBUG("%s gpio=%u val=%d\n", __func__, pin, value);
|
||||
assert(pin < GPIO_PIN_NUMOF);
|
||||
if (value) {
|
||||
GPIO_OUT_SET(pin);
|
||||
_gpio_reg_out_set(pin);
|
||||
}
|
||||
else {
|
||||
GPIO_OUT_CLR(pin);
|
||||
_gpio_reg_out_clr(pin);
|
||||
}
|
||||
}
|
||||
|
||||
@ -375,14 +428,14 @@ void gpio_set(gpio_t pin)
|
||||
{
|
||||
DEBUG("%s gpio=%u\n", __func__, pin);
|
||||
assert(pin < GPIO_PIN_NUMOF);
|
||||
GPIO_OUT_SET(pin);
|
||||
_gpio_reg_out_set(pin);
|
||||
}
|
||||
|
||||
void gpio_clear(gpio_t pin)
|
||||
{
|
||||
DEBUG("%s gpio=%u\n", __func__, pin);
|
||||
assert(pin < GPIO_PIN_NUMOF);
|
||||
GPIO_OUT_CLR(pin);
|
||||
_gpio_reg_out_clr(pin);
|
||||
|
||||
}
|
||||
|
||||
@ -390,7 +443,7 @@ void gpio_toggle(gpio_t pin)
|
||||
{
|
||||
DEBUG("%s gpio=%u\n", __func__, pin);
|
||||
assert(pin < GPIO_PIN_NUMOF);
|
||||
GPIO_OUT_XOR(pin);
|
||||
_gpio_reg_out_xor(pin);
|
||||
}
|
||||
|
||||
#endif /* IS_USED(MODULE_ESP_IDF_GPIO_HAL) */
|
||||
|
182
cpu/esp32/periph/gpio_ll.c
Normal file
182
cpu/esp32/periph/gpio_ll.c
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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_ll
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Peripheral GPIO Low-Level API implementation for the ESP32
|
||||
*
|
||||
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "irq.h"
|
||||
#include "periph/gpio_ll.h"
|
||||
|
||||
#include "esp/common_macros.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "hal/gpio_types.h"
|
||||
#include "gpio_ll_arch.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
|
||||
#include "esp_idf_api/gpio.h"
|
||||
|
||||
/* variables that have to be used together with periph/gpio */
|
||||
#ifdef ESP_PM_WUP_PINS
|
||||
extern bool _gpio_pin_pu[GPIO_PIN_NUMOF];
|
||||
extern bool _gpio_pin_pd[GPIO_PIN_NUMOF];
|
||||
#endif
|
||||
|
||||
static gpio_conf_t _gpio_conf[GPIO_PIN_NUMOF] = { };
|
||||
|
||||
const _esp32_port_t _esp32_ports[GPIO_PORT_NUMOF] = {
|
||||
{
|
||||
.out = (uint32_t *)GPIO_OUT_REG,
|
||||
.out_w1ts = (uint32_t *)GPIO_OUT_W1TS_REG,
|
||||
.out_w1tc = (uint32_t *)GPIO_OUT_W1TC_REG,
|
||||
.in = (uint32_t *)GPIO_IN_REG,
|
||||
.enable = (uint32_t *)GPIO_ENABLE_REG,
|
||||
.enable_w1ts = (uint32_t *)GPIO_ENABLE_W1TS_REG,
|
||||
.enable_w1tc = (uint32_t *)GPIO_ENABLE_W1TC_REG,
|
||||
.status_w1tc = (uint32_t *)GPIO_STATUS_W1TC_REG,
|
||||
},
|
||||
#if GPIO_PORT_NUMOF > 1
|
||||
{
|
||||
.out = (uint32_t *)GPIO_OUT1_REG,
|
||||
.out_w1ts = (uint32_t *)GPIO_OUT1_W1TS_REG,
|
||||
.out_w1tc = (uint32_t *)GPIO_OUT1_W1TC_REG,
|
||||
.in = (uint32_t *)GPIO_IN1_REG,
|
||||
.enable = (uint32_t *)GPIO_ENABLE1_REG,
|
||||
.enable_w1ts = (uint32_t *)GPIO_ENABLE1_W1TS_REG,
|
||||
.enable_w1tc = (uint32_t *)GPIO_ENABLE1_W1TC_REG,
|
||||
.status_w1tc = (uint32_t *)GPIO_STATUS1_W1TC_REG,
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
int gpio_ll_init(gpio_port_t port, uint8_t pin, const gpio_conf_t *conf)
|
||||
{
|
||||
assert(port);
|
||||
assert(conf);
|
||||
assert(GPIO_PORT_NUM(port) < GPIO_PORT_NUMOF);
|
||||
assert(pin < GPIO_PORT_PIN_NUMOF(port));
|
||||
|
||||
gpio_t gpio = GPIO_PIN(GPIO_PORT_NUM(port), pin);
|
||||
|
||||
gpio_config_t cfg = {
|
||||
.pin_bit_mask = (1ULL << gpio),
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
.pull_up_en = false,
|
||||
.pull_down_en = false,
|
||||
};
|
||||
|
||||
switch (conf->state) {
|
||||
case GPIO_OUTPUT_PUSH_PULL:
|
||||
cfg.mode = GPIO_MODE_DEF_OUTPUT;
|
||||
break;
|
||||
case GPIO_OUTPUT_OPEN_DRAIN:
|
||||
cfg.mode = GPIO_MODE_DEF_OUTPUT | GPIO_MODE_DEF_OD;
|
||||
break;
|
||||
case GPIO_INPUT:
|
||||
cfg.mode = GPIO_MODE_DEF_INPUT;
|
||||
break;
|
||||
case GPIO_DISCONNECT:
|
||||
cfg.mode = GPIO_MODE_DEF_DISABLE;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
switch (conf->pull) {
|
||||
case GPIO_FLOATING:
|
||||
break;
|
||||
case GPIO_PULL_UP:
|
||||
cfg.pull_up_en = true;
|
||||
break;
|
||||
case GPIO_PULL_DOWN:
|
||||
cfg.pull_down_en = true;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Some ESP32x GPIOs may not be available at all */
|
||||
if (cfg.pin_bit_mask & ~SOC_GPIO_VALID_GPIO_MASK) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Some ESP32x GPIOs may have limited features (input only and no pull-up/-down) */
|
||||
if ((cfg.pin_bit_mask & ~SOC_GPIO_VALID_OUTPUT_GPIO_MASK) &&
|
||||
((cfg.mode & GPIO_MODE_DEF_OUTPUT) || cfg.pull_up_en || cfg.pull_down_en)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
if (conf->state == GPIO_DISCONNECT) {
|
||||
/* reset the pin to disconnects any other peripheral output configured
|
||||
via GPIO Matrix, the pin is reconfigured according to given conf */
|
||||
esp_idf_gpio_reset_pin(gpio);
|
||||
}
|
||||
|
||||
/* since we can't read back the configuration, we have to save it */
|
||||
_gpio_conf[gpio] = *conf;
|
||||
_gpio_conf[gpio].schmitt_trigger = false;
|
||||
|
||||
if (esp_idf_gpio_config(&cfg) != ESP_OK) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* if output pin, try to set drive strength */
|
||||
if ((cfg.pin_bit_mask & SOC_GPIO_VALID_OUTPUT_GPIO_MASK) &&
|
||||
(esp_idf_gpio_set_drive_capability(gpio,
|
||||
conf->drive_strength) != ESP_OK)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (conf->initial_value) {
|
||||
gpio_ll_set(port, 1UL << pin);
|
||||
}
|
||||
else {
|
||||
gpio_ll_clear(port, 1UL << pin);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gpio_ll_query_conf(gpio_conf_t *dest, gpio_port_t port, uint8_t pin)
|
||||
{
|
||||
assert(dest);
|
||||
|
||||
unsigned state = irq_disable();
|
||||
|
||||
*dest = _gpio_conf[GPIO_PIN(GPIO_PORT_NUM(port), pin)];
|
||||
if (dest->state == GPIO_INPUT) {
|
||||
dest->initial_value = (gpio_ll_read(port) >> pin) & 1UL;
|
||||
}
|
||||
else {
|
||||
dest->initial_value = (gpio_ll_read_output(port) >> pin) & 1UL;
|
||||
}
|
||||
irq_restore(state);
|
||||
}
|
131
cpu/esp32/periph/gpio_ll_irq.c
Normal file
131
cpu/esp32/periph/gpio_ll_irq.c
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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_ll_irq
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief IRQ implementation of the GPIO Low-Level API for ESP32
|
||||
*
|
||||
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "periph/gpio_ll_irq.h"
|
||||
|
||||
#include "esp/common_macros.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "hal/gpio_types.h"
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#if __xtensa__
|
||||
#include "xtensa/xtensa_api.h"
|
||||
#endif
|
||||
|
||||
#include "esp_idf_api/gpio.h"
|
||||
|
||||
#include "irq_arch.h"
|
||||
|
||||
#if MODULE_PERIPH_GPIO_IRQ
|
||||
/* variables that have to be used together with periph/gpio_irq */
|
||||
extern bool gpio_int_enabled_table[];
|
||||
extern bool gpio_isr_service_installed;
|
||||
#else
|
||||
bool gpio_int_enabled_table[GPIO_PIN_NUMOF] = { };
|
||||
bool gpio_isr_service_installed = false;
|
||||
#endif
|
||||
|
||||
extern void IRAM gpio_int_handler(void* arg);
|
||||
|
||||
int gpio_ll_irq(gpio_port_t port, uint8_t pin, gpio_irq_trig_t trig,
|
||||
gpio_ll_cb_t cb, void *arg)
|
||||
{
|
||||
assert(port);
|
||||
assert(arg);
|
||||
assert(GPIO_PORT_NUM(port) < GPIO_PORT_NUMOF);
|
||||
assert(pin < GPIO_PORT_PIN_NUMOF(port));
|
||||
|
||||
unsigned state = irq_disable();
|
||||
|
||||
gpio_t gpio = GPIO_PIN(GPIO_PORT_NUM(port), pin);
|
||||
|
||||
DEBUG("%s gpio=%u port=%u pin=%u trig=%d cb=%p arg=%p\n",
|
||||
__func__, gpio, GPIO_PORT_NUM(port), pin, trig, cb, arg);
|
||||
|
||||
/* 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(gpio, trig) != ESP_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* add interrupt handler for the pin */
|
||||
if (esp_idf_gpio_isr_handler_add(gpio, cb, arg) != ESP_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* unmask and clear pending interrupts for the pin */
|
||||
gpio_ll_irq_unmask_and_clear(port, pin);
|
||||
|
||||
irq_restore(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gpio_ll_irq_mask(gpio_port_t port, uint8_t pin)
|
||||
{
|
||||
gpio_t gpio = GPIO_PIN(GPIO_PORT_NUM(port), pin);
|
||||
|
||||
DEBUG("%s gpio=%u port=%u pin=%u\n",
|
||||
__func__, gpio, GPIO_PORT_NUM(port), pin);
|
||||
|
||||
if (esp_idf_gpio_intr_disable(gpio) == ESP_OK) {
|
||||
gpio_int_enabled_table[gpio] = false;
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_ll_irq_unmask(gpio_port_t port, uint8_t pin)
|
||||
{
|
||||
gpio_t gpio = GPIO_PIN(GPIO_PORT_NUM(port), pin);
|
||||
|
||||
DEBUG("%s gpio=%u port=%u pin=%u\n",
|
||||
__func__, gpio, port, pin);
|
||||
|
||||
if (esp_idf_gpio_intr_enable(gpio) == ESP_OK) {
|
||||
gpio_int_enabled_table[gpio] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_ll_irq_unmask_and_clear(gpio_port_t port, uint8_t pin)
|
||||
{
|
||||
_esp32_port_t *p = (_esp32_port_t *)port;
|
||||
gpio_t gpio = GPIO_PIN(GPIO_PORT_NUM(port), pin);
|
||||
|
||||
DEBUG("%s gpio=%u port=%u pin=%u\n",
|
||||
__func__, gpio, GPIO_PORT_NUM(port), pin);
|
||||
|
||||
*p->status_w1tc = BIT(pin);
|
||||
if (esp_idf_gpio_intr_enable(gpio) == ESP_OK) {
|
||||
gpio_int_enabled_table[gpio] = true;
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user