1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/esp32/periph/gpio_ll.c
2023-04-17 07:32:48 +02:00

199 lines
5.3 KiB
C

/*
* 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 */
gpio_drive_cap_t strength;
switch (conf->drive_strength) {
case GPIO_DRIVE_WEAKEST:
strength = GPIO_DRIVE_CAP_0;
break;
case GPIO_DRIVE_WEAK:
strength = GPIO_DRIVE_CAP_1;
break;
case GPIO_DRIVE_STRONG:
strength = GPIO_DRIVE_CAP_2;
break;
case GPIO_DRIVE_STRONGEST:
strength = GPIO_DRIVE_CAP_3;
break;
default:
strength = GPIO_DRIVE_CAP_DEFAULT;
}
if ((cfg.pin_bit_mask & SOC_GPIO_VALID_OUTPUT_GPIO_MASK) &&
(esp_idf_gpio_set_drive_capability(gpio, 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);
}