Merge pull request #301 from UncleRus/gpio_intr
More convenient GPIO interrupt handlers
This commit is contained in:
commit
61caf8c9f4
4 changed files with 67 additions and 92 deletions
|
@ -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);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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]();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -127,21 +127,44 @@ static inline bool gpio_read(const uint8_t gpio_num)
|
||||||
return GPIO.IN & BIT(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
|
/* Set the interrupt type for a given pin
|
||||||
*
|
*
|
||||||
* If int_type is not GPIO_INTTYPE_NONE, the gpio_interrupt_handler will be
|
* If int_type is not GPIO_INTTYPE_NONE, the gpio_interrupt_handler will be
|
||||||
* attached and unmasked.
|
* attached and unmasked.
|
||||||
*/
|
*/
|
||||||
static inline void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type)
|
void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type, gpio_interrupt_handler_t 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the interrupt type set for a pin */
|
/* Return the interrupt type set for a pin */
|
||||||
static inline gpio_inttype_t gpio_get_interrupt(const uint8_t gpio_num)
|
static inline gpio_inttype_t gpio_get_interrupt(const uint8_t gpio_num)
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
const int gpio = 0; /* gpio 0 usually has "PROGRAM" button attached */
|
const int gpio = 0; /* gpio 0 usually has "PROGRAM" button attached */
|
||||||
const int active = 0; /* active == 0 for active low */
|
const int active = 0; /* active == 0 for active low */
|
||||||
const gpio_inttype_t int_type = GPIO_INTTYPE_EDGE_NEG;
|
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
|
/* 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
|
/* This task configures the GPIO interrupt and uses it to tell
|
||||||
when the button is pressed.
|
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);
|
printf("Waiting for button press interrupt on gpio %d...\r\n", gpio);
|
||||||
QueueHandle_t *tsqueue = (QueueHandle_t *)pvParameters;
|
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;
|
uint32_t last = 0;
|
||||||
while(1) {
|
while(1) {
|
||||||
|
@ -67,7 +68,7 @@ void buttonIntTask(void *pvParameters)
|
||||||
|
|
||||||
static QueueHandle_t tsqueue;
|
static QueueHandle_t tsqueue;
|
||||||
|
|
||||||
void GPIO_HANDLER(void)
|
void gpio_intr_handler(uint8_t gpio_num)
|
||||||
{
|
{
|
||||||
uint32_t now = xTaskGetTickCountFromISR();
|
uint32_t now = xTaskGetTickCountFromISR();
|
||||||
xQueueSendToBackFromISR(tsqueue, &now, NULL);
|
xQueueSendToBackFromISR(tsqueue, &now, NULL);
|
||||||
|
|
Loading…
Reference in a new issue