diff options
Diffstat (limited to 'ports')
-rw-r--r-- | ports/alif/irq.h | 1 | ||||
-rw-r--r-- | ports/alif/machine_pin.c | 197 | ||||
-rw-r--r-- | ports/alif/machine_spi.c | 60 | ||||
-rw-r--r-- | ports/alif/main.c | 2 | ||||
-rw-r--r-- | ports/alif/mphalport.h | 3 |
5 files changed, 249 insertions, 14 deletions
diff --git a/ports/alif/irq.h b/ports/alif/irq.h index 08b8ef8086..02df524a49 100644 --- a/ports/alif/irq.h +++ b/ports/alif/irq.h @@ -48,6 +48,7 @@ #define IRQ_PRI_USB NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 7, 0) #define IRQ_PRI_HWSEM NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 8, 0) #define IRQ_PRI_GPU NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 10, 0) +#define IRQ_PRI_GPIO NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 50, 0) #define IRQ_PRI_RTC NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 100, 0) #define IRQ_PRI_CYW43 NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 126, 0) #define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 127, 0) diff --git a/ports/alif/machine_pin.c b/ports/alif/machine_pin.c index 02c5e482ad..b8773f103f 100644 --- a/ports/alif/machine_pin.c +++ b/ports/alif/machine_pin.c @@ -30,8 +30,76 @@ #include "extmod/virtpin.h" #include "shared/runtime/mpirq.h" +#ifndef MACHINE_PIN_NUM_VECTORS +#define MACHINE_PIN_NUM_PORT_IO (8) +#define MACHINE_PIN_NUM_VECTORS (16 * MACHINE_PIN_NUM_PORT_IO) +#endif + +typedef struct _machine_pin_irq_obj_t { + mp_irq_obj_t base; + uint32_t flags; + uint32_t trigger; + IRQn_Type irq_num; + bool reserved; // for use by other drivers +} machine_pin_irq_obj_t; + +#define MACHINE_PIN_IRQ_INDEX(port, pin) \ + ((port) * MACHINE_PIN_NUM_PORT_IO + (pin)) + +#define MACHINE_PIN_IRQ_OBJECT(port, pin) \ + (MP_STATE_PORT(machine_pin_irq_obj[MACHINE_PIN_IRQ_INDEX((port), (pin))])) + +// Defines a single GPIO IRQ handler +#define DEFINE_GPIO_IRQ_HANDLER(pname, port, pin) \ + void pname##_IRQ##pin##Handler(void) { \ + machine_pin_irq_obj_t *irq = MACHINE_PIN_IRQ_OBJECT(port, pin); \ + machine_pin_obj_t *self = MP_OBJ_TO_PTR(irq->base.parent); \ + gpio_interrupt_eoi(self->gpio, pin); \ + irq->flags = irq->trigger; \ + mp_irq_handler(&irq->base); \ + } + +// Defines all 8 pin IRQ handlers for a port +#define DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(gpio, port) \ + DEFINE_GPIO_IRQ_HANDLER(gpio, port, 0) \ + DEFINE_GPIO_IRQ_HANDLER(gpio, port, 1) \ + DEFINE_GPIO_IRQ_HANDLER(gpio, port, 2) \ + DEFINE_GPIO_IRQ_HANDLER(gpio, port, 3) \ + DEFINE_GPIO_IRQ_HANDLER(gpio, port, 4) \ + DEFINE_GPIO_IRQ_HANDLER(gpio, port, 5) \ + DEFINE_GPIO_IRQ_HANDLER(gpio, port, 6) \ + DEFINE_GPIO_IRQ_HANDLER(gpio, port, 7) + +// Generate handlers for GPIO ports 0 to 14 + LPGPIO +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO0, 0) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO1, 1) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO2, 2) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO3, 3) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO4, 4) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO5, 5) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO6, 6) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO7, 7) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO8, 8) + +DEFINE_GPIO_IRQ_HANDLER(GPIO9, 9, 0) +DEFINE_GPIO_IRQ_HANDLER(GPIO9, 9, 1) +DEFINE_GPIO_IRQ_HANDLER(GPIO9, 9, 2) +DEFINE_GPIO_IRQ_HANDLER(GPIO9, 9, 3) +DEFINE_GPIO_IRQ_HANDLER(GPIO9, 9, 4) +DEFINE_GPIO_IRQ_HANDLER(GPIO9, 9, 5) +// DEFINE_GPIO_IRQ_HANDLER(GPIO9, 9, 6) // Reserved for WiFi +DEFINE_GPIO_IRQ_HANDLER(GPIO9, 9, 7) + +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO10, 10) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO11, 11) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO12, 12) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO13, 13) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO14, 14) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(LPGPIO, 15) + extern const mp_obj_dict_t machine_pin_cpu_pins_locals_dict; extern const mp_obj_dict_t machine_pin_board_pins_locals_dict; +static const mp_irq_methods_t machine_pin_irq_methods; static const machine_pin_obj_t *machine_pin_find_named(const mp_obj_dict_t *named_pins, mp_obj_t name) { const mp_map_t *named_map = &named_pins->map; @@ -171,6 +239,7 @@ mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); machine_pin_obj_init_helper(self, n_args - 1, args + 1, &kw_args); } + return MP_OBJ_FROM_PTR(self); } @@ -225,6 +294,129 @@ static mp_obj_t machine_pin_toggle(mp_obj_t self_in) { } static MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_toggle_obj, machine_pin_toggle); +static mp_uint_t machine_pin_irq_trigger(mp_obj_t self_in, mp_uint_t trigger) { + machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + machine_pin_irq_obj_t *irq = MACHINE_PIN_IRQ_OBJECT(self->port, self->pin); + + irq->flags = 0; + irq->trigger = trigger; + + // Disable IRQs. + gpio_disable_interrupt(self->gpio, self->pin); + gpio_mask_interrupt(self->gpio, self->pin); + + NVIC_ClearPendingIRQ(irq->irq_num); + NVIC_DisableIRQ(irq->irq_num); + + // Return if the trigger is disabled. + if (trigger == 0) { + return 0; + } + + // Clear and enable GPIO IRQ. + gpio_enable_interrupt(self->gpio, self->pin); + gpio_unmask_interrupt(self->gpio, self->pin); + + // Clear GPIO config. + self->gpio->GPIO_INT_BOTHEDGE &= ~(1 << self->pin); + self->gpio->GPIO_INT_POLARITY &= ~(1 << self->pin); + self->gpio->GPIO_INTTYPE_LEVEL &= ~(1 << self->pin); + + // Configure GPIO IRQ trigger + if (trigger == MP_HAL_PIN_TRIGGER_FALL) { + gpio_interrupt_set_edge_trigger(self->gpio, self->pin); + gpio_interrupt_set_polarity_low(self->gpio, self->pin); + } else if (trigger == MP_HAL_PIN_TRIGGER_RISE) { + gpio_interrupt_set_edge_trigger(self->gpio, self->pin); + gpio_interrupt_set_polarity_high(self->gpio, self->pin); + } else if (trigger == (MP_HAL_PIN_TRIGGER_FALL | MP_HAL_PIN_TRIGGER_RISE)) { + gpio_interrupt_set_both_edge_trigger(self->gpio, self->pin); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("Invalid IRQ trigger")); + } + + // Clear GPIO IRQ (must be done after configuring trigger) + gpio_interrupt_eoi(self->gpio, self->pin); + + // Clear and enable NVIC GPIO IRQ. + NVIC_ClearPendingIRQ(irq->irq_num); + NVIC_SetPriority(irq->irq_num, IRQ_PRI_GPIO); + NVIC_EnableIRQ(irq->irq_num); + + 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); + machine_pin_irq_obj_t *irq = MACHINE_PIN_IRQ_OBJECT(self->port, 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, +}; + +// 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 = MP_HAL_PIN_TRIGGER_FALL | MP_HAL_PIN_TRIGGER_RISE} }, + { 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); + + machine_pin_irq_obj_t *irq = MACHINE_PIN_IRQ_OBJECT(self->port, self->pin); + + // Allocate a new IRQ object if it doesn't exist. + if (irq == NULL) { + irq = m_new_obj(machine_pin_irq_obj_t); + uint32_t idx = MACHINE_PIN_IRQ_INDEX(self->port, self->pin); + + 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->reserved = false; + irq->irq_num = (self->port < 15) ? (GPIO0_IRQ0_IRQn + idx) : (LPGPIO_IRQ0_IRQn + self->pin); + MP_STATE_PORT(machine_pin_irq_obj[idx]) = irq; + } + + if (n_args > 1 || kw_args->used != 0) { + if (irq->reserved) { + mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Pin IRQ is reserved")); + } + irq->base.handler = args[ARG_handler].u_obj; + irq->base.ishard = args[ARG_hard].u_bool; + machine_pin_irq_trigger(self, args[ARG_trigger].u_int); + } + + return MP_OBJ_FROM_PTR(irq); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_irq_obj, 1, machine_pin_irq); + +void machine_pin_irq_deinit(void) { + for (size_t i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(machine_pin_irq_obj)); i++) { + machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_obj[i]); + if (irq != NULL) { + machine_pin_obj_t *self = MP_OBJ_TO_PTR(irq->base.parent); + machine_pin_irq_trigger(self, 0); + MP_STATE_PORT(machine_pin_irq_obj[i]) = NULL; + } + } +} + static MP_DEFINE_CONST_OBJ_TYPE( pin_cpu_pins_obj_type, MP_QSTR_cpu, @@ -248,6 +440,7 @@ static const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&machine_pin_low_obj) }, { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&machine_pin_high_obj) }, { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&machine_pin_toggle_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(&pin_board_pins_obj_type) }, @@ -259,6 +452,8 @@ static const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(MP_HAL_PIN_MODE_OPEN_DRAIN) }, { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(MP_HAL_PIN_PULL_UP) }, { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(MP_HAL_PIN_PULL_DOWN) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(MP_HAL_PIN_TRIGGER_FALL) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(MP_HAL_PIN_TRIGGER_RISE) }, }; static MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table); @@ -296,3 +491,5 @@ MP_DEFINE_CONST_OBJ_TYPE( mp_hal_pin_obj_t mp_hal_get_pin_obj(mp_obj_t obj) { return machine_pin_find(obj); } + +MP_REGISTER_ROOT_POINTER(void *machine_pin_irq_obj[MACHINE_PIN_NUM_VECTORS]); diff --git a/ports/alif/machine_spi.c b/ports/alif/machine_spi.c index abb60bc4e8..b2c14745cf 100644 --- a/ports/alif/machine_spi.c +++ b/ports/alif/machine_spi.c @@ -39,6 +39,7 @@ typedef struct _machine_spi_obj_t { uint8_t id; SPI_Type *inst; bool is_lp; + uint32_t bits; } machine_spi_obj_t; static machine_spi_obj_t machine_spi_obj[] = { @@ -246,6 +247,9 @@ mp_obj_t machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n // Get static peripheral object. machine_spi_obj_t *self = &machine_spi_obj[spi_id]; + // Set args + self->bits = args[ARG_bits].u_int; + // here we would check the sck/mosi/miso pins and configure them, but it's not implemented if (args[ARG_sck].u_obj != MP_OBJ_NULL || args[ARG_mosi].u_obj != MP_OBJ_NULL || @@ -294,22 +298,50 @@ static void machine_spi_deinit(mp_obj_base_t *self_in) { } } +static void machine_spi_poll_flag(SPI_Type *spi, uint32_t flag, uint32_t timeout) { + mp_uint_t tick_start = mp_hal_ticks_ms(); + while (!(spi->SPI_SR & flag)) { + if (mp_hal_ticks_ms() - tick_start >= timeout) { + mp_raise_OSError(MP_ETIMEDOUT); + } + mp_event_handle_nowait(); + } +} + static void machine_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { machine_spi_obj_t *self = (machine_spi_obj_t *)self_in; - spi_transfer_t spi_xfer = { - .tx_buff = src, - .tx_total_cnt = len, - .rx_buff = dest, - .rx_total_cnt = len, - .tx_default_val = 0xFF, - .tx_default_enable = true, - .mode = SPI_TMOD_TX_AND_RX, - }; - // TODO redo transfer_blocking to timeout and poll events. - if (!self->is_lp) { - spi_transfer_blocking(self->inst, &spi_xfer); - } else { - lpspi_transfer_blocking(self->inst, &spi_xfer); + volatile uint32_t *dr = self->inst->SPI_DR; + + spi_set_tmod(self->inst, SPI_TMOD_TX_AND_RX); + + for (size_t i = 0; i < len; i++) { + // Wait for space in the TX FIFO + machine_spi_poll_flag(self->inst, SPI_SR_TFNF, 100); + + // Send data + if (src == NULL) { + *dr = 0xFFFFFFFFU; + } else if (self->bits > 16) { + *dr = ((uint32_t *)src)[i]; + } else if (self->bits > 8) { + *dr = ((uint16_t *)src)[i]; + } else { + *dr = ((uint8_t *)src)[i]; + } + + // Wait for data in the RX FIFO + machine_spi_poll_flag(self->inst, SPI_SR_RFNE, 100); + + // Recv data + if (dest == NULL) { + (void)*dr; + } else if (self->bits > 16) { + ((uint32_t *)dest)[i] = *dr; + } else if (self->bits > 8) { + ((uint16_t *)dest)[i] = *dr; + } else { + ((uint8_t *)dest)[i] = *dr; + } } } diff --git a/ports/alif/main.c b/ports/alif/main.c index 4783611357..ab5e85d5b9 100644 --- a/ports/alif/main.c +++ b/ports/alif/main.c @@ -55,6 +55,7 @@ extern uint8_t __StackTop, __StackLimit; extern uint8_t __GcHeapStart, __GcHeapEnd; +extern void machine_pin_irq_deinit(void); MP_NORETURN void panic(const char *msg) { mp_hal_stdout_tx_strn("\nFATAL ERROR:\n", 14); @@ -164,6 +165,7 @@ int main(void) { mp_bluetooth_deinit(); #endif soft_timer_deinit(); + machine_pin_irq_deinit(); gc_sweep_all(); mp_deinit(); } diff --git a/ports/alif/mphalport.h b/ports/alif/mphalport.h index 4f81439b54..f03dc7c1c1 100644 --- a/ports/alif/mphalport.h +++ b/ports/alif/mphalport.h @@ -90,6 +90,9 @@ extern ringbuf_t stdin_ringbuf; #define MP_HAL_PIN_SPEED_LOW (0) #define MP_HAL_PIN_SPEED_HIGH (PADCTRL_SLEW_RATE_FAST) +#define MP_HAL_PIN_TRIGGER_FALL (1) +#define MP_HAL_PIN_TRIGGER_RISE (2) + #define mp_hal_pin_obj_t const machine_pin_obj_t * #define MP_HAL_PIN_ALT(function, unit) (MP_HAL_PIN_ALT_MAKE((MP_HAL_PIN_ALT_##function), (unit))) |