/***************************************************************************//**
* @file
* @brief General Purpose IO (GPIO) peripheral API
*******************************************************************************
* # License
* Copyright 2018 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.
*
******************************************************************************/
#ifndef SL_HAL_GPIO_H
#define SL_HAL_GPIO_H
#include "em_device.h"
#if defined(GPIO_PRESENT)
#ifdef __cplusplus
extern "C" {
#endif
#include
#include
#include "sl_assert.h"
#include "sl_device_gpio.h"
#include "sl_code_classification.h"
/* *INDENT-OFF* */
// *****************************************************************************
/// @addtogroup gpio GPIO - General Purpose Input Output
/// @brief General Purpose Input Output peripheral
///
/// @li @ref gpio_intro
///
///@n @section gpio_intro Introduction
/// This module contains functions to control the GPIO peripheral of Silicon Labs 32-bit MCUs and SoCs.
/// The GPIO peripheral is used for interrupt configuration, pin configuration and direct pin manipulation
/// as well as routing for peripheral pin connections.
///
/// @{
// *****************************************************************************
/* *INDENT-ON* */
/*******************************************************************************
******************************** DEFINES **********************************
******************************************************************************/
/// Define for port specific pin mask
#if defined(GPIO_PA_MASK)
#define SL_HAL_GPIO_PORT_A_PIN_MASK (GPIO_PA_MASK)
#else
#define SL_HAL_GPIO_PORT_A_PIN_MASK 0
#endif
#if defined(GPIO_PB_MASK)
#define SL_HAL_GPIO_PORT_B_PIN_MASK (GPIO_PB_MASK)
#else
#define SL_HAL_GPIO_PORT_B_PIN_MASK 0
#endif
#if defined(GPIO_PC_MASK)
#define SL_HAL_GPIO_PORT_C_PIN_MASK (GPIO_PC_MASK)
#else
#define SL_HAL_GPIO_PORT_C_PIN_MASK 0
#endif
#if defined(GPIO_PD_MASK)
#define SL_HAL_GPIO_PORT_D_PIN_MASK (GPIO_PD_MASK)
#else
#define SL_HAL_GPIO_PORT_D_PIN_MASK 0
#endif
#if defined(GPIO_PE_MASK)
#define SL_HAL_GPIO_PORT_E_PIN_MASK (GPIO_PE_MASK)
#else
#define SL_HAL_GPIO_PORT_E_PIN_MASK 0
#endif
#if defined(GPIO_PF_MASK)
#define SL_HAL_GPIO_PORT_F_PIN_MASK (GPIO_PF_MASK)
#else
#define SL_HAL_GPIO_PORT_F_PIN_MASK 0
#endif
#if defined(GPIO_PG_MASK)
#define SL_HAL_GPIO_PORT_G_PIN_MASK (GPIO_PG_MASK)
#else
#define SL_HAL_GPIO_PORT_G_PIN_MASK 0
#endif
#if defined(GPIO_PH_MASK)
#define SL_HAL_GPIO_PORT_H_PIN_MASK (GPIO_PH_MASK)
#else
#define SL_HAL_GPIO_PORT_H_PIN_MASK 0
#endif
#if defined(GPIO_PI_MASK)
#define SL_HAL_GPIO_PORT_I_PIN_MASK (GPIO_PI_MASK)
#else
#define SL_HAL_GPIO_PORT_I_PIN_MASK 0
#endif
#if defined(GPIO_PJ_MASK)
#define SL_HAL_GPIO_PORT_J_PIN_MASK (GPIO_PJ_MASK)
#else
#define SL_HAL_GPIO_PORT_J_PIN_MASK 0
#endif
#if defined(GPIO_PK_MASK)
#define SL_HAL_GPIO_PORT_K_PIN_MASK (GPIO_PK_MASK)
#else
#define SL_HAL_GPIO_PORT_K_PIN_MASK 0
#endif
/// Define for port specific pin count
#if defined(GPIO_PA_COUNT)
#define SL_HAL_GPIO_PORT_A_PIN_COUNT (GPIO_PA_COUNT)
#else
#define SL_HAL_GPIO_PORT_A_PIN_COUNT 0
#endif
#if defined(GPIO_PB_COUNT)
#define SL_HAL_GPIO_PORT_B_PIN_COUNT (GPIO_PB_COUNT)
#else
#define SL_HAL_GPIO_PORT_B_PIN_COUNT 0
#endif
#if defined(GPIO_PC_COUNT)
#define SL_HAL_GPIO_PORT_C_PIN_COUNT (GPIO_PC_COUNT)
#else
#define SL_HAL_GPIO_PORT_C_PIN_COUNT 0
#endif
#if defined(GPIO_PD_COUNT)
#define SL_HAL_GPIO_PORT_D_PIN_COUNT (GPIO_PD_COUNT)
#else
#define SL_HAL_GPIO_PORT_D_PIN_COUNT 0
#endif
#if defined(GPIO_PE_COUNT)
#define SL_HAL_GPIO_PORT_E_PIN_COUNT (GPIO_PE_COUNT)
#else
#define SL_HAL_GPIO_PORT_E_PIN_COUNT 0
#endif
#if defined(GPIO_PF_COUNT)
#define SL_HAL_GPIO_PORT_F_PIN_COUNT (GPIO_PF_COUNT)
#else
#define SL_HAL_GPIO_PORT_F_PIN_COUNT 0
#endif
#if defined(GPIO_PG_COUNT)
#define SL_HAL_GPIO_PORT_G_PIN_COUNT (GPIO_PG_COUNT)
#else
#define SL_HAL_GPIO_PORT_G_PIN_COUNT 0
#endif
#if defined(GPIO_PH_COUNT)
#define SL_HAL_GPIO_PORT_H_PIN_COUNT (GPIO_PH_COUNT)
#else
#define SL_HAL_GPIO_PORT_H_PIN_COUNT 0
#endif
#if defined(GPIO_PI_COUNT)
#define SL_HAL_GPIO_PORT_I_PIN_COUNT (GPIO_PI_COUNT)
#else
#define SL_HAL_GPIO_PORT_I_PIN_COUNT 0
#endif
#if defined(GPIO_PJ_COUNT)
#define SL_HAL_GPIO_PORT_J_PIN_COUNT (GPIO_PJ_COUNT)
#else
#define SL_HAL_GPIO_PORT_J_PIN_COUNT 0
#endif
#if defined(GPIO_PK_COUNT)
#define SL_HAL_GPIO_PORT_K_PIN_COUNT (GPIO_PK_COUNT)
#else
#define SL_HAL_GPIO_PORT_K_PIN_COUNT 0
#endif
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
/// Highest GPIO port number.
#if (SL_HAL_GPIO_PORT_K_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 10
#elif (SL_HAL_GPIO_PORT_J_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 9
#elif (SL_HAL_GPIO_PORT_I_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 8
#elif (SL_HAL_GPIO_PORT_H_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 7
#elif (SL_HAL_GPIO_PORT_G_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 6
#elif (SL_HAL_GPIO_PORT_F_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 5
#elif (SL_HAL_GPIO_PORT_E_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 4
#elif (SL_HAL_GPIO_PORT_D_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 3
#elif (SL_HAL_GPIO_PORT_C_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 2
#elif (SL_HAL_GPIO_PORT_B_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 1
#elif (SL_HAL_GPIO_PORT_A_PIN_COUNT > 0)
#define SL_HAL_GPIO_PORT_MAX 0
#else
#error "Max GPIO port number is undefined for this part."
#endif
/// Highest GPIO pin number.
#define SL_HAL_GPIO_PIN_MAX 15
/// @endcond
#define SL_HAL_GPIO_PORT_SIZE(port) ( \
(port) == 0 ? SL_HAL_GPIO_PORT_A_PIN_COUNT \
: (port) == 1 ? SL_HAL_GPIO_PORT_B_PIN_COUNT \
: (port) == 2 ? SL_HAL_GPIO_PORT_C_PIN_COUNT \
: (port) == 3 ? SL_HAL_GPIO_PORT_D_PIN_COUNT \
: (port) == 4 ? SL_HAL_GPIO_PORT_E_PIN_COUNT \
: (port) == 5 ? SL_HAL_GPIO_PORT_F_PIN_COUNT \
: (port) == 6 ? SL_HAL_GPIO_PORT_G_PIN_COUNT \
: (port) == 7 ? SL_HAL_GPIO_PORT_H_PIN_COUNT \
: (port) == 8 ? SL_HAL_GPIO_PORT_I_PIN_COUNT \
: (port) == 9 ? SL_HAL_GPIO_PORT_J_PIN_COUNT \
: (port) == 10 ? SL_HAL_GPIO_PORT_K_PIN_COUNT \
: 0)
#define SL_HAL_GPIO_PORT_MASK(port) ( \
((int)port) == 0 ? SL_HAL_GPIO_PORT_A_PIN_MASK \
: ((int)port) == 1 ? SL_HAL_GPIO_PORT_B_PIN_MASK \
: ((int)port) == 2 ? SL_HAL_GPIO_PORT_C_PIN_MASK \
: ((int)port) == 3 ? SL_HAL_GPIO_PORT_D_PIN_MASK \
: ((int)port) == 4 ? SL_HAL_GPIO_PORT_E_PIN_MASK \
: ((int)port) == 5 ? SL_HAL_GPIO_PORT_F_PIN_MASK \
: ((int)port) == 6 ? SL_HAL_GPIO_PORT_G_PIN_MASK \
: ((int)port) == 7 ? SL_HAL_GPIO_PORT_H_PIN_MASK \
: ((int)port) == 8 ? SL_HAL_GPIO_PORT_I_PIN_MASK \
: ((int)port) == 9 ? SL_HAL_GPIO_PORT_J_PIN_MASK \
: ((int)port) == 10 ? SL_HAL_GPIO_PORT_K_PIN_MASK \
: 0UL)
/// Validation of port.
#define SL_HAL_GPIO_PORT_IS_VALID(port) (SL_HAL_GPIO_PORT_MASK(port) != 0x0UL)
/// Validation of port and pin.
#define SL_HAL_GPIO_PORT_PIN_IS_VALID(port, pin) ((((SL_HAL_GPIO_PORT_MASK(port)) >> (pin)) & 0x1UL) == 0x1UL)
/// Max interrupt lines for external and EM4 interrupts.
#define SL_HAL_GPIO_INTERRUPT_MAX 15
/// Shift value for EM4WUEN
#define SL_HAL_GPIO_EM4WUEN_SHIFT _GPIO_EM4WUEN_EM4WUEN_SHIFT
/// Masks for even and odd interrupt bits.
#define SL_HAL_GPIO_INT_IF_EVEN_MASK ((_GPIO_IF_MASK) & 0x55555555UL)
#define SL_HAL_GPIO_INT_IF_ODD_MASK ((_GPIO_IF_MASK) & 0xAAAAAAAAUL)
/// Validation of mode.
#define SL_HAL_GPIO_MODE_IS_VALID(mode) ((mode & _GPIO_P_MODEL_MODE0_MASK) == mode)
/// Validation of interrupt number and pin.
#define SL_HAL_GPIO_INTNO_PIN_VALID(int_no, pin) (((int_no) & ~_GPIO_EXTIPINSELL_EXTIPINSEL0_MASK) == ((pin) & ~_GPIO_EXTIPINSELL_EXTIPINSEL0_MASK))
/*******************************************************************************
******************************** ENUMS ************************************
******************************************************************************/
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
/***************************************************************************//**
* Set the mode for a GPIO pin.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
* @param[in] mode The desired pin mode.
* @param[in] output_value A value to set for the pin in the DOUT register. The DOUT setting is important for
* some input mode configurations to determine the pull-up/down direction.
******************************************************************************/
void sl_hal_gpio_set_pin_mode(const sl_gpio_t *gpio,
sl_gpio_mode_t mode,
bool output_value);
/***************************************************************************//**
* Get the mode for a GPIO pin.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
*
* @return Return the pin mode.
******************************************************************************/
sl_gpio_mode_t sl_hal_gpio_get_pin_mode(const sl_gpio_t *gpio);
/***************************************************************************//**
* Configure the GPIO external pin interrupt by connecting external interrupt id with gpio pin.
*
* @note This function configure the pin interrupt with pin ,port and external interrupt id as input.
* If external interrupt id is provided as input it will be considered as the input or else
* available interrupt number will be generated by looping through the interrupt group and will be used.
* User can provide SL_HAL_GPIO_INTERRUPT_UNAVAILABLE if user don't want to provide interrupt id.
* @note the pin number can be selected freely within a group.
* Interrupt numbers are divided into 4 groups (int_no / 4) and valid pin
* number within the interrupt groups are:
* 0: pins 0-3 (interrupt number 0-3)
* 1: pins 4-7 (interrupt number 4-7)
* 2: pins 8-11 (interrupt number 8-11)
* 3: pins 12-15 (interrupt number 12-15)
* @note It is recommended to disable interrupts before configuring the GPIO pin interrupt.
* See @ref sl_hal_gpio_disable_interrupts() for more information.
* The GPIO interrupt handler must be in place before enabling the interrupt.
* Notice that any pending interrupt for the selected interrupt is cleared by this function.
* Notice that only interrupt will be configured by this function. It is not enabled.
* It is recommended to enable interrupts after configuring the GPIO pin interrupt if needed.
* See @ref sl_hal_gpio_enable_interrupts() for more information.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
* @param[in] int_no The interrupt number to trigger.
* @param[in] flags Interrupt configuration flags. @ref sl_hal_gpio_interrupt_flag_t for more information.
*
* @return Return the available interrupt number
******************************************************************************/
int32_t sl_hal_gpio_configure_external_interrupt(const sl_gpio_t *gpio,
int32_t int_no,
sl_gpio_interrupt_flag_t flags);
/**************************************************************************//**
* Enable GPIO pin wake-up from EM4. When the function exits,
* EM4 mode can be safely entered.
*
* @note It is assumed that the GPIO pin modes are set correctly.
* Valid modes are SL_GPIO_MODE_INPUT and SL_GPIO_MODE_INPUT_PULL.
*
* @param[in] pinmask A bitmask containing the bitwise logic OR of which GPIO pin(s) to enable.
* @param[in] polaritymask A bitmask containing the bitwise logic OR of GPIO pin(s) wake-up polarity.
*****************************************************************************/
void sl_hal_gpio_enable_pin_em4_wakeup(uint32_t pinmask,
uint32_t polaritymask);
/***************************************************************************//**
* Configure EM4WU pins as external level-sensitive interrupts.
*
* @note It is recommended to disable interrupts before configuring the GPIO pin interrupt.
* See @ref sl_hal_gpio_disable_interrupts() for more information.
* The provided port, pin and int_no inputs should be valid EM4 related parameters
* because there are dedicated port, pin and EM4 Wakeup interrupt combination for
* configuring the port, pin for EM4 functionality.
* User can provide SL_HAL_GPIO_INTERRUPT_UNAVAILABLE if user don't want to provide interrupt id.
* The GPIO interrupt handler must be in place before enabling the interrupt.
* Notice that any pending interrupt for the selected interrupt is cleared by this function.
* Notice that any only EM4WU interrupt is configured by this function. It is not enabled.
* It is recommended to enable interrupts after configuring the GPIO pin interrupt if needed.
* See @ref sl_hal_gpio_enable_interrupts() for more information.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
* @param[in] int_no The EM4WU interrupt number to trigger.
* @param[in] polarity true = Active high level-sensitive interrupt.
* false = Active low level-sensitive interrupt.
*
* @return Return the available EM4WU interrupt number
******************************************************************************/
int32_t sl_hal_gpio_configure_wakeup_em4_external_interrupt(const sl_gpio_t *gpio,
int32_t int_no,
bool polarity);
/***************************************************************************//**
* Lock the GPIO configuration.
*
* @note Configuration lock affects the GPIO_Px_MODEL, GPIO_Px_MODEH, GPIO_Px_CTRL,
* GPIO_Px_PINLOCKN, GPIO_EXTIPSELL, GPIO_EXTIPSELH, GPIO_EXTIPINSELL,
* GPIO_EXTIPINSELH, GPIO_INSENSE, GPIO_ROUTE, GPIO_ROUTEPEN, and
* GPIO_ROUTELOC0 registers when they are present on a specific device.
* @note Unwanted or accidental changes to GPIO configuration can be avoided by
* using the configuration lock register. Any value other than 0xA534 written to
* GPIO_LOCK enables the configuration lock. Pins are unlocked by a reset or
* by writing 0xA534 to the GPIO_LOCK register.
******************************************************************************/
__INLINE void sl_hal_gpio_lock(void)
{
GPIO->LOCK = ~GPIO_LOCK_LOCKKEY_UNLOCK;
}
/***************************************************************************//**
* Unlock the GPIO configuration.
*
* @note Configuration lock affects the GPIO_Px_MODEL, GPIO_Px_MODEH, GPIO_Px_CTRL,
* GPIO_Px_PINLOCKN, GPIO_EXTIPSELL, GPIO_EXTIPSELH, GPIO_EXTIPINSELL,
* GPIO_EXTIPINSELH, GPIO_INSENSE, GPIO_ROUTE, GPIO_ROUTEPEN, and
* GPIO_ROUTELOC0 registers when they are present on a specific device.
* @note Unwanted or accidental changes to GPIO configuration can be avoided by
* using the configuration lock register. Any value other than 0xA534 written to
* GPIO_LOCK enables the configuration lock. Pins are unlocked by a reset or
* by writing 0xA534 to the GPIO_LOCK register.
******************************************************************************/
__INLINE void sl_hal_gpio_unlock(void)
{
GPIO->LOCK = GPIO_LOCK_LOCKKEY_UNLOCK;
}
/***************************************************************************//**
* Gets the GPIO configuration state.
*
* @return Return the GPIO lock state.
******************************************************************************/
__INLINE uint32_t sl_hal_gpio_get_lock_status(void)
{
return GPIO->GPIOLOCKSTATUS;
}
/***************************************************************************//**
* Set a single pin in GPIO data out register to 1.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
******************************************************************************/
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_HAL_GPIO, SL_CODE_CLASS_TIME_CRITICAL)
__INLINE void sl_hal_gpio_set_pin(const sl_gpio_t *gpio)
{
EFM_ASSERT(gpio != NULL);
EFM_ASSERT(SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin));
GPIO->P_SET[gpio->port].DOUT = 1UL << gpio->pin;
}
/***************************************************************************//**
* Set bits GPIO data out register to 1.
*
* @param[in] port The GPIO port to access.
* @param[in] pins Bit mask for bits to set to 1 in DOUT register.
******************************************************************************/
__INLINE void sl_hal_gpio_set_port(sl_gpio_port_t port,
uint32_t pins)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
GPIO->P_SET[port].DOUT = pins;
}
/***************************************************************************//**
* Set GPIO port data out register.
*
* @param[in] port The GPIO port to access.
* @param[in] val Value to write to port data out register.
* @param[in] mask Mask indicating which bits to modify.
******************************************************************************/
__INLINE void sl_hal_gpio_set_port_value(sl_gpio_port_t port,
uint32_t val,
uint32_t mask)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
GPIO->P[port].DOUT = (GPIO->P[port].DOUT & ~mask) | (val & mask);
}
/***************************************************************************//**
* Set slewrate for pins on a GPIO port which are configured into normal modes.
*
* @param[in] port The GPIO port to configure.
* @param[in] slewrate The slewrate to configure for pins on this GPIO port.
******************************************************************************/
__INLINE void sl_hal_gpio_set_slew_rate(sl_gpio_port_t port,
uint8_t slewrate)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
EFM_ASSERT(slewrate <= (_GPIO_P_CTRL_SLEWRATE_MASK
>> _GPIO_P_CTRL_SLEWRATE_SHIFT));
GPIO->P[port].CTRL = (GPIO->P[port].CTRL
& ~_GPIO_P_CTRL_SLEWRATE_MASK)
| (slewrate << _GPIO_P_CTRL_SLEWRATE_SHIFT);
}
/***************************************************************************//**
* Set slewrate for pins on a GPIO port which are configured into alternate modes.
*
* @param[in] port The GPIO port to configure.
* @param[in] slewrate_alt The slewrate to configure for pins using alternate modes on this GPIO port.
******************************************************************************/
__INLINE void sl_hal_gpio_set_slew_rate_alternate(sl_gpio_port_t port,
uint8_t slewrate_alt)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
EFM_ASSERT(slewrate_alt <= (_GPIO_P_CTRL_SLEWRATEALT_MASK
>> _GPIO_P_CTRL_SLEWRATEALT_SHIFT));
GPIO->P[port].CTRL = (GPIO->P[port].CTRL
& ~_GPIO_P_CTRL_SLEWRATEALT_MASK)
| (slewrate_alt << _GPIO_P_CTRL_SLEWRATEALT_SHIFT);
}
/***************************************************************************//**
* Get slewrate for pins on a GPIO port.
*
* @param[in] port The GPIO port to access to get slew rate.
*
* @return Return the slewrate setting for the selected GPIO port.
******************************************************************************/
__INLINE uint8_t sl_hal_gpio_get_slew_rate(sl_gpio_port_t port)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
return (GPIO->P[port].CTRL & _GPIO_P_CTRL_SLEWRATE_MASK) >> _GPIO_P_CTRL_SLEWRATE_SHIFT;
}
/***************************************************************************//**
* Get slewrate for pins on a GPIO port which are configured into alternate modes.
*
* @param[in] port The GPIO port to access to get slew rate.
*
* @return Return the alternate slewrate setting for selected GPIO port.
******************************************************************************/
__INLINE uint8_t sl_hal_gpio_get_slew_rate_alternate(sl_gpio_port_t port)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
return (GPIO->P[port].CTRL & _GPIO_P_CTRL_SLEWRATEALT_MASK) >> _GPIO_P_CTRL_SLEWRATEALT_SHIFT;
}
/***************************************************************************//**
* Set a single pin in GPIO data out port register to 0.
*
* @param[in] gpio Pointer to GPIO structure with port and pin
******************************************************************************/
__INLINE void sl_hal_gpio_clear_pin(const sl_gpio_t *gpio)
{
EFM_ASSERT(gpio != NULL);
EFM_ASSERT(SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin));
GPIO->P_CLR[gpio->port].DOUT = 1UL << gpio->pin;
}
/***************************************************************************//**
* Set bits in DOUT register for a port to 0.
*
* @param[in] port The GPIO port to access.
* @param[in] pins Bit mask for bits to clear in DOUT register.
******************************************************************************/
__INLINE void sl_hal_gpio_clear_port(sl_gpio_port_t port,
uint32_t pins)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
GPIO->P_CLR[port].DOUT = pins;
}
/***************************************************************************//**
* Read the pad value for a single pin in a GPIO port.
*
* @param[in] gpio Pointer to GPIO structure with port and pin.
*
* @return The pin value, 0 or 1.
******************************************************************************/
__INLINE bool sl_hal_gpio_get_pin_input(const sl_gpio_t *gpio)
{
EFM_ASSERT(gpio != NULL);
EFM_ASSERT(SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin));
bool pin_input = ((GPIO->P[gpio->port].DIN) >> gpio->pin) & 1UL;
return pin_input;
}
/***************************************************************************//**
* Get current setting for a pin in a GPIO port data out register.
*
* @param[in] gpio Pointer to GPIO structure with port and pin.
*
* @return The DOUT setting for the requested pin, 0 or 1.
******************************************************************************/
__INLINE bool sl_hal_gpio_get_pin_output(const sl_gpio_t *gpio)
{
EFM_ASSERT(gpio != NULL);
EFM_ASSERT(SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin));
bool pin_output = ((GPIO->P[gpio->port].DOUT) >> gpio->pin) & 1UL;
return pin_output;
}
/***************************************************************************//**
* Read the pad values for GPIO port.
*
* @param[in] port The GPIO port to access.
*
* @return The pad values for the GPIO port.
******************************************************************************/
__INLINE uint32_t sl_hal_gpio_get_port_input(sl_gpio_port_t port)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
return GPIO->P[port].DIN;
}
/***************************************************************************//**
* Get current setting for a GPIO port data out register.
*
* @param[in] port The GPIO port to access.
*
* @return The data out setting for the requested port.
******************************************************************************/
__INLINE uint32_t sl_hal_gpio_get_port_output(sl_gpio_port_t port)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
return GPIO->P[port].DOUT;
}
/***************************************************************************//**
* Toggle a single pin in GPIO port data out register.
*
* @param[in] gpio Pointer to GPIO structure with port and pin.
******************************************************************************/
__INLINE void sl_hal_gpio_toggle_pin(const sl_gpio_t *gpio)
{
EFM_ASSERT(gpio != NULL);
EFM_ASSERT(SL_HAL_GPIO_PORT_PIN_IS_VALID(gpio->port, gpio->pin));
GPIO->P_TGL[gpio->port].DOUT = 1UL << gpio->pin;
}
/***************************************************************************//**
* Toggle pins in GPIO port data out register.
*
* @param[in] port The GPIO port to access.
* @param[in] pins Bit mask with pins to toggle.
******************************************************************************/
__INLINE void sl_hal_gpio_toggle_port(sl_gpio_port_t port,
uint32_t pins)
{
EFM_ASSERT(SL_HAL_GPIO_PORT_IS_VALID(port));
GPIO->P_TGL[port].DOUT = pins;
}
/***************************************************************************//**
* Enable one or more GPIO interrupts.
*
* @param[in] flags GPIO interrupt sources to enable.
******************************************************************************/
__INLINE void sl_hal_gpio_enable_interrupts(uint32_t flags)
{
GPIO->IEN_SET = flags;
}
/***************************************************************************//**
* Disable one or more GPIO interrupts.
*
* @param[in] flags GPIO interrupt sources to disable.
******************************************************************************/
__INLINE void sl_hal_gpio_disable_interrupts(uint32_t flags)
{
GPIO->IEN_CLR = flags;
}
/***************************************************************************//**
* Clear one or more pending GPIO interrupts.
*
* @param[in] flags Bitwise logic OR of GPIO interrupt sources to clear.
******************************************************************************/
__INLINE void sl_hal_gpio_clear_interrupts(uint32_t flags)
{
GPIO->IF_CLR = flags;
}
/**************************************************************************//**
* Set one or more pending GPIO interrupts from SW.
*
* @param[in] flags GPIO interrupt sources to set to pending.
*****************************************************************************/
__INLINE void sl_hal_gpio_set_interrupts(uint32_t flags)
{
GPIO->IF_SET = flags;
}
/***************************************************************************//**
* Get pending GPIO interrupts.
*
* @return GPIO interrupt sources pending.
******************************************************************************/
__INLINE uint32_t sl_hal_gpio_get_pending_interrupts(void)
{
return GPIO->IF;
}
/***************************************************************************//**
* Get enabled GPIO interrupts.
*
* @return Enabled GPIO interrupt sources.
******************************************************************************/
__INLINE uint32_t sl_hal_gpio_get_enabled_interrupts(void)
{
return GPIO->IEN;
}
/***************************************************************************//**
* Get enabled and pending GPIO interrupt flags.
*
* @return Enabled and pending interrupt sources.
*
* @note Useful for handling more interrupt sources in the same interrupt handler.
******************************************************************************/
__INLINE uint32_t sl_hal_gpio_get_enabled_pending_interrupts(void)
{
uint32_t tmp;
tmp = GPIO->IEN;
return GPIO->IF & tmp;
}
/***************************************************************************//**
* The available external interrupt number getter.
*
* @param[in] pin The GPIO pin to access.
* @param[in] enabled_interrupts_mask Contains enabled GPIO interrupts mask.
*
* @return The available interrupt number based on interrupt and pin grouping.
******************************************************************************/
__INLINE int32_t sl_hal_gpio_get_external_interrupt_number(uint8_t pin,
uint32_t enabled_interrupts_mask)
{
uint32_t interrupt_to_check;
uint32_t int_group_start = (pin & 0xFFC);
int32_t int_no = -1;
// loop through the interrupt group, starting
// from the pin number, and take
// the first available.
for (uint8_t i = 0; i < 4; i++) {
interrupt_to_check = int_group_start + ((pin + i) & 0x3); // modulo 4
if (((enabled_interrupts_mask >> interrupt_to_check) & 0x1) == 0) {
int_no = interrupt_to_check;
break;
}
}
return int_no;
}
/***************************************************************************//**
* The available em4 wakeup interrupt number getter.
*
* @param[in] gpio Pointer to GPIO structure with port and pin.
*
* @return The available em4 wakeup interrupt number based on associated port and pin.
******************************************************************************/
__INLINE int32_t sl_hal_gpio_get_em4_interrupt_number(const sl_gpio_t *gpio)
{
EFM_ASSERT(gpio != NULL);
int32_t em4_int_no;
if (false) {
// Check all the EM4WU Pins and check if given port, pin matches any of them.
#if defined(GPIO_EM4WU0_PORT)
} else if (GPIO_EM4WU0_PORT == gpio->port && GPIO_EM4WU0_PIN == gpio->pin) {
em4_int_no = 0;
#endif
#if defined(GPIO_EM4WU1_PORT)
} else if (GPIO_EM4WU1_PORT == gpio->port && GPIO_EM4WU1_PIN == gpio->pin) {
em4_int_no = 1;
#endif
#if defined(GPIO_EM4WU3_PORT)
} else if (GPIO_EM4WU3_PORT == gpio->port && GPIO_EM4WU3_PIN == gpio->pin) {
em4_int_no = 3;
#endif
#if defined(GPIO_EM4WU4_PORT)
} else if (GPIO_EM4WU4_PORT == gpio->port && GPIO_EM4WU4_PIN == gpio->pin) {
em4_int_no = 4;
#endif
#if defined(GPIO_EM4WU6_PORT)
} else if (GPIO_EM4WU6_PORT == gpio->port && GPIO_EM4WU6_PIN == gpio->pin) {
em4_int_no = 6;
#endif
#if defined(GPIO_EM4WU7_PORT)
} else if (GPIO_EM4WU7_PORT == gpio->port && GPIO_EM4WU7_PIN == gpio->pin) {
em4_int_no = 7;
#endif
#if defined(GPIO_EM4WU8_PORT)
} else if (GPIO_EM4WU8_PORT == gpio->port && GPIO_EM4WU8_PIN == gpio->pin) {
em4_int_no = 8;
#endif
#if defined(GPIO_EM4WU9_PORT)
} else if (GPIO_EM4WU9_PORT == gpio->port && GPIO_EM4WU9_PIN == gpio->pin) {
em4_int_no = 9;
#endif
#if defined(GPIO_EM4WU10_PORT)
} else if (GPIO_EM4WU10_PORT == gpio->port && GPIO_EM4WU10_PIN == gpio->pin) {
em4_int_no = 10;
#endif
} else {
em4_int_no = -1;
}
return em4_int_no;
}
/*************************************************************************//**
* Disable GPIO pin wake-up from EM4.
*
* @param[in] pinmask Bit mask containing the bitwise logic OR of which GPIO pin(s) to disable.
*****************************************************************************/
__INLINE void sl_hal_gpio_disable_pin_em4_wakeup(uint32_t pinmask)
{
EFM_ASSERT((pinmask & ~_GPIO_EM4WUEN_MASK) == 0UL);
GPIO->EM4WUEN &= ~pinmask;
}
/**************************************************************************//**
* Enable GPIO pin retention of output enable, output value, pull enable, and
* pull direction in EM4.
*
* @note The behavior of this function depends on the configured GPIO retention mode.
* If the GPIO retention mode is configured to be "SWUNLATCH" then this
* function will not change anything. If the retention mode is anything else
* then this function will set the GPIO retention mode to "EM4EXIT" when the
* enable argument is true, and "Disabled" when false.
*
* @param[in] enable true - enable EM4 pin retention.
* false - disable EM4 pin retention.
*****************************************************************************/
__INLINE void sl_hal_gpio_set_pin_em4_retention(bool enable)
{
// Leave configuration alone when software unlatch is used.
uint32_t mode = EMU->EM4CTRL & _EMU_EM4CTRL_EM4IORETMODE_MASK;
if (mode == EMU_EM4CTRL_EM4IORETMODE_SWUNLATCH) {
return;
}
if (enable) {
EMU->EM4CTRL = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4IORETMODE_MASK)
| EMU_EM4CTRL_EM4IORETMODE_EM4EXIT;
} else {
EMU->EM4CTRL = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4IORETMODE_MASK)
| EMU_EM4CTRL_EM4IORETMODE_DISABLE;
}
}
/**************************************************************************//**
* Check which GPIO pin(s) that caused a wake-up from EM4.
*
* @return Bit mask containing the bitwise logic OR of which GPIO pin(s) caused the wake-up.
*****************************************************************************/
__INLINE uint32_t sl_hal_gpio_get_pin_em4_wakeup_cause(void)
{
return GPIO->IF & _GPIO_EM4WUEN_EM4WUEN_MASK;
}
/***************************************************************************//**
* Enable/Disable serial wire output pin.
*
* @note Enabling this pin is not sufficient to fully enable serial wire output,
* which is also dependent on issues outside the GPIO module.
* @note If debug port is locked, SWO pin is not disabled automatically. To avoid
* information leakage through SWO, disable SWO pin after locking debug port.
*
* @param[in] enable false - disable serial wire viewer pin (default after reset).
* true - enable serial wire viewer pin.
******************************************************************************/
__INLINE void sl_hal_gpio_enable_debug_swo(bool enable)
{
uint32_t bit = enable ? 0x1UL : 0x0UL;
if (bit != 0U) {
GPIO->TRACEROUTEPEN_SET = 1UL << _GPIO_TRACEROUTEPEN_SWVPEN_SHIFT;
} else {
GPIO->TRACEROUTEPEN_CLR = 1UL << _GPIO_TRACEROUTEPEN_SWVPEN_SHIFT;
}
}
/***************************************************************************//**
* Enable/disable serial wire clock pin.
*
* @note Disabling SWDClk will disable the debug interface, which may result in
* a lockout if done early in startup (before debugger is able to halt core).
*
* @param[in] enable false - disable serial wire clock.
* true - enable serial wire clock (default after reset).
******************************************************************************/
__INLINE void sl_hal_gpio_enable_debug_swd_clk(bool enable)
{
uint32_t bit = enable ? 0x1UL : 0x0UL;
if (bit != 0U) {
GPIO->DBGROUTEPEN_SET = 1UL << _GPIO_DBGROUTEPEN_SWCLKTCKPEN_SHIFT;
} else {
GPIO->DBGROUTEPEN_CLR = 1UL << _GPIO_DBGROUTEPEN_SWCLKTCKPEN_SHIFT;
}
}
/***************************************************************************//**
* Enable/disable serial wire data I/O pin.
*
* @note Disabling SWDClk will disable the debug interface, which may result in
* a lockout if done early in startup (before debugger is able to halt core).
*
* @param[in] enable false - disable serial wire data pin.
* true - enable serial wire data pin (default after reset).
******************************************************************************/
__INLINE void sl_hal_gpio_enable_debug_swd_io(bool enable)
{
uint32_t bit = enable ? 0x1UL : 0x0UL;
if (bit != 0U) {
GPIO->DBGROUTEPEN_SET = 1UL << _GPIO_DBGROUTEPEN_SWDIOTMSPEN_SHIFT;
} else {
GPIO->DBGROUTEPEN_CLR = 1UL << _GPIO_DBGROUTEPEN_SWDIOTMSPEN_SHIFT;
}
}
/** @} (end addtogroup gpio) */
#ifdef __cplusplus
}
#endif
#endif /* GPIO_PRESENT */
#endif /* SL_HAL_GPIO_H */