OSStatus platform_gpio_irq_disable( const platform_gpio_t* gpio ) { OSStatus err = kNoErr; ioport_port_mask_t mask = ioport_pin_to_mask ( gpio->pin ); ioport_port_t port = ioport_pin_to_port_id( gpio->pin ); volatile Pio* port_register = arch_ioport_port_to_base( port ); platform_mcu_powersave_disable(); require_action_quiet( gpio != NULL, exit, err = kParamErr); /* Disable interrupt on pin */ port_register->PIO_IDR = mask; /* Disable Cortex-M interrupt vector as well if no pin interrupt is enabled */ if ( port_register->PIO_IMR == 0 ) { NVIC_DisableIRQ( irq_vectors[port] ); } gpio_irq_data[port][mask].wakeup_pin = false; gpio_irq_data[port][mask].arg = 0; gpio_irq_data[port][mask].callback = NULL; exit: platform_mcu_powersave_enable(); return err; }
/** * \brief Set callback for given GPIO pin * * \param [in] pin The pin number * \param [in] callback callback function pointer * \param [in] irq_level interrupt level * * \retval true Set successfully * \retval false Wrong parameters or maximum number of interrupt * sources has been exceeding */ bool gpio_set_pin_callback(ioport_pin_t pin, gpio_pin_callback_t callback, uint8_t irq_level) { int8_t i; int8_t irq_line; if (gpio_nb_sources >= GPIO_MAX_INTERRUPT_SOURCES) { return false; } /* * Get IRQ line for the given pin. * * \note Grouping interrupt generators into groups of eight, four * different interrupt handlers can be installed for each GPIO port. */ for (i = 0; i < 4; i++) { if (ioport_pin_to_mask(pin) & (GPIO_INT_GROUP_MASK << (i * 8))) { break; } } irq_line = GPIO_0_IRQn + ioport_pin_to_port_id(pin) * 4 + i; gpio_int_sources[gpio_nb_sources].pin = pin; gpio_int_sources[gpio_nb_sources].callback = callback; NVIC_ClearPendingIRQ((IRQn_Type)irq_line); NVIC_SetPriority((IRQn_Type)irq_line, irq_level); NVIC_EnableIRQ((IRQn_Type)irq_line); gpio_nb_sources++; return true; }
/** * Common GPIO handler. */ static void gpio_common_handler(uint32_t port_id, uint32_t port_mask) { GpioPort *gpio_port = &(GPIO->GPIO_PORT[port_id]); uint32_t i; uint32_t int_flags; ioport_pin_t pin; int_flags = gpio_port->GPIO_IFR; for (i = 0; i < gpio_nb_sources; i++) { pin = gpio_int_sources[i].pin; if ((ioport_pin_to_port_id(pin) == port_id) && (ioport_pin_to_mask(pin) & int_flags)) { if (gpio_int_sources[i].callback != NULL) { gpio_int_sources[i].callback(); } else { Assert(false); /* Catch unexpected interrupt */ } } } gpio_port->GPIO_IFRC = (int_flags & port_mask); }
OSStatus platform_gpio_irq_enable( const platform_gpio_t* gpio, platform_gpio_irq_trigger_t trigger, platform_gpio_irq_callback_t handler, void* arg ) { ioport_port_mask_t mask = ioport_pin_to_mask( gpio->pin ); ioport_port_t port = ioport_pin_to_port_id( gpio->pin ); volatile Pio* port_register = arch_ioport_port_to_base( port ); uint8_t pin_number = (gpio->pin) & 0x1F; uint32_t temp; uint8_t samg5x_irq_trigger; OSStatus err = kNoErr; platform_mcu_powersave_disable(); require_action_quiet( gpio != NULL, exit, err = kParamErr); NVIC_DisableIRQ( irq_vectors[port] ); NVIC_ClearPendingIRQ( irq_vectors[port] ); gpio_irq_data[port][pin_number].wakeup_pin = gpio->is_wakeup_pin; gpio_irq_data[port][pin_number].arg = arg; gpio_irq_data[port][pin_number].callback = handler; switch ( trigger ) { case IRQ_TRIGGER_RISING_EDGE: samg5x_irq_trigger = IOPORT_SENSE_RISING; break; case IRQ_TRIGGER_FALLING_EDGE: samg5x_irq_trigger = IOPORT_SENSE_FALLING; break; case IRQ_TRIGGER_BOTH_EDGES: samg5x_irq_trigger = IOPORT_SENSE_BOTHEDGES; break; default: err = kParamErr; goto exit; } if( gpio->is_wakeup_pin == true ) { platform_powersave_enable_wakeup_pin( gpio ); } if ( samg5x_irq_trigger == IOPORT_SENSE_RISING || samg5x_irq_trigger == IOPORT_SENSE_BOTHEDGES ) { port_register->PIO_AIMER |= mask; port_register->PIO_ESR |= mask; port_register->PIO_REHLSR |= mask; } if ( samg5x_irq_trigger == IOPORT_SENSE_FALLING || samg5x_irq_trigger == IOPORT_SENSE_BOTHEDGES ) { port_register->PIO_AIMER |= mask; port_register->PIO_ESR |= mask; port_register->PIO_FELLSR |= mask; } /* Read ISR to clear residual interrupt status */ temp = port_register->PIO_ISR; UNUSED_PARAMETER( temp ); /* Enable interrupt source */ port_register->PIO_IER |= mask; NVIC_EnableIRQ( irq_vectors[port] ); exit: platform_mcu_powersave_enable(); return err; }