/***************************************************************************//** * @file * @brief Analog Comparator (ACMP) 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. * ******************************************************************************/ #include "em_acmp.h" #if defined(ACMP_COUNT) && (ACMP_COUNT > 0) #include #include "em_bus.h" #include "sl_assert.h" #include "em_gpio.h" /***************************************************************************//** * @addtogroup acmp ACMP - Analog Comparator * @brief Analog comparator (ACMP) Peripheral API * * @details * The Analog Comparator is used to compare voltage of two analog inputs * with a digital output indicating which input voltage is higher. Inputs can * either be one of the selectable internal references or from external pins. * Response time and current consumption can be configured by * altering the current supply to the comparator. * * ACMP is available down to EM3 and is able to wake up the system when * input signals pass a certain threshold. Use @ref ACMP_IntEnable() to enable * an edge interrupt to use this functionality. * * This example shows how to use the em_acmp.h API for comparing an input * pin to an internal 2.5 V reference voltage. * * @if DOXYDOC_P1_DEVICE * @include em_acmp_compare_s0.c * @endif * * @if DOXYDOC_P2_DEVICE * @include em_acmp_compare_s1.c * @endif * * @if DOXYDOC_S2_DEVICE * @include em_acmp_compare_s2.c * @endif * * @note * ACMP can also be used to compare two separate input pins. * * @details * ACMP also contains specialized hardware for capacitive sensing. This * module contains the @ref ACMP_CapsenseInit() function to initialize * ACMP for capacitive sensing and the @ref ACMP_CapsenseChannelSet() function * to select the current capsense channel. * * For applications that require capacitive sensing it is recommended to use a * library, such as cslib, which is provided by Silicon Labs. * * @{ ******************************************************************************/ /******************************************************************************* ******************************* 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)) #elif (ACMP_COUNT == 3) #define ACMP_REF_VALID(ref) (((ref) == ACMP0) || ((ref) == ACMP1) || ((ref) == ACMP2)) #elif (ACMP_COUNT == 4) #define ACMP_REF_VALID(ref) (((ref) == ACMP0) \ || ((ref) == ACMP1) \ || ((ref) == ACMP2) \ || ((ref) == ACMP3)) #else #error Undefined number of analog comparators (ACMP). #endif /** The maximum value that can be inserted in the route location register * for the specific device. */ #if defined(_ACMP_ROUTE_LOCATION_LOC3) #define _ACMP_ROUTE_LOCATION_MAX _ACMP_ROUTE_LOCATION_LOC3 #elif defined(_ACMP_ROUTE_LOCATION_LOC2) #define _ACMP_ROUTE_LOCATION_MAX _ACMP_ROUTE_LOCATION_LOC2 #elif defined(_ACMP_ROUTE_LOCATION_LOC1) #define _ACMP_ROUTE_LOCATION_MAX _ACMP_ROUTE_LOCATION_LOC1 #elif defined(_ACMP_ROUTELOC0_OUTLOC_LOC31) #define _ACMP_ROUTE_LOCATION_MAX _ACMP_ROUTELOC0_OUTLOC_LOC31 #elif defined(_ACMP_ROUTELOC0_OUTLOC_MASK) #define _ACMP_ROUTE_LOCATION_MAX _ACMP_ROUTELOC0_OUTLOC_MASK #endif /** Map ACMP reference to index of device. */ #if (ACMP_COUNT == 1) #define ACMP_DEVICE_ID(acmp) ( \ (acmp) == ACMP0 ? 0 \ : 0) #elif (ACMP_COUNT == 2) #define ACMP_DEVICE_ID(acmp) ( \ (acmp) == ACMP0 ? 0 \ : (acmp) == ACMP1 ? 1 \ : 0) #endif /** @endcond */ /******************************************************************************* ************************** GLOBAL FUNCTIONS ******************************* ******************************************************************************/ /***************************************************************************//** * @brief * Set up ACMP for use in capacitive sense applications. * * @details * This function sets up ACMP for use in capacitive sense applications. * To use the capacitive sense functionality in the ACMP, use * the PRS output of the ACMP module to count the number of oscillations * in the capacitive sense circuit (possibly using a TIMER). * * @note * A basic example of capacitive sensing can be found in the STK BSP * (capsense demo). * * @cond DOXYDOC_S2_DEVICE * @note * A call to ACMP_CapsenseInit will enable and disable the ACMP peripheral, * which can cause side effects if it was previously set up. * @endcond * * @param[in] acmp * A pointer to the ACMP peripheral register block. * * @param[in] init * A pointer to the initialization structure used to configure ACMP for capacitive * sensing operation. ******************************************************************************/ void ACMP_CapsenseInit(ACMP_TypeDef *acmp, const ACMP_CapsenseInit_TypeDef *init) { EFM_ASSERT(ACMP_REF_VALID(acmp)); #if defined(_SILICON_LABS_32B_SERIES_2) EFM_ASSERT(init->vrefDiv < 64); EFM_ASSERT(init->biasProg <= (_ACMP_CFG_BIAS_MASK >> _ACMP_CFG_BIAS_SHIFT)); ACMP_Disable(acmp); acmp->CFG = (init->biasProg << _ACMP_CFG_BIAS_SHIFT) | (init->hysteresisLevel << _ACMP_CFG_HYST_SHIFT); acmp->CTRL = _ACMP_CTRL_RESETVALUE; ACMP_Enable(acmp); acmp->INPUTCTRL = (init->resistor << _ACMP_INPUTCTRL_CSRESSEL_SHIFT) | (init->vrefDiv << _ACMP_INPUTCTRL_VREFDIV_SHIFT) | (ACMP_INPUTCTRL_NEGSEL_CAPSENSE); if (!init->enable) { ACMP_Disable(acmp); } #elif defined(_SILICON_LABS_32B_SERIES_1) EFM_ASSERT(init->vddLevelLow < 64); EFM_ASSERT(init->vddLevelHigh < 64); EFM_ASSERT(init->biasProg <= (_ACMP_CTRL_BIASPROG_MASK >> _ACMP_CTRL_BIASPROG_SHIFT)); /* Set the control register. No need to set interrupt modes. */ acmp->CTRL = (init->fullBias << _ACMP_CTRL_FULLBIAS_SHIFT) | (init->biasProg << _ACMP_CTRL_BIASPROG_SHIFT) | ACMP_CTRL_ACCURACY_HIGH; acmp->HYSTERESIS0 = (init->vddLevelHigh << _ACMP_HYSTERESIS0_DIVVA_SHIFT) | (init->hysteresisLevel_0 << _ACMP_HYSTERESIS0_HYST_SHIFT); acmp->HYSTERESIS1 = (init->vddLevelLow << _ACMP_HYSTERESIS1_DIVVA_SHIFT) | (init->hysteresisLevel_1 << _ACMP_HYSTERESIS1_HYST_SHIFT); /* Select capacitive sensing mode by selecting a resistor and enabling it. */ acmp->INPUTSEL = (init->resistor << _ACMP_INPUTSEL_CSRESSEL_SHIFT) | ACMP_INPUTSEL_CSRESEN | ACMP_INPUTSEL_VASEL_VDD | ACMP_INPUTSEL_NEGSEL_VADIV; BUS_RegBitWrite(&acmp->CTRL, _ACMP_CTRL_EN_SHIFT, init->enable); #elif defined(_SILICON_LABS_32B_SERIES_0) EFM_ASSERT(init->vddLevel < 64); EFM_ASSERT(init->biasProg <= (_ACMP_CTRL_BIASPROG_MASK >> _ACMP_CTRL_BIASPROG_SHIFT)); /* Set the 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 capacitive 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; BUS_RegBitWrite(&acmp->CTRL, _ACMP_CTRL_EN_SHIFT, init->enable); #endif } /***************************************************************************//** * @brief * Set the ACMP channel used for capacitive sensing. * * @note * A basic example of capacitive sensing can be found in the STK BSP * (capsense demo). * * @cond DOXYDOC_S2_DEVICE * @note * Can only be called when the peripheral is enabled. * @endcond * * @param[in] acmp * A pointer to the ACMP peripheral register block. * * @param[in] channel * The ACMP channel to use for capacitive sensing (Possel). ******************************************************************************/ void ACMP_CapsenseChannelSet(ACMP_TypeDef *acmp, ACMP_Channel_TypeDef channel) { /* Make sure the module exists on the selected chip. */ EFM_ASSERT(ACMP_REF_VALID(acmp)); #if defined(_ACMP_INPUTSEL_POSSEL_CH7) /* Make sure that only external channels are used. */ EFM_ASSERT(channel <= _ACMP_INPUTSEL_POSSEL_CH7); #elif defined(_ACMP_INPUTCTRL_POSSEL_PD15) EFM_ASSERT(channel != _ACMP_INPUTCTRL_NEGSEL_CAPSENSE); EFM_ASSERT(_ACMP_INPUTCTRL_POSSEL_PA0 <= channel); EFM_ASSERT(channel <= _ACMP_INPUTCTRL_POSSEL_PD15); #endif #if defined(_ACMP_INPUTCTRL_MASK) /* Make sure that the ACMP is enabled before changing INPUTCTRL. */ EFM_ASSERT(acmp->EN & ACMP_EN_EN); while (acmp->SYNCBUSY != 0U) { /* Wait for synchronization to finish */ } /* Set channel as positive channel in ACMP */ BUS_RegMaskedWrite(&acmp->INPUTCTRL, _ACMP_INPUTCTRL_POSSEL_MASK, channel << _ACMP_INPUTCTRL_POSSEL_SHIFT); #else /* Set channel as a positive channel in ACMP. */ BUS_RegMaskedWrite(&acmp->INPUTSEL, _ACMP_INPUTSEL_POSSEL_MASK, channel << _ACMP_INPUTSEL_POSSEL_SHIFT); #endif } /***************************************************************************//** * @brief * Disable ACMP. * * @param[in] acmp * A pointer to the ACMP peripheral register block. ******************************************************************************/ void ACMP_Disable(ACMP_TypeDef *acmp) { /* Make sure the module exists on the selected chip. */ EFM_ASSERT(ACMP_REF_VALID(acmp)); #if defined(_ACMP_EN_MASK) while ((acmp->EN != 0U) && (acmp->SYNCBUSY != 0U)) { /* Wait for synchronization to finish */ } acmp->EN_CLR = ACMP_EN_EN; #if defined(_ACMP_EN_DISABLING_MASK) while (acmp->EN & _ACMP_EN_DISABLING_MASK) { // Wait for disabling to finish } #endif #else acmp->CTRL &= ~ACMP_CTRL_EN; #endif } /***************************************************************************//** * @brief * Enable ACMP. * * @param[in] acmp * A pointer to the ACMP peripheral register block. ******************************************************************************/ void ACMP_Enable(ACMP_TypeDef *acmp) { /* Make sure the module exists on the selected chip. */ EFM_ASSERT(ACMP_REF_VALID(acmp)); #if defined(_ACMP_EN_MASK) acmp->EN_SET = ACMP_EN_EN; #else acmp->CTRL |= ACMP_CTRL_EN; #endif } #if defined(_ACMP_EXTIFCTRL_MASK) /***************************************************************************//** * @brief * Select and enable external input. * * @details * This is used when an external module needs to take control of the ACMP * POSSEL field to configure the APORT input for the ACMP. Modules, * such as LESENSE, use this to change the ACMP input during a scan sequence. * * @param[in] acmp * A pointer to the ACMP peripheral register block. * * @param[in] aport * This parameter decides which APORT(s) the ACMP will use when it's * controlled by an external module. ******************************************************************************/ void ACMP_ExternalInputSelect(ACMP_TypeDef *acmp, ACMP_ExternalInput_Typedef aport) { acmp->EXTIFCTRL = (aport << _ACMP_EXTIFCTRL_APORTSEL_SHIFT) | ACMP_EXTIFCTRL_EN; while (!(acmp->STATUS & ACMP_STATUS_EXTIFACT)) { } } #endif /***************************************************************************//** * @brief * Reset ACMP to the same state that it was in after a hardware reset. * * @note * The GPIO ACMP ROUTE register is NOT reset by this function to allow for * centralized setup of this feature. * * @note * The peripheral may be enabled and disabled during reset. * * @param[in] acmp * A 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)); #if defined(_SILICON_LABS_32B_SERIES_2) #if defined(ACMP_SWRST_SWRST) acmp->SWRST_SET = ACMP_SWRST_SWRST; while (acmp->SWRST & _ACMP_SWRST_RESETTING_MASK) { } #else acmp->IEN = _ACMP_IEN_RESETVALUE; ACMP_Enable(acmp); acmp->INPUTCTRL = _ACMP_INPUTCTRL_RESETVALUE; ACMP_Disable(acmp); acmp->CFG = PM5507_ACMP_CFG_RESETVALUE; acmp->CTRL = _ACMP_CTRL_RESETVALUE; acmp->IF_CLR = _ACMP_IF_MASK; #endif #else // Series 0 and Series 1 devices acmp->IEN = _ACMP_IEN_RESETVALUE; acmp->CTRL = _ACMP_CTRL_RESETVALUE; acmp->INPUTSEL = _ACMP_INPUTSEL_RESETVALUE; #if defined(_ACMP_HYSTERESIS0_HYST_MASK) acmp->HYSTERESIS0 = _ACMP_HYSTERESIS0_RESETVALUE; acmp->HYSTERESIS1 = _ACMP_HYSTERESIS1_RESETVALUE; #endif acmp->IFC = _ACMP_IF_MASK; #endif } #if defined(_GPIO_ACMP_ROUTEEN_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 port * The GPIO port to use. * * @param pin * The GPIO pin to use. * * @param enable * Enable or disable pin output. * * @param invert * Invert output. ******************************************************************************/ void ACMP_GPIOSetup(ACMP_TypeDef *acmp, GPIO_Port_TypeDef port, unsigned int pin, bool enable, bool invert) { int acmpIndex = ACMP_DEVICE_ID(acmp); /* Make sure the module exists on the selected chip */ EFM_ASSERT(ACMP_REF_VALID(acmp)); /* Make sure that the port/pin combination is valid. */ EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin)); /* Set GPIO inversion */ acmp->CTRL = (acmp->CTRL & _ACMP_CTRL_NOTRDYVAL_MASK) | (invert << _ACMP_CTRL_GPIOINV_SHIFT); GPIO->ACMPROUTE[acmpIndex].ACMPOUTROUTE = (port << _GPIO_ACMP_ACMPOUTROUTE_PORT_SHIFT) | (pin << _GPIO_ACMP_ACMPOUTROUTE_PIN_SHIFT); GPIO->ACMPROUTE[acmpIndex].ROUTEEN = enable ? GPIO_ACMP_ROUTEEN_ACMPOUTPEN : 0; } #else /***************************************************************************//** * @brief * Set up GPIO output from 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 * A pointer to the ACMP peripheral register block. * * @param location * The pin location to use. See the data sheet 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) { /* Make sure the module exists on the selected chip */ EFM_ASSERT(ACMP_REF_VALID(acmp)); /* Sanity checking of location */ EFM_ASSERT(location <= _ACMP_ROUTE_LOCATION_MAX); /* Set GPIO inversion */ BUS_RegMaskedWrite(&acmp->CTRL, _ACMP_CTRL_GPIOINV_MASK, invert << _ACMP_CTRL_GPIOINV_SHIFT); #if defined(_ACMP_ROUTE_MASK) acmp->ROUTE = (location << _ACMP_ROUTE_LOCATION_SHIFT) | (enable << _ACMP_ROUTE_ACMPPEN_SHIFT); #endif #if defined(_ACMP_ROUTELOC0_MASK) acmp->ROUTELOC0 = location << _ACMP_ROUTELOC0_OUTLOC_SHIFT; acmp->ROUTEPEN = enable ? ACMP_ROUTEPEN_OUTPEN : 0; #endif } #endif /* defined(_GPIO_ACMP_ROUTEEN_MASK) */ /***************************************************************************//** * @brief * Set which channels should be used in ACMP comparisons. * * @cond DOXYDOC_S2_DEVICE * @note * Can only be called when the peripheral is enabled. * * @note * If GPIO is used for both posSel and negSel, they cannot both use even * or odd pins. * @endcond * * @param[in] acmp * A pointer to the ACMP peripheral register block. * * @param negSel * A channel to use on the negative input to the ACMP. * * @param posSel * A 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 the module exists on the selected chip. */ EFM_ASSERT(ACMP_REF_VALID(acmp)); /* Make sure that posSel and negSel channel selectors are valid. */ #if defined(_ACMP_INPUTSEL_NEGSEL_DAC0CH1) EFM_ASSERT(negSel <= _ACMP_INPUTSEL_NEGSEL_DAC0CH1); #elif defined(_ACMP_INPUTSEL_NEGSEL_CAPSENSE) EFM_ASSERT(negSel <= _ACMP_INPUTSEL_NEGSEL_CAPSENSE); #endif #if defined(_ACMP_INPUTSEL_POSSEL_CH7) EFM_ASSERT(posSel <= _ACMP_INPUTSEL_POSSEL_CH7); #endif /* Make sure that posSel and negSel channel selectors are valid. */ #if defined(_ACMP_INPUTCTRL_POSSEL_PD15) EFM_ASSERT(negSel <= _ACMP_INPUTCTRL_POSSEL_PD15); EFM_ASSERT(posSel <= _ACMP_INPUTCTRL_POSSEL_PD15); EFM_ASSERT(posSel != _ACMP_INPUTCTRL_NEGSEL_CAPSENSE); /* Make sure that posSel and negSel channel selectors don't both * use odd or even pins. */ #if (_SILICON_LABS_32B_SERIES_2_CONFIG > 2) EFM_ASSERT(!((((posSel >= _ACMP_INPUTCTRL_POSSEL_EXTPA) && (posSel <= _ACMP_INPUTCTRL_POSSEL_EXTPD)) || (posSel >= _ACMP_INPUTCTRL_POSSEL_PA0)) && (negSel >= _ACMP_INPUTCTRL_NEGSEL_PA0) && (posSel % 2 == negSel % 2))); #else EFM_ASSERT(!((posSel >= _ACMP_INPUTCTRL_POSSEL_PA0) && (negSel >= _ACMP_INPUTCTRL_NEGSEL_PA0) && (posSel % 2 == negSel % 2))); #endif #endif #if defined(_ACMP_INPUTCTRL_MASK) /* Make sure that the ACMP is enabled before changing INPUTCTRL. */ EFM_ASSERT(acmp->EN & ACMP_EN_EN); while (acmp->SYNCBUSY != 0U) { /* Wait for synchronization to finish */ } acmp->INPUTCTRL = (acmp->INPUTCTRL & ~(_ACMP_INPUTCTRL_POSSEL_MASK | _ACMP_INPUTCTRL_NEGSEL_MASK)) | (negSel << _ACMP_INPUTCTRL_NEGSEL_SHIFT) | (posSel << _ACMP_INPUTCTRL_POSSEL_SHIFT); #else acmp->INPUTSEL = (acmp->INPUTSEL & ~(_ACMP_INPUTSEL_POSSEL_MASK | _ACMP_INPUTSEL_NEGSEL_MASK)) | (negSel << _ACMP_INPUTSEL_NEGSEL_SHIFT) | (posSel << _ACMP_INPUTSEL_POSSEL_SHIFT); #endif } /***************************************************************************//** * @brief * Initialize ACMP. * * @cond DOXYDOC_S2_DEVICE * @note * A call to ACMP_Init can cause side effects since it can enable/disable * the peripheral. * @endcond * * @param[in] acmp * A pointer to the ACMP peripheral register block. * * @param[in] init * A pointer to the initialization structure used to configure ACMP. ******************************************************************************/ 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)); #if defined(_SILICON_LABS_32B_SERIES_2) EFM_ASSERT(init->biasProg <= (_ACMP_CFG_BIAS_MASK >> _ACMP_CFG_BIAS_SHIFT)); // PM-5507: enforce that biasProg is a functional value #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1) EFM_ASSERT(init->biasProg >= 4); #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3) // Allow customer to use BIASPROG in [2; 3] EFM_ASSERT(init->biasProg >= 2); #else // Allow customer to use BIASPROG in [0; 3] // but the implementation of the wait operation would be their responsibility #endif /* Make sure the ACMP is disabled since ACMP power source might be changed.*/ ACMP_Disable(acmp); acmp->CFG = (init->biasProg << _ACMP_CFG_BIAS_SHIFT) | (init->inputRange << _ACMP_CFG_INPUTRANGE_SHIFT) | (init->accuracy << _ACMP_CFG_ACCURACY_SHIFT) | (init->hysteresisLevel << _ACMP_CFG_HYST_SHIFT); acmp->CTRL = init->inactiveValue << _ACMP_CTRL_NOTRDYVAL_SHIFT; ACMP_Enable(acmp); BUS_RegMaskedWrite(&acmp->INPUTCTRL, _ACMP_INPUTCTRL_VREFDIV_MASK, init->vrefDiv << _ACMP_INPUTCTRL_VREFDIV_SHIFT); #elif defined(_SILICON_LABS_32B_SERIES_1) EFM_ASSERT(init->biasProg <= (_ACMP_CTRL_BIASPROG_MASK >> _ACMP_CTRL_BIASPROG_SHIFT)); /* Make sure the ACMP is disabled since ACMP power source might be changed.*/ ACMP_Disable(acmp); acmp->CTRL = (init->fullBias << _ACMP_CTRL_FULLBIAS_SHIFT) | (init->biasProg << _ACMP_CTRL_BIASPROG_SHIFT) | (init->interruptOnFallingEdge << _ACMP_CTRL_IFALL_SHIFT) | (init->interruptOnRisingEdge << _ACMP_CTRL_IRISE_SHIFT) | (init->inputRange << _ACMP_CTRL_INPUTRANGE_SHIFT) | (init->accuracy << _ACMP_CTRL_ACCURACY_SHIFT) | (init->powerSource << _ACMP_CTRL_PWRSEL_SHIFT) | (init->inactiveValue << _ACMP_CTRL_INACTVAL_SHIFT); acmp->INPUTSEL = init->vlpInput << _ACMP_INPUTSEL_VLPSEL_SHIFT; acmp->HYSTERESIS0 = init->hysteresisLevel_0; acmp->HYSTERESIS1 = init->hysteresisLevel_1; #elif defined(_SILICON_LABS_32B_SERIES_0) EFM_ASSERT(init->biasProg <= (_ACMP_CTRL_BIASPROG_MASK >> _ACMP_CTRL_BIASPROG_SHIFT)); /* Make sure the ACMP is disabled since ACMP power source might be changed.*/ ACMP_Disable(acmp); 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); #endif if (init->enable) { ACMP_Enable(acmp); } else { ACMP_Disable(acmp); } } #if defined(_ACMP_INPUTSEL_VASEL_MASK) /***************************************************************************//** * @brief * Set up the VA source. * * @param[in] acmp * A pointer to the ACMP peripheral register block. * * @param[in] vaconfig * A pointer to the structure used to configure the VA source. This structure * contains the input source and the 2 divider values. ******************************************************************************/ void ACMP_VASetup(ACMP_TypeDef *acmp, const ACMP_VAConfig_TypeDef *vaconfig) { EFM_ASSERT(vaconfig->div0 < 64); EFM_ASSERT(vaconfig->div1 < 64); BUS_RegMaskedWrite(&acmp->INPUTSEL, _ACMP_INPUTSEL_VASEL_MASK, vaconfig->input << _ACMP_INPUTSEL_VASEL_SHIFT); BUS_RegMaskedWrite(&acmp->HYSTERESIS0, _ACMP_HYSTERESIS0_DIVVA_MASK, vaconfig->div0 << _ACMP_HYSTERESIS0_DIVVA_SHIFT); BUS_RegMaskedWrite(&acmp->HYSTERESIS1, _ACMP_HYSTERESIS1_DIVVA_MASK, vaconfig->div1 << _ACMP_HYSTERESIS1_DIVVA_SHIFT); } #endif #if defined(_ACMP_INPUTSEL_VBSEL_MASK) /***************************************************************************//** * @brief * Set up the VB Source. * * @param[in] acmp * A pointer to the ACMP peripheral register block. * * @param[in] vbconfig * A pointer to the structure used to configure the VB source. This structure * contains the input source and the 2 divider values. ******************************************************************************/ void ACMP_VBSetup(ACMP_TypeDef *acmp, const ACMP_VBConfig_TypeDef *vbconfig) { EFM_ASSERT(vbconfig->div0 < 64); EFM_ASSERT(vbconfig->div1 < 64); BUS_RegMaskedWrite(&acmp->INPUTSEL, _ACMP_INPUTSEL_VBSEL_MASK, vbconfig->input << _ACMP_INPUTSEL_VBSEL_SHIFT); BUS_RegMaskedWrite(&acmp->HYSTERESIS0, _ACMP_HYSTERESIS0_DIVVB_MASK, vbconfig->div0 << _ACMP_HYSTERESIS0_DIVVB_SHIFT); BUS_RegMaskedWrite(&acmp->HYSTERESIS1, _ACMP_HYSTERESIS1_DIVVB_MASK, vbconfig->div1 << _ACMP_HYSTERESIS1_DIVVB_SHIFT); } #endif /** @} (end addtogroup acmp) */ #endif /* defined(ACMP_COUNT) && (ACMP_COUNT > 0) */