/***************************************************************************//** * @file * @brief Analog Comparator (ACMP) peripheral module library implementation * for EFM32 devices. * @author Energy Micro AS * @version 2.3.2 ******************************************************************************* * @section License * (C) Copyright 2010 Energy Micro AS, http://www.energymicro.com ******************************************************************************* * * This source code is the property of Energy Micro AS. The source and compiled * code may only be used on Energy Micro "EFM32" microcontrollers. * * This copyright notice may not be removed from the source code nor changed. * * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no * obligation to support this Software. Energy Micro AS 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. * * Energy Micro AS 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 #include "efm32_acmp.h" #include "efm32_bitband.h" #include "efm32_assert.h" /***************************************************************************//** * @addtogroup EFM32_Library * @{ ******************************************************************************/ /***************************************************************************//** * @addtogroup ACMP * @brief Analog comparator (ACMP) Peripheral API for EFM32 * @{ ******************************************************************************/ /******************************************************************************* ******************************* DEFINES *********************************** ******************************************************************************/ /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ /** Validation of ACMP register block pointer reference * for assert statements. */ #if (ACMP_COUNT == 1) #define ACMP_REF_VALID(ref) ((ref) == ACMP0) #elif (ACMP_COUNT == 2) #define ACMP_REF_VALID(ref) (((ref) == ACMP0) || ((ref) == ACMP1)) #else #error Undefined number of analog comparators (ACMP). #endif /** @endcond */ /******************************************************************************* ************************** GLOBAL FUNCTIONS ******************************* ******************************************************************************/ /***************************************************************************//** * @brief * Sets up the ACMP for use in capacative sense applications. * * @details * This function sets up the ACMP for use in capacacitve sense applications. * To use the capacative sense functionality in the ACMP you need to use * the PRS output of the ACMP module to count the number of oscillations * in the capacative sense circuit (possibly using a TIMER). * * @note * A basic example of capacative sensing can be found in the STK BSP * (capsense demo). * * @param[in] acmp * Pointer to ACMP peripheral register block. * * @param[in] init * Pointer to initialization structure used to configure ACMP for capacative * sensing operation. ******************************************************************************/ void ACMP_CapsenseInit(ACMP_TypeDef *acmp, const ACMP_CapsenseInit_TypeDef *init) { /* Make sure the module exists on the selected chip */ EFM_ASSERT(ACMP_REF_VALID(acmp)); /* Make sure that vddLevel is within bounds */ EFM_ASSERT(init->vddLevel < 64); /* Make sure biasprog is within bounds */ EFM_ASSERT(init->biasProg < 16); /* Set control register. No need to set interrupt modes */ acmp->CTRL = (init->fullBias << _ACMP_CTRL_FULLBIAS_SHIFT) | (init->halfBias << _ACMP_CTRL_HALFBIAS_SHIFT) | (init->biasProg << _ACMP_CTRL_BIASPROG_SHIFT) | (init->warmTime << _ACMP_CTRL_WARMTIME_SHIFT) | (init->hysteresisLevel << _ACMP_CTRL_HYSTSEL_SHIFT); /* Select capacative sensing mode by selecting a resistor and enabling it */ acmp->INPUTSEL = (init->resistor << _ACMP_INPUTSEL_CSRESSEL_SHIFT) | ACMP_INPUTSEL_CSRESEN | (init->lowPowerReferenceEnabled << _ACMP_INPUTSEL_LPREF_SHIFT) | (init->vddLevel << _ACMP_INPUTSEL_VDDLEVEL_SHIFT) | ACMP_INPUTSEL_NEGSEL_CAPSENSE; /* Enable ACMP if requested. * Note: BITBAND_Peripheral() function is used for setting/clearing single * bit peripheral register bitfields. */ BITBAND_Peripheral(&(acmp->CTRL), (uint32_t)_ACMP_CTRL_EN_SHIFT, (uint32_t)init->enable); } /***************************************************************************//** * @brief * Sets the ACMP channel used for capacative sensing. * * @note * A basic example of capacative sensing can be found in the STK BSP * (capsense demo). * * @param[in] acmp * Pointer to ACMP peripheral register block. * * @param[in] channel * The ACMP channel to use for capacative sensing (Possel). ******************************************************************************/ void ACMP_CapsenseChannelSet(ACMP_TypeDef *acmp, ACMP_Channel_TypeDef channel) { /* Make sure that only external channels are used */ EFM_ASSERT(channel < _ACMP_INPUTSEL_NEGSEL_1V25); /* Set channel as positive channel in ACMP */ SET_BIT_FIELD(acmp->INPUTSEL, _ACMP_INPUTSEL_POSSEL_MASK, channel, _ACMP_INPUTSEL_POSSEL_SHIFT); } /***************************************************************************//** * @brief * Disables the ACMP. * * @param[in] acmp * Pointer to ACMP peripheral register block. ******************************************************************************/ void ACMP_Disable(ACMP_TypeDef *acmp) { acmp->CTRL &= ~ACMP_CTRL_EN; } /***************************************************************************//** * @brief * Enables the ACMP. * * @param[in] acmp * Pointer to ACMP peripheral register block. ******************************************************************************/ void ACMP_Enable(ACMP_TypeDef *acmp) { acmp->CTRL |= ACMP_CTRL_EN; } /***************************************************************************//** * @brief * Reset ACMP to same state as after a HW reset. * * @note * The ROUTE register is NOT reset by this function, in order to allow for * centralized setup of this feature. * * @param[in] acmp * Pointer to the ACMP peripheral register block. ******************************************************************************/ void ACMP_Reset(ACMP_TypeDef *acmp) { /* Make sure the module exists on the selected chip */ EFM_ASSERT(ACMP_REF_VALID(acmp)); acmp->CTRL = _ACMP_CTRL_RESETVALUE; acmp->INPUTSEL = _ACMP_INPUTSEL_RESETVALUE; acmp->IEN = _ACMP_IEN_RESETVALUE; acmp->IFC = _ACMP_IF_MASK; } /***************************************************************************//** * @brief * Sets up GPIO output from the ACMP. * * @note * GPIO must be enabled in the CMU before this function call, i.e. * @verbatim CMU_ClockEnable(cmuClock_GPIO, true); @endverbatim * * @param[in] acmp * Pointer to the ACMP peripheral register block. * * @param location * The pin location to use. See the datasheet for location to pin mappings. * * @param enable * Enable or disable pin output. * * @param invert * Invert output. ******************************************************************************/ void ACMP_GPIOSetup(ACMP_TypeDef *acmp, uint32_t location, bool enable, bool invert) { /* Sanity checking of location */ EFM_ASSERT(location < 4); /* Set GPIO inversion */ SET_BIT_FIELD(acmp->CTRL, _ACMP_CTRL_GPIOINV_MASK, invert, _ACMP_CTRL_GPIOINV_SHIFT); acmp->ROUTE = (location << _ACMP_ROUTE_LOCATION_SHIFT) | (enable << _ACMP_ROUTE_ACMPPEN_SHIFT); } /***************************************************************************//** * @brief * Sets which channels should be used in ACMP comparisons. * * @param[in] acmp * Pointer to the ACMP peripheral register block. * * @param negSel * Channel to use on the negative input to the ACMP. * * @param posSel * Channel to use on the positive input to the ACMP. ******************************************************************************/ void ACMP_ChannelSet(ACMP_TypeDef *acmp, ACMP_Channel_TypeDef negSel, ACMP_Channel_TypeDef posSel) { /* Make sure that only external channels are used as ACMP positive input */ EFM_ASSERT(posSel < _ACMP_INPUTSEL_NEGSEL_1V25); /* Sanity checking of ACMP negative input */ EFM_ASSERT(negSel <= _ACMP_INPUTSEL_NEGSEL_VDD); acmp->INPUTSEL = (acmp->INPUTSEL & ~(_ACMP_INPUTSEL_POSSEL_MASK | _ACMP_INPUTSEL_NEGSEL_MASK)) | (negSel << _ACMP_INPUTSEL_NEGSEL_SHIFT) | (posSel << _ACMP_INPUTSEL_POSSEL_SHIFT); } /***************************************************************************//** * @brief * * * @param[in] acmp * Pointer to the ACMP peripheral register block. * * @param[in] init * Pointer to initialization structure used to configure ACMP for capacative * sensing operation. ******************************************************************************/ void ACMP_Init(ACMP_TypeDef *acmp, const ACMP_Init_TypeDef *init) { /* Make sure the module exists on the selected chip */ EFM_ASSERT(ACMP_REF_VALID(acmp)); /* Make sure biasprog is within bounds */ EFM_ASSERT(init->biasProg < 16); /* Set control register. No need to set interrupt modes */ acmp->CTRL = (init->fullBias << _ACMP_CTRL_FULLBIAS_SHIFT) | (init->halfBias << _ACMP_CTRL_HALFBIAS_SHIFT) | (init->biasProg << _ACMP_CTRL_BIASPROG_SHIFT) | (init->interruptOnFallingEdge << _ACMP_CTRL_IFALL_SHIFT) | (init->interruptOnRisingEdge << _ACMP_CTRL_IRISE_SHIFT) | (init->warmTime << _ACMP_CTRL_WARMTIME_SHIFT) | (init->hysteresisLevel << _ACMP_CTRL_HYSTSEL_SHIFT) | (init->inactiveValue << _ACMP_CTRL_INACTVAL_SHIFT); acmp->INPUTSEL = (init->lowPowerReferenceEnabled << _ACMP_INPUTSEL_LPREF_SHIFT) | (init->vddLevel << _ACMP_INPUTSEL_VDDLEVEL_SHIFT); /* Enable ACMP if requested. * Note: BITBAND_Peripheral() function is used for setting/clearing single * bit peripheral register bitfields. */ BITBAND_Peripheral(&(acmp->CTRL), (uint32_t)_ACMP_CTRL_EN_SHIFT, (uint32_t)init->enable); } /** @} (end addtogroup ACMP) */ /** @} (end addtogroup EFM32_Library) */