Merge pull request #301 from UncleRus/gpio_intr

More convenient GPIO interrupt handlers
This commit is contained in:
Ruslan V. Uss 2016-12-04 09:52:20 +06:00 committed by GitHub
commit 61caf8c9f4
4 changed files with 67 additions and 92 deletions

View file

@ -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);
}
}

View file

@ -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]();
}
}

View file

@ -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)

View file

@ -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);