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.c

532 lines
18 KiB
C

/*
* Copyright (C) 2018 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 Low-level GPIO driver implementation for ESP32
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#define ENABLE_DEBUG (0)
#include "debug.h"
#include <stdbool.h>
#include "log.h"
#include "periph/gpio.h" /* RIOT gpio.h */
#include "esp/common_macros.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_io_reg.h"
#include "soc/rtc_io_struct.h"
#include "xtensa/xtensa_api.h"
#include "esp_common.h"
#include "adc_arch.h"
#include "gpio_arch.h"
#include "irq_arch.h"
#include "syscalls.h"
#define GPIO_PRO_CPU_INTR_ENA (BIT(2))
/* GPIO to IOMUX register mapping (see Technical Reference, Section 4.12 Register Summary)
https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf */
const uint32_t _gpio_to_iomux_reg[GPIO_PIN_NUMOF] =
{
PERIPHS_IO_MUX_GPIO0_U, /* GPIO0 */
PERIPHS_IO_MUX_U0TXD_U, /* GPIO1 */
PERIPHS_IO_MUX_GPIO2_U, /* GPIO2 */
PERIPHS_IO_MUX_U0RXD_U, /* GPIO3 */
PERIPHS_IO_MUX_GPIO4_U, /* GPIO4 */
PERIPHS_IO_MUX_GPIO5_U, /* GPIO5 */
PERIPHS_IO_MUX_SD_CLK_U, /* GPIO6 used for FLASH */
PERIPHS_IO_MUX_SD_DATA0_U, /* GPIO7 used for FLASH */
PERIPHS_IO_MUX_SD_DATA1_U, /* GPIO8 used for FLASH */
PERIPHS_IO_MUX_SD_DATA2_U, /* GPIO9 used for FLASH in qio or qout mode */
PERIPHS_IO_MUX_SD_DATA3_U, /* GPIO10 used for FLASH in qio or qout mode */
PERIPHS_IO_MUX_SD_CMD_U, /* GPIO11 used for FLASH */
PERIPHS_IO_MUX_MTDI_U, /* GPIO12 used as JTAG for OCD */
PERIPHS_IO_MUX_MTCK_U, /* GPIO13 used as JTAG for OCD */
PERIPHS_IO_MUX_MTMS_U, /* GPIO14 used as JTAG for OCD */
PERIPHS_IO_MUX_MTDO_U, /* GPIO15 used as JTAG for OCD */
PERIPHS_IO_MUX_GPIO16_U, /* GPIO16 used as CS for PSRAM TODO */
PERIPHS_IO_MUX_GPIO17_U, /* GPIO17 */
PERIPHS_IO_MUX_GPIO18_U, /* GPIO18 */
PERIPHS_IO_MUX_GPIO19_U, /* GPIO19 */
0, /* GPIO20 not available */
PERIPHS_IO_MUX_GPIO21_U, /* GPIO21 */
PERIPHS_IO_MUX_GPIO22_U, /* GPIO22 */
PERIPHS_IO_MUX_GPIO23_U, /* GPIO23 */
0, /* GPIO24 not available */
PERIPHS_IO_MUX_GPIO25_U, /* GPIO25 */
PERIPHS_IO_MUX_GPIO26_U, /* GPIO26 */
PERIPHS_IO_MUX_GPIO27_U, /* GPIO27 */
0, /* GPIO28 not available */
0, /* GPIO29 not available */
0, /* GPIO30 not available */
0, /* GPIO31 not available */
PERIPHS_IO_MUX_GPIO32_U, /* GPIO32 */
PERIPHS_IO_MUX_GPIO33_U, /* GPIO33 */
PERIPHS_IO_MUX_GPIO34_U, /* GPIO34 */
PERIPHS_IO_MUX_GPIO35_U, /* GPIO35 */
PERIPHS_IO_MUX_GPIO36_U, /* GPIO36 */
PERIPHS_IO_MUX_GPIO37_U, /* GPIO37 */
PERIPHS_IO_MUX_GPIO38_U, /* GPIO38 */
PERIPHS_IO_MUX_GPIO39_U, /* GPIO39 */
};
/*
* Following table defines which GPIOs have to be handled using RTC_GPIO
* registers since pull-up and pull-down resistors for pads with both GPIO
* and RTC_GPIO functionality can only be controlled via RTC_GPIO registers
* https://www.espressif.com/sites/default/files/documentation/eco_and_workarounds_for_bugs_in_esp32_en.pdf
*
* The table contains the RTC_GPIO num or -1 if it is not an RTC_GPIO pin.
*/
static const int8_t _gpio_to_rtc[GPIO_PIN_NUMOF] = {
11, /* gpio0 */
-1, /* gpio1 */
12, /* gpio2 */
-1, /* gpio3 */
10, /* gpio4 */
-1, /* gpio5 */
-1, /* gpio6 */
-1, /* gpio7 */
-1, /* gpio8 */
-1, /* gpio9 */
-1, /* gpio10 */
-1, /* gpio11 */
15, /* gpio12 */
14, /* gpio13 */
16, /* gpio14 */
13, /* gpio15 */
-1, /* gpio16 */
-1, /* gpio17 */
-1, /* gpio18 */
-1, /* gpio19 */
-1, /* gpio20 */
-1, /* gpio21 */
-1, /* gpio22 */
-1, /* gpio23 */
-1, /* gpio24 */
6, /* gpio25 */
7, /* gpio26 */
17, /* gpio27 */
-1, /* gpio28 */
-1, /* gpio29 */
-1, /* gpio30 */
-1, /* gpio31 */
9, /* gpio32 */
8, /* gpio33 */
4, /* gpio34 */
5, /* gpio35 */
0, /* gpio36 */
1, /* gpio37 */
2, /* gpio38 */
9 /* gpio39 */
};
/**
* @brief Register information type for RTCIO GPIO pins (for internal use only)
*/
struct _rtc_gpio_t {
uint8_t num; /**< RTC_GPIO pin number */
uint32_t reg; /**< register of the RTC_GPIO pin */
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 */
};
/* 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) */
};
/* Table of the usage type of each GPIO pin */
gpio_pin_usage_t _gpio_pin_usage [GPIO_PIN_NUMOF] = {
_GPIO, /* gpio0 */
_UART, /* gpio1 configured as direct I/O UART0 RxD */
_GPIO, /* gpio2 */
_UART, /* gpio3 configured as direct I/O UART0 TxD */
_GPIO, /* gpio4 */
_GPIO, /* gpio5 configurable as direct I/O VSPI CS0 */
_SPIF, /* gpio6 not configurable, used as SPI SCK */
_SPIF, /* gpio7 not configurable, used as SPI MISO */
_SPIF, /* gpio8 not configurable, used as SPI MOSI */
#if defined(FLASH_MODE_QIO) || defined(FLASH_MODE_QOUT)
/* in qio and qout mode thes pins are used for quad SPI */
_SPIF, /* gpio9 not configurable, used as SPI HD */
_SPIF, /* gpio10 not configurable, used as SPI WP */
#else
/* otherwise these pins can be used as GPIO */
_GPIO, /* gpio9 */
_GPIO, /* gpio10 */
#endif
_SPIF, /* gpio11 not configurable, used as SPI CS0 */
_GPIO, /* gpio12 configurable as direct I/O HSPI MISO */
_GPIO, /* gpio13 configurable as direct I/O HSPI MOSI */
_GPIO, /* gpio14 configurable as direct I/O HSPI SCK */
_GPIO, /* gpio15 configurable as direct I/O HSPI CS0 */
_GPIO, /* gpio16 */
_GPIO, /* gpio17 */
_GPIO, /* gpio18 configurable as direct I/O VSPI SCK */
_GPIO, /* gpio19 configurable as direct I/O VSPI MISO */
_NOT_EXIST, /* gpio20 */
_GPIO, /* gpio21 */
_GPIO, /* gpio22 */
_GPIO, /* gpio23 configurable as direct I/O VSPI MOSI */
_NOT_EXIST, /* gpio24 */
_GPIO, /* gpio25 */
_GPIO, /* gpio26 */
_GPIO, /* gpio27 */
_NOT_EXIST, /* gpio28 */
_NOT_EXIST, /* gpio29 */
_NOT_EXIST, /* gpio30 */
_NOT_EXIST, /* gpio31 */
_GPIO, /* gpio32 */
_GPIO, /* gpio33 */
_GPIO, /* gpio34 */
_GPIO, /* gpio35 */
_GPIO, /* gpio36 */
_GPIO, /* gpio37 */
_GPIO, /* gpio38 */
_GPIO /* gpio39 */
};
/* String representation of usage types */
const char* _gpio_pin_usage_str[] =
{
"GPIO", "ADC", "CAN", "DAC", "EMAC", "I2C", "PWM", "SPI", "SPI Flash", "UART", "N/A"
};
#define FUN_GPIO 2 /* the function number for all GPIOs */
#define GPIO_PIN_SET(b) if (b < 32) GPIO.out_w1ts = BIT(b); else GPIO.out1_w1ts.val = BIT(b-32)
#define GPIO_PIN_CLR(b) if (b < 32) GPIO.out_w1tc = BIT(b); else GPIO.out1_w1tc.val = BIT(b-32)
#define GPIO_REG_BIT_GET(l,h,b) ((b < 32) ? GPIO.l & BIT(b) : GPIO.h.val & BIT(b-32))
#define GPIO_REG_BIT_SET(l,h,b) if (b < 32) GPIO.l |= BIT(b); else GPIO.h.val |= BIT(b-32)
#define GPIO_REG_BIT_CLR(l,h,b) if (b < 32) GPIO.l &= ~BIT(b); else GPIO.h.val &= ~BIT(b-32)
#define GPIO_REG_BIT_XOR(l,h,b) if (b < 32) GPIO.l ^= BIT(b); else GPIO.h.val ^= BIT(b-32)
#define REG_SET_CLR_BIT(c,r,f) if (c) REG_SET_BIT(r,f); else REG_CLR_BIT(r,f)
int gpio_init(gpio_t pin, gpio_mode_t mode)
{
CHECK_PARAM_RET(pin < GPIO_PIN_NUMOF, -1);
/* 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;
}
/* check additional limitations for GPIOs 34 ... 39 */
if (pin > GPIO33) {
switch (mode) {
case GPIO_OUT:
case GPIO_OD:
case GPIO_OD_PU:
case GPIO_IN_OUT:
case GPIO_IN_OD:
case GPIO_IN_OD_PU:
/* GPIOs 34 ... 39 cannot be used as output */
LOG_TAG_ERROR("gpio",
"GPIO%d can only be used as input\n", pin);
return -1;
case GPIO_IN_PD:
case GPIO_IN_PU:
/* GPIOs 34 ... 39 have no software controlable pullups/pulldowns */
LOG_TAG_ERROR("gpio",
"GPIO%d has no pullups/pulldowns\n", pin);
return -1;
default: break;
}
}
const struct _rtc_gpio_t* rtc = (_gpio_to_rtc[pin] != -1) ?
&_rtc_gpios[_gpio_to_rtc[pin]] : NULL;
/* if pin is a RTC_GPIO, reset RTC function to route RTC pin to GPIO pin */
if (rtc) {
REG_CLR_BIT(rtc->reg, BIT(rtc->mux));
}
switch (mode) {
case GPIO_IN:
case GPIO_IN_PD:
case GPIO_IN_PU:
/* according to Technical Reference it is not necessary
to configure the GPIO matrix to read GPIOs from
GPIO_IN_REG/GPIO_IN1_REG */
#if 0
/* configure the GPIO matrix for the inputs */
GPIO.func_in_sel_cfg[signal].sig_in_sel = 0; /* route through GPIO matrix */
GPIO.func_in_sel_cfg[signal].sig_in_inv = 0; /* do not invert input */
GPIO.func_in_sel_cfg[signal].func_sel = pin; /* connect signal to GPIOx */
#endif
/* disable the output for input-only signals */
GPIO.func_out_sel_cfg[pin].oen_sel = 1;
GPIO_REG_BIT_SET(enable_w1tc, enable1_w1tc, pin);
/* set the FUN_IE bit for input */
REG_SET_BIT(_gpio_to_iomux_reg[pin], FUN_IE);
/* FUN_GPIO / FUN_WPU / FUN_WPD are set later */
break;
case GPIO_OUT:
case GPIO_OD:
case GPIO_OD_PU:
/* configure GPIO signal in the GPIO matrix */
GPIO.func_out_sel_cfg[pin].func_sel = SIG_GPIO_OUT_IDX;
/* enable the output */
GPIO.func_out_sel_cfg[pin].oen_sel = 1;
GPIO_REG_BIT_SET(enable_w1ts, enable1_w1ts, pin);
/* set pad driver to one for open drain outputs */
GPIO.pin[pin].pad_driver = (mode == GPIO_OD || mode == GPIO_OD_PU) ? 1 : 0;
/* set pad driver also for RTC pin if it is a RTC_GPIO */
if (rtc) {
RTCIO.pin[rtc->num].pad_driver = GPIO.pin[pin].pad_driver;
}
/* clear the FUN_IE bit */
REG_CLR_BIT(_gpio_to_iomux_reg[pin], FUN_IE);
/* FUN_GPIO / FUN_WPU / FUN_WPD are set later */
break;
case GPIO_IN_OUT:
case GPIO_IN_OD:
case GPIO_IN_OD_PU:
/* configure GPIO signal in the GPIO matrix */
GPIO.func_out_sel_cfg[pin].func_sel = SIG_GPIO_OUT_IDX;
/* enable the output */
GPIO.func_out_sel_cfg[pin].oen_sel = 1;
GPIO_REG_BIT_SET(enable_w1ts, enable1_w1ts, pin);
/* set pad driver to one for open drain outputs */
GPIO.pin[pin].pad_driver = (mode == GPIO_IN_OD || mode == GPIO_IN_OD_PU) ? 1 : 0;
/* set pad driver also for RTC pin if it is a RTC_GPIO */
if (rtc) {
RTCIO.pin[rtc->num].pad_driver = GPIO.pin[pin].pad_driver;
}
/* enable the input */
REG_SET_BIT(_gpio_to_iomux_reg[pin], FUN_IE);
/* FUN_GPIO / FUN_WPU / FUN_WPD are set later */
break;
}
/* select GPIO as IO_MUX function (FUN_GPIO) */
REG_SET_FIELD(_gpio_to_iomux_reg[pin], MCU_SEL, FUN_GPIO);
/* enable/disable the pull-up resistor (FUN_WPU) */
REG_SET_CLR_BIT(mode == GPIO_IN_PU || mode == GPIO_OD_PU || mode == GPIO_IN_OD_PU,
_gpio_to_iomux_reg[pin], FUN_PU);
/* enable/disable the pull-down resistor (FUN_WPD) */
REG_SET_CLR_BIT(mode == GPIO_IN_PD, _gpio_to_iomux_reg[pin], FUN_PD);
/* handle pull-up/pull-down resistors for RTC_GPIOs */
if (rtc) {
/* enable/disable the pull-up resistor (FUN_WPU) */
REG_SET_CLR_BIT(mode == GPIO_IN_PU || mode == GPIO_OD_PU || mode == GPIO_IN_OD_PU,
rtc->reg, BIT(rtc->pullup));
/* enable/disable the pull-down resistor (FUN_WPD) */
REG_SET_CLR_BIT(mode == GPIO_IN_PD, rtc->reg, BIT(rtc->pulldown));
}
return 0;
}
#if MODULE_PERIPH_GPIO_IRQ
static gpio_isr_ctx_t gpio_isr_ctx_table [GPIO_PIN_NUMOF] = { };
static bool gpio_int_enabled_table [GPIO_PIN_NUMOF] = { };
void IRAM gpio_int_handler (void* arg)
{
irq_isr_enter();
(void)arg;
for (unsigned i = 0; i < GPIO_PIN_NUMOF; i++) {
if (GPIO_REG_BIT_GET(status, status1, i)) {
GPIO_REG_BIT_SET(status_w1tc, status1_w1tc, i);
if (gpio_int_enabled_table[i] && GPIO.pin[i].int_type) {
gpio_isr_ctx_table[i].cb (gpio_isr_ctx_table[i].arg);
}
}
}
irq_isr_exit();
}
int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
gpio_cb_t cb, void *arg)
{
if (gpio_init(pin, mode)) {
return -1;
}
gpio_isr_ctx_table[pin].cb = cb;
gpio_isr_ctx_table[pin].arg = arg;
GPIO.pin[pin].int_type = 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;
intr_matrix_set(PRO_CPU_NUM, ETS_GPIO_INTR_SOURCE, CPU_INUM_GPIO);
xt_set_interrupt_handler(CPU_INUM_GPIO, gpio_int_handler, NULL);
xt_ints_on(BIT(CPU_INUM_GPIO));
}
return 0;
}
void gpio_irq_enable (gpio_t pin)
{
CHECK_PARAM(pin < GPIO_PIN_NUMOF);
gpio_int_enabled_table [pin] = true;
}
void gpio_irq_disable (gpio_t pin)
{
CHECK_PARAM(pin < GPIO_PIN_NUMOF);
gpio_int_enabled_table [pin] = false;
}
#endif /* MODULE_PERIPH_GPIO_IRQ */
int gpio_read (gpio_t pin)
{
CHECK_PARAM_RET(pin < GPIO_PIN_NUMOF, -1);
return GPIO_REG_BIT_GET(in, in1, pin) ? 1 : 0;
}
void gpio_write (gpio_t pin, int value)
{
DEBUG("%s gpio=%u val=%d\n", __func__, pin, value);
CHECK_PARAM(pin < GPIO_PIN_NUMOF);
if (value) {
GPIO_PIN_SET(pin);
}
else {
GPIO_PIN_CLR(pin);
}
}
void gpio_set (gpio_t pin)
{
DEBUG("%s gpio=%u\n", __func__, pin);
CHECK_PARAM(pin < GPIO_PIN_NUMOF);
GPIO_PIN_SET(pin);
}
void gpio_clear (gpio_t pin)
{
DEBUG("%s gpio=%u\n", __func__, pin);
CHECK_PARAM(pin < GPIO_PIN_NUMOF);
GPIO_PIN_CLR(pin);
}
void gpio_toggle (gpio_t pin)
{
DEBUG("%s gpio=%u\n", __func__, pin);
CHECK_PARAM(pin < GPIO_PIN_NUMOF);
GPIO_REG_BIT_XOR(out, out1, pin);
}
int gpio_set_pin_usage(gpio_t pin, gpio_pin_usage_t usage)
{
CHECK_PARAM_RET(pin < GPIO_PIN_NUMOF, -1);
_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)]];
}
void gpio_pullup_dis (gpio_t pin)
{
CHECK_PARAM(pin < GPIO_PIN_NUMOF);
const struct _rtc_gpio_t* rtc = (_gpio_to_rtc[pin] != -1) ?
&_rtc_gpios[_gpio_to_rtc[pin]] : NULL;
REG_CLR_BIT(_gpio_to_iomux_reg[pin], FUN_PU);
if (rtc) {
REG_CLR_BIT(rtc->reg, BIT(rtc->pullup));
}
}
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);
}