Add support of counting of interrupts (#2149)
* Add support of counting of interrupts * Update the timestamp when interrupt happens during dispatch. Also clear out interrupts when setting up a new callback
This commit is contained in:
parent
368c25db8b
commit
9aebc84b72
|
@ -53,17 +53,31 @@ static void gpio_intr_callback_task (task_param_t param, uint8 priority)
|
|||
// GPIO callbacks are run in L0 and include the level as a parameter
|
||||
lua_State *L = lua_getstate();
|
||||
NODE_DBG("Calling: %08x\n", gpio_cb_ref[pin]);
|
||||
//
|
||||
if (!INTERRUPT_TYPE_IS_LEVEL(pin_int_type[pin])) {
|
||||
// Edge triggered -- re-enable the interrupt
|
||||
platform_gpio_intr_init(pin, pin_int_type[pin]);
|
||||
}
|
||||
|
||||
bool needs_callback = 1;
|
||||
|
||||
while (needs_callback) {
|
||||
// Note that the interrupt level only modifies 'seen' and
|
||||
// the base level only modifies 'reported'.
|
||||
|
||||
// Do the actual callback
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, gpio_cb_ref[pin]);
|
||||
lua_pushinteger(L, level);
|
||||
lua_pushinteger(L, then);
|
||||
lua_call(L, 2, 0);
|
||||
uint16_t seen = pin_counter[pin].seen;
|
||||
lua_pushinteger(L, 0x7fff & (seen - pin_counter[pin].reported));
|
||||
pin_counter[pin].reported = seen & 0x7fff; // This will cause the next interrupt to trigger a callback
|
||||
uint16_t diff = (seen ^ pin_counter[pin].seen);
|
||||
// Needs another callback if seen changed but not if the top bit is set
|
||||
needs_callback = diff <= 0x7fff && diff > 0;
|
||||
if (needs_callback) {
|
||||
// Fake this for next time (this only happens if another interrupt happens since
|
||||
// we loaded the 'seen' variable.
|
||||
then = system_get_time() & 0x7fffffff;
|
||||
}
|
||||
|
||||
lua_call(L, 3, 0);
|
||||
}
|
||||
|
||||
if (INTERRUPT_TYPE_IS_LEVEL(pin_int_type[pin])) {
|
||||
// Level triggered -- re-enable the callback
|
||||
|
@ -108,6 +122,14 @@ static int lgpio_trig( lua_State* L )
|
|||
// unreference any overwritten callback
|
||||
if(old_pin_ref != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, old_pin_ref);
|
||||
|
||||
uint16_t seen;
|
||||
|
||||
// Make sure that we clear out any queued interrupts
|
||||
do {
|
||||
seen = pin_counter[pin].seen;
|
||||
pin_counter[pin].reported = seen & 0x7fff;
|
||||
} while (seen != pin_counter[pin].seen);
|
||||
|
||||
NODE_DBG("Pin data: %d %d %08x, %d %d %d, %08x\n",
|
||||
pin, type, pin_mux[pin], pin_num[pin], pin_func[pin], pin_int_type[pin], gpio_cb_ref[pin]);
|
||||
platform_gpio_intr_init(pin, type);
|
||||
|
|
|
@ -9,6 +9,7 @@ uint8_t pin_func[GPIO_PIN_NUM];
|
|||
#ifdef GPIO_INTERRUPT_ENABLE
|
||||
uint8_t pin_num_inv[GPIO_PIN_NUM_INV];
|
||||
uint8_t pin_int_type[GPIO_PIN_NUM];
|
||||
GPIO_INT_COUNTER pin_counter[GPIO_PIN_NUM];
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -15,6 +15,13 @@ extern uint8_t pin_func[GPIO_PIN_NUM];
|
|||
#ifdef GPIO_INTERRUPT_ENABLE
|
||||
extern uint8_t pin_num_inv[GPIO_PIN_NUM_INV];
|
||||
extern uint8_t pin_int_type[GPIO_PIN_NUM];
|
||||
typedef struct {
|
||||
// These values have 15 bits of count, and the top bit
|
||||
// in 'seen' is set if we are missing a task post
|
||||
volatile uint16_t seen;
|
||||
volatile uint16_t reported;
|
||||
} GPIO_INT_COUNTER;
|
||||
extern GPIO_INT_COUNTER pin_counter[GPIO_PIN_NUM];
|
||||
#endif
|
||||
|
||||
void get_pin_map(void);
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include "driver/uart.h"
|
||||
#include "driver/sigma_delta.h"
|
||||
|
||||
#define INTERRUPT_TYPE_IS_LEVEL(x) ((x) >= GPIO_PIN_INTR_LOLEVEL)
|
||||
|
||||
#ifdef GPIO_INTERRUPT_ENABLE
|
||||
static task_handle_t gpio_task_handle;
|
||||
|
||||
|
@ -226,13 +228,25 @@ static void ICACHE_RAM_ATTR platform_gpio_intr_dispatcher (void *dummy){
|
|||
if (gpio_status&1) {
|
||||
int i = pin_num_inv[j];
|
||||
if (pin_int_type[i]) {
|
||||
uint16_t diff = pin_counter[i].seen ^ pin_counter[i].reported;
|
||||
|
||||
pin_counter[i].seen = 0x7fff & (pin_counter[i].seen + 1);
|
||||
|
||||
if (INTERRUPT_TYPE_IS_LEVEL(pin_int_type[i])) {
|
||||
//disable interrupt
|
||||
gpio_pin_intr_state_set(GPIO_ID_PIN(j), GPIO_PIN_INTR_DISABLE);
|
||||
}
|
||||
//clear interrupt status
|
||||
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(j));
|
||||
|
||||
if (diff == 0 || diff & 0x8000) {
|
||||
uint32 level = 0x1 & GPIO_INPUT_GET(GPIO_ID_PIN(j));
|
||||
task_post_high (gpio_task_handle, (now << 8) + (i<<1) + level);
|
||||
// We re-enable the interrupt when we execute the callback
|
||||
if (!task_post_high (gpio_task_handle, (now << 8) + (i<<1) + level)) {
|
||||
// If we fail to post, then try on the next interrupt
|
||||
pin_counter[i].seen |= 0x8000;
|
||||
}
|
||||
// We re-enable the interrupt when we execute the callback (if level)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,10 +125,15 @@ This function is not available if GPIO_INTERRUPT_ENABLE was undefined at compile
|
|||
- `type` "up", "down", "both", "low", "high", which represent *rising edge*, *falling edge*, *both
|
||||
edges*, *low level*, and *high level* trigger modes respectivey. If the type is "none" or omitted
|
||||
then the callback function is removed and the interrupt is disabled.
|
||||
- `callback_function(level, when)` callback function when trigger occurs. The level of the specified pin
|
||||
- `callback_function(level, when, eventcount)` callback function when trigger occurs. The level of the specified pin
|
||||
at the interrupt passed as the first parameter to the callback. The timestamp of the event is passed
|
||||
as the second parameter. This is in microseconds and has the same base as for `tmr.now()`. This timestamp
|
||||
is grabbed at interrupt level and is more consistent than getting the time in the callback function.
|
||||
This timestamp is normally of the first interrupt detected, but, under overload conditions, might be a later one.
|
||||
The eventcount is the number of interrupts that were elided for this callback. This works best for edge triggered
|
||||
interrupts and enables counting of edges. However, beware
|
||||
of switch bounces -- you can get multiple pulses for a single switch closure. Counting
|
||||
works best when the edges are digitally generated.
|
||||
The previous callback function will be used if the function is omitted.
|
||||
|
||||
#### Returns
|
||||
|
|
Loading…
Reference in New Issue