| /***************************************************************************//** |
| * @file em_opamp.c |
| * @brief Operational Amplifier (OPAMP) peripheral API |
| * @version 5.6.0 |
| ****************************************************************************** |
| * # License |
| * <b>Copyright 2016 Silicon Laboratories, Inc. 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_opamp.h" |
| #if ((defined(_SILICON_LABS_32B_SERIES_0) && defined(OPAMP_PRESENT) && (OPAMP_COUNT == 1)) \ |
| || (defined(_SILICON_LABS_32B_SERIES_1) && defined(VDAC_PRESENT) && (VDAC_COUNT > 0))) |
| |
| #include "em_system.h" |
| #include "em_assert.h" |
| |
| /***************************************************************************//** |
| * @addtogroup emlib |
| * @{ |
| ******************************************************************************/ |
| |
| /* *INDENT-OFF* */ |
| /***************************************************************************//** |
| * @addtogroup OPAMP |
| * @brief Operational Amplifier (OPAMP) peripheral API |
| * @details |
| * This module contains functions to: |
| * @li OPAMP_Enable() Configure and enable OPAMP. |
| * @li OPAMP_Disable() Disable OPAMP. |
| * |
| * @if DOXYDOC_P1_DEVICE |
| * All OPAMP functions assume that the DAC clock is running. If DAC is not |
| * used, the clock can be turned off when OPAMPs are configured. |
| * @elseif DOXYDOC_P2_DEVICE |
| * All OPAMP functions assume that the VDAC clock is running. If VDAC is not |
| * used, the clock can be turned off when the OPAMPs are configured. |
| * @endif |
| * |
| * If the available gain values don't suit the application at hand, the resistor |
| * ladders can be disabled and external gain programming resistors used. |
| * |
| * A number of predefined OPAMP setup macros are available for configuration |
| * of the most common OPAMP topologies (see figures below). |
| * |
| * @note |
| * <em>The terms POSPAD and NEGPAD in the figures are used to indicate that these |
| * pads should be connected to a suitable signal ground.</em> |
| * |
| * \n<b>Unity gain voltage follower.</b>\n |
| * @if DOXYDOC_P1_DEVICE |
| * Use predefined macros @ref OPA_INIT_UNITY_GAIN and |
| * @ref OPA_INIT_UNITY_GAIN_OPA2. |
| * @elseif DOXYDOC_P2_DEVICE |
| * Use predefined macro @ref OPA_INIT_UNITY_GAIN. |
| * @endif |
| * @verbatim |
| |
| |\ |
| ___________|+\ |
| | \_______ |
| ___|_ / | |
| | | / | |
| | |/ | |
| |___________| |
| @endverbatim |
| * |
| * \n<b>Non-inverting amplifier.</b>\n |
| * @if DOXYDOC_P1_DEVICE |
| * Use predefined macros @ref OPA_INIT_NON_INVERTING and |
| * @ref OPA_INIT_NON_INVERTING_OPA2. |
| * @elseif DOXYDOC_P2_DEVICE |
| * Use predefined macro @ref OPA_INIT_NON_INVERTING. |
| * @endif |
| * @verbatim |
| |
| |\ |
| ___________|+\ |
| | \_______ |
| ___|_ / | |
| | | / | |
| | |/ | |
| |_____R2____| |
| | |
| R1 |
| | |
| NEGPAD @endverbatim |
| * |
| * \n<b>Inverting amplifier.</b>\n |
| * @if DOXYDOC_P1_DEVICE |
| * Use predefined macros @ref OPA_INIT_INVERTING and |
| * @ref OPA_INIT_INVERTING_OPA2. |
| * @elseif DOXYDOC_P2_DEVICE |
| * Use predefined macro @ref OPA_INIT_INVERTING. |
| * @endif |
| * @verbatim |
| |
| _____R2____ |
| | | |
| | |\ | |
| ____R1_|___|_\ | |
| | \____|___ |
| ___| / |
| | |+/ |
| | |/ |
| | |
| POSPAD @endverbatim |
| * |
| * \n<b>Cascaded non-inverting amplifiers.</b>\n |
| * Use predefined macros @ref OPA_INIT_CASCADED_NON_INVERTING_OPA0, |
| * @ref OPA_INIT_CASCADED_NON_INVERTING_OPA1 and |
| * @ref OPA_INIT_CASCADED_NON_INVERTING_OPA2. |
| * @verbatim |
| |
| |\ |\ |\ |
| ___________|+\ OPA0 ___________|+\ OPA1 ___________|+\ OPA2 |
| | \_________| | \_________| | \_______ |
| ___|_ / | ___|_ / | ___|_ / | |
| | | / | | | / | | | / | |
| | |/ | | |/ | | |/ | |
| |_____R2____| |_____R2____| |_____R2____| |
| | | | |
| R1 R1 R1 |
| | | | |
| NEGPAD NEGPAD NEGPAD @endverbatim |
| * |
| * \n<b>Cascaded inverting amplifiers.</b>\n |
| * Use predefined macros @ref OPA_INIT_CASCADED_INVERTING_OPA0, |
| * @ref OPA_INIT_CASCADED_INVERTING_OPA1 and |
| * @ref OPA_INIT_CASCADED_INVERTING_OPA2. |
| * @verbatim |
| |
| _____R2____ _____R2____ _____R2____ |
| | | | | | | |
| | |\ | | |\ | | |\ | |
| ____R1_|___|_\ | ____R1_|___|_\ | ____R1_|___|_\ | |
| | \____|____| | \____|___| | \____|__ |
| ___| / ___| / ___| / |
| | |+/ OPA0 | |+/ OPA1 | |+/ OPA2 |
| | |/ | |/ | |/ |
| | | | |
| POSPAD POSPAD POSPAD @endverbatim |
| * |
| * \n<b>Differential driver with two opamp's.</b>\n |
| * Use predefined macros @ref OPA_INIT_DIFF_DRIVER_OPA0 and |
| * @ref OPA_INIT_DIFF_DRIVER_OPA1. |
| * @verbatim |
| |
| __________________________ |
| | + |
| | _____R2____ |
| |\ | | | |
| ___________|+\ OPA0 | | |\ OPA1 | |
| | \_________|____R1_|___|_\ | _ |
| ___|_ / | | \____|______ |
| | | / | ___| / |
| | |/ | | |+/ |
| |________________| | |/ |
| | |
| POSPAD @endverbatim |
| * |
| * \n<b>Differential receiver with three opamp's.</b>\n |
| * Use predefined macros @ref OPA_INIT_DIFF_RECEIVER_OPA0, |
| * @ref OPA_INIT_DIFF_RECEIVER_OPA1 and @ref OPA_INIT_DIFF_RECEIVER_OPA2. |
| * @verbatim |
| |
| |\ |
| __________|+\ OPA1 |
| _ | \_________ |
| ___|_ / | | _____R2____ |
| | | / | | | | |
| | |/ | | | |\ | |
| |___________| |____R1_|___|_\ | |
| | \____|___ |
| |\ ____R1_ ___| / |
| +__________|+\ OPA0 | | |+/ OPA2 |
| | \_________| | |/ |
| ___|_ / | R2 |
| | | / | | |
| | |/ | NEGPAD OPA0 |
| |___________| |
| @endverbatim |
| * |
| * @if DOXYDOC_P2_DEVICE |
| * \n<b>Instrumentation amplifier.</b>\n |
| * Use predefined macros @ref OPA_INIT_INSTR_AMP_OPA0 and |
| * @ref OPA_INIT_INSTR_AMP_OPA1. |
| * @verbatim |
| |
| |\ |
| __________|+\ OPA1 |
| | \______________ |
| ___|_ / | |
| | | / | |
| | |/ R2 |
| |____________| |
| | |
| R1 |
| | |
| R1 |
| ____________| |
| | | |
| | R2 |
| | |\ | |
| |___|+\ OPA0 | |
| | \_____|________ |
| __________|_ / |
| | / |
| |/ |
| |
| @endverbatim |
| * @endif |
| * |
| * @{ |
| ******************************************************************************/ |
| /* *INDENT-ON* */ |
| |
| /******************************************************************************* |
| ************************** GLOBAL FUNCTIONS ******************************* |
| ******************************************************************************/ |
| |
| /***************************************************************************//** |
| * @brief |
| * Disable an Operational Amplifier. |
| * |
| * @if DOXYDOC_P1_DEVICE |
| * @param[in] dac |
| * A pointer to the DAC peripheral register block. |
| * @elseif DOXYDOC_P2_DEVICE |
| * @param[in] dac |
| * A pointer to the VDAC peripheral register block. |
| * @endif |
| * |
| * |
| * @param[in] opa |
| * Selects an OPA, valid values are @ref OPA0, @ref OPA1, and @ref OPA2. |
| ******************************************************************************/ |
| void OPAMP_Disable( |
| #if defined(_SILICON_LABS_32B_SERIES_0) |
| DAC_TypeDef *dac, |
| #elif defined(_SILICON_LABS_32B_SERIES_1) |
| VDAC_TypeDef *dac, |
| #endif |
| OPAMP_TypeDef opa) |
| { |
| #if defined(_SILICON_LABS_32B_SERIES_0) |
| EFM_ASSERT(DAC_REF_VALID(dac)); |
| EFM_ASSERT(DAC_OPA_VALID(opa)); |
| |
| if (opa == OPA0) { |
| dac->CH0CTRL &= ~DAC_CH0CTRL_EN; |
| dac->OPACTRL &= ~DAC_OPACTRL_OPA0EN; |
| } else if (opa == OPA1) { |
| dac->CH1CTRL &= ~DAC_CH1CTRL_EN; |
| dac->OPACTRL &= ~DAC_OPACTRL_OPA1EN; |
| } else { /* OPA2 */ |
| dac->OPACTRL &= ~DAC_OPACTRL_OPA2EN; |
| } |
| |
| #elif defined(_SILICON_LABS_32B_SERIES_1) |
| EFM_ASSERT(VDAC_REF_VALID(dac)); |
| EFM_ASSERT(VDAC_OPA_VALID(opa)); |
| |
| if (opa == OPA0) { |
| #if defined(VDAC_STATUS_OPA0ENS) |
| dac->CMD |= VDAC_CMD_OPA0DIS; |
| while (dac->STATUS & VDAC_STATUS_OPA0ENS) { |
| } |
| #endif |
| #if defined(VDAC_STATUS_OPA1ENS) |
| } else if (opa == OPA1) { |
| dac->CMD |= VDAC_CMD_OPA1DIS; |
| while (dac->STATUS & VDAC_STATUS_OPA1ENS) { |
| } |
| #endif |
| #if defined(VDAC_STATUS_OPA2ENS) |
| } else if (opa == OPA2) { |
| dac->CMD |= VDAC_CMD_OPA2DIS; |
| while (dac->STATUS & VDAC_STATUS_OPA2ENS) { |
| } |
| #endif |
| } else { /* OPA3 */ |
| #if defined(VDAC_STATUS_OPA3ENS) |
| dac->CMD |= VDAC_CMD_OPA3DIS; |
| while (dac->STATUS & VDAC_STATUS_OPA3ENS) { |
| } |
| #endif |
| } |
| #endif |
| } |
| |
| /***************************************************************************//** |
| * @brief |
| * Configure and enable an Operational Amplifier. |
| * |
| * @if DOXYDOC_P1_DEVICE |
| * @note |
| * The value of the alternate output enable bit mask in the OPAMP_Init_TypeDef |
| * structure should consist of one or more of the |
| * DAC_OPA[opa#]MUX_OUTPEN_OUT[output#] flags |
| * (defined in \<part_name\>_dac.h) OR'ed together. @n @n |
| * For OPA0: |
| * @li DAC_OPA0MUX_OUTPEN_OUT0 |
| * @li DAC_OPA0MUX_OUTPEN_OUT1 |
| * @li DAC_OPA0MUX_OUTPEN_OUT2 |
| * @li DAC_OPA0MUX_OUTPEN_OUT3 |
| * @li DAC_OPA0MUX_OUTPEN_OUT4 |
| * |
| * For OPA1: |
| * @li DAC_OPA1MUX_OUTPEN_OUT0 |
| * @li DAC_OPA1MUX_OUTPEN_OUT1 |
| * @li DAC_OPA1MUX_OUTPEN_OUT2 |
| * @li DAC_OPA1MUX_OUTPEN_OUT3 |
| * @li DAC_OPA1MUX_OUTPEN_OUT4 |
| * |
| * For OPA2: |
| * @li DAC_OPA2MUX_OUTPEN_OUT0 |
| * @li DAC_OPA2MUX_OUTPEN_OUT1 |
| * |
| * E.g: @n |
| * init.outPen = DAC_OPA0MUX_OUTPEN_OUT0 | DAC_OPA0MUX_OUTPEN_OUT4; |
| * |
| * @param[in] dac |
| * A pointer to the DAC peripheral register block. |
| * @elseif DOXYDOC_P2_DEVICE |
| * @note |
| * The value of the alternate output enable bit mask in the OPAMP_Init_TypeDef |
| * structure should consist of one or more of the |
| * VDAC_OPA_OUT_ALTOUTPADEN_OUT[output#] flags |
| * (defined in \<part_name\>_vdac.h) OR'ed together. @n @n |
| * @li VDAC_OPA_OUT_ALTOUTPADEN_OUT0 |
| * @li VDAC_OPA_OUT_ALTOUTPADEN_OUT1 |
| * @li VDAC_OPA_OUT_ALTOUTPADEN_OUT2 |
| * @li VDAC_OPA_OUT_ALTOUTPADEN_OUT3 |
| * @li VDAC_OPA_OUT_ALTOUTPADEN_OUT4 |
| * |
| * For example: @n |
| * init.outPen = VDAC_OPA_OUT_ALTOUTPADEN_OUT0 | VDAC_OPA_OUT_ALTOUTPADEN_OUT4; |
| * @param[in] dac |
| * A pointer to the VDAC peripheral register block. |
| * @endif |
| * |
| * @param[in] opa |
| * Selects an OPA, valid values are @ref OPA0, @ref OPA1, and @ref OPA2. |
| * |
| * @param[in] init |
| * A pointer to a structure containing OPAMP initialization information. |
| ******************************************************************************/ |
| void OPAMP_Enable( |
| #if defined(_SILICON_LABS_32B_SERIES_0) |
| DAC_TypeDef *dac, |
| #elif defined(_SILICON_LABS_32B_SERIES_1) |
| VDAC_TypeDef *dac, |
| #endif |
| OPAMP_TypeDef opa, |
| const OPAMP_Init_TypeDef *init) |
| { |
| #if defined(_SILICON_LABS_32B_SERIES_0) |
| uint32_t gain; |
| |
| EFM_ASSERT(DAC_REF_VALID(dac)); |
| EFM_ASSERT(DAC_OPA_VALID(opa)); |
| EFM_ASSERT(init->bias <= (_DAC_BIASPROG_BIASPROG_MASK |
| >> _DAC_BIASPROG_BIASPROG_SHIFT)); |
| |
| if (opa == OPA0) { |
| EFM_ASSERT((init->outPen & ~_DAC_OPA0MUX_OUTPEN_MASK) == 0); |
| |
| dac->BIASPROG = (dac->BIASPROG |
| & ~(_DAC_BIASPROG_BIASPROG_MASK |
| | DAC_BIASPROG_HALFBIAS)) |
| | (init->bias << _DAC_BIASPROG_BIASPROG_SHIFT) |
| | (init->halfBias ? DAC_BIASPROG_HALFBIAS : 0); |
| |
| if (init->defaultOffset) { |
| gain = dac->CAL & _DAC_CAL_GAIN_MASK; |
| SYSTEM_GetCalibrationValue(&dac->CAL); |
| dac->CAL = (dac->CAL & ~_DAC_CAL_GAIN_MASK) | gain; |
| } else { |
| EFM_ASSERT(init->offset <= (_DAC_CAL_CH0OFFSET_MASK |
| >> _DAC_CAL_CH0OFFSET_SHIFT)); |
| |
| dac->CAL = (dac->CAL & ~_DAC_CAL_CH0OFFSET_MASK) |
| | (init->offset << _DAC_CAL_CH0OFFSET_SHIFT); |
| } |
| |
| dac->OPA0MUX = (uint32_t)init->resSel |
| | (uint32_t)init->outMode |
| | init->outPen |
| | (uint32_t)init->resInMux |
| | (uint32_t)init->negSel |
| | (uint32_t)init->posSel |
| | (init->nextOut ? DAC_OPA0MUX_NEXTOUT : 0) |
| | (init->npEn ? DAC_OPA0MUX_NPEN : 0) |
| | (init->ppEn ? DAC_OPA0MUX_PPEN : 0); |
| |
| dac->CH0CTRL |= DAC_CH0CTRL_EN; |
| dac->OPACTRL = (dac->OPACTRL |
| & ~(DAC_OPACTRL_OPA0SHORT |
| | _DAC_OPACTRL_OPA0LPFDIS_MASK |
| | DAC_OPACTRL_OPA0HCMDIS)) |
| | (init->shortInputs ? DAC_OPACTRL_OPA0SHORT : 0) |
| | (init->lpfPosPadDisable |
| ? DAC_OPACTRL_OPA0LPFDIS_PLPFDIS : 0) |
| | (init->lpfNegPadDisable |
| ? DAC_OPACTRL_OPA0LPFDIS_NLPFDIS : 0) |
| | (init->hcmDisable ? DAC_OPACTRL_OPA0HCMDIS : 0) |
| | DAC_OPACTRL_OPA0EN; |
| } else if ( opa == OPA1 ) { |
| EFM_ASSERT((init->outPen & ~_DAC_OPA1MUX_OUTPEN_MASK) == 0); |
| |
| dac->BIASPROG = (dac->BIASPROG |
| & ~(_DAC_BIASPROG_BIASPROG_MASK |
| | DAC_BIASPROG_HALFBIAS)) |
| | (init->bias << _DAC_BIASPROG_BIASPROG_SHIFT) |
| | (init->halfBias ? DAC_BIASPROG_HALFBIAS : 0); |
| |
| if (init->defaultOffset) { |
| gain = dac->CAL & _DAC_CAL_GAIN_MASK; |
| SYSTEM_GetCalibrationValue(&dac->CAL); |
| dac->CAL = (dac->CAL & ~_DAC_CAL_GAIN_MASK) | gain; |
| } else { |
| EFM_ASSERT(init->offset <= (_DAC_CAL_CH1OFFSET_MASK |
| >> _DAC_CAL_CH1OFFSET_SHIFT)); |
| |
| dac->CAL = (dac->CAL & ~_DAC_CAL_CH1OFFSET_MASK) |
| | (init->offset << _DAC_CAL_CH1OFFSET_SHIFT); |
| } |
| |
| dac->OPA1MUX = (uint32_t)init->resSel |
| | (uint32_t)init->outMode |
| | init->outPen |
| | (uint32_t)init->resInMux |
| | (uint32_t)init->negSel |
| | (uint32_t)init->posSel |
| | (init->nextOut ? DAC_OPA1MUX_NEXTOUT : 0) |
| | (init->npEn ? DAC_OPA1MUX_NPEN : 0) |
| | (init->ppEn ? DAC_OPA1MUX_PPEN : 0); |
| |
| dac->CH1CTRL |= DAC_CH1CTRL_EN; |
| dac->OPACTRL = (dac->OPACTRL |
| & ~(DAC_OPACTRL_OPA1SHORT |
| | _DAC_OPACTRL_OPA1LPFDIS_MASK |
| | DAC_OPACTRL_OPA1HCMDIS)) |
| | (init->shortInputs ? DAC_OPACTRL_OPA1SHORT : 0) |
| | (init->lpfPosPadDisable |
| ? DAC_OPACTRL_OPA1LPFDIS_PLPFDIS : 0) |
| | (init->lpfNegPadDisable |
| ? DAC_OPACTRL_OPA1LPFDIS_NLPFDIS : 0) |
| | (init->hcmDisable ? DAC_OPACTRL_OPA1HCMDIS : 0) |
| | DAC_OPACTRL_OPA1EN; |
| } else { /* OPA2 */ |
| EFM_ASSERT((init->posSel == DAC_OPA2MUX_POSSEL_DISABLE) |
| || (init->posSel == DAC_OPA2MUX_POSSEL_POSPAD) |
| || (init->posSel == DAC_OPA2MUX_POSSEL_OPA1INP) |
| || (init->posSel == DAC_OPA2MUX_POSSEL_OPATAP)); |
| |
| EFM_ASSERT((init->outMode & ~DAC_OPA2MUX_OUTMODE) == 0); |
| |
| EFM_ASSERT((init->outPen & ~_DAC_OPA2MUX_OUTPEN_MASK) == 0); |
| |
| dac->BIASPROG = (dac->BIASPROG |
| & ~(_DAC_BIASPROG_OPA2BIASPROG_MASK |
| | DAC_BIASPROG_OPA2HALFBIAS)) |
| | (init->bias << _DAC_BIASPROG_OPA2BIASPROG_SHIFT) |
| | (init->halfBias ? DAC_BIASPROG_OPA2HALFBIAS : 0); |
| |
| if (init->defaultOffset) { |
| SYSTEM_GetCalibrationValue(&dac->OPAOFFSET); |
| } else { |
| EFM_ASSERT(init->offset <= (_DAC_OPAOFFSET_OPA2OFFSET_MASK |
| >> _DAC_OPAOFFSET_OPA2OFFSET_SHIFT)); |
| dac->OPAOFFSET = (dac->OPAOFFSET & ~_DAC_OPAOFFSET_OPA2OFFSET_MASK) |
| | (init->offset << _DAC_OPAOFFSET_OPA2OFFSET_SHIFT); |
| } |
| |
| dac->OPA2MUX = (uint32_t)init->resSel |
| | (uint32_t)init->outMode |
| | init->outPen |
| | (uint32_t)init->resInMux |
| | (uint32_t)init->negSel |
| | (uint32_t)init->posSel |
| | (init->nextOut ? DAC_OPA2MUX_NEXTOUT : 0) |
| | (init->npEn ? DAC_OPA2MUX_NPEN : 0) |
| | (init->ppEn ? DAC_OPA2MUX_PPEN : 0); |
| |
| dac->OPACTRL = (dac->OPACTRL |
| & ~(DAC_OPACTRL_OPA2SHORT |
| | _DAC_OPACTRL_OPA2LPFDIS_MASK |
| | DAC_OPACTRL_OPA2HCMDIS)) |
| | (init->shortInputs ? DAC_OPACTRL_OPA2SHORT : 0) |
| | (init->lpfPosPadDisable |
| ? DAC_OPACTRL_OPA2LPFDIS_PLPFDIS : 0) |
| | (init->lpfNegPadDisable |
| ? DAC_OPACTRL_OPA2LPFDIS_NLPFDIS : 0) |
| | (init->hcmDisable ? DAC_OPACTRL_OPA2HCMDIS : 0) |
| | DAC_OPACTRL_OPA2EN; |
| } |
| |
| #elif defined(_SILICON_LABS_32B_SERIES_1) |
| uint32_t calData = 0; |
| uint32_t warmupTime; |
| |
| EFM_ASSERT(VDAC_REF_VALID(dac)); |
| EFM_ASSERT(VDAC_OPA_VALID(opa)); |
| EFM_ASSERT(init->settleTime <= (_VDAC_OPA_TIMER_SETTLETIME_MASK |
| >> _VDAC_OPA_TIMER_SETTLETIME_SHIFT)); |
| EFM_ASSERT(init->startupDly <= (_VDAC_OPA_TIMER_STARTUPDLY_MASK |
| >> _VDAC_OPA_TIMER_STARTUPDLY_SHIFT)); |
| EFM_ASSERT((init->outPen & ~_VDAC_OPA_OUT_ALTOUTPADEN_MASK) == 0); |
| EFM_ASSERT(!((init->gain3xEn == true) |
| && ((init->negSel == opaNegSelResTap) |
| || (init->posSel == opaPosSelResTap)))); |
| EFM_ASSERT((init->drvStr == opaDrvStrLowerAccLowStr) |
| || (init->drvStr == opaDrvStrLowAccLowStr) |
| || (init->drvStr == opaDrvStrHighAccHighStr) |
| || (init->drvStr == opaDrvStrHigherAccHighStr)); |
| |
| /* Disable OPAMP before writing to registers. */ |
| OPAMP_Disable(dac, opa); |
| |
| /* Get the calibration value based on OPAMP, Drive Strength, and INCBW. */ |
| switch (opa) { |
| #if defined(VDAC_STATUS_OPA0ENS) |
| case OPA0: |
| switch (init->drvStr) { |
| case opaDrvStrLowerAccLowStr: |
| calData = (init->ugBwScale ? DEVINFO->OPA0CAL0 : DEVINFO->OPA0CAL4); |
| break; |
| case opaDrvStrLowAccLowStr: |
| calData = (init->ugBwScale ? DEVINFO->OPA0CAL1 : DEVINFO->OPA0CAL5); |
| break; |
| case opaDrvStrHighAccHighStr: |
| calData = (init->ugBwScale ? DEVINFO->OPA0CAL2 : DEVINFO->OPA0CAL6); |
| break; |
| case opaDrvStrHigherAccHighStr: |
| calData = (init->ugBwScale ? DEVINFO->OPA0CAL3 : DEVINFO->OPA0CAL7); |
| break; |
| } |
| break; |
| #endif |
| |
| #if defined(VDAC_STATUS_OPA1ENS) |
| case OPA1: |
| switch (init->drvStr) { |
| case opaDrvStrLowerAccLowStr: |
| calData = (init->ugBwScale ? DEVINFO->OPA1CAL0 : DEVINFO->OPA1CAL4); |
| break; |
| case opaDrvStrLowAccLowStr: |
| calData = (init->ugBwScale ? DEVINFO->OPA1CAL1 : DEVINFO->OPA1CAL5); |
| break; |
| case opaDrvStrHighAccHighStr: |
| calData = (init->ugBwScale ? DEVINFO->OPA1CAL2 : DEVINFO->OPA1CAL6); |
| break; |
| case opaDrvStrHigherAccHighStr: |
| calData = (init->ugBwScale ? DEVINFO->OPA1CAL3 : DEVINFO->OPA1CAL7); |
| break; |
| } |
| break; |
| #endif |
| |
| #if defined(VDAC_STATUS_OPA2ENS) |
| case OPA2: |
| switch (init->drvStr) { |
| case opaDrvStrLowerAccLowStr: |
| calData = (init->ugBwScale ? DEVINFO->OPA2CAL0 : DEVINFO->OPA2CAL4); |
| break; |
| case opaDrvStrLowAccLowStr: |
| calData = (init->ugBwScale ? DEVINFO->OPA2CAL1 : DEVINFO->OPA2CAL5); |
| break; |
| case opaDrvStrHighAccHighStr: |
| calData = (init->ugBwScale ? DEVINFO->OPA2CAL2 : DEVINFO->OPA2CAL6); |
| break; |
| case opaDrvStrHigherAccHighStr: |
| calData = (init->ugBwScale ? DEVINFO->OPA2CAL3 : DEVINFO->OPA2CAL7); |
| break; |
| } |
| break; |
| #endif |
| |
| #if defined(VDAC_STATUS_OPA3ENS) |
| case OPA3: |
| switch (init->drvStr) { |
| case opaDrvStrLowerAccLowStr: |
| calData = (init->ugBwScale ? DEVINFO->OPA3CAL0 : DEVINFO->OPA3CAL4); |
| break; |
| case opaDrvStrLowAccLowStr: |
| calData = (init->ugBwScale ? DEVINFO->OPA3CAL1 : DEVINFO->OPA3CAL5); |
| break; |
| case opaDrvStrHighAccHighStr: |
| calData = (init->ugBwScale ? DEVINFO->OPA3CAL2 : DEVINFO->OPA3CAL6); |
| break; |
| case opaDrvStrHigherAccHighStr: |
| calData = (init->ugBwScale ? DEVINFO->OPA3CAL3 : DEVINFO->OPA3CAL7); |
| break; |
| } |
| break; |
| #endif |
| } |
| if (!init->defaultOffsetN) { |
| EFM_ASSERT(init->offsetN <= (_VDAC_OPA_CAL_OFFSETN_MASK |
| >> _VDAC_OPA_CAL_OFFSETN_SHIFT)); |
| calData = (calData & ~_VDAC_OPA_CAL_OFFSETN_MASK) |
| | (init->offsetN << _VDAC_OPA_CAL_OFFSETN_SHIFT); |
| } |
| if (!init->defaultOffsetP) { |
| EFM_ASSERT(init->offsetP <= (_VDAC_OPA_CAL_OFFSETP_MASK |
| >> _VDAC_OPA_CAL_OFFSETP_SHIFT)); |
| calData = (calData & ~_VDAC_OPA_CAL_OFFSETP_MASK) |
| | (init->offsetP << _VDAC_OPA_CAL_OFFSETP_SHIFT); |
| } |
| |
| dac->OPA[opa].CAL = (calData & _VDAC_OPA_CAL_MASK); |
| |
| dac->OPA[opa].MUX = (uint32_t)init->resSel |
| | (init->gain3xEn ? VDAC_OPA_MUX_GAIN3X : 0) |
| | (uint32_t)init->resInMux |
| | (uint32_t)init->negSel |
| | (uint32_t)init->posSel; |
| |
| dac->OPA[opa].OUT = (uint32_t)init->outMode |
| | (uint32_t)init->outPen; |
| |
| switch (init->drvStr) { |
| case opaDrvStrHigherAccHighStr: |
| warmupTime = 6; |
| break; |
| |
| case opaDrvStrHighAccHighStr: |
| warmupTime = 8; |
| break; |
| |
| case opaDrvStrLowAccLowStr: |
| warmupTime = 85; |
| break; |
| |
| case opaDrvStrLowerAccLowStr: |
| default: |
| warmupTime = 100; |
| break; |
| } |
| |
| dac->OPA[opa].TIMER = (uint32_t)(init->settleTime |
| << _VDAC_OPA_TIMER_SETTLETIME_SHIFT) |
| | (uint32_t)(warmupTime |
| << _VDAC_OPA_TIMER_WARMUPTIME_SHIFT) |
| | (uint32_t)(init->startupDly |
| << _VDAC_OPA_TIMER_STARTUPDLY_SHIFT); |
| |
| dac->OPA[opa].CTRL = (init->aportYMasterDisable |
| ? VDAC_OPA_CTRL_APORTYMASTERDIS : 0) |
| | (init->aportXMasterDisable |
| ? VDAC_OPA_CTRL_APORTXMASTERDIS : 0) |
| | (uint32_t)init->prsOutSel |
| | (uint32_t)init->prsSel |
| | (uint32_t)init->prsMode |
| | (init->prsEn ? VDAC_OPA_CTRL_PRSEN : 0) |
| | (init->halfDrvStr |
| ? VDAC_OPA_CTRL_OUTSCALE_HALF |
| : VDAC_OPA_CTRL_OUTSCALE_FULL) |
| | (init->hcmDisable ? VDAC_OPA_CTRL_HCMDIS : 0) |
| | (init->ugBwScale ? VDAC_OPA_CTRL_INCBW : 0) |
| | (uint32_t)init->drvStr; |
| |
| if (opa == OPA0) { |
| #if defined(VDAC_STATUS_OPA0ENS) |
| dac->CMD |= VDAC_CMD_OPA0EN; |
| #endif |
| #if defined(VDAC_STATUS_OPA1ENS) |
| } else if (opa == OPA1) { |
| dac->CMD |= VDAC_CMD_OPA1EN; |
| #endif |
| #if defined(VDAC_STATUS_OPA2ENS) |
| } else if (opa == OPA2) { |
| dac->CMD |= VDAC_CMD_OPA2EN; |
| #endif |
| #if defined(VDAC_STATUS_OPA3ENS) |
| } else { /* OPA3 */ |
| dac->CMD |= VDAC_CMD_OPA3EN; |
| #endif |
| } |
| |
| #endif |
| } |
| |
| /** @} (end addtogroup OPAMP) */ |
| /** @} (end addtogroup emlib) */ |
| |
| #endif /* (defined(OPAMP_PRESENT) && (OPAMP_COUNT == 1) |
| || defined(VDAC_PRESENT) && (VDAC_COUNT > 0) */ |