|
|
|
|
@@ -35,10 +35,50 @@
|
|
|
|
|
#include "py/runtime.h"
|
|
|
|
|
#include "py/gc.h"
|
|
|
|
|
#include "py/mphal.h"
|
|
|
|
|
#include "lib/utils/mpirq.h"
|
|
|
|
|
#include "modmachine.h"
|
|
|
|
|
|
|
|
|
|
#if MICROPY_PY_MACHINE
|
|
|
|
|
|
|
|
|
|
typedef struct _machine_pin_irq_obj_t {
|
|
|
|
|
mp_irq_obj_t base;
|
|
|
|
|
struct _machine_pin_irq_obj_t *next;
|
|
|
|
|
struct gpio_callback callback;
|
|
|
|
|
} machine_pin_irq_obj_t;
|
|
|
|
|
|
|
|
|
|
STATIC const mp_irq_methods_t machine_pin_irq_methods;
|
|
|
|
|
const mp_obj_base_t machine_pin_obj_template = {&machine_pin_type};
|
|
|
|
|
|
|
|
|
|
void machine_pin_deinit(void) {
|
|
|
|
|
for (machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_list); irq != NULL; irq = irq->next) {
|
|
|
|
|
machine_pin_obj_t *pin = MP_OBJ_TO_PTR(irq->base.parent);
|
|
|
|
|
gpio_pin_interrupt_configure(pin->port, pin->pin, GPIO_INT_DISABLE);
|
|
|
|
|
gpio_remove_callback(pin->port, &irq->callback);
|
|
|
|
|
}
|
|
|
|
|
MP_STATE_PORT(machine_pin_irq_list) = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STATIC void gpio_callback_handler(struct device *port, struct gpio_callback *cb, gpio_port_pins_t pins) {
|
|
|
|
|
machine_pin_irq_obj_t *irq = CONTAINER_OF(cb, machine_pin_irq_obj_t, callback);
|
|
|
|
|
|
|
|
|
|
#if MICROPY_STACK_CHECK
|
|
|
|
|
// This callback executes in an ISR context so the stack-limit check must be changed to
|
|
|
|
|
// use the ISR stack for the duration of this function (so that hard IRQ callbacks work).
|
|
|
|
|
char *orig_stack_top = MP_STATE_THREAD(stack_top);
|
|
|
|
|
size_t orig_stack_limit = MP_STATE_THREAD(stack_limit);
|
|
|
|
|
MP_STATE_THREAD(stack_top) = (void *)&irq;
|
|
|
|
|
MP_STATE_THREAD(stack_limit) = CONFIG_ISR_STACK_SIZE - 512;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
mp_irq_handler(&irq->base);
|
|
|
|
|
|
|
|
|
|
#if MICROPY_STACK_CHECK
|
|
|
|
|
// Restore original stack-limit checking values.
|
|
|
|
|
MP_STATE_THREAD(stack_top) = orig_stack_top;
|
|
|
|
|
MP_STATE_THREAD(stack_limit) = orig_stack_limit;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
|
|
|
|
machine_pin_obj_t *self = self_in;
|
|
|
|
|
mp_printf(print, "<Pin %p %d>", self->port, self->pin);
|
|
|
|
|
@@ -151,6 +191,66 @@ STATIC mp_obj_t machine_pin_on(mp_obj_t self_in) {
|
|
|
|
|
}
|
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_on_obj, machine_pin_on);
|
|
|
|
|
|
|
|
|
|
// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING, hard=False)
|
|
|
|
|
STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
|
|
|
|
enum { ARG_handler, ARG_trigger, ARG_hard };
|
|
|
|
|
static const mp_arg_t allowed_args[] = {
|
|
|
|
|
{ MP_QSTR_handler, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
|
|
|
|
|
{ MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_INT_EDGE_BOTH} },
|
|
|
|
|
{ MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
|
|
|
|
|
};
|
|
|
|
|
machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
|
|
|
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
|
|
|
|
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
|
|
|
|
|
|
|
|
|
if (self->irq == NULL) {
|
|
|
|
|
machine_pin_irq_obj_t *irq;
|
|
|
|
|
for (irq = MP_STATE_PORT(machine_pin_irq_list); irq != NULL; irq = irq->next) {
|
|
|
|
|
machine_pin_obj_t *irq_pin = MP_OBJ_TO_PTR(irq->base.parent);
|
|
|
|
|
if (irq_pin->port == self->port && irq_pin->pin == self->pin) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (irq == NULL) {
|
|
|
|
|
irq = m_new_obj(machine_pin_irq_obj_t);
|
|
|
|
|
irq->base.base.type = &mp_irq_type;
|
|
|
|
|
irq->base.methods = (mp_irq_methods_t *)&machine_pin_irq_methods;
|
|
|
|
|
irq->base.parent = MP_OBJ_FROM_PTR(self);
|
|
|
|
|
irq->base.handler = mp_const_none;
|
|
|
|
|
irq->base.ishard = false;
|
|
|
|
|
irq->next = MP_STATE_PORT(machine_pin_irq_list);
|
|
|
|
|
gpio_init_callback(&irq->callback, gpio_callback_handler, BIT(self->pin));
|
|
|
|
|
int ret = gpio_add_callback(self->port, &irq->callback);
|
|
|
|
|
if (ret != 0) {
|
|
|
|
|
mp_raise_OSError(-ret);
|
|
|
|
|
}
|
|
|
|
|
MP_STATE_PORT(machine_pin_irq_list) = irq;
|
|
|
|
|
}
|
|
|
|
|
self->irq = irq;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (n_args > 1 || kw_args->used != 0) {
|
|
|
|
|
// configure irq
|
|
|
|
|
int ret = gpio_pin_interrupt_configure(self->port, self->pin, GPIO_INT_DISABLE);
|
|
|
|
|
if (ret != 0) {
|
|
|
|
|
mp_raise_OSError(-ret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self->irq->base.handler = args[ARG_handler].u_obj;
|
|
|
|
|
self->irq->base.ishard = args[ARG_hard].u_bool;
|
|
|
|
|
|
|
|
|
|
if (args[ARG_handler].u_obj != mp_const_none) {
|
|
|
|
|
ret = gpio_pin_interrupt_configure(self->port, self->pin, args[ARG_trigger].u_int);
|
|
|
|
|
if (ret != 0) {
|
|
|
|
|
mp_raise_OSError(-ret);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return MP_OBJ_FROM_PTR(self->irq);
|
|
|
|
|
}
|
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_irq_obj, 1, machine_pin_irq);
|
|
|
|
|
|
|
|
|
|
STATIC mp_uint_t machine_pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
|
|
|
|
|
(void)errcode;
|
|
|
|
|
machine_pin_obj_t *self = self_in;
|
|
|
|
|
@@ -172,12 +272,15 @@ STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
|
|
|
|
|
{ MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) },
|
|
|
|
|
{ MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&machine_pin_off_obj) },
|
|
|
|
|
{ MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&machine_pin_on_obj) },
|
|
|
|
|
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_pin_irq_obj) },
|
|
|
|
|
|
|
|
|
|
// class constants
|
|
|
|
|
{ MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_INPUT) },
|
|
|
|
|
{ MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_OUTPUT) },
|
|
|
|
|
{ MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULL_UP) },
|
|
|
|
|
{ MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULL_DOWN) },
|
|
|
|
|
{ MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_INT_EDGE_RISING) },
|
|
|
|
|
{ MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_INT_EDGE_FALLING) },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table);
|
|
|
|
|
@@ -195,3 +298,33 @@ const mp_obj_type_t machine_pin_type = {
|
|
|
|
|
.protocol = &machine_pin_pin_p,
|
|
|
|
|
.locals_dict = (mp_obj_t)&machine_pin_locals_dict,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
STATIC mp_uint_t machine_pin_irq_trigger(mp_obj_t self_in, mp_uint_t new_trigger) {
|
|
|
|
|
machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
|
|
|
|
if (new_trigger == 0) {
|
|
|
|
|
new_trigger = GPIO_INT_DISABLE;
|
|
|
|
|
}
|
|
|
|
|
int ret = gpio_pin_interrupt_configure(self->port, self->pin, new_trigger);
|
|
|
|
|
if (ret != 0) {
|
|
|
|
|
mp_raise_OSError(-ret);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STATIC mp_uint_t machine_pin_irq_info(mp_obj_t self_in, mp_uint_t info_type) {
|
|
|
|
|
machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
|
|
|
|
if (info_type == MP_IRQ_INFO_FLAGS) {
|
|
|
|
|
return gpio_get_pending_int(self->port);
|
|
|
|
|
} else if (info_type == MP_IRQ_INFO_TRIGGERS) {
|
|
|
|
|
return 0; // TODO
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STATIC const mp_irq_methods_t machine_pin_irq_methods = {
|
|
|
|
|
.init = machine_pin_irq,
|
|
|
|
|
.trigger = machine_pin_irq_trigger,
|
|
|
|
|
.info = machine_pin_irq_info,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif // MICROPY_PY_MACHINE
|
|
|
|
|
|