diff --git a/components/esp8266/component.mk b/components/esp8266/component.mk index bfcf1272..3b69f801 100644 --- a/components/esp8266/component.mk +++ b/components/esp8266/component.mk @@ -18,7 +18,7 @@ endif #Linker scripts used to link the final application. #Warning: These linker scripts are only used when the normal app is compiled; the bootloader #specifies its own scripts. -LINKER_SCRIPTS += esp8266.common.ld esp8266.rom.ld +LINKER_SCRIPTS += esp8266.common.ld esp8266.rom.ld esp8266.peripherals.ld COMPONENT_ADD_LDFLAGS += -L$(COMPONENT_PATH)/lib \ $(addprefix -l,$(LIBS)) \ diff --git a/components/esp8266/driver/gpio.c b/components/esp8266/driver/gpio.c index e6151ef3..98da4e8f 100644 --- a/components/esp8266/driver/gpio.c +++ b/components/esp8266/driver/gpio.c @@ -1,4 +1,4 @@ -// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2018-2025 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,198 +12,477 @@ // See the License for the specific language governing permissions and // limitations under the License. - #include +#include #include "esp8266/eagle_soc.h" #include "esp8266/pin_mux_register.h" +#include "esp8266/gpio_struct.h" + #include "rom/ets_sys.h" +#include "driver/gpio.h" + +#include "esp_err.h" +#include "esp_log.h" //TODO:No dependence on RTOS + +// Temporary use the FreeRTOS critical function #include "FreeRTOS.h" +#define ENTER_CRITICAL() portENTER_CRITICAL() +#define EXIT_CRITICAL() portEXIT_CRITICAL() -#include "gpio.h" +static const char *GPIO_TAG = "gpio"; -void gpio_config(GPIO_ConfigTypeDef* pGPIOConfig) +#define GPIO_CHECK(a, str, ret_val) \ + if (!(a)) { \ + ESP_LOGE(GPIO_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \ + return (ret_val); \ + } + +#define GPIO_PIN_REG_0 PERIPHS_IO_MUX_GPIO0_U +#define GPIO_PIN_REG_1 PERIPHS_IO_MUX_U0TXD_U +#define GPIO_PIN_REG_2 PERIPHS_IO_MUX_GPIO2_U +#define GPIO_PIN_REG_3 PERIPHS_IO_MUX_U0RXD_U +#define GPIO_PIN_REG_4 PERIPHS_IO_MUX_GPIO4_U +#define GPIO_PIN_REG_5 PERIPHS_IO_MUX_GPIO5_U +#define GPIO_PIN_REG_6 PERIPHS_IO_MUX_SD_CLK_U +#define GPIO_PIN_REG_7 PERIPHS_IO_MUX_SD_DATA0_U +#define GPIO_PIN_REG_8 PERIPHS_IO_MUX_SD_DATA1_U +#define GPIO_PIN_REG_9 PERIPHS_IO_MUX_SD_DATA2_U +#define GPIO_PIN_REG_10 PERIPHS_IO_MUX_SD_DATA3_U +#define GPIO_PIN_REG_11 PERIPHS_IO_MUX_SD_CMD_U +#define GPIO_PIN_REG_12 PERIPHS_IO_MUX_MTDI_U +#define GPIO_PIN_REG_13 PERIPHS_IO_MUX_MTCK_U +#define GPIO_PIN_REG_14 PERIPHS_IO_MUX_MTMS_U +#define GPIO_PIN_REG_15 PERIPHS_IO_MUX_MTDO_U +#define GPIO_PIN_REG_16 PAD_XPD_DCDC_CONF + +#define GPIO_PIN_REG(i) \ + (i==0) ? GPIO_PIN_REG_0: \ + (i==1) ? GPIO_PIN_REG_1: \ + (i==2) ? GPIO_PIN_REG_2: \ + (i==3) ? GPIO_PIN_REG_3: \ + (i==4) ? GPIO_PIN_REG_4: \ + (i==5) ? GPIO_PIN_REG_5: \ + (i==6) ? GPIO_PIN_REG_6: \ + (i==7) ? GPIO_PIN_REG_7: \ + (i==8) ? GPIO_PIN_REG_8: \ + (i==9) ? GPIO_PIN_REG_9: \ + (i==10)? GPIO_PIN_REG_10: \ + (i==11)? GPIO_PIN_REG_11: \ + (i==12)? GPIO_PIN_REG_12: \ + (i==13)? GPIO_PIN_REG_13: \ + (i==14)? GPIO_PIN_REG_14: \ + (i==15)? GPIO_PIN_REG_15: \ + GPIO_PIN_REG_16 + +typedef struct { + gpio_isr_t fn; /*!< isr function */ + void *args; /*!< isr function args */ +} gpio_isr_func_t; + +static gpio_isr_func_t *gpio_isr_func = NULL; + +esp_err_t gpio_pullup_en(gpio_num_t gpio_num) { - uint16_t gpio_pin_mask = pGPIOConfig->GPIO_Pin; - uint32_t io_reg; - uint8_t io_num = 0; - uint32_t pin_reg; + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + GPIO_CHECK(!RTC_GPIO_IS_VALID_GPIO(gpio_num), "The RTC GPIO of esp8266 can not be pulled up.", ESP_ERR_INVALID_ARG); - if (pGPIOConfig->GPIO_Mode == GPIO_Mode_Input) { - GPIO_AS_INPUT(gpio_pin_mask); - } else if (pGPIOConfig->GPIO_Mode == GPIO_Mode_Output) { - GPIO_AS_OUTPUT(gpio_pin_mask); + gpio_pin_reg_t pin_reg; + pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(gpio_num)); + pin_reg.pullup = 1; + WRITE_PERI_REG(GPIO_PIN_REG(gpio_num), pin_reg.val); + return ESP_OK; +} + +esp_err_t gpio_pullup_dis(gpio_num_t gpio_num) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + GPIO_CHECK(!RTC_GPIO_IS_VALID_GPIO(gpio_num), "The RTC GPIO of esp8266 can not be pulled up.", ESP_ERR_INVALID_ARG); + + gpio_pin_reg_t pin_reg; + pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(gpio_num)); + pin_reg.pullup = 0; + WRITE_PERI_REG(GPIO_PIN_REG(gpio_num), pin_reg.val); + return ESP_OK; +} + +esp_err_t gpio_pulldown_en(gpio_num_t gpio_num) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + GPIO_CHECK(RTC_GPIO_IS_VALID_GPIO(gpio_num), "The GPIO of esp8266 can not be pulled down except RTC GPIO.", ESP_ERR_INVALID_ARG); + + gpio_pin_reg_t pin_reg; + pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(gpio_num)); + pin_reg.rtc_pin.pulldown = 1; + WRITE_PERI_REG(GPIO_PIN_REG(gpio_num), pin_reg.val); + return ESP_OK; +} + +esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + GPIO_CHECK(RTC_GPIO_IS_VALID_GPIO(gpio_num), "The GPIO of esp8266 can not be pulled down except RTC GPIO.", ESP_ERR_INVALID_ARG); + + gpio_pin_reg_t pin_reg; + pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(gpio_num)); + pin_reg.rtc_pin.pulldown = 0; + WRITE_PERI_REG(GPIO_PIN_REG(gpio_num), pin_reg.val); + return ESP_OK; +} + +esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + GPIO_CHECK(!RTC_GPIO_IS_VALID_GPIO(gpio_num), "GPIO is RTC GPIO", ESP_ERR_INVALID_ARG); + GPIO_CHECK(intr_type < GPIO_INTR_MAX, "GPIO interrupt type error", ESP_ERR_INVALID_ARG); + + GPIO.pin[gpio_num].int_type = intr_type; + return ESP_OK; +} + +esp_err_t gpio_intr_enable(gpio_num_t gpio_num) +{ + _xt_isr_unmask(0x1 << ETS_GPIO_INUM); + return ESP_OK; +} + +esp_err_t gpio_intr_disable(gpio_num_t gpio_num) +{ + _xt_isr_mask(0x1 << ETS_GPIO_INUM); + return ESP_OK; +} + +static esp_err_t gpio_output_disable(gpio_num_t gpio_num) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + + if (RTC_GPIO_IS_VALID_GPIO(gpio_num)) { + WRITE_PERI_REG(PAD_XPD_DCDC_CONF, ((READ_PERI_REG(PAD_XPD_DCDC_CONF) & (uint32_t)0xffffffbc)) | (uint32_t)0x1); // mux configuration for XPD_DCDC and rtc_gpio0 connection + CLEAR_PERI_REG_MASK(RTC_GPIO_CONF, 0x1); //mux configuration for out enable + CLEAR_PERI_REG_MASK(RTC_GPIO_ENABLE, 0x1); //out disable + } else { + GPIO.enable_w1tc |= (0x1 << gpio_num); + } + + return ESP_OK; +} + +static esp_err_t gpio_output_enable(gpio_num_t gpio_num) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + + if (RTC_GPIO_IS_VALID_GPIO(gpio_num)) { + WRITE_PERI_REG(PAD_XPD_DCDC_CONF, ((READ_PERI_REG(PAD_XPD_DCDC_CONF) & (uint32_t)0xffffffbc)) | (uint32_t)0x1); // mux configuration for XPD_DCDC and rtc_gpio0 connection + CLEAR_PERI_REG_MASK(RTC_GPIO_CONF, 0x1); //mux configuration for out enable + SET_PERI_REG_MASK(RTC_GPIO_ENABLE, 0x1); //out enable + } else { + GPIO.enable_w1ts |= (0x1 << gpio_num); + } + + return ESP_OK; +} + +esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + + if (RTC_GPIO_IS_VALID_GPIO(gpio_num)) { + if (level) { + SET_PERI_REG_MASK(RTC_GPIO_OUT, 0x1); //set_high_level + } else { + CLEAR_PERI_REG_MASK(RTC_GPIO_OUT, 0x1); //set_low_level + } + } else { + if (level) { + GPIO.out_w1ts |= (0x1 << gpio_num); + } else { + GPIO.out_w1tc |= (0x1 << gpio_num); + } + } + + return ESP_OK; +} + +int gpio_get_level(gpio_num_t gpio_num) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + + if (RTC_GPIO_IS_VALID_GPIO(gpio_num)) { + return READ_PERI_REG(RTC_GPIO_IN_DATA) & 0x1; + } else { + return (GPIO.in >> gpio_num) & 0x1; + } +} + +esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + GPIO_CHECK(pull <= GPIO_FLOATING, "GPIO pull mode error", ESP_ERR_INVALID_ARG); + + esp_err_t ret = ESP_OK; + + switch (pull) { + case GPIO_PULLUP_ONLY: + gpio_pulldown_dis(gpio_num); + gpio_pullup_en(gpio_num); + break; + + case GPIO_PULLDOWN_ONLY: + gpio_pulldown_en(gpio_num); + gpio_pullup_dis(gpio_num); + break; + + case GPIO_FLOATING: + gpio_pulldown_dis(gpio_num); + gpio_pullup_dis(gpio_num); + break; + + default: + ESP_LOGE(GPIO_TAG, "Unknown pull up/down mode,gpio_num=%u,pull=%u", gpio_num, pull); + ret = ESP_ERR_INVALID_ARG; + break; + } + + return ret; +} + +esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + + // esp8266 input is always connected + if (mode & GPIO_MODE_DEF_OUTPUT) { + gpio_output_enable(gpio_num); + } else { + gpio_output_disable(gpio_num); + } + + if ((mode & GPIO_MODE_DEF_OD) && !RTC_GPIO_IS_VALID_GPIO(gpio_num)) { + GPIO.pin[gpio_num].driver = 1; + } else { + GPIO.pin[gpio_num].driver = 0; + } + + return ESP_OK; +} + +esp_err_t gpio_config(const gpio_config_t *gpio_cfg) +{ + uint32_t gpio_pin_mask = (gpio_cfg->pin_bit_mask); + uint32_t io_reg = 0; + uint32_t io_num = 0; + uint8_t input_en = 0; + uint8_t output_en = 0; + uint8_t od_en = 0; + uint8_t pu_en = 0; + uint8_t pd_en = 0; + gpio_pin_reg_t pin_reg; + + if (gpio_cfg->pin_bit_mask == 0 || gpio_cfg->pin_bit_mask >= (((uint32_t) 1) << GPIO_PIN_COUNT)) { + ESP_LOGE(GPIO_TAG, "GPIO_PIN mask error "); + return ESP_ERR_INVALID_ARG; } do { - if ((gpio_pin_mask >> io_num) & 0x1) { - io_reg = GPIO_PIN_REG(io_num); + io_reg = GPIO_PIN_REG(io_num); + if (((gpio_pin_mask >> io_num) & BIT(0))) { + if (!io_reg) { + ESP_LOGE(GPIO_TAG, "IO%d is not a valid GPIO", io_num); + return ESP_ERR_INVALID_ARG; + } + + if (gpio_cfg->mode & GPIO_MODE_OUTPUT) { + output_en = 1; + } else { + input_en = 1; + } + + if ((gpio_cfg->mode & GPIO_MODE_DEF_OD) && !RTC_GPIO_IS_VALID_GPIO(io_num)) { + od_en = 1; + } + + gpio_set_direction(io_num, gpio_cfg->mode); + + if (!RTC_GPIO_IS_VALID_GPIO(io_num)) { + if (gpio_cfg->pull_up_en) { + pu_en = 1; + gpio_pullup_en(io_num); + } else { + gpio_pullup_dis(io_num); + } + } + + if (RTC_GPIO_IS_VALID_GPIO(io_num)) { + if (gpio_cfg->pull_down_en) { + pd_en = 1; + gpio_pulldown_en(io_num); + } else { + gpio_pulldown_dis(io_num); + } + } + + ESP_LOGI(GPIO_TAG, "GPIO[%d]| InputEn: %d| OutputEn: %d| OpenDrain: %d| Pullup: %d| Pulldown: %d| Intr:%d ", io_num, input_en, output_en, od_en, pu_en, pd_en, gpio_cfg->intr_type); + + if (!RTC_GPIO_IS_VALID_GPIO(io_num)) { + gpio_set_intr_type(io_num, gpio_cfg->intr_type); + + if (gpio_cfg->intr_type) { + gpio_intr_enable(io_num); + } else { + gpio_intr_disable(io_num); + } + } + + pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(io_num)); + + // It should be noted that GPIO0, 2, 4, and 5 need to set the func register to 0, + // and the other GPIO needs to be set to 3 so that IO can be GPIO function. if ((0x1 << io_num) & (GPIO_Pin_0 | GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_5)) { - PIN_FUNC_SELECT(io_reg, 0); + pin_reg.rtc_pin.func_low_bit = 0; + pin_reg.rtc_pin.func_high_bit = 0; } else { - PIN_FUNC_SELECT(io_reg, 3); + pin_reg.func_low_bit = 3; + pin_reg.func_high_bit = 0; } - if (pGPIOConfig->GPIO_Pullup) { - PIN_PULLUP_EN(io_reg); - } else { - PIN_PULLUP_DIS(io_reg); - } - - if (pGPIOConfig->GPIO_Mode == GPIO_Mode_Out_OD) { - portENTER_CRITICAL(); - - pin_reg = GPIO_REG_READ(GPIO_PIN_ADDR(io_num)); - pin_reg &= (~GPIO_PIN_DRIVER_MASK); - pin_reg |= (GPIO_PAD_DRIVER_ENABLE << GPIO_PIN_DRIVER_LSB); - GPIO_REG_WRITE(GPIO_PIN_ADDR(io_num), pin_reg); - - portEXIT_CRITICAL(); - } else if (pGPIOConfig->GPIO_Mode == GPIO_Mode_Sigma_Delta) { - portENTER_CRITICAL(); - - pin_reg = GPIO_REG_READ(GPIO_PIN_ADDR(io_num)); - pin_reg &= (~GPIO_PIN_SOURCE_MASK); - pin_reg |= (0x1 << GPIO_PIN_SOURCE_LSB); - GPIO_REG_WRITE(GPIO_PIN_ADDR(io_num), pin_reg); - GPIO_REG_WRITE(GPIO_SIGMA_DELTA_ADDRESS, SIGMA_DELTA_ENABLE); - - portEXIT_CRITICAL(); - } - - gpio_pin_intr_state_set(io_num, pGPIOConfig->GPIO_IntrType); + WRITE_PERI_REG(GPIO_PIN_REG(io_num), pin_reg.val); } io_num++; - } while (io_num < 16); + } while (io_num < GPIO_PIN_COUNT); + + return ESP_OK; } -/* - * Change GPIO pin output by setting, clearing, or disabling pins. - * In general, it is expected that a bit will be set in at most one - * of these masks. If a bit is clear in all masks, the output state - * remains unchanged. - * - * There is no particular ordering guaranteed; so if the order of - * writes is significant, calling code should divide a single call - * into multiple calls. - */ -void gpio_output_conf(uint32_t set_mask, uint32_t clear_mask, uint32_t enable_mask, uint32_t disable_mask) +void gpio_intr_service(void *arg) { - GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, set_mask); - GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, clear_mask); - GPIO_REG_WRITE(GPIO_ENABLE_W1TS_ADDRESS, enable_mask); - GPIO_REG_WRITE(GPIO_ENABLE_W1TC_ADDRESS, disable_mask); -} + //GPIO intr process + uint32_t gpio_num = 0; + //read status to get interrupt status for GPIO0-15 + uint32_t gpio_intr_status = GPIO.status; -/* - * Sample the value of GPIO input pins and returns a bitmask. - */ -uint32_t gpio_input_get(void) -{ - return GPIO_REG_READ(GPIO_IN_ADDRESS); -} - -/* - * Register an application-specific interrupt handler for GPIO pin - * interrupts. Once the interrupt handler is called, it will not - * be called again until after a call to gpio_intr_ack. Any GPIO - * interrupts that occur during the interim are masked. - * - * The application-specific handler is called with a mask of - * pending GPIO interrupts. After processing pin interrupts, the - * application-specific handler may wish to use gpio_intr_pending - * to check for any additional pending interrupts before it returns. - */ -void gpio_intr_handler_register(void* fn, void* arg) -{ - _xt_isr_attach(ETS_GPIO_INUM, fn, arg); -} - -/* - only highlevel and lowlevel intr can use for wakeup -*/ -void gpio_pin_wakeup_enable(uint32_t i, GPIO_INT_TYPE intr_state) -{ - uint32_t pin_reg; - - if ((intr_state == GPIO_PIN_INTR_LOLEVEL) || (intr_state == GPIO_PIN_INTR_HILEVEL)) { - portENTER_CRITICAL(); - - pin_reg = GPIO_REG_READ(GPIO_PIN_ADDR(i)); - pin_reg &= (~GPIO_PIN_INT_TYPE_MASK); - pin_reg |= (intr_state << GPIO_PIN_INT_TYPE_LSB); - pin_reg |= GPIO_PIN_WAKEUP_ENABLE_SET(GPIO_WAKEUP_ENABLE); - GPIO_REG_WRITE(GPIO_PIN_ADDR(i), pin_reg); - - portEXIT_CRITICAL(); + if (gpio_isr_func == NULL) { + return; } -} -void gpio_pin_wakeup_disable(void) -{ - uint8_t i; - uint32_t pin_reg; + do { + if (gpio_num < GPIO_PIN_COUNT - 1) { + if (gpio_intr_status & BIT(gpio_num)) { //gpio0-gpio15 + if (gpio_isr_func[gpio_num].fn != NULL) { + gpio_isr_func[gpio_num].fn(gpio_isr_func[gpio_num].args); + } - for (i = 0; i < GPIO_PIN_COUNT; i++) { - pin_reg = GPIO_REG_READ(GPIO_PIN_ADDR(i)); - - if (pin_reg & GPIO_PIN_WAKEUP_ENABLE_MASK) { - pin_reg &= (~GPIO_PIN_INT_TYPE_MASK); - pin_reg |= (GPIO_PIN_INTR_DISABLE << GPIO_PIN_INT_TYPE_LSB); - pin_reg &= ~(GPIO_PIN_WAKEUP_ENABLE_SET(GPIO_WAKEUP_ENABLE)); - GPIO_REG_WRITE(GPIO_PIN_ADDR(i), pin_reg); + GPIO.status_w1tc = BIT(gpio_num); + } } + } while (++gpio_num < GPIO_PIN_COUNT - 1); +} + +esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void *args) +{ + GPIO_CHECK(gpio_isr_func != NULL, "GPIO isr service is not installed, call gpio_install_isr_service() first", ESP_ERR_INVALID_STATE); + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + GPIO_CHECK(!RTC_GPIO_IS_VALID_GPIO(gpio_num), "GPIO is RTC GPIO", ESP_ERR_INVALID_ARG); + + ENTER_CRITICAL(); + _xt_isr_mask(1 << ETS_GPIO_INUM); + + if (gpio_isr_func) { + gpio_isr_func[gpio_num].fn = isr_handler; + gpio_isr_func[gpio_num].args = args; } + + _xt_isr_unmask(1 << ETS_GPIO_INUM); + EXIT_CRITICAL(); + return ESP_OK; } -void gpio_pin_intr_state_set(uint32_t i, GPIO_INT_TYPE intr_state) +esp_err_t gpio_isr_handler_remove(gpio_num_t gpio_num) { - uint32_t pin_reg; + GPIO_CHECK(gpio_isr_func != NULL, "GPIO isr service is not installed, call gpio_install_isr_service() first", ESP_ERR_INVALID_STATE); + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + GPIO_CHECK(!RTC_GPIO_IS_VALID_GPIO(gpio_num), "GPIO is RTC GPIO", ESP_ERR_INVALID_ARG); - portENTER_CRITICAL(); + ENTER_CRITICAL(); + _xt_isr_mask(1 << ETS_GPIO_INUM); - pin_reg = GPIO_REG_READ(GPIO_PIN_ADDR(i)); - pin_reg &= (~GPIO_PIN_INT_TYPE_MASK); - pin_reg |= (intr_state << GPIO_PIN_INT_TYPE_LSB); - GPIO_REG_WRITE(GPIO_PIN_ADDR(i), pin_reg); + if (gpio_isr_func) { + gpio_isr_func[gpio_num].fn = NULL; + gpio_isr_func[gpio_num].args = NULL; + } - portEXIT_CRITICAL(); + _xt_isr_unmask(1 << ETS_GPIO_INUM); + EXIT_CRITICAL(); + return ESP_OK; } -void gpio16_output_conf(void) +esp_err_t gpio_isr_register(void (*fn)(void *), void *arg, int no_use, gpio_isr_handle_t *handle) { - WRITE_PERI_REG(PAD_XPD_DCDC_CONF, - (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32_t)0x1); // mux configuration for XPD_DCDC to output rtc_gpio0 + GPIO_CHECK(fn, "GPIO ISR null", ESP_ERR_INVALID_ARG); - WRITE_PERI_REG(RTC_GPIO_CONF, - (READ_PERI_REG(RTC_GPIO_CONF) & (uint32_t)0xfffffffe) | (uint32_t)0x0); //mux configuration for out enable - - WRITE_PERI_REG(RTC_GPIO_ENABLE, - (READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32_t)0xfffffffe) | (uint32_t)0x1); //out enable + _xt_isr_attach(ETS_GPIO_INUM, gpio_intr_service, NULL); + return ESP_OK; } -void gpio16_output_set(uint8_t value) + +esp_err_t gpio_install_isr_service(int no_use) { - WRITE_PERI_REG(RTC_GPIO_OUT, - (READ_PERI_REG(RTC_GPIO_OUT) & (uint32_t)0xfffffffe) | (uint32_t)(value & 1)); + GPIO_CHECK(gpio_isr_func == NULL, "GPIO isr service already installed", ESP_FAIL); + + esp_err_t ret; + ENTER_CRITICAL(); + gpio_isr_func = (gpio_isr_func_t *) calloc(GPIO_PIN_COUNT - 1, sizeof(gpio_isr_func_t)); + + if (gpio_isr_func == NULL) { + ret = ESP_ERR_NO_MEM; + } else { + ret = gpio_isr_register(gpio_intr_service, NULL, 0, NULL); + } + + EXIT_CRITICAL(); + return ret; } -void gpio16_input_conf(void) +void gpio_uninstall_isr_service() { - WRITE_PERI_REG(PAD_XPD_DCDC_CONF, - (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32_t)0x1); // mux configuration for XPD_DCDC and rtc_gpio0 connection + if (gpio_isr_func == NULL) { + return; + } - WRITE_PERI_REG(RTC_GPIO_CONF, - (READ_PERI_REG(RTC_GPIO_CONF) & (uint32_t)0xfffffffe) | (uint32_t)0x0); //mux configuration for out enable - - WRITE_PERI_REG(RTC_GPIO_ENABLE, - READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32_t)0xfffffffe); //out disable + ENTER_CRITICAL(); + _xt_isr_mask(1 << ETS_GPIO_INUM); + _xt_isr_attach(ETS_GPIO_INUM, NULL, NULL); + free(gpio_isr_func); + gpio_isr_func = NULL; + EXIT_CRITICAL(); + return; } -uint8_t gpio16_input_get(void) +/*only level interrupt can be used for wake-up function*/ +esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type) { - return (uint8_t)(READ_PERI_REG(RTC_GPIO_IN_DATA) & 1); + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + GPIO_CHECK(!RTC_GPIO_IS_VALID_GPIO(gpio_num), "RTC IO can not use the wakeup function", ESP_ERR_INVALID_ARG); + + esp_err_t ret = ESP_OK; + + if ((intr_type == GPIO_INTR_LOW_LEVEL) || (intr_type == GPIO_INTR_HIGH_LEVEL)) { + GPIO.pin[gpio_num].int_type = intr_type; + GPIO.pin[gpio_num].wakeup_enable = 0x1; + } else { + ret = ESP_ERR_INVALID_ARG; + } + + return ret; +} + +esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num) +{ + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + GPIO_CHECK(!RTC_GPIO_IS_VALID_GPIO(gpio_num), "RTC IO can not use the wakeup function", ESP_ERR_INVALID_ARG); + + GPIO.pin[gpio_num].wakeup_enable = 0; + return ESP_OK; } diff --git a/components/esp8266/driver/i2c_master.c b/components/esp8266/driver/i2c_master.c index c3735c26..b0488a29 100644 --- a/components/esp8266/driver/i2c_master.c +++ b/components/esp8266/driver/i2c_master.c @@ -16,7 +16,7 @@ #include #include "rom/ets_sys.h" - +#if 0 #include "gpio.h" #include "i2c_master.h" @@ -315,3 +315,5 @@ void i2c_master_writeByte(uint8_t wrdata) i2c_master_wait(5); } } + +#endif diff --git a/components/esp8266/include/driver/gpio.h b/components/esp8266/include/driver/gpio.h index 4051cd57..942186a7 100644 --- a/components/esp8266/include/driver/gpio.h +++ b/components/esp8266/include/driver/gpio.h @@ -1,4 +1,4 @@ -// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2018-2025 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,19 +16,19 @@ #define __GPIO_H__ #include +#include "esp_err.h" #include "esp8266/eagle_soc.h" -#include "esp8266/gpio_register.h" #include "esp8266/pin_mux_register.h" - -#include "freertos/portmacro.h" +#include "esp8266/gpio_register.h" #ifdef __cplusplus extern "C" { #endif -#define ETS_GPIO_INTR_ENABLE() _xt_isr_unmask(1 << ETS_GPIO_INUM) -#define ETS_GPIO_INTR_DISABLE() _xt_isr_mask(1 << ETS_GPIO_INUM) +#ifndef BIT +#define BIT(x) (1 << (x)) +#endif #define GPIO_Pin_0 (BIT(0)) /* Pin 0 selected */ #define GPIO_Pin_1 (BIT(1)) /* Pin 1 selected */ @@ -46,263 +46,347 @@ extern "C" { #define GPIO_Pin_13 (BIT(13)) /* Pin 13 selected */ #define GPIO_Pin_14 (BIT(14)) /* Pin 14 selected */ #define GPIO_Pin_15 (BIT(15)) /* Pin 15 selected */ -#define GPIO_Pin_All (0xFFFF) /* All pins selected */ +#define GPIO_Pin_16 (BIT(16)) /* Pin 16 selected */ +#define GPIO_Pin_All (0x1FFFF) /* All pins selected */ -#define GPIO_PIN_REG_0 PERIPHS_IO_MUX_GPIO0_U -#define GPIO_PIN_REG_1 PERIPHS_IO_MUX_U0TXD_U -#define GPIO_PIN_REG_2 PERIPHS_IO_MUX_GPIO2_U -#define GPIO_PIN_REG_3 PERIPHS_IO_MUX_U0RXD_U -#define GPIO_PIN_REG_4 PERIPHS_IO_MUX_GPIO4_U -#define GPIO_PIN_REG_5 PERIPHS_IO_MUX_GPIO5_U -#define GPIO_PIN_REG_6 PERIPHS_IO_MUX_SD_CLK_U -#define GPIO_PIN_REG_7 PERIPHS_IO_MUX_SD_DATA0_U -#define GPIO_PIN_REG_8 PERIPHS_IO_MUX_SD_DATA1_U -#define GPIO_PIN_REG_9 PERIPHS_IO_MUX_SD_DATA2_U -#define GPIO_PIN_REG_10 PERIPHS_IO_MUX_SD_DATA3_U -#define GPIO_PIN_REG_11 PERIPHS_IO_MUX_SD_CMD_U -#define GPIO_PIN_REG_12 PERIPHS_IO_MUX_MTDI_U -#define GPIO_PIN_REG_13 PERIPHS_IO_MUX_MTCK_U -#define GPIO_PIN_REG_14 PERIPHS_IO_MUX_MTMS_U -#define GPIO_PIN_REG_15 PERIPHS_IO_MUX_MTDO_U +#define GPIO_MODE_DEF_DISABLE (0) +#define GPIO_MODE_DEF_INPUT (BIT(0)) +#define GPIO_MODE_DEF_OUTPUT (BIT(1)) +#define GPIO_MODE_DEF_OD (BIT(2)) -#define GPIO_PIN_REG(i) \ - (i==0) ? GPIO_PIN_REG_0: \ - (i==1) ? GPIO_PIN_REG_1: \ - (i==2) ? GPIO_PIN_REG_2: \ - (i==3) ? GPIO_PIN_REG_3: \ - (i==4) ? GPIO_PIN_REG_4: \ - (i==5) ? GPIO_PIN_REG_5: \ - (i==6) ? GPIO_PIN_REG_6: \ - (i==7) ? GPIO_PIN_REG_7: \ - (i==8) ? GPIO_PIN_REG_8: \ - (i==9) ? GPIO_PIN_REG_9: \ - (i==10)? GPIO_PIN_REG_10: \ - (i==11)? GPIO_PIN_REG_11: \ - (i==12)? GPIO_PIN_REG_12: \ - (i==13)? GPIO_PIN_REG_13: \ - (i==14)? GPIO_PIN_REG_14: \ - GPIO_PIN_REG_15 +#define GPIO_PIN_COUNT 17 -#define GPIO_PIN_ADDR(i) (GPIO_PIN0_ADDRESS + i*4) - -#define GPIO_ID_IS_PIN_REGISTER(reg_id) \ - ((reg_id >= GPIO_ID_PIN0) && (reg_id <= GPIO_ID_PIN(GPIO_PIN_COUNT-1))) - -#define GPIO_REGID_TO_PINIDX(reg_id) ((reg_id) - GPIO_ID_PIN0) +#define GPIO_IS_VALID_GPIO(gpio_num) ((gpio_num < GPIO_PIN_COUNT)) /*!< Check whether it is a valid GPIO number */ +#define RTC_GPIO_IS_VALID_GPIO(gpio_num) ((gpio_num == 16)) /*!< Check whether it is a valid RTC GPIO number */ typedef enum { - GPIO_PIN_INTR_DISABLE = 0, /**< disable GPIO interrupt */ - GPIO_PIN_INTR_POSEDGE = 1, /**< GPIO interrupt type : rising edge */ - GPIO_PIN_INTR_NEGEDGE = 2, /**< GPIO interrupt type : falling edge */ - GPIO_PIN_INTR_ANYEDGE = 3, /**< GPIO interrupt type : bothe rising and falling edge */ - GPIO_PIN_INTR_LOLEVEL = 4, /**< GPIO interrupt type : low level */ - GPIO_PIN_INTR_HILEVEL = 5 /**< GPIO interrupt type : high level */ -} GPIO_INT_TYPE; + GPIO_NUM_0 = 0, /*!< GPIO0, input and output */ + GPIO_NUM_1 = 1, /*!< GPIO1, input and output */ + GPIO_NUM_2 = 2, /*!< GPIO2, input and output */ + GPIO_NUM_3 = 3, /*!< GPIO3, input and output */ + GPIO_NUM_4 = 4, /*!< GPIO4, input and output */ + GPIO_NUM_5 = 5, /*!< GPIO5, input and output */ + GPIO_NUM_6 = 6, /*!< GPIO6, input and output */ + GPIO_NUM_7 = 7, /*!< GPIO7, input and output */ + GPIO_NUM_8 = 8, /*!< GPIO8, input and output */ + GPIO_NUM_9 = 9, /*!< GPIO9, input and output */ + GPIO_NUM_10 = 10, /*!< GPIO10, input and output */ + GPIO_NUM_11 = 11, /*!< GPIO11, input and output */ + GPIO_NUM_12 = 12, /*!< GPIO12, input and output */ + GPIO_NUM_13 = 13, /*!< GPIO13, input and output */ + GPIO_NUM_14 = 14, /*!< GPIO14, input and output */ + GPIO_NUM_15 = 15, /*!< GPIO15, input and output */ + GPIO_NUM_16 = 16, /*!< GPIO15, input and output */ + GPIO_NUM_MAX = 17, + /** @endcond */ +} gpio_num_t; typedef enum { - GPIO_Mode_Input = 0x0, /**< GPIO mode : Input */ - GPIO_Mode_Out_OD, /**< GPIO mode : Output_OD */ - GPIO_Mode_Output, /**< GPIO mode : Output */ - GPIO_Mode_Sigma_Delta, /**< GPIO mode : Sigma_Delta */ -} GPIOMode_TypeDef; + GPIO_INTR_DISABLE = 0, /*!< Disable GPIO interrupt */ + GPIO_INTR_POSEDGE = 1, /*!< GPIO interrupt type : rising edge */ + GPIO_INTR_NEGEDGE = 2, /*!< GPIO interrupt type : falling edge */ + GPIO_INTR_ANYEDGE = 3, /*!< GPIO interrupt type : both rising and falling edge */ + GPIO_INTR_LOW_LEVEL = 4, /*!< GPIO interrupt type : input low level trigger */ + GPIO_INTR_HIGH_LEVEL = 5, /*!< GPIO interrupt type : input high level trigger */ + GPIO_INTR_MAX, +} gpio_int_type_t; typedef enum { - GPIO_PullUp_DIS = 0x0, /**< disable GPIO pullup */ - GPIO_PullUp_EN = 0x1, /**< enable GPIO pullup */ -} GPIO_Pullup_IF; + GPIO_MODE_DISABLE = GPIO_MODE_DEF_DISABLE, /*!< GPIO mode : disable input and output */ + GPIO_MODE_INPUT = GPIO_MODE_DEF_INPUT, /*!< GPIO mode : input only */ + GPIO_MODE_OUTPUT = GPIO_MODE_DEF_OUTPUT, /*!< GPIO mode : output only mode */ + GPIO_MODE_OUTPUT_OD = ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)), /*!< GPIO mode : output only with open-drain mode */ +} gpio_mode_t; +typedef enum { + GPIO_PULLUP_ONLY, /*!< Pad pull up */ + GPIO_PULLDOWN_ONLY, /*!< Pad pull down */ + GPIO_FLOATING, /*!< Pad floating */ +} gpio_pull_mode_t; + +typedef enum { + GPIO_PULLUP_DISABLE = 0x0, /*!< Disable GPIO pull-up resistor */ + GPIO_PULLUP_ENABLE = 0x1, /*!< Enable GPIO pull-up resistor */ +} gpio_pullup_t; + +typedef enum { + GPIO_PULLDOWN_DISABLE = 0x0, /*!< Disable GPIO pull-down resistor */ + GPIO_PULLDOWN_ENABLE = 0x1, /*!< Enable GPIO pull-down resistor */ +} gpio_pulldown_t; + +/** + * @brief Configuration parameters of GPIO pad for gpio_config function + */ typedef struct { - uint16_t GPIO_Pin; /**< GPIO pin */ - GPIOMode_TypeDef GPIO_Mode; /**< GPIO mode */ - GPIO_Pullup_IF GPIO_Pullup; /**< GPIO pullup */ - GPIO_INT_TYPE GPIO_IntrType; /**< GPIO interrupt type */ -} GPIO_ConfigTypeDef; + uint32_t pin_bit_mask; /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */ + gpio_mode_t mode; /*!< GPIO mode: set input/output mode */ + gpio_pullup_t pull_up_en; /*!< GPIO pull-up */ + gpio_pulldown_t pull_down_en; /*!< GPIO pull-down */ + gpio_int_type_t intr_type; /*!< GPIO interrupt type */ +} gpio_config_t; -/** \defgroup Driver_APIs Driver APIs - * @brief Driver APIs - */ - -/** @addtogroup Driver_APIs - * @{ - */ - -/** \defgroup GPIO_Driver_APIs GPIO Driver APIs - * @brief GPIO APIs - */ - -/** @addtogroup GPIO_Driver_APIs - * @{ - */ +typedef void (*gpio_isr_t)(void *); +typedef void *gpio_isr_handle_t; /** - * @brief Set GPIO pin output level. - * - * @param gpio_no : The GPIO sequence number. - * @param bit_value : GPIO pin output level. - * - * @return null - */ -#define GPIO_OUTPUT_SET(gpio_no, bit_value) \ - gpio_output_conf(bit_value<>gpio_no)&BIT(0)) + * @brief GPIO get input level + * + * @note If the pad is not configured for input (or input and output) the returned value is always 0. + * + * @param gpio_num GPIO number. If you want to get the logic level of e.g. pin GPIO16, gpio_num should be GPIO_NUM_16 (16); + * + * @return + * - 0 the GPIO input level is 0 + * - 1 the GPIO input level is 1 + */ +int gpio_get_level(gpio_num_t gpio_num); /** - * @brief Enable GPIO16 output. - * - * @param null - * - * @return null - */ -void gpio16_output_conf(void); + * @brief GPIO set direction + * + * Configure GPIO direction,such as output_only,input_only + * + * @param gpio_num Configure GPIO pins number, it should be GPIO number. If you want to set direction of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param mode GPIO direction + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG GPIO error + */ +esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode); /** - * @brief Set GPIO16 output level. - * - * @param uint8_t value : GPIO16 output level. - * - * @return null - */ -void gpio16_output_set(uint8_t value); + * @brief Configure GPIO pull-up/pull-down resistors + * + * @param gpio_num GPIO number. If you want to set pull up or down mode for e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param pull GPIO pull up/down mode. + * + * @note The GPIO of esp8266 can not be pulled down except RTC GPIO which can not be pulled up. + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG : Parameter error + */ +esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull); /** - * @brief Enable GPIO pin intput. + * @brief Enable GPIO wake-up function. + * + * @note RTC IO can not use the wakeup function * - * @param null + * @param gpio_num GPIO number. * - * @return null + * @param intr_type GPIO wake-up type. Only GPIO_INTR_LOW_LEVEL or GPIO_INTR_HIGH_LEVEL can be used. + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error */ -void gpio16_input_conf(void); +esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type); /** - * @brief Sample the value of GPIO16 input. + * @brief Disable GPIO wake-up function. * - * @param null + * @note RTC IO can not use the wakeup function + * + * @param gpio_num GPIO number * - * @return the level of GPIO16 input. + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error */ -uint8_t gpio16_input_get(void); +esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num); /** - * @brief Configure Gpio pins out or input. - * - * @param uint32_t set_mask : Set the output for the high bit, the - * corresponding bit is 1, the output of high, - * the corresponding bit is 0, do not change the state. - * @param uint32_t set_mask : Set the output for the high bit, the - * corresponding bit is 1, the output of low, - * the corresponding bit is 0, do not change the state. - * @param uint32_t enable_mask : Enable Output - * @param uint32_t disable_mask : Enable Input - * - * @return null - */ -void gpio_output_conf(uint32_t set_mask, uint32_t clear_mask, uint32_t enable_mask, uint32_t disable_mask); + * @brief Register GPIO interrupt handler, the handler is an ISR. + * + * This ISR function is called whenever any GPIO interrupt occurs. See + * the alternative gpio_install_isr_service() and + * gpio_isr_handler_add() API in order to have the driver support + * per-GPIO ISRs. + * + * @param fn Interrupt handler function. + * @param no_use In order to be compatible with esp32, the parameter has no practical meaning and can be filled with 0. + * @param arg Parameter for handler function + * @param handle Pointer to return handle. In order to be compatible with esp32,the parameter has no practical meaning and can be filled with NULL. + * + * @return + * - ESP_OK Success ; + * - ESP_ERR_INVALID_ARG GPIO error + * - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags + */ +esp_err_t gpio_isr_register(void (*fn)(void *), void *arg, int no_use, gpio_isr_handle_t *handle); /** - * @brief Register an application-specific interrupt handler for GPIO pin interrupts. + * @brief Enable pull-up on GPIO. * - * @param void *fn:interrupt handler for GPIO pin interrupts. - * @param void *arg:interrupt handler's arg + * @param gpio_num GPIO number * - * @return null + * @note The GPIO of esp8266 can not be pulled down except RTC GPIO which can not be pulled up. + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error */ -void gpio_intr_handler_register(void* fn, void* arg); +esp_err_t gpio_pullup_en(gpio_num_t gpio_num); /** - * @brief Configure GPIO wake up to light sleep,Only level way is effective. + * @brief Disable pull-up on GPIO. * - * @param uint32_t i : Gpio sequence number - * @param GPIO_INT_TYPE intr_state : the level of wake up to light sleep + * @param gpio_num GPIO number * - * @return null + * @note The GPIO of esp8266 can not be pulled down except RTC GPIO which can not be pulled up. + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error */ -void gpio_pin_wakeup_enable(uint32_t i, GPIO_INT_TYPE intr_state); +esp_err_t gpio_pullup_dis(gpio_num_t gpio_num); /** - * @brief Disable GPIO wake up to light sleep. + * @brief Enable pull-down on GPIO. * - * @param null + * @param gpio_num GPIO number * - * @return null + * @note The GPIO of esp8266 can not be pulled down except RTC GPIO which can not be pulled up. + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error */ -void gpio_pin_wakeup_disable(); +esp_err_t gpio_pulldown_en(gpio_num_t gpio_num); /** - * @brief Config interrupt types of GPIO pin. + * @brief Disable pull-down on GPIO. * - * @param uint32_t i : The GPIO sequence number. - * @param GPIO_INT_TYPE intr_state : GPIO interrupt types. + * @param gpio_num GPIO number * - * @return null + * @note The GPIO of esp8266 can not be pulled down except RTC GPIO which can not be pulled up. + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error */ -void gpio_pin_intr_state_set(uint32_t i, GPIO_INT_TYPE intr_state); +esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num); /** - * @brief Sample the value of GPIO input pins and returns a bitmask. + * @brief Install the driver's GPIO ISR handler service, which allows per-pin GPIO interrupt handlers. * - * @param null + * This function is incompatible with gpio_isr_register() - if that function is used, a single global ISR is registered for all GPIO interrupts. If this function is used, the ISR service provides a global GPIO ISR and individual pin handlers are registered via the gpio_isr_handler_add() function. * - * @return bitmask of GPIO pins input + * @param no_use In order to be compatible with esp32, the parameter has no practical meaning and can be filled with 0. + * + * @return + * - ESP_OK Success + * - ESP_ERR_NO_MEM No memory to install this service + * - ESP_ERR_INVALID_STATE ISR service already installed. + * - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags + * - ESP_ERR_INVALID_ARG GPIO error */ -uint32_t gpio_input_get(void); +esp_err_t gpio_install_isr_service(int no_use); /** - * @} + * @brief Uninstall the driver's GPIO ISR service, freeing related resources. */ +void gpio_uninstall_isr_service(); /** - * @} + * @brief Add ISR handler for the corresponding GPIO pin. + * + * Call this function after using gpio_install_isr_service() to + * install the driver's GPIO ISR handler service. + * + * This ISR handler will be called from an ISR. So there is a stack + * size limit (configurable as "ISR stack size" in menuconfig). This + * limit is smaller compared to a global GPIO interrupt handler due + * to the additional level of indirection. + * + * @param gpio_num GPIO number + * @param isr_handler ISR handler function for the corresponding GPIO number. + * @param args parameter for ISR handler. + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_STATE Wrong state, the ISR service has not been initialized. + * - ESP_ERR_INVALID_ARG Parameter error */ +esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void *args); + +/** + * @brief Remove ISR handler for the corresponding GPIO pin. + * + * @param gpio_num GPIO number + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_STATE Wrong state, the ISR service has not been initialized. + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t gpio_isr_handler_remove(gpio_num_t gpio_num); + + #ifdef __cplusplus } #endif -#endif +#endif /* _DRIVER_GPIO_H_ */ \ No newline at end of file diff --git a/components/esp8266/include/esp8266/eagle_soc.h b/components/esp8266/include/esp8266/eagle_soc.h index df873923..1a49b12c 100644 --- a/components/esp8266/include/esp8266/eagle_soc.h +++ b/components/esp8266/include/esp8266/eagle_soc.h @@ -27,6 +27,12 @@ #include +/* IO definitions (access restrictions to peripheral registers) */ + +#define __RO__ volatile const /*!< Defines 'read only' permissions */ +#define __WO__ volatile /*!< Defines 'write only' permissions */ +#define __RW__ volatile /*!< Defines 'read / write' permissions */ + //Register Bits{{ #define BIT31 0x80000000 #define BIT30 0x40000000 diff --git a/components/esp8266/include/esp8266/gpio_register.h b/components/esp8266/include/esp8266/gpio_register.h index 043610e1..8cd73192 100644 --- a/components/esp8266/include/esp8266/gpio_register.h +++ b/components/esp8266/include/esp8266/gpio_register.h @@ -83,7 +83,6 @@ #define GPIO_ID_PIN(n) (GPIO_ID_PIN0+(n)) #define GPIO_LAST_REGISTER_ID GPIO_ID_PIN(15) #define GPIO_ID_NONE 0xffffffff -#define GPIO_PIN_COUNT 16 #define GPIO_PIN_CONFIG_MSB 12 #define GPIO_PIN_CONFIG_LSB 11 diff --git a/components/esp8266/include/esp8266/gpio_struct.h b/components/esp8266/include/esp8266/gpio_struct.h new file mode 100644 index 00000000..703d7425 --- /dev/null +++ b/components/esp8266/include/esp8266/gpio_struct.h @@ -0,0 +1,93 @@ +/* + * Copyright 2018 Espressif Systems (Shanghai) PTE LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _GPIO_STRUCT_H_ +#define _GPIO_STRUCT_H_ + +#include +#include "esp8266/eagle_soc.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* ESP8266 GPIO Register Definitions */ + +typedef union { + __RW__ struct { + uint32_t sleep_oe: 1; + uint32_t sleep_sel: 1; + uint32_t reserved1: 1; + uint32_t sleep_pullup: 1; + uint32_t func_low_bit: 2; + uint32_t reserved2: 1; + uint32_t pullup: 1; + uint32_t func_high_bit: 1; + }; + __RW__ struct { + uint32_t func_low_bit: 2; + uint32_t reserved1: 1; + uint32_t pulldown: 1; + uint32_t reserved2: 1; + uint32_t sleep_pulldown: 1; + uint32_t func_high_bit: 1; + } rtc_pin; + __RW__ uint32_t val; +} gpio_pin_reg_t; + +typedef struct { + __RO__ uint32_t out; + __WO__ uint32_t out_w1ts; + __WO__ uint32_t out_w1tc; + + __RO__ uint32_t enable; + __WO__ uint32_t enable_w1ts; + __WO__ uint32_t enable_w1tc; + + __RO__ uint32_t in; + + __RO__ uint32_t status; + __WO__ uint32_t status_w1ts; + __WO__ uint32_t status_w1tc; + + __RW__ union { + struct { + uint32_t source: 1; + uint32_t reserved1: 1; + uint32_t driver: 1; + uint32_t reserved2: 4; + uint32_t int_type: 3; + uint32_t wakeup_enable: 1; + uint32_t reserved3: 21; + }; + uint32_t val; + } pin[16]; + + __RW__ uint32_t sigma_delta; + + __RW__ uint32_t rtc_calib_sync; + __RW__ uint32_t rtc_calib_value; +} gpio_struct_t; + +extern volatile gpio_struct_t GPIO; + +#ifdef __cplusplus +} +#endif /* end of __cplusplus */ + +#endif /* _GPIO_STRUCT_H_ */ diff --git a/components/esp8266/ld/esp8266.peripherals.ld b/components/esp8266/ld/esp8266.peripherals.ld new file mode 100644 index 00000000..7f6e6809 --- /dev/null +++ b/components/esp8266/ld/esp8266.peripherals.ld @@ -0,0 +1 @@ +PROVIDE ( GPIO = 0x60000300); \ No newline at end of file diff --git a/examples/peripherals/gpio/Makefile b/examples/peripherals/gpio/Makefile new file mode 100644 index 00000000..0589a9f2 --- /dev/null +++ b/examples/peripherals/gpio/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := gpio + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/peripherals/gpio/README.md b/examples/peripherals/gpio/README.md new file mode 100644 index 00000000..092c434f --- /dev/null +++ b/examples/peripherals/gpio/README.md @@ -0,0 +1,80 @@ +# _GPIO Example_ + +_This test code shows how to configure gpio and how to use gpio interrupt._ + +## GPIO functions + + * GPIO15: output + * GPIO16: output + * GPIO4: input, pulled up, interrupt from rising edge and falling edge + * GPIO5: input, pulled up, interrupt from rising edge. + +## How to use example + +### Hardware Required + + * Connect GPIO15 with GPIO4 + * Connect GPIO16 with GPIO5 + +### Configure the project + +``` +make menuconfig +``` + +* Set serial port under Serial Flasher Options. + + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +make -j4 flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output + + * Generate pulses on GPIO15/16, that triggers interrupt on GPIO4/5 + +``` +I (0) gpio: GPIO[15]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 +I (0) gpio: GPIO[16]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 +I (0) gpio: GPIO[4]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:1 +I (0) gpio: GPIO[5]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:1 +I (0) main: cnt: 0 + +I (1) main: cnt: 1 + +I (1) main: GPIO[4] intr, val: 1 + +I (1) main: GPIO[5] intr, val: 1 + +I (2) main: cnt: 2 + +I (2) main: GPIO[4] intr, val: 0 + +I (3) main: cnt: 3 + +I (3) main: GPIO[4] intr, val: 1 + +I (3) main: GPIO[5] intr, val: 1 + +I (4) main: cnt: 4 + +I (4) main: GPIO[4] intr, val: 0 + +I (5) main: cnt: 5 + +I (5) main: GPIO[4] intr, val: 1 + +I (5) main: GPIO[5] intr, val: 1 + +I (6) main: cnt: 6 + +I (6) main: GPIO[4] intr, val: 0 +``` diff --git a/examples/peripherals/gpio/main/component.mk b/examples/peripherals/gpio/main/component.mk new file mode 100644 index 00000000..44bd2b52 --- /dev/null +++ b/examples/peripherals/gpio/main/component.mk @@ -0,0 +1,3 @@ +# +# Main Makefile. This is basically the same as a component makefile. +# diff --git a/examples/peripherals/gpio/main/user_main.c b/examples/peripherals/gpio/main/user_main.c new file mode 100644 index 00000000..967d4705 --- /dev/null +++ b/examples/peripherals/gpio/main/user_main.c @@ -0,0 +1,129 @@ +// Copyright 2018-2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" + +#include "driver/gpio.h" + +#include "esp_log.h" +#include "esp_system.h" + +static const char *TAG = "main"; + +/** + * Brief: + * This test code shows how to configure gpio and how to use gpio interrupt. + * + * GPIO status: + * GPIO15: output + * GPIO16: output + * GPIO4: input, pulled up, interrupt from rising edge and falling edge + * GPIO5: input, pulled up, interrupt from rising edge. + * + * Test: + * Connect GPIO15 with GPIO4 + * Connect GPIO16 with GPIO5 + * Generate pulses on GPIO15/16, that triggers interrupt on GPIO4/5 + * + */ + +#define GPIO_OUTPUT_IO_0 15 +#define GPIO_OUTPUT_IO_1 16 +#define GPIO_OUTPUT_PIN_SEL ((1ULL<