/***************************************************************************//** * @file * @brief General Purpose IO (GPIO) driver API ******************************************************************************* * # License * Copyright 2024 Silicon Laboratories Inc. www.silabs.com ******************************************************************************* * * SPDX-License-Identifier: Zlib * * The licensor of this software is Silicon Laboratories Inc. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * ******************************************************************************/ #include #include "sl_core.h" #include "sl_common.h" #include "sl_interrupt_manager.h" #include "sl_clock_manager.h" #include "sl_hal_gpio.h" #include "sl_gpio.h" /******************************************************************************* ******************************* DEFINES *********************************** ******************************************************************************/ /// Define for supporting gpiointerrupt porting #define SL_GPIO_PORT_INTERRUPT (0xFF) /// Pin direction validation. #define SL_GPIO_DIRECTION_IS_VALID(direction) (direction <= SL_GPIO_PIN_DIRECTION_OUT) /******************************************************************************* ******************************* STRUCTS *********************************** ******************************************************************************/ typedef struct { // Pin interrupt number in range 0 to 15. uint32_t int_no; // Pointer to callback function. void *callback; // Pointer to callback context. void *context; } sl_gpio_callback_desc_t; typedef struct { // An array of user callbacks for external interrupts. // We have external interrupts configured from 0 to 15 bits. sl_gpio_callback_desc_t callback_ext[SL_HAL_GPIO_INTERRUPT_MAX]; // An array of user callbacks for EM4 interrupts. // We have EM4 interrupts configured from 16 to 31 bits. sl_gpio_callback_desc_t callback_em4[SL_HAL_GPIO_INTERRUPT_MAX]; } sl_gpio_callbacks_t; /******************************************************************************* ******************************** GLOBALS ********************************** ******************************************************************************/ // Variable to manage and organize the callback functions for External and EM4 interrupts. static sl_gpio_callbacks_t gpio_interrupts = { 0 }; /******************************************************************************* ****************************** LOCAL FUCTIONS ***************************** ******************************************************************************/ static void sl_gpio_dispatch_interrupt(uint32_t iflags); /***************************************************************************//** * Driver GPIO Initialization. ******************************************************************************/ sl_status_t sl_gpio_init() { sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_GPIO); if (sl_interrupt_manager_is_irq_disabled(GPIO_ODD_IRQn)) { sl_interrupt_manager_clear_irq_pending(GPIO_ODD_IRQn); sl_interrupt_manager_enable_irq(GPIO_ODD_IRQn); } if (sl_interrupt_manager_is_irq_disabled(GPIO_EVEN_IRQn)) { sl_interrupt_manager_clear_irq_pending(GPIO_EVEN_IRQn); sl_interrupt_manager_enable_irq(GPIO_EVEN_IRQn); } return SL_STATUS_OK; } /***************************************************************************//** * Sets the pin direction for GPIO pin. ******************************************************************************/ sl_status_t sl_gpio_set_pin_direction(const sl_gpio_t *gpio, sl_gpio_pin_direction_t pin_direction) { CORE_DECLARE_IRQ_STATE; if (gpio == NULL) { EFM_ASSERT(false); return SL_STATUS_NULL_POINTER; } if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin) || !SL_GPIO_DIRECTION_IS_VALID(pin_direction)) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } if (sl_hal_gpio_get_lock_status() != 0) { EFM_ASSERT(false); return SL_STATUS_INVALID_STATE; } CORE_ENTER_ATOMIC(); if (pin_direction == SL_GPIO_PIN_DIRECTION_OUT) { sl_hal_gpio_set_pin_mode(gpio, SL_GPIO_MODE_PUSH_PULL, 1); } else if (pin_direction == SL_GPIO_PIN_DIRECTION_IN) { sl_hal_gpio_set_pin_mode(gpio, SL_GPIO_MODE_INPUT, 0); } CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Sets the mode for GPIO pin and pin direction. ******************************************************************************/ sl_status_t sl_gpio_set_pin_mode(const sl_gpio_t *gpio, sl_gpio_mode_t mode, bool output_value) { CORE_DECLARE_IRQ_STATE; if (gpio == NULL) { EFM_ASSERT(false); return SL_STATUS_NULL_POINTER; } if (!SL_HAL_GPIO_MODE_IS_VALID(mode) || !SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } if (sl_hal_gpio_get_lock_status() != 0) { EFM_ASSERT(false); return SL_STATUS_INVALID_STATE; } CORE_ENTER_ATOMIC(); sl_hal_gpio_set_pin_mode(gpio, mode, output_value); CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Gets the current configuration selected pin on selected port. ******************************************************************************/ sl_status_t sl_gpio_get_pin_config(const sl_gpio_t *gpio, sl_gpio_pin_config_t *pin_config) { CORE_DECLARE_IRQ_STATE; if (gpio == NULL || pin_config == NULL) { EFM_ASSERT(false); return SL_STATUS_NULL_POINTER; } if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } CORE_ENTER_ATOMIC(); pin_config->mode = sl_hal_gpio_get_pin_mode(gpio); switch (pin_config->mode) { case SL_GPIO_MODE_INPUT: case SL_GPIO_MODE_INPUT_PULL: case SL_GPIO_MODE_INPUT_PULL_FILTER: pin_config->direction = SL_GPIO_PIN_DIRECTION_IN; break; case SL_GPIO_MODE_DISABLED: case SL_GPIO_MODE_PUSH_PULL: case SL_GPIO_MODE_PUSH_PULL_ALTERNATE: case SL_GPIO_MODE_WIRED_OR: case SL_GPIO_MODE_WIRED_OR_PULL_DOWN: case SL_GPIO_MODE_WIRED_AND: case SL_GPIO_MODE_WIRED_AND_FILTER: case SL_GPIO_MODE_WIRED_AND_PULLUP: case SL_GPIO_MODE_WIRED_AND_PULLUP_FILTER: case SL_GPIO_MODE_WIRED_AND_ALTERNATE: case SL_GPIO_MODE_WIRED_AND_ALTERNATE_FILTER: case SL_GPIO_MODE_WIRED_AND_ALTERNATE_PULLUP: case SL_GPIO_MODE_WIRED_AND_ALTERNATE_PULLUP_FILTER: pin_config->direction = SL_GPIO_PIN_DIRECTION_OUT; break; default: CORE_EXIT_ATOMIC(); EFM_ASSERT(false); return SL_STATUS_INVALID_MODE; } CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Sets the DOUT of selected pin on selected port. ******************************************************************************/ sl_status_t sl_gpio_set_pin(const sl_gpio_t *gpio) { CORE_DECLARE_IRQ_STATE; if (gpio == NULL) { EFM_ASSERT(false); return SL_STATUS_NULL_POINTER; } if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } CORE_ENTER_ATOMIC(); sl_hal_gpio_set_pin(gpio); CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Clears the DOUT of selected pin on selected port. ******************************************************************************/ sl_status_t sl_gpio_clear_pin(const sl_gpio_t *gpio) { CORE_DECLARE_IRQ_STATE; if (gpio == NULL) { EFM_ASSERT(false); return SL_STATUS_NULL_POINTER; } if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } CORE_ENTER_ATOMIC(); sl_hal_gpio_clear_pin(gpio); CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Toggles the DOUT of selected pin on selected port. ******************************************************************************/ sl_status_t sl_gpio_toggle_pin(const sl_gpio_t *gpio) { CORE_DECLARE_IRQ_STATE; if (gpio == NULL) { EFM_ASSERT(false); return SL_STATUS_NULL_POINTER; } if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } CORE_ENTER_ATOMIC(); sl_hal_gpio_toggle_pin(gpio); CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Gets the output state of selected pin on selected port. ******************************************************************************/ sl_status_t sl_gpio_get_pin_output(const sl_gpio_t *gpio, bool *pin_value) { CORE_DECLARE_IRQ_STATE; if (gpio == NULL || pin_value == NULL) { EFM_ASSERT(false); return SL_STATUS_NULL_POINTER; } if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } CORE_ENTER_ATOMIC(); *pin_value = sl_hal_gpio_get_pin_output(gpio); CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Gets the input state of selected pin on selected port. ******************************************************************************/ sl_status_t sl_gpio_get_pin_input(const sl_gpio_t *gpio, bool *pin_value) { CORE_DECLARE_IRQ_STATE; if (gpio == NULL || pin_value == NULL) { EFM_ASSERT(false); return SL_STATUS_NULL_POINTER; } if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin)) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } CORE_ENTER_ATOMIC(); *pin_value = sl_hal_gpio_get_pin_input(gpio); CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Sets the selected pin(s) on selected port. ******************************************************************************/ sl_status_t sl_gpio_set_port(sl_gpio_port_t port, uint32_t pins) { CORE_DECLARE_IRQ_STATE; if (!SL_HAL_GPIO_PORT_IS_VALID(port)) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } CORE_ENTER_ATOMIC(); sl_hal_gpio_set_port(port, pins); CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Clears the selected pin on selected port. ******************************************************************************/ sl_status_t sl_gpio_clear_port(sl_gpio_port_t port, uint32_t pins) { CORE_DECLARE_IRQ_STATE; if (!SL_HAL_GPIO_PORT_IS_VALID(port)) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } CORE_ENTER_ATOMIC(); sl_hal_gpio_clear_port(port, pins); CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Gets the output state of pins of selected port. ******************************************************************************/ sl_status_t sl_gpio_get_port_output(sl_gpio_port_t port, uint32_t *port_value) { CORE_DECLARE_IRQ_STATE; if (!SL_HAL_GPIO_PORT_IS_VALID(port)) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } if (port_value == NULL) { EFM_ASSERT(false); return SL_STATUS_NULL_POINTER; } CORE_ENTER_ATOMIC(); *port_value = sl_hal_gpio_get_port_output(port); CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Gets the input state of pins of selected port. ******************************************************************************/ sl_status_t sl_gpio_get_port_input(sl_gpio_port_t port, uint32_t *port_value) { CORE_DECLARE_IRQ_STATE; if (!SL_HAL_GPIO_PORT_IS_VALID(port)) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } if (port_value == NULL) { EFM_ASSERT(false); return SL_STATUS_NULL_POINTER; } CORE_ENTER_ATOMIC(); *port_value = sl_hal_gpio_get_port_input(port); CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Configuring the GPIO external pin interrupt. * This API can be used to configure interrupt and to register the callback. ******************************************************************************/ sl_status_t sl_gpio_configure_external_interrupt(const sl_gpio_t *gpio, int32_t *int_no, sl_gpio_interrupt_flag_t flags, sl_gpio_irq_callback_t gpio_callback, void *context) { uint32_t enabled_interrupts; CORE_DECLARE_IRQ_STATE; if (gpio == NULL || int_no == NULL) { EFM_ASSERT(false); return SL_STATUS_NULL_POINTER; } if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin) && (gpio->port != SL_GPIO_PORT_INTERRUPT)) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } if (!SL_GPIO_FLAG_IS_VALID(flags)) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } CORE_ENTER_ATOMIC(); if (gpio->port != SL_GPIO_PORT_INTERRUPT) { *int_no = sl_hal_gpio_configure_external_interrupt(gpio, *int_no, flags); } if (*int_no == SL_GPIO_INTERRUPT_UNAVAILABLE && gpio->port == SL_GPIO_PORT_INTERRUPT) { enabled_interrupts = sl_hal_gpio_get_enabled_interrupts(); *int_no = sl_hal_gpio_get_external_interrupt_number(gpio->pin, enabled_interrupts); } if (*int_no != SL_GPIO_INTERRUPT_UNAVAILABLE) { // Callback registration. gpio_interrupts.callback_ext[*int_no].callback = (void *)gpio_callback; gpio_interrupts.callback_ext[*int_no].context = context; if (gpio->port != SL_GPIO_PORT_INTERRUPT) { sl_hal_gpio_enable_interrupts(1 << *int_no); } } else { CORE_EXIT_ATOMIC(); return SL_STATUS_NOT_FOUND; } CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Deconfigures the GPIO external pin interrupt. * This API can be used to deconfigure the interrupt and to unregister the callback. ******************************************************************************/ sl_status_t sl_gpio_deconfigure_external_interrupt(int32_t int_no) { CORE_DECLARE_IRQ_STATE; if (!((int_no != SL_GPIO_INTERRUPT_UNAVAILABLE) && (int_no <= SL_HAL_GPIO_INTERRUPT_MAX) && (int_no >= 0))) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } CORE_ENTER_ATOMIC(); // Clear pending interrupt. sl_hal_gpio_clear_interrupts(1 << int_no); sl_hal_gpio_disable_interrupts(1 << int_no); // Callback deregistration. gpio_interrupts.callback_ext[int_no].callback = NULL; gpio_interrupts.callback_ext[int_no].context = NULL; CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Enables one or more GPIO interrupts. ******************************************************************************/ sl_status_t sl_gpio_enable_interrupts(uint32_t flags) { CORE_DECLARE_IRQ_STATE; CORE_ENTER_ATOMIC(); sl_hal_gpio_enable_interrupts(flags); CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Disables one or more GPIO interrupts. ******************************************************************************/ sl_status_t sl_gpio_disable_interrupts(uint32_t flags) { CORE_DECLARE_IRQ_STATE; CORE_ENTER_ATOMIC(); sl_hal_gpio_disable_interrupts(flags); CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Configures the EM4WU pin as external level interrupts for waking up from EM mode. * Registering/unregistering the callbacks and Configuring the EM4 interrupts to enable/disable ******************************************************************************/ sl_status_t sl_gpio_configure_wakeup_em4_interrupt(const sl_gpio_t *gpio, int32_t *em4_int_no, bool polarity, sl_gpio_irq_callback_t gpio_callback, void *context) { CORE_DECLARE_IRQ_STATE; if (gpio == NULL || em4_int_no == NULL) { EFM_ASSERT(false); return SL_STATUS_NULL_POINTER; } if (!SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin) && (gpio->port != SL_GPIO_PORT_INTERRUPT)) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } CORE_ENTER_ATOMIC(); if (gpio->port != SL_GPIO_PORT_INTERRUPT) { *em4_int_no = sl_hal_gpio_configure_wakeup_em4_external_interrupt(gpio, *em4_int_no, polarity); } if (*em4_int_no != SL_GPIO_INTERRUPT_UNAVAILABLE) { // Callback registration. gpio_interrupts.callback_em4[*em4_int_no].callback = (void *)gpio_callback; gpio_interrupts.callback_em4[*em4_int_no].context = context; if (gpio->port != SL_GPIO_PORT_INTERRUPT) { sl_hal_gpio_enable_interrupts(1 << (*em4_int_no + SL_HAL_GPIO_EM4WUEN_SHIFT)); } } else { CORE_EXIT_ATOMIC(); return SL_STATUS_NOT_FOUND; } CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Deconfigures the EM4 GPIO pin interrupt. * Unregisters a callback, disable/clear interrupt and clear em4 wakeup source ******************************************************************************/ sl_status_t sl_gpio_deconfigure_wakeup_em4_interrupt(int32_t em4_int_no) { CORE_DECLARE_IRQ_STATE; if (!((em4_int_no != SL_GPIO_INTERRUPT_UNAVAILABLE) && (em4_int_no <= SL_HAL_GPIO_INTERRUPT_MAX) && (em4_int_no >= 0))) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } CORE_ENTER_ATOMIC(); // Clear any pending interrupt. sl_hal_gpio_clear_interrupts(1 << (em4_int_no + SL_HAL_GPIO_EM4WUEN_SHIFT)); sl_hal_gpio_disable_pin_em4_wakeup(1 << (em4_int_no + SL_HAL_GPIO_EM4WUEN_SHIFT)); sl_hal_gpio_disable_interrupts(1 << (em4_int_no + SL_HAL_GPIO_EM4WUEN_SHIFT)); /* Callback deregistration */ gpio_interrupts.callback_em4[em4_int_no].callback = NULL; gpio_interrupts.callback_em4[em4_int_no].context = NULL; CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Sets GPIO EM4 Wake up interrupt to Enable and EM4 Wake up interrupt polarity ******************************************************************************/ sl_status_t sl_gpio_enable_pin_em4_wakeup(uint32_t em4_int_mask, uint32_t em4_polarity_mask) { uint32_t int_mask = 0; uint32_t polarity_mask = 0; CORE_DECLARE_IRQ_STATE; CORE_ENTER_ATOMIC(); // Enable EM4WU function and set polarity. int_mask |= (em4_int_mask << _GPIO_EM4WUEN_EM4WUEN_SHIFT); polarity_mask |= (em4_polarity_mask << _GPIO_EM4WUEN_EM4WUEN_SHIFT); sl_hal_gpio_enable_pin_em4_wakeup(int_mask, polarity_mask); CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Clears GPIO EM4 Wake up enable ******************************************************************************/ sl_status_t sl_gpio_disable_pin_em4_wakeup(uint32_t em4_int_mask) { uint32_t int_mask = 0; CORE_DECLARE_IRQ_STATE; CORE_ENTER_ATOMIC(); // Disable EM4WU function. int_mask |= (em4_int_mask << _GPIO_EM4WUEN_EM4WUEN_SHIFT); sl_hal_gpio_disable_pin_em4_wakeup(int_mask); CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Enable GPIO pin retention of output enable, output value, pull direction, pull enable in EM4 ******************************************************************************/ sl_status_t sl_gpio_set_pin_em4_retention(bool enable) { CORE_DECLARE_IRQ_STATE; CORE_ENTER_ATOMIC(); sl_hal_gpio_set_pin_em4_retention(enable); CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Sets slewrate for selected port. ******************************************************************************/ sl_status_t sl_gpio_set_slew_rate(sl_gpio_port_t port, uint8_t slewrate) { CORE_DECLARE_IRQ_STATE; if (!SL_HAL_GPIO_PORT_IS_VALID(port)) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } CORE_ENTER_ATOMIC(); sl_hal_gpio_set_slew_rate(port, slewrate); CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Gets slewrate for selected port. ******************************************************************************/ sl_status_t sl_gpio_get_slew_rate(sl_gpio_port_t port, uint8_t *slewrate) { CORE_DECLARE_IRQ_STATE; if (!SL_HAL_GPIO_PORT_IS_VALID(port)) { EFM_ASSERT(false); return SL_STATUS_INVALID_PARAMETER; } if (slewrate == NULL) { EFM_ASSERT(false); return SL_STATUS_NULL_POINTER; } CORE_ENTER_ATOMIC(); *slewrate = sl_hal_gpio_get_slew_rate(port); CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Locks the GPIO Configuration ******************************************************************************/ sl_status_t sl_gpio_lock(void) { sl_hal_gpio_lock(); return SL_STATUS_OK; } /***************************************************************************//** * Unlocks the GPIO Configuration ******************************************************************************/ sl_status_t sl_gpio_unlock(void) { sl_hal_gpio_unlock(); return SL_STATUS_OK; } /***************************************************************************//** * Gets the GPIO State ******************************************************************************/ sl_status_t sl_gpio_is_locked(bool *state) { uint32_t status; CORE_DECLARE_IRQ_STATE; if (state == NULL) { EFM_ASSERT(false); return SL_STATUS_NULL_POINTER; } CORE_ENTER_ATOMIC(); status = sl_hal_gpio_get_lock_status(); if (status) { // true - GPIO configuration registers are locked. *state = true; } else { // false - GPIO configuration registers are unlocked. *state = false; } CORE_EXIT_ATOMIC(); return SL_STATUS_OK; } /***************************************************************************//** * Function calls users callback for registered pin interrupts. * * @details This function is called when GPIO interrupts are handled by the IRQHandlers. * Function gets even or odd interrupt flags and calls user callback * registered for that pin. Function iterates on flags starting from MSB. * * @param iflags Interrupt flags which shall be handled by the dispatcher. ******************************************************************************/ static void sl_gpio_dispatch_interrupt(uint32_t iflags) { uint32_t irq_idx; sl_gpio_callback_desc_t *callback; sl_gpio_irq_callback_t func; // Check for flags set in IF register. while (iflags != 0) { irq_idx = SL_CTZ(iflags); iflags &= ~(1UL << irq_idx); if (irq_idx <= SL_HAL_GPIO_INTERRUPT_MAX) { callback = &gpio_interrupts.callback_ext[irq_idx]; } else { callback = &gpio_interrupts.callback_em4[irq_idx - SL_HAL_GPIO_EM4WUEN_SHIFT]; irq_idx = irq_idx - SL_HAL_GPIO_EM4WUEN_SHIFT; } // Call user callback. if (callback->callback) { func = (sl_gpio_irq_callback_t)(callback->callback); func((uint8_t)irq_idx, callback->context); } } } /***************************************************************************//** * GPIO EVEN interrupt handler. Interrupt handler clears all IF even flags and * call the dispatcher passing the flags which triggered the interrupt. ******************************************************************************/ void GPIO_EVEN_IRQHandler(void) { uint32_t even_flags; // Gets all enabled and pending even interrupts. even_flags = sl_hal_gpio_get_enabled_pending_interrupts() & SL_HAL_GPIO_INT_IF_EVEN_MASK; // Clears only even interrupts. sl_hal_gpio_clear_interrupts(even_flags); sl_gpio_dispatch_interrupt(even_flags); } /***************************************************************************//** * @brief * GPIO ODD interrupt handler. Interrupt handler clears all IF odd flags and * call the dispatcher passing the flags which triggered the interrupt. ******************************************************************************/ void GPIO_ODD_IRQHandler(void) { uint32_t odd_flags; // Gets all enabled and pending odd interrupts. odd_flags = sl_hal_gpio_get_enabled_pending_interrupts() & SL_HAL_GPIO_INT_IF_ODD_MASK; // Clears only odd interrupts. sl_hal_gpio_clear_interrupts(odd_flags); sl_gpio_dispatch_interrupt(odd_flags); }