diff --git a/ports/zephyr/Makefile b/ports/zephyr/Makefile index 4fe6552846..169aebc267 100644 --- a/ports/zephyr/Makefile +++ b/ports/zephyr/Makefile @@ -52,6 +52,7 @@ SRC_C = main.c \ uart_core.c \ zephyr_storage.c \ lib/timeutils/timeutils.c \ + lib/utils/mpirq.c \ lib/utils/stdout_helpers.c \ lib/utils/printf.c \ lib/utils/pyexec.c \ diff --git a/ports/zephyr/machine_pin.c b/ports/zephyr/machine_pin.c index ad5f54baaf..79d759eb28 100644 --- a/ports/zephyr/machine_pin.c +++ b/ports/zephyr/machine_pin.c @@ -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, "", 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 diff --git a/ports/zephyr/main.c b/ports/zephyr/main.c index 104954f595..78b947d7af 100644 --- a/ports/zephyr/main.c +++ b/ports/zephyr/main.c @@ -55,6 +55,7 @@ #include "extmod/vfs.h" #endif +#include "modmachine.h" #include "modzephyr.h" #ifdef TEST @@ -166,6 +167,11 @@ soft_reset: } printf("soft reboot\n"); + + #if MICROPY_PY_MACHINE + machine_pin_deinit(); + #endif + goto soft_reset; return 0; diff --git a/ports/zephyr/modmachine.h b/ports/zephyr/modmachine.h index 84e4d10a88..766a9d7ea3 100644 --- a/ports/zephyr/modmachine.h +++ b/ports/zephyr/modmachine.h @@ -11,6 +11,9 @@ typedef struct _machine_pin_obj_t { mp_obj_base_t base; struct device *port; uint32_t pin; + struct _machine_pin_irq_obj_t *irq; } machine_pin_obj_t; +void machine_pin_deinit(void); + #endif // MICROPY_INCLUDED_ZEPHYR_MODMACHINE_H diff --git a/ports/zephyr/mpconfigport.h b/ports/zephyr/mpconfigport.h index 7044c175d0..f94ee72707 100644 --- a/ports/zephyr/mpconfigport.h +++ b/ports/zephyr/mpconfigport.h @@ -81,6 +81,7 @@ #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) #define MICROPY_PY_BUILTINS_COMPLEX (0) +#define MICROPY_ENABLE_SCHEDULER (1) #define MICROPY_VFS (1) #define MICROPY_READER_VFS (MICROPY_VFS) @@ -119,7 +120,8 @@ typedef long mp_off_t; #define MP_STATE_PORT MP_STATE_VM #define MICROPY_PORT_ROOT_POINTERS \ - const char *readline_hist[8]; + const char *readline_hist[8]; \ + void *machine_pin_irq_list; /* Linked list of pin irq objects */ extern const struct _mp_obj_module_t mp_module_machine; extern const struct _mp_obj_module_t mp_module_time; @@ -169,3 +171,6 @@ extern const struct _mp_obj_module_t mp_module_zsensor; // extra built in names to add to the global namespace #define MICROPY_PORT_BUILTINS \ { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) }, + +#define MICROPY_BEGIN_ATOMIC_SECTION irq_lock +#define MICROPY_END_ATOMIC_SECTION irq_unlock