From 7417c6ac91e47798b9c9eba2e7cd8f3dc1bbcc57 Mon Sep 17 00:00:00 2001 From: robert-hh Date: Sat, 5 Jun 2021 14:06:04 +0200 Subject: [PATCH] mimxrt/machine_pin: Implement pin.irq() functionality. --- ports/mimxrt/Makefile | 2 + .../boards/MIMXRT1010_EVK/mpconfigboard.h | 2 + .../boards/MIMXRT1020_EVK/mpconfigboard.h | 2 + .../boards/MIMXRT1050_EVK/mpconfigboard.h | 2 + .../boards/MIMXRT1060_EVK/mpconfigboard.h | 2 + .../boards/MIMXRT1064_EVK/mpconfigboard.h | 2 + ports/mimxrt/boards/TEENSY40/mpconfigboard.h | 2 + ports/mimxrt/boards/TEENSY41/mpconfigboard.h | 2 + ports/mimxrt/machine_pin.c | 193 +++++++++++++++++- ports/mimxrt/main.c | 2 + ports/mimxrt/modmachine.h | 1 + ports/mimxrt/mpconfigport.h | 3 +- ports/mimxrt/pin.h | 7 + 13 files changed, 220 insertions(+), 2 deletions(-) mode change 100755 => 100644 ports/mimxrt/boards/TEENSY41/mpconfigboard.h diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile index 3af2a55472..638c6b124e 100644 --- a/ports/mimxrt/Makefile +++ b/ports/mimxrt/Makefile @@ -151,6 +151,7 @@ SRC_C = \ lib/mp-readline/readline.c \ lib/libc/string0.c \ lib/utils/gchelper_native.c \ + lib/utils/mpirq.c \ lib/utils/printf.c \ lib/utils/pyexec.c \ lib/utils/stdout_helpers.c \ @@ -271,6 +272,7 @@ SRC_QSTR += \ modmimxrt.c \ moduos.c \ pin.c \ + lib/utils/mpirq.c \ lib/utils/sys_stdio_mphal.c \ extmod/modonewire.c \ $(GEN_PINS_SRC) \ diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h index 5a373a3ca6..fdaeac7eed 100644 --- a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h @@ -9,6 +9,8 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) #define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1010_flexspi_nor_config.h" +#define MICROPY_HW_NUM_PIN_IRQS (2 * 32) + // Define mapping logical UART # to hardware UART # // LPUART1 on D0/D1 -> 1 // LPUART3 on A0/D4 -> 3 diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h index 5a595074ad..8238762a0b 100644 --- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h @@ -10,6 +10,8 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) #define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1020_flexspi_nor_config.h" +#define MICROPY_HW_NUM_PIN_IRQS (3 * 32) + // Define mapping logical UART # to hardware UART # // D3/D5 LPUART1 Not usable, Since D3 is blocked. // D0/D1 LPUART2 -> 1 diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h index 51e0e2dc47..659c33263e 100644 --- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h @@ -9,6 +9,8 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) #define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1050_flexspi_nor_config.h" +#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3) + // Define mapping logical UART # to hardware UART # // LPUART3 on D0/D1 -> 1 // LPUART2 on D7/D6 -> 2 diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h index 02372a3c54..4fcc697e26 100644 --- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h @@ -9,6 +9,8 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) #define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1060_flexspi_nor_config.h" +#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3) + // Define mapping logical UART # to hardware UART # // LPUART3 on D0/D1 -> 1 // LPUART2 on D7/D6 -> 2 diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h index e8492c9224..7549899512 100644 --- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h +++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h @@ -7,6 +7,8 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) #define BOARD_FLASH_CONFIG_HEADER_H "evkmimxrt1064_flexspi_nor_config.h" +#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3) + // Define mapping logical UART # to hardware UART # // LPUART3 on D0/D1 -> 1 // LPUART2 on D7/D6 -> 2 diff --git a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h index 6bbac0a976..316116b2b9 100644 --- a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h +++ b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h @@ -9,6 +9,8 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) #define BOARD_FLASH_CONFIG_HEADER_H "teensy40_flexspi_nor_config.h" +#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3) + // UART config: 7 UARTs at the pins for Teensy 4.0 #define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0]) #define MICROPY_HW_UART_INDEX { 0, 6, 4, 2, 3, 8, 1, 7 } diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h old mode 100755 new mode 100644 index 1e07cb29ca..4bbb41f309 --- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h +++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h @@ -9,6 +9,8 @@ #define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) #define BOARD_FLASH_CONFIG_HEADER_H "teensy41_flexspi_nor_config.h" +#define MICROPY_HW_NUM_PIN_IRQS (4 * 32 + 3) + // UART config: 8 UARTs at the pins for Teensy 4.1 #define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0]) #define MICROPY_HW_UART_INDEX { 0, 6, 4, 2, 3, 8, 1, 7, 5 } diff --git a/ports/mimxrt/machine_pin.c b/ports/mimxrt/machine_pin.c index ebe95059bf..dc26cdfc12 100644 --- a/ports/mimxrt/machine_pin.c +++ b/ports/mimxrt/machine_pin.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2020 Philipp Ebensberger + * Copyright (c) 2021 Robert Hammelrath * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,8 +31,8 @@ #include "py/runtime.h" #include "py/mphal.h" +#include "lib/utils/mpirq.h" #include "pin.h" -#include "mphalport.h" // Local functions STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); @@ -68,6 +69,95 @@ const mp_obj_type_t machine_pin_board_pins_obj_type = { .locals_dict = (mp_obj_t)&machine_pin_board_pins_locals_dict, }; +STATIC const mp_irq_methods_t machine_pin_irq_methods; + +static GPIO_Type *gpiobases[] = GPIO_BASE_PTRS; +STATIC const uint16_t GPIO_combined_low_irqs[] = GPIO_COMBINED_LOW_IRQS; +STATIC const uint16_t GPIO_combined_high_irqs[] = GPIO_COMBINED_HIGH_IRQS; +STATIC const uint16_t IRQ_mapping[] = {kGPIO_NoIntmode, kGPIO_IntRisingEdge, kGPIO_IntFallingEdge, kGPIO_IntRisingOrFallingEdge}; +#define GET_PIN_IRQ_INDEX(gpio_nr, pin) ((gpio_nr - 1) * 32 + pin) + +int GPIO_get_instance(GPIO_Type *gpio) { + int gpio_nr; + for (gpio_nr = 0; gpio_nr < ARRAY_SIZE(gpiobases); gpio_nr++) { + if (gpio == gpiobases[gpio_nr]) { + return gpio_nr; + } + } + return 0; +} + +void call_handler(GPIO_Type *gpio, int gpio_nr, int pin) { + uint32_t mask = 1 << pin; + uint32_t isr = gpio->ISR & gpio->IMR; + for (int i = 0; i < 16; i++, pin++, mask <<= 1) { + // Did the ISR fire? Consider only the bits that are enabled. + if (isr & mask) { + gpio->ISR = mask; // clear the ISR flag + int index = GET_PIN_IRQ_INDEX(gpio_nr, pin); + machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_objects[index]); + if (irq != NULL) { + irq->flags = irq->trigger; + mp_irq_handler(&irq->base); + } + } + } +} + +// 10 GPIO IRQ handlers, each covering 16 bits. + +void GPIO1_Combined_0_15_IRQHandler(void) { + call_handler(gpiobases[1], 1, 0); +} + +void GPIO1_Combined_16_31_IRQHandler(void) { + call_handler(gpiobases[1], 1, 16); +} + +void GPIO2_Combined_0_15_IRQHandler(void) { + call_handler(gpiobases[2], 2, 0); +} + +void GPIO2_Combined_16_31_IRQHandler(void) { + call_handler(gpiobases[2], 2, 16); +} + +void GPIO3_Combined_0_15_IRQHandler(void) { + call_handler(gpiobases[3], 3, 0); +} + +void GPIO3_Combined_16_31_IRQHandler(void) { + call_handler(gpiobases[3], 3, 16); +} + +void GPIO4_Combined_0_15_IRQHandler(void) { + call_handler(gpiobases[4], 4, 0); +} + +void GPIO4_Combined_16_31_IRQHandler(void) { + call_handler(gpiobases[4], 4, 16); +} + +void GPIO5_Combined_0_15_IRQHandler(void) { + call_handler(gpiobases[5], 5, 0); +} + +void GPIO5_Combined_16_31_IRQHandler(void) { + call_handler(gpiobases[5], 5, 16); +} + +// Deinit all pin IRQ handlers. +void machine_pin_irq_deinit(void) { + for (int i = 0; i < ARRAY_SIZE(MP_STATE_PORT(machine_pin_irq_objects)); ++i) { + machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_objects[i]); + if (irq != NULL) { + machine_pin_obj_t *self = MP_OBJ_TO_PTR(irq->base.parent); + GPIO_PortDisableInterrupts(self->gpio, 1U << self->pin); + MP_STATE_PORT(machine_pin_irq_objects[i]) = NULL; + } + } +} + // Simplified mode setting used by the extmod modules void machine_pin_set_mode(const machine_pin_obj_t *self, uint8_t mode) { gpio_pin_config_t pin_config = {kGPIO_DigitalInput, 1, kGPIO_NoIntmode}; @@ -234,6 +324,69 @@ STATIC mp_obj_t machine_pin_init(size_t n_args, const mp_obj_t *args, mp_map_t * } MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_init); +// 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 = 3} }, + { 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); + + // Get the IRQ object. + uint32_t gpio_nr = GPIO_get_instance(self->gpio); + uint32_t index = GET_PIN_IRQ_INDEX(gpio_nr, self->pin); + if (index >= ARRAY_SIZE(MP_STATE_PORT(machine_pin_irq_objects))) { + mp_raise_ValueError(MP_ERROR_TEXT("IRQ not supported on given Pin")); + } + machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_objects[index]); + + // Allocate the IRQ object if it doesn't already exist. + 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; + MP_STATE_PORT(machine_pin_irq_objects[index]) = irq; + } + + if (n_args > 1 || kw_args->used != 0) { + // Configure IRQ. + uint32_t irq_num = self->pin < 16 ? GPIO_combined_low_irqs[gpio_nr] : GPIO_combined_high_irqs[gpio_nr]; + + // Disable all IRQs from the affected source while data is updated. + DisableIRQ(irq_num); + GPIO_PortDisableInterrupts(self->gpio, 1U << self->pin); + + // Update IRQ data. + irq->base.handler = args[ARG_handler].u_obj; + irq->base.ishard = args[ARG_hard].u_bool; + irq->flags = 0; + if (args[ARG_trigger].u_int >= ARRAY_SIZE(IRQ_mapping)) { + mp_raise_ValueError(MP_ERROR_TEXT("IRQ mode not supported")); + } + irq->trigger = IRQ_mapping[args[ARG_trigger].u_int]; + + // Enable IRQ if a handler is given. + if (args[ARG_handler].u_obj != mp_const_none) { + // Set the pin mode + GPIO_PinSetInterruptConfig(self->gpio, self->pin, irq->trigger); + // Enable the specific Pin interrupt + GPIO_PortEnableInterrupts(self->gpio, 1U << self->pin); + } + // Enable LEVEL1 interrupt again + EnableIRQ(irq_num); + } + + return MP_OBJ_FROM_PTR(irq); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_irq_obj, 1, machine_pin_irq); + STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { // instance methods { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&machine_pin_off_obj) }, @@ -242,6 +395,7 @@ STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_high), MP_ROM_PTR(&machine_pin_on_obj) }, { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) }, { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_pin_irq_obj) }, // class attributes { MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&machine_pin_board_pins_obj_type) }, { MP_ROM_QSTR(MP_QSTR_cpu), MP_ROM_PTR(&machine_pin_cpu_pins_obj_type) }, @@ -265,6 +419,9 @@ STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_POWER_5), MP_ROM_INT(PIN_DRIVE_POWER_5) }, // R0/6 { MP_ROM_QSTR(MP_QSTR_POWER_6), MP_ROM_INT(PIN_DRIVE_POWER_6) }, // R0/7 + { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(2) }, + }; STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table); @@ -285,3 +442,37 @@ const mp_obj_type_t machine_pin_af_type = { .make_new = mp_pin_make_new, .locals_dict = (mp_obj_dict_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); + uint32_t gpio_nr = GPIO_get_instance(self->gpio); + machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_objects[GET_PIN_IRQ_INDEX(gpio_nr, self->pin)]); + uint32_t irq_num = self->pin < 16 ? GPIO_combined_low_irqs[gpio_nr] : GPIO_combined_high_irqs[gpio_nr]; + DisableIRQ(irq_num); + irq->flags = 0; + irq->trigger = new_trigger; + // Configure the interrupt. + GPIO_PinSetInterruptConfig(self->gpio, self->pin, irq->trigger); + // Enable LEVEL1 interrupt. + EnableIRQ(irq_num); + // Enable the specific pin interrupt. + GPIO_PortEnableInterrupts(self->gpio, 1U << self->pin); + 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); + uint32_t gpio_nr = GPIO_get_instance(self->gpio); + machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_objects[GET_PIN_IRQ_INDEX(gpio_nr, self->pin)]); + if (info_type == MP_IRQ_INFO_FLAGS) { + return irq->flags; + } else if (info_type == MP_IRQ_INFO_TRIGGERS) { + return irq->trigger; + } + return 0; +} + +STATIC const mp_irq_methods_t machine_pin_irq_methods = { + .trigger = machine_pin_irq_trigger, + .info = machine_pin_irq_info, +}; diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c index 74c8a7014b..bd1c3e8884 100644 --- a/ports/mimxrt/main.c +++ b/ports/mimxrt/main.c @@ -36,6 +36,7 @@ #include "ticks.h" #include "tusb.h" #include "led.h" +#include "modmachine.h" extern uint8_t _sstack, _estack, _gc_heap_start, _gc_heap_end; @@ -90,6 +91,7 @@ int main(void) { soft_reset_exit: mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n"); + machine_pin_irq_deinit(); gc_sweep_all(); mp_deinit(); } diff --git a/ports/mimxrt/modmachine.h b/ports/mimxrt/modmachine.h index 0b9e89cb23..5ac8655764 100644 --- a/ports/mimxrt/modmachine.h +++ b/ports/mimxrt/modmachine.h @@ -35,6 +35,7 @@ extern const mp_obj_type_t machine_rtc_type; extern const mp_obj_type_t machine_uart_type; void machine_adc_init(void); +void machine_pin_irq_deinit(void); void machine_timer_init_PIT(void); #endif // MICROPY_INCLUDED_MIMXRT_MODMACHINE_H diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h index 0af87264a5..49953bb57e 100644 --- a/ports/mimxrt/mpconfigport.h +++ b/ports/mimxrt/mpconfigport.h @@ -167,7 +167,8 @@ extern const struct _mp_obj_module_t mp_module_utime; #define MICROPY_PORT_ROOT_POINTERS \ const char *readline_hist[8]; \ - struct _machine_timer_obj_t *timer_table[MICROPY_HW_PIT_NUM_CHANNELS]; + struct _machine_timer_obj_t *timer_table[MICROPY_HW_PIT_NUM_CHANNELS]; \ + void *machine_pin_irq_objects[MICROPY_HW_NUM_PIN_IRQS]; \ #define MP_STATE_PORT MP_STATE_VM diff --git a/ports/mimxrt/pin.h b/ports/mimxrt/pin.h index 7a05d2d64d..ace4d18436 100644 --- a/ports/mimxrt/pin.h +++ b/ports/mimxrt/pin.h @@ -29,6 +29,7 @@ #include #include "py/obj.h" +#include "lib/utils/mpirq.h" #include "fsl_gpio.h" // ------------------------------------------------------------------------------------------------------------------ // @@ -118,6 +119,12 @@ typedef struct { const machine_pin_adc_obj_t *adc_list; // pointer to list with ADC options } machine_pin_obj_t; +typedef struct _machine_pin_irq_obj_t { + mp_irq_obj_t base; + uint32_t flags; + uint32_t trigger; +} machine_pin_irq_obj_t; + // ------------------------------------------------------------------------------------------------------------------ // extern const mp_obj_type_t machine_pin_type;