/***************************************************************************//** | |
* @file em_gpio.c | |
* @brief General Purpose IO (GPIO) peripheral API | |
* devices. | |
* @version 4.2.1 | |
******************************************************************************* | |
* @section License | |
* <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b> | |
******************************************************************************* | |
* | |
* 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. | |
* 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. | |
* | |
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no | |
* obligation to support this Software. Silicon Labs is providing the | |
* Software "AS IS", with no express or implied warranties of any kind, | |
* including, but not limited to, any implied warranties of merchantability | |
* or fitness for any particular purpose or warranties against infringement | |
* of any proprietary rights of a third party. | |
* | |
* Silicon Labs will not be liable for any consequential, incidental, or | |
* special damages, or any other relief, or for any claim by any third party, | |
* arising from your use of this Software. | |
* | |
******************************************************************************/ | |
#include "em_gpio.h" | |
#if defined(GPIO_COUNT) && (GPIO_COUNT > 0) | |
/***************************************************************************//** | |
* @addtogroup EM_Library | |
* @{ | |
******************************************************************************/ | |
/***************************************************************************//** | |
* @addtogroup GPIO | |
* @brief General Purpose Input/Output (GPIO) API | |
* @{ | |
******************************************************************************/ | |
/******************************************************************************* | |
******************************* DEFINES *********************************** | |
******************************************************************************/ | |
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ | |
/** Validation of pin typically usable in assert statements. */ | |
#define GPIO_DRIVEMODE_VALID(mode) ((mode) <= 3) | |
#define GPIO_STRENGHT_VALID(strenght) (!((strenght) & \ | |
~(_GPIO_P_CTRL_DRIVESTRENGTH_MASK \ | |
| _GPIO_P_CTRL_DRIVESTRENGTHALT_MASK))) | |
/** @endcond */ | |
/******************************************************************************* | |
************************** GLOBAL FUNCTIONS ******************************* | |
******************************************************************************/ | |
/***************************************************************************//** | |
* @brief | |
* Sets the pin location of the debug pins (Serial Wire interface). | |
* | |
* @note | |
* Changing the pins used for debugging uncontrolled, may result in a lockout. | |
* | |
* @param[in] location | |
* The debug pin location to use (0-3). | |
******************************************************************************/ | |
void GPIO_DbgLocationSet(unsigned int location) | |
{ | |
#if defined ( _GPIO_ROUTE_SWLOCATION_MASK ) | |
EFM_ASSERT(location < AFCHANLOC_MAX); | |
GPIO->ROUTE = (GPIO->ROUTE & ~_GPIO_ROUTE_SWLOCATION_MASK) | | |
(location << _GPIO_ROUTE_SWLOCATION_SHIFT); | |
#else | |
(void)location; | |
#endif | |
} | |
#if defined (_GPIO_P_CTRL_DRIVEMODE_MASK) | |
/***************************************************************************//** | |
* @brief | |
* Sets the drive mode for a GPIO port. | |
* | |
* @param[in] port | |
* The GPIO port to access. | |
* | |
* @param[in] mode | |
* Drive mode to use for port. | |
******************************************************************************/ | |
void GPIO_DriveModeSet(GPIO_Port_TypeDef port, GPIO_DriveMode_TypeDef mode) | |
{ | |
EFM_ASSERT(GPIO_PORT_VALID(port) && GPIO_DRIVEMODE_VALID(mode)); | |
GPIO->P[port].CTRL = (GPIO->P[port].CTRL & ~(_GPIO_P_CTRL_DRIVEMODE_MASK)) | |
| (mode << _GPIO_P_CTRL_DRIVEMODE_SHIFT); | |
} | |
#endif | |
#if defined (_GPIO_P_CTRL_DRIVESTRENGTH_MASK) | |
/***************************************************************************//** | |
* @brief | |
* Sets the drive strength for a GPIO port. | |
* | |
* @param[in] port | |
* The GPIO port to access. | |
* | |
* @param[in] strength | |
* Drive strength to use for port. | |
******************************************************************************/ | |
void GPIO_DriveStrengthSet(GPIO_Port_TypeDef port, | |
GPIO_DriveStrength_TypeDef strength) | |
{ | |
EFM_ASSERT(GPIO_PORT_VALID(port) && GPIO_STRENGHT_VALID(strength)); | |
BUS_RegMaskedWrite(&GPIO->P[port].CTRL, | |
_GPIO_P_CTRL_DRIVESTRENGTH_MASK | _GPIO_P_CTRL_DRIVESTRENGTHALT_MASK, | |
strength); | |
} | |
#endif | |
/***************************************************************************//** | |
* @brief | |
* Configure GPIO interrupt. | |
* | |
* @details | |
* If reconfiguring a GPIO interrupt that is already enabled, it is generally | |
* recommended to disable it first, see GPIO_Disable(). | |
* | |
* The actual GPIO interrupt handler must be in place before enabling the | |
* interrupt. | |
* | |
* Notice that any pending interrupt for the selected pin is cleared by this | |
* function. | |
* | |
* @note | |
* A certain pin number can only be associated with one port. Ie, if GPIO | |
* interrupt 1 is assigned to port A/pin 1, then it is not possibly to use | |
* pin 1 from any other ports for interrupts. Please refer to the reference | |
* manual. | |
* | |
* @param[in] port | |
* The port to associate with @p pin. | |
* | |
* @param[in] pin | |
* The GPIO interrupt number (= port pin). | |
* | |
* @param[in] risingEdge | |
* Set to true if interrupts shall be enabled on rising edge, otherwise false. | |
* | |
* @param[in] fallingEdge | |
* Set to true if interrupts shall be enabled on falling edge, otherwise false. | |
* | |
* @param[in] enable | |
* Set to true if interrupt shall be enabled after configuration completed, | |
* false to leave disabled. See GPIO_IntDisable() and GPIO_IntEnable(). | |
******************************************************************************/ | |
void GPIO_IntConfig(GPIO_Port_TypeDef port, | |
unsigned int pin, | |
bool risingEdge, | |
bool fallingEdge, | |
bool enable) | |
{ | |
uint32_t tmp; | |
EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin)); | |
/* There are two registers controlling the interrupt configuration: | |
* The EXTIPSELL register controls pins 0-7 and EXTIPSELH controls | |
* pins 8-15. */ | |
if (pin < 8) | |
{ | |
BUS_RegMaskedWrite(&GPIO->EXTIPSELL, | |
0xF << (4 * pin), | |
port << (4 * pin)); | |
} | |
else | |
{ | |
tmp = pin - 8; | |
BUS_RegMaskedWrite(&GPIO->EXTIPSELH, | |
0xF << (4 * tmp), | |
port << (4 * tmp)); | |
} | |
/* Enable/disable rising edge */ | |
BUS_RegBitWrite(&(GPIO->EXTIRISE), pin, risingEdge); | |
/* Enable/disable falling edge */ | |
BUS_RegBitWrite(&(GPIO->EXTIFALL), pin, fallingEdge); | |
/* Clear any pending interrupt */ | |
GPIO->IFC = 1 << pin; | |
/* Finally enable/disable interrupt */ | |
BUS_RegBitWrite(&(GPIO->IEN), pin, enable); | |
} | |
/***************************************************************************//** | |
* @brief | |
* Set the mode for a GPIO pin. | |
* | |
* @param[in] port | |
* The GPIO port to access. | |
* | |
* @param[in] pin | |
* The pin number in the port. | |
* | |
* @param[in] mode | |
* The desired pin mode. | |
* | |
* @param[in] out | |
* Value to set for pin in DOUT register. The DOUT setting is important for | |
* even some input mode configurations, determining pull-up/down direction. | |
******************************************************************************/ | |
void GPIO_PinModeSet(GPIO_Port_TypeDef port, | |
unsigned int pin, | |
GPIO_Mode_TypeDef mode, | |
unsigned int out) | |
{ | |
EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin)); | |
/* If disabling pin, do not modify DOUT in order to reduce chance for */ | |
/* glitch/spike (may not be sufficient precaution in all use cases) */ | |
if (mode != gpioModeDisabled) | |
{ | |
if (out) | |
{ | |
GPIO_PinOutSet(port, pin); | |
} | |
else | |
{ | |
GPIO_PinOutClear(port, pin); | |
} | |
} | |
/* There are two registers controlling the pins for each port. The MODEL | |
* register controls pins 0-7 and MODEH controls pins 8-15. */ | |
if (pin < 8) | |
{ | |
BUS_RegMaskedWrite(&GPIO->P[port].MODEL, | |
0xF << (pin * 4), | |
mode << (pin * 4)); | |
} | |
else | |
{ | |
BUS_RegMaskedWrite(&GPIO->P[port].MODEH, | |
0xF << ((pin - 8) * 4), | |
mode << ((pin - 8) * 4)); | |
} | |
if (mode == gpioModeDisabled) | |
{ | |
if (out) | |
{ | |
GPIO_PinOutSet(port, pin); | |
} | |
else | |
{ | |
GPIO_PinOutClear(port, pin); | |
} | |
} | |
} | |
#if defined( _GPIO_EM4WUEN_MASK ) | |
/**************************************************************************//** | |
* @brief | |
* 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 @ref gpioModeInput and @ref gpioModeInputPull. | |
* | |
* @param[in] pinmask | |
* Bitmask containing the bitwise logic OR of which GPIO pin(s) to enable. | |
* Refer to Reference Manuals for pinmask to GPIO port/pin mapping. | |
* @param[in] polaritymask | |
* Bitmask containing the bitwise logic OR of GPIO pin(s) wake-up polarity. | |
* Refer to Reference Manuals for pinmask to GPIO port/pin mapping. | |
*****************************************************************************/ | |
void GPIO_EM4EnablePinWakeup(uint32_t pinmask, uint32_t polaritymask) | |
{ | |
EFM_ASSERT((pinmask & ~_GPIO_EM4WUEN_MASK) == 0); | |
#if defined( _GPIO_EM4WUPOL_MASK ) | |
EFM_ASSERT((polaritymask & ~_GPIO_EM4WUPOL_MASK) == 0); | |
GPIO->EM4WUPOL &= ~pinmask; /* Set wakeup polarity */ | |
GPIO->EM4WUPOL |= pinmask & polaritymask; | |
#elif defined( _GPIO_EXTILEVEL_MASK ) | |
EFM_ASSERT((polaritymask & ~_GPIO_EXTILEVEL_MASK) == 0); | |
GPIO->EXTILEVEL &= ~pinmask; | |
GPIO->EXTILEVEL |= pinmask & polaritymask; | |
#endif | |
GPIO->EM4WUEN |= pinmask; /* Enable wakeup */ | |
GPIO_EM4SetPinRetention(true); /* Enable pin retention */ | |
#if defined( _GPIO_CMD_EM4WUCLR_MASK ) | |
GPIO->CMD = GPIO_CMD_EM4WUCLR; /* Clear wake-up logic */ | |
#elif defined( _GPIO_IFC_EM4WU_MASK ) | |
GPIO_IntClear(pinmask); | |
#endif | |
} | |
#endif | |
/** @} (end addtogroup GPIO) */ | |
/** @} (end addtogroup EM_Library) */ | |
#endif /* defined(GPIO_COUNT) && (GPIO_COUNT > 0) */ |