1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/esp8266/periph/gpio.c
Marian Buschsieweke c2c2cc8592
drivers/periph_gpio: let gpio_read() return bool
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.
2024-10-23 13:24:09 +02:00

313 lines
8.6 KiB
C

/*
* Copyright (C) 2019 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_esp8266
* @ingroup drivers_periph_gpio
* @{
*
* @file
* @brief Low-level GPIO driver implementation for ESP8266
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#include <stdbool.h>
#include "log.h"
#include "periph/gpio.h" /* RIOT gpio.h */
#include "esp8266/eagle_soc.h"
#include "esp8266/gpio_register.h"
#include "rom/ets_sys.h"
#include "sdk/ets.h"
#include "esp/gpio_regs.h"
#include "esp/iomux_regs.h"
#include "esp/rtc_regs.h"
#include "esp_common.h"
#include "gpio_arch.h"
#include "irq_arch.h"
#include "syscalls.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/*
* IOMUX to GPIO mapping
* source https://www.espressif.com/sites/default/files/documentation/0d-esp8266_pin_list_release_15-11-2014.xlsx
*/
const uint8_t _gpio_to_iomux[] = { 12, 5, 13, 4, 14, 15, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3 };
const uint8_t _iomux_to_gpio[] = { 12, 13, 14, 15, 3, 1, 6, 7, 8, 9, 10, 11, 0, 2, 4, 5 };
gpio_pin_usage_t _gpio_pin_usage [GPIO_PIN_NUMOF] =
{
_GPIO, /* gpio0 */
/* UART0 is initialized by the boot ROM, this only reflects our selection so
* other devices don't step on it. */
UART0_TXD == GPIO1 ? _UART : _GPIO, /* gpio1 */
UART0_TXD == GPIO2 ? _UART : _GPIO, /* gpio2 */
UART0_RXD == GPIO3 ? _UART : _GPIO, /* gpio3 */
_GPIO, /* gpio4 */
_GPIO, /* gpio5 */
_SPIF, /* gpio6 SPI flash CLK */
_SPIF, /* gpio7 SPI flash MISO */
_SPIF, /* gpio8 SPI flash MOSI */
#if defined(CONFIG_FLASHMODE_QIO) || defined(CONFIG_FLASHMODE_QOUT)
_SPIF, /* gpio9 SPI flash HD (qio/qout flash mode) */
_SPIF, /* gpio10 SPI flash WP (qio/qout flash mode) */
#else
_GPIO, /* gpio9 can be used as GPIO if not needed for flash */
_GPIO, /* gpio10 can be used as GPIO if not needed for flash */
#endif
_SPIF, /* gpio11 SPI flash CS */
_GPIO, /* gpio12 */
_GPIO, /* gpio13 */
_GPIO, /* gpio14 */
_GPIO, /* gpio15 */
_GPIO /* gpio16 */
};
/* String representation of usage types */
const char* _gpio_pin_usage_str[] =
{
"GPIO", "I2C", "PWM", "SPI", "SPI Flash", "UART", "N/A"
};
int gpio_init(gpio_t pin, gpio_mode_t mode)
{
DEBUG("%s: %d %d\n", __func__, pin, mode);
CHECK_PARAM_RET(pin < GPIO_PIN_NUMOF, -1);
/* check whether pin can be used as GPIO or is used in anyway else */
switch (_gpio_pin_usage[pin]) {
case _I2C: LOG_ERROR("GPIO%d is used as I2C signal.\n", pin); return -1;
case _PWM: LOG_ERROR("GPIO%d is used as PWM output.\n", pin); return -1;
case _SPI: LOG_ERROR("GPIO%d is used as SPI interface.\n", pin); return -1;
case _SPIF: LOG_ERROR("GPIO%d is used as SPI flash.\n", pin); return -1;
case _UART: LOG_ERROR("GPIO%d is used as UART interface.\n", pin); return -1;
default: break;
}
/* GPIO16 requires separate handling */
if (pin == GPIO16) {
RTC.GPIO_CFG[3] = (RTC.GPIO_CFG[3] & 0xffffffbc) | BIT(0);
RTC.GPIO_CONF = RTC.GPIO_CONF & ~RTC_GPIO_CONF_OUT_ENABLE;
switch (mode) {
case GPIO_OUT:
RTC.GPIO_ENABLE = RTC.GPIO_OUT | RTC_GPIO_CONF_OUT_ENABLE;
break;
case GPIO_OD:
LOG_ERROR("GPIO mode GPIO_OD is not supported for GPIO16.\n");
return -1;
case GPIO_OD_PU:
LOG_ERROR("GPIO mode GPIO_OD_PU is not supported for GPIO16.\n");
return -1;
case GPIO_IN:
RTC.GPIO_ENABLE = RTC.GPIO_OUT & ~RTC_GPIO_CONF_OUT_ENABLE;
RTC.GPIO_CFG[3] &= ~RTC_GPIO_CFG3_PIN_PULLUP;
break;
case GPIO_IN_PU:
LOG_ERROR("GPIO mode GPIO_IN_PU is not supported for GPIO16.\n");
return -1;
case GPIO_IN_PD:
LOG_ERROR("GPIO mode GPIO_IN_PD is not supported for GPIO16.\n");
return -1;
default:
LOG_ERROR("Invalid GPIO mode for GPIO%d.\n", pin);
return -1;
}
return 0;
}
uint8_t iomux = _gpio_to_iomux [pin];
uint32_t iomux_conf = (iomux > 11) ? IOMUX_FUNC(0) : IOMUX_FUNC(3);
switch (mode) {
case GPIO_OUT: iomux_conf |= IOMUX_PIN_OUTPUT_ENABLE;
iomux_conf |= IOMUX_PIN_OUTPUT_ENABLE_SLEEP;
GPIO.CONF[pin] &= ~GPIO_CONF_OPEN_DRAIN;
GPIO.ENABLE_OUT_SET = BIT(pin);
break;
case GPIO_OD_PU: iomux_conf |= IOMUX_PIN_PULLUP;
iomux_conf |= IOMUX_PIN_PULLUP_SLEEP;
case GPIO_OD: iomux_conf |= IOMUX_PIN_OUTPUT_ENABLE;
iomux_conf |= IOMUX_PIN_OUTPUT_ENABLE_SLEEP;
GPIO.CONF[pin] |= GPIO_CONF_OPEN_DRAIN;
GPIO.ENABLE_OUT_SET = BIT(pin);
break;
case GPIO_IN_PU: iomux_conf |= IOMUX_PIN_PULLUP;
iomux_conf |= IOMUX_PIN_PULLUP_SLEEP;
case GPIO_IN: GPIO.CONF[pin] |= GPIO_CONF_OPEN_DRAIN;
GPIO.ENABLE_OUT_CLEAR = BIT(pin);
break;
case GPIO_IN_PD: LOG_ERROR("GPIO mode GPIO_IN_PD is not supported.\n");
return -1;
default: LOG_ERROR("Invalid GPIO mode for GPIO%d.\n", pin);
}
IOMUX.PIN[iomux] = iomux_conf;
return 0;
}
#ifdef 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();
for (int i = 0; i < GPIO_PIN_NUMOF; i++) {
uint32_t mask = BIT(i);
if (GPIO.STATUS & mask) {
GPIO.STATUS_CLEAR = mask;
if (gpio_int_enabled_table[i] && (GPIO.CONF[i] & GPIO_PIN_INT_TYPE_MASK)) {
gpio_isr_ctx_table[i].cb (gpio_isr_ctx_table[i].arg);
}
}
mask = mask << 1;
}
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;
}
if (pin == GPIO16) {
/* GPIO16 requires separate handling */
LOG_ERROR("GPIO16 cannot generate interrupts.\n");
return -1;
}
gpio_isr_ctx_table[pin].cb = cb;
gpio_isr_ctx_table[pin].arg = arg;
GPIO.CONF[pin] = SET_FIELD(GPIO.CONF[pin], GPIO_CONF_INTTYPE, flank);
if (flank != GPIO_NONE) {
gpio_int_enabled_table [pin] = (gpio_isr_ctx_table[pin].cb != NULL);
ets_isr_attach (ETS_GPIO_INUM, gpio_int_handler, 0);
ets_isr_unmask ((1 << ETS_GPIO_INUM));
}
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 */
bool gpio_read (gpio_t pin)
{
CHECK_PARAM_RET(pin < GPIO_PIN_NUMOF, -1);
if (pin == GPIO16) {
/* GPIO16 requires separate handling */
return RTC.GPIO_IN & BIT(0);
}
return (GPIO.IN & BIT(pin)) ? 1 : 0;
}
void gpio_write (gpio_t pin, bool value)
{
DEBUG("%s: %d %d\n", __func__, pin, value);
CHECK_PARAM(pin < GPIO_PIN_NUMOF);
if (pin == GPIO16) {
/* GPIO16 requires separate handling */
RTC.GPIO_OUT = (RTC.GPIO_OUT & ~BIT(0)) | (value ? 1 : 0);
return;
}
if (value) {
GPIO.OUT_SET = BIT(pin) & GPIO_OUT_PIN_MASK;
}
else {
GPIO.OUT_CLEAR = BIT(pin) & GPIO_OUT_PIN_MASK;
}
}
void gpio_set (gpio_t pin)
{
gpio_write (pin, 1);
}
void gpio_clear (gpio_t pin)
{
gpio_write (pin, 0);
}
void gpio_toggle (gpio_t pin)
{
DEBUG("%s: %d\n", __func__, pin);
CHECK_PARAM(pin < GPIO_PIN_NUMOF);
if (pin == GPIO16) {
/* GPIO16 requires separate handling */
RTC.GPIO_OUT = (RTC.GPIO_OUT & ~BIT(0)) | ((RTC.GPIO_IN & BIT(0)) ? 0 : 1);
return;
}
GPIO.OUT ^= BIT(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)]];
}