diff --git a/core/esp_gpio.c b/core/esp_gpio.c index f6db1ef..a3011e1 100644 --- a/core/esp_gpio.c +++ b/core/esp_gpio.c @@ -56,3 +56,34 @@ void gpio_set_pullup(uint8_t gpio_num, bool enabled, bool enabled_during_sleep) iomux_set_pullup_flags(gpio_to_iomux(gpio_num), flags); } +static gpio_interrupt_handler_t gpio_interrupt_handlers[16] = { 0 }; + +void __attribute__((weak)) IRAM gpio_interrupt_handler(void) +{ + uint32_t status_reg = GPIO.STATUS; + GPIO.STATUS_CLEAR = status_reg; + + uint8_t gpio_idx; + while((gpio_idx = __builtin_ffs(status_reg))) + { + gpio_idx--; + status_reg &= ~BIT(gpio_idx); + if(FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_idx])) { + gpio_interrupt_handler_t handler = gpio_interrupt_handlers[gpio_idx]; + if (handler) { + handler(gpio_idx); + } + } + } +} + +void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type, gpio_interrupt_handler_t handler) +{ + gpio_interrupt_handlers[gpio_num] = handler; + + GPIO.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type); + if(int_type != GPIO_INTTYPE_NONE) { + _xt_isr_attach(INUM_GPIO, gpio_interrupt_handler); + _xt_isr_unmask(1<<INUM_GPIO); + } +} diff --git a/core/esp_gpio_interrupts.c b/core/esp_gpio_interrupts.c deleted file mode 100644 index ef0a47d..0000000 --- a/core/esp_gpio_interrupts.c +++ /dev/null @@ -1,80 +0,0 @@ -/* ESP GPIO interrupts. - - Use with gpio_set_interrupt(), defined in esp/gpio.h - - These interrupt vectors are default implementations with weak - linkage. If you write your own GPIO interrupt vectors in your program - then they will replace these at link time. - - Look in examples/button/ for a simple GPIO interrupt example. - - You can implement GPIO interrupt handlers in either of two ways: - - - Implement gpXX_interrupt_handler() for each GPIO pin number that - you want to use interrupt with. This is simple but it may not - be enough in all cases. - - void gpio01_interrupt_handler(void) { - // Do something when GPIO 01 changes - } - - void gpio12_interrupt_handler(void) { - // Do something when GPIO 12 changes - } - - OR - - - Implement a single function named gpio_interrupt_handler(). This - will need to manually check GPIO.STATUS and clear any status - bits after handling interrupts. This gives you full control, but - you can't combine it with the first approach. - - - Part of esp-open-rtos - Copyright (C) 2015 Superhouse Automation Pty Ltd - BSD Licensed as described in the file LICENSE - */ -#include "esp8266.h" - -void gpio_interrupt_handler(void); -void gpio_noop_interrupt_handler(void) { } -void gpio00_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler"))); -void gpio01_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler"))); -void gpio02_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler"))); -void gpio03_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler"))); -void gpio04_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler"))); -void gpio05_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler"))); -void gpio06_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler"))); -void gpio07_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler"))); -void gpio08_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler"))); -void gpio09_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler"))); -void gpio10_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler"))); -void gpio11_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler"))); -void gpio12_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler"))); -void gpio13_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler"))); -void gpio14_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler"))); -void gpio15_interrupt_handler(void) __attribute__((weak, alias("gpio_noop_interrupt_handler"))); - -typedef void (* gpio_interrupt_handler_t)(void); - -const gpio_interrupt_handler_t gpio_interrupt_handlers[16] = { - gpio00_interrupt_handler, gpio01_interrupt_handler, gpio02_interrupt_handler, - gpio03_interrupt_handler, gpio04_interrupt_handler, gpio05_interrupt_handler, - gpio06_interrupt_handler, gpio07_interrupt_handler, gpio08_interrupt_handler, - gpio09_interrupt_handler, gpio10_interrupt_handler, gpio11_interrupt_handler, - gpio12_interrupt_handler, gpio13_interrupt_handler, gpio14_interrupt_handler, - gpio15_interrupt_handler }; - -void __attribute__((weak)) IRAM gpio_interrupt_handler(void) -{ - uint32_t status_reg = GPIO.STATUS; - GPIO.STATUS_CLEAR = status_reg; - uint8_t gpio_idx; - while((gpio_idx = __builtin_ffs(status_reg))) - { - gpio_idx--; - status_reg &= ~BIT(gpio_idx); - if(FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_idx])) - gpio_interrupt_handlers[gpio_idx](); - } -} diff --git a/core/include/esp/gpio.h b/core/include/esp/gpio.h index f3f6308..9187087 100644 --- a/core/include/esp/gpio.h +++ b/core/include/esp/gpio.h @@ -127,21 +127,44 @@ static inline bool gpio_read(const uint8_t gpio_num) return GPIO.IN & BIT(gpio_num); } -extern void gpio_interrupt_handler(void); +typedef void (* gpio_interrupt_handler_t)(uint8_t gpio_num); + +/* + * You can implement GPIO interrupt handlers in either of two ways: + * - Implement handler and use it with the gpio_set_interrupt() + * + * Example: + * + * void my_intr_handler(uint8_t gpio_num) { + * // Do something when GPIO changes + * } + * ... + * gpio_set_interrupt(MY_GPIO_NUM, GPIO_INTTYPE_EDGE_ANY, my_intr_handler); + * + * OR + * + * - Implement a single function named gpio_interrupt_handler(). This + * will need to manually check GPIO.STATUS and clear any status + * bits after handling interrupts. This gives you full control, but + * you can't combine it with the first approach. + * + * Example: + * + * void IRAM gpio_interrupt_handler(void) { + * // check GPIO.STATUS + * // write GPIO.STATUS_CLEAR + * // Do something when GPIO changes + * } + * ... + * gpio_set_interrupt(MY_GPIO_NUM, GPIO_INTTYPE_EDGE_ANY, NULL); + */ /* Set the interrupt type for a given pin * * If int_type is not GPIO_INTTYPE_NONE, the gpio_interrupt_handler will be * attached and unmasked. */ -static inline void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type) -{ - GPIO.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type); - if(int_type != GPIO_INTTYPE_NONE) { - _xt_isr_attach(INUM_GPIO, gpio_interrupt_handler); - _xt_isr_unmask(1<<INUM_GPIO); - } -} +void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type, gpio_interrupt_handler_t handler); /* Return the interrupt type set for a pin */ static inline gpio_inttype_t gpio_get_interrupt(const uint8_t gpio_num) diff --git a/examples/button/button.c b/examples/button/button.c index a371f0d..c12d78b 100644 --- a/examples/button/button.c +++ b/examples/button/button.c @@ -16,7 +16,6 @@ const int gpio = 0; /* gpio 0 usually has "PROGRAM" button attached */ const int active = 0; /* active == 0 for active low */ const gpio_inttype_t int_type = GPIO_INTTYPE_EDGE_NEG; -#define GPIO_HANDLER gpio00_interrupt_handler /* This task polls for the button and prints the tick @@ -39,6 +38,8 @@ void buttonPollTask(void *pvParameters) } } +void gpio_intr_handler(uint8_t gpio_num); + /* This task configures the GPIO interrupt and uses it to tell when the button is pressed. @@ -51,7 +52,7 @@ void buttonIntTask(void *pvParameters) { printf("Waiting for button press interrupt on gpio %d...\r\n", gpio); QueueHandle_t *tsqueue = (QueueHandle_t *)pvParameters; - gpio_set_interrupt(gpio, int_type); + gpio_set_interrupt(gpio, int_type, gpio_intr_handler); uint32_t last = 0; while(1) { @@ -67,7 +68,7 @@ void buttonIntTask(void *pvParameters) static QueueHandle_t tsqueue; -void GPIO_HANDLER(void) +void gpio_intr_handler(uint8_t gpio_num) { uint32_t now = xTaskGetTickCountFromISR(); xQueueSendToBackFromISR(tsqueue, &now, NULL);