added prescaler for 16 bit pwm in LPC1347 target
Fork of mbed-dev by
Diff: targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_emu.c
- Revision:
- 50:a417edff4437
- Parent:
- 0:9b334a45a8ff
- Child:
- 144:ef7eb2e8f9f7
--- a/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_emu.c Wed Jan 13 12:45:11 2016 +0000 +++ b/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_emu.c Fri Jan 15 07:45:16 2016 +0000 @@ -1,10 +1,10 @@ /***************************************************************************//** * @file em_emu.c * @brief Energy Management Unit (EMU) Peripheral API - * @version 3.20.12 + * @version 4.2.1 ******************************************************************************* * @section License - * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b> + * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b> ******************************************************************************* * * Permission is granted to anyone to use this software for any purpose, @@ -30,6 +30,7 @@ * ******************************************************************************/ +#include <limits.h> #include "em_emu.h" #if defined( EMU_PRESENT ) && ( EMU_COUNT > 0 ) @@ -67,32 +68,50 @@ /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ /* Fix for errata EMU_E107 - non-WIC interrupt masks. */ -#if defined(_EFM32_GECKO_FAMILY) - #define ERRATA_FIX_EMU_E107_EN - #define NON_WIC_INT_MASK_0 (~(0x0dfc0323U)) - #define NON_WIC_INT_MASK_1 (~(0x0U)) -#elif defined(_EFM32_TINY_FAMILY) - #define ERRATA_FIX_EMU_E107_EN - #define NON_WIC_INT_MASK_0 (~(0x001be323U)) - #define NON_WIC_INT_MASK_1 (~(0x0U)) -#elif defined(_EFM32_GIANT_FAMILY) - #define ERRATA_FIX_EMU_E107_EN - #define NON_WIC_INT_MASK_0 (~(0xff020e63U)) - #define NON_WIC_INT_MASK_1 (~(0x00000046U)) -#elif defined(_EFM32_WONDER_FAMILY) - #define ERRATA_FIX_EMU_E107_EN - #define NON_WIC_INT_MASK_0 (~(0xff020e63U)) - #define NON_WIC_INT_MASK_1 (~(0x00000046U)) +#if defined( _EFM32_GECKO_FAMILY ) +#define ERRATA_FIX_EMU_E107_EN +#define NON_WIC_INT_MASK_0 (~(0x0dfc0323U)) +#define NON_WIC_INT_MASK_1 (~(0x0U)) + +#elif defined( _EFM32_TINY_FAMILY ) +#define ERRATA_FIX_EMU_E107_EN +#define NON_WIC_INT_MASK_0 (~(0x001be323U)) +#define NON_WIC_INT_MASK_1 (~(0x0U)) + +#elif defined( _EFM32_GIANT_FAMILY ) +#define ERRATA_FIX_EMU_E107_EN +#define NON_WIC_INT_MASK_0 (~(0xff020e63U)) +#define NON_WIC_INT_MASK_1 (~(0x00000046U)) + +#elif defined( _EFM32_WONDER_FAMILY ) +#define ERRATA_FIX_EMU_E107_EN +#define NON_WIC_INT_MASK_0 (~(0xff020e63U)) +#define NON_WIC_INT_MASK_1 (~(0x00000046U)) + #else /* Zero Gecko and future families are not affected by errata EMU_E107 */ #endif /* Fix for errata EMU_E108 - High Current Consumption on EM4 Entry. */ -#if defined(_EFM32_HAPPY_FAMILY) +#if defined( _EFM32_HAPPY_FAMILY ) #define ERRATA_FIX_EMU_E108_EN #endif /** @endcond */ + +#if defined( _EMU_DCDCCTRL_MASK ) +/* DCDCTODVDD output range min/max */ +#define PWRCFG_DCDCTODVDD_VMIN 1200 +#define PWRCFG_DCDCTODVDD_VMAX 3000 +typedef enum +{ + errataFixDcdcHsInit, + errataFixDcdcHsTrimSet, + errataFixDcdcHsLnWaitDone +} errataFixDcdcHs_TypeDef; +errataFixDcdcHs_TypeDef errataFixDcdcHsState = errataFixDcdcHsInit; +#endif + /******************************************************************************* ************************** LOCAL VARIABLES ******************************** ******************************************************************************/ @@ -108,6 +127,14 @@ * for oscillator control). */ static uint32_t cmuStatus; +#if defined( _CMU_HFCLKSTATUS_RESETVALUE ) +static uint16_t cmuHfclkStatus; +#endif +#if defined( _EMU_DCDCCTRL_MASK ) +static uint16_t dcdcMaxCurrent_mA; +static uint16_t dcdcOutput_mVout; +#endif + /** @endcond */ @@ -121,11 +148,10 @@ * @brief * Restore oscillators and core clock after having been in EM2 or EM3. ******************************************************************************/ -static void EMU_Restore(void) +static void emuRestore(void) { uint32_t oscEnCmd; uint32_t cmuLocked; - uint32_t statusClkSelMask; /* Although we could use the CMU API for most of the below handling, we */ /* would like this function to be as efficient as possible. */ @@ -149,52 +175,91 @@ #endif CMU->OSCENCMD = oscEnCmd; - statusClkSelMask = - (CMU_STATUS_HFRCOSEL | - CMU_STATUS_HFXOSEL | - CMU_STATUS_LFRCOSEL | -#if defined( CMU_STATUS_USHFRCODIV2SEL ) - CMU_STATUS_USHFRCODIV2SEL | -#endif - CMU_STATUS_LFXOSEL); +#if defined( _CMU_HFCLKSTATUS_RESETVALUE ) /* Restore oscillator used for clocking core */ - switch (cmuStatus & statusClkSelMask) + switch (cmuHfclkStatus & _CMU_HFCLKSTATUS_SELECTED_MASK) { - case CMU_STATUS_LFRCOSEL: - /* Wait for LFRCO to stabilize */ - while (!(CMU->STATUS & CMU_STATUS_LFRCORDY)) - ; - CMU->CMD = CMU_CMD_HFCLKSEL_LFRCO; - break; + case CMU_HFCLKSTATUS_SELECTED_LFRCO: + /* HFRCO could only be selected if the autostart HFXO feature is not + * enabled, otherwise the HFXO would be started and selected automatically. + * Note: this error hook helps catching erroneous oscillator configurations, + * when the AUTOSTARTSELEM0EM1 is set in CMU_HFXOCTRL. */ + if (!(CMU->HFXOCTRL & CMU_HFXOCTRL_AUTOSTARTSELEM0EM1)) + { + /* Wait for LFRCO to stabilize */ + while (!(CMU->STATUS & CMU_STATUS_LFRCORDY)) + ; + CMU->HFCLKSEL = CMU_HFCLKSEL_HF_LFRCO; + } + else + { + EFM_ASSERT(0); + } + break; + + case CMU_HFCLKSTATUS_SELECTED_LFXO: + /* Wait for LFXO to stabilize */ + while (!(CMU->STATUS & CMU_STATUS_LFXORDY)) + ; + CMU->HFCLKSEL = CMU_HFCLKSEL_HF_LFXO; + break; + + case CMU_HFCLKSTATUS_SELECTED_HFXO: + /* Wait for HFXO to stabilize */ + while (!(CMU->STATUS & CMU_STATUS_HFXORDY)) + ; + CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFXO; + break; - case CMU_STATUS_LFXOSEL: - /* Wait for LFXO to stabilize */ - while (!(CMU->STATUS & CMU_STATUS_LFXORDY)) - ; - CMU->CMD = CMU_CMD_HFCLKSEL_LFXO; - break; + default: /* CMU_HFCLKSTATUS_SELECTED_HFRCO */ + /* If core clock was HFRCO core clock, it is automatically restored to */ + /* state prior to entering energy mode. No need for further action. */ + break; + } +#else + switch (cmuStatus & (CMU_STATUS_HFRCOSEL + | CMU_STATUS_HFXOSEL + | CMU_STATUS_LFRCOSEL +#if defined( CMU_STATUS_USHFRCODIV2SEL ) + | CMU_STATUS_USHFRCODIV2SEL +#endif + | CMU_STATUS_LFXOSEL)) + { + case CMU_STATUS_LFRCOSEL: + /* Wait for LFRCO to stabilize */ + while (!(CMU->STATUS & CMU_STATUS_LFRCORDY)) + ; + CMU->CMD = CMU_CMD_HFCLKSEL_LFRCO; + break; - case CMU_STATUS_HFXOSEL: - /* Wait for HFXO to stabilize */ - while (!(CMU->STATUS & CMU_STATUS_HFXORDY)) - ; - CMU->CMD = CMU_CMD_HFCLKSEL_HFXO; - break; + case CMU_STATUS_LFXOSEL: + /* Wait for LFXO to stabilize */ + while (!(CMU->STATUS & CMU_STATUS_LFXORDY)) + ; + CMU->CMD = CMU_CMD_HFCLKSEL_LFXO; + break; + + case CMU_STATUS_HFXOSEL: + /* Wait for HFXO to stabilize */ + while (!(CMU->STATUS & CMU_STATUS_HFXORDY)) + ; + CMU->CMD = CMU_CMD_HFCLKSEL_HFXO; + break; #if defined( CMU_STATUS_USHFRCODIV2SEL ) - case CMU_STATUS_USHFRCODIV2SEL: - /* Wait for USHFRCO to stabilize */ - while (!(CMU->STATUS & CMU_STATUS_USHFRCORDY)) - ; - CMU->CMD = _CMU_CMD_HFCLKSEL_USHFRCODIV2; - break; + case CMU_STATUS_USHFRCODIV2SEL: + /* Wait for USHFRCO to stabilize */ + while (!(CMU->STATUS & CMU_STATUS_USHFRCORDY)) + ; + CMU->CMD = _CMU_CMD_HFCLKSEL_USHFRCODIV2; + break; #endif - default: /* CMU_STATUS_HFRCOSEL */ - /* If core clock was HFRCO core clock, it is automatically restored to */ - /* state prior to entering energy mode. No need for further action. */ - break; + default: /* CMU_STATUS_HFRCOSEL */ + /* If core clock was HFRCO core clock, it is automatically restored to */ + /* state prior to entering energy mode. No need for further action. */ + break; } /* If HFRCO was disabled before entering Energy Mode, turn it off again */ @@ -203,7 +268,7 @@ { CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS; } - +#endif /* Restore CMU register locking */ if (cmuLocked) { @@ -212,27 +277,34 @@ } +#if defined( ERRATA_FIX_EMU_E107_EN ) /* Get enable conditions for errata EMU_E107 fix. */ -#if defined(ERRATA_FIX_EMU_E107_EN) static __INLINE bool getErrataFixEmuE107En(void) { - /* SYSTEM_ChipRevisionGet could have been used here, but we would like a faster implementation in this case. */ + /* SYSTEM_ChipRevisionGet could have been used here, but we would like a + * faster implementation in this case. + */ uint16_t majorMinorRev; /* CHIP MAJOR bit [3:0] */ - majorMinorRev = (((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK) >> _ROMTABLE_PID0_REVMAJOR_SHIFT) << 8); + majorMinorRev = ((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK) + >> _ROMTABLE_PID0_REVMAJOR_SHIFT) + << 8; /* CHIP MINOR bit [7:4] */ - majorMinorRev |= (((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK) >> _ROMTABLE_PID2_REVMINORMSB_SHIFT) << 4); + majorMinorRev |= ((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK) + >> _ROMTABLE_PID2_REVMINORMSB_SHIFT) + << 4; /* CHIP MINOR bit [3:0] */ - majorMinorRev |= ((ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK) >> _ROMTABLE_PID3_REVMINORLSB_SHIFT); + majorMinorRev |= (ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK) + >> _ROMTABLE_PID3_REVMINORLSB_SHIFT; -#if defined(_EFM32_GECKO_FAMILY) +#if defined( _EFM32_GECKO_FAMILY ) return (majorMinorRev <= 0x0103); -#elif defined(_EFM32_TINY_FAMILY) +#elif defined( _EFM32_TINY_FAMILY ) return (majorMinorRev <= 0x0102); -#elif defined(_EFM32_GIANT_FAMILY) +#elif defined( _EFM32_GIANT_FAMILY ) return (majorMinorRev <= 0x0103) || (majorMinorRev == 0x0204); -#elif defined(_EFM32_WONDER_FAMILY) +#elif defined( _EFM32_WONDER_FAMILY ) return (majorMinorRev == 0x0100); #else /* Zero Gecko and future families are not affected by errata EMU_E107 */ @@ -241,6 +313,50 @@ } #endif + +#if defined( _EMU_DCDCCTRL_MASK ) +/* LP prepare / LN restore P/NFET count */ +static void maxCurrentUpdate(void); +#define DCDC_LP_PFET_CNT 7 +#define DCDC_LP_NFET_CNT 15 +void dcdcFetCntSet(bool lpModeSet) +{ + uint32_t tmp; + static uint32_t emuDcdcMiscCtrlReg; + + if (lpModeSet) + { + emuDcdcMiscCtrlReg = EMU->DCDCMISCCTRL; + tmp = EMU->DCDCMISCCTRL + & ~(_EMU_DCDCMISCCTRL_PFETCNT_MASK | _EMU_DCDCMISCCTRL_NFETCNT_MASK); + tmp |= (DCDC_LP_PFET_CNT << _EMU_DCDCMISCCTRL_PFETCNT_SHIFT) + | (DCDC_LP_NFET_CNT << _EMU_DCDCMISCCTRL_NFETCNT_SHIFT); + EMU->DCDCMISCCTRL = tmp; + maxCurrentUpdate(); + } + else + { + EMU->DCDCMISCCTRL = emuDcdcMiscCtrlReg; + maxCurrentUpdate(); + } +} + +void dcdcHsFixLnBlock(void) +{ +#define EMU_DCDCSTATUS (* (volatile uint32_t *)(EMU_BASE + 0x7C)) + if (errataFixDcdcHsState == errataFixDcdcHsTrimSet) + { + /* Wait for LNRUNNING */ + if ((EMU->DCDCCTRL & ~_EMU_DCDCCTRL_DCDCMODE_MASK) == EMU_DCDCCTRL_DCDCMODE_LOWNOISE) + { + while (!(EMU_DCDCSTATUS & (0x1 << 16))); + } + errataFixDcdcHsState = errataFixDcdcHsLnWaitDone; + } +} +#endif + + /** @endcond */ @@ -281,6 +397,11 @@ * If a debugger is attached, the AUXHFRCO will not be disabled if enabled * upon entering EM2. It will thus remain enabled when returning to EM0 * regardless of the @p restore parameter. + * @par + * If HFXO autostart and select is enabled by using CMU_HFXOAutostartEnable(), + * the starting and selecting of the core clocks will be identical to the user + * independently of the value of the @p restore parameter when waking up on + * the wakeup sources corresponding to the autostart and select setting. * * @param[in] restore * @li true - restore oscillators and clocks, see function details. @@ -291,7 +412,7 @@ ******************************************************************************/ void EMU_EnterEM2(bool restore) { -#if defined(ERRATA_FIX_EMU_E107_EN) +#if defined( ERRATA_FIX_EMU_E107_EN ) bool errataFixEmuE107En; uint32_t nonWicIntEn[2]; #endif @@ -299,13 +420,16 @@ /* Auto-update CMU status just in case before entering energy mode. */ /* This variable is normally kept up-to-date by the CMU API. */ cmuStatus = CMU->STATUS; +#if defined( _CMU_HFCLKSTATUS_RESETVALUE ) + cmuHfclkStatus = (uint16_t)(CMU->HFCLKSTATUS); +#endif - /* Enter Cortex-M3 deep sleep mode */ + /* Enter Cortex deep sleep mode */ SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; /* Fix for errata EMU_E107 - store non-WIC interrupt enable flags. Disable the enabled non-WIC interrupts. */ -#if defined(ERRATA_FIX_EMU_E107_EN) +#if defined( ERRATA_FIX_EMU_E107_EN ) errataFixEmuE107En = getErrataFixEmuE107En(); if (errataFixEmuE107En) { @@ -318,10 +442,19 @@ } #endif +#if defined( _EMU_DCDCCTRL_MASK ) + dcdcFetCntSet(true); + dcdcHsFixLnBlock(); +#endif + __WFI(); +#if defined( _EMU_DCDCCTRL_MASK ) + dcdcFetCntSet(false); +#endif + /* Fix for errata EMU_E107 - restore state of non-WIC interrupt enable flags. */ -#if defined(ERRATA_FIX_EMU_E107_EN) +#if defined( ERRATA_FIX_EMU_E107_EN ) if (errataFixEmuE107En) { NVIC->ISER[0] = nonWicIntEn[0]; @@ -334,12 +467,17 @@ /* Restore oscillators/clocks if specified */ if (restore) { - EMU_Restore(); + emuRestore(); } /* If not restoring, and original clock was not HFRCO, we have to */ /* update CMSIS core clock variable since core clock has changed */ /* to using HFRCO. */ +#if defined( _CMU_HFCLKSTATUS_RESETVALUE ) + else if ((cmuHfclkStatus & _CMU_HFCLKSTATUS_SELECTED_MASK) + != CMU_HFCLKSTATUS_SELECTED_HFRCO) +#else else if (!(cmuStatus & CMU_STATUS_HFRCOSEL)) +#endif { SystemCoreClockUpdate(); } @@ -392,7 +530,7 @@ { uint32_t cmuLocked; -#if defined(ERRATA_FIX_EMU_E107_EN) +#if defined( ERRATA_FIX_EMU_E107_EN ) bool errataFixEmuE107En; uint32_t nonWicIntEn[2]; #endif @@ -400,6 +538,9 @@ /* Auto-update CMU status just in case before entering energy mode. */ /* This variable is normally kept up-to-date by the CMU API. */ cmuStatus = CMU->STATUS; +#if defined( _CMU_HFCLKSTATUS_RESETVALUE ) + cmuHfclkStatus = (uint16_t)(CMU->HFCLKSTATUS); +#endif /* CMU registers may be locked */ cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED; @@ -414,12 +555,12 @@ CMU_Lock(); } - /* Enter Cortex-M3 deep sleep mode */ + /* Enter Cortex deep sleep mode */ SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; /* Fix for errata EMU_E107 - store non-WIC interrupt enable flags. Disable the enabled non-WIC interrupts. */ -#if defined(ERRATA_FIX_EMU_E107_EN) +#if defined( ERRATA_FIX_EMU_E107_EN ) errataFixEmuE107En = getErrataFixEmuE107En(); if (errataFixEmuE107En) { @@ -433,10 +574,19 @@ } #endif +#if defined( _EMU_DCDCCTRL_MASK ) + dcdcFetCntSet(true); + dcdcHsFixLnBlock(); +#endif + __WFI(); +#if defined( _EMU_DCDCCTRL_MASK ) + dcdcFetCntSet(false); +#endif + /* Fix for errata EMU_E107 - restore state of non-WIC interrupt enable flags. */ -#if defined(ERRATA_FIX_EMU_E107_EN) +#if defined( ERRATA_FIX_EMU_E107_EN ) if (errataFixEmuE107En) { NVIC->ISER[0] = nonWicIntEn[0]; @@ -449,12 +599,17 @@ /* Restore oscillators/clocks if specified */ if (restore) { - EMU_Restore(); + emuRestore(); } /* If not restoring, and original clock was not HFRCO, we have to */ /* update CMSIS core clock variable since core clock has changed */ /* to using HFRCO. */ +#if defined( _CMU_HFCLKSTATUS_RESETVALUE ) + else if ((cmuHfclkStatus & _CMU_HFCLKSTATUS_SELECTED_MASK) + != CMU_HFCLKSTATUS_SELECTED_HFRCO) +#else else if (!(cmuStatus & CMU_STATUS_HFRCOSEL)) +#endif { SystemCoreClockUpdate(); } @@ -471,27 +626,46 @@ void EMU_EnterEM4(void) { int i; - uint32_t em4seq2; - uint32_t em4seq3; - em4seq2 = (EMU->CTRL & ~_EMU_CTRL_EM4CTRL_MASK) | (2 << _EMU_CTRL_EM4CTRL_SHIFT); - em4seq3 = (EMU->CTRL & ~_EMU_CTRL_EM4CTRL_MASK) | (3 << _EMU_CTRL_EM4CTRL_SHIFT); +#if defined( _EMU_EM4CTRL_EM4ENTRY_SHIFT ) + uint32_t em4seq2 = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4ENTRY_MASK) + | (2 << _EMU_EM4CTRL_EM4ENTRY_SHIFT); + uint32_t em4seq3 = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4ENTRY_MASK) + | (3 << _EMU_EM4CTRL_EM4ENTRY_SHIFT); +#else + uint32_t em4seq2 = (EMU->CTRL & ~_EMU_CTRL_EM4CTRL_MASK) + | (2 << _EMU_CTRL_EM4CTRL_SHIFT); + uint32_t em4seq3 = (EMU->CTRL & ~_EMU_CTRL_EM4CTRL_MASK) + | (3 << _EMU_CTRL_EM4CTRL_SHIFT); +#endif /* Make sure register write lock is disabled */ EMU_Unlock(); -#if defined(ERRATA_FIX_EMU_E108_EN) +#if defined( ERRATA_FIX_EMU_E108_EN ) /* Fix for errata EMU_E108 - High Current Consumption on EM4 Entry. */ __disable_irq(); *(volatile uint32_t *)0x400C80E4 = 0; #endif +#if defined( _EMU_DCDCCTRL_MASK ) + dcdcFetCntSet(true); + dcdcHsFixLnBlock(); +#endif + for (i = 0; i < 4; i++) { +#if defined( _EMU_EM4CTRL_EM4ENTRY_SHIFT ) + EMU->EM4CTRL = em4seq2; + EMU->EM4CTRL = em4seq3; + } + EMU->EM4CTRL = em4seq2; +#else EMU->CTRL = em4seq2; EMU->CTRL = em4seq3; } EMU->CTRL = em4seq2; +#endif } @@ -502,7 +676,7 @@ * @param[in] blocks * Specifies a logical OR of bits indicating memory blocks to power down. * Bit 0 selects block 1, bit 1 selects block 2, etc. Memory block 0 cannot - * be disabled. Please refer to the EFM32 reference manual for available + * be disabled. Please refer to the reference manual for available * memory blocks for a device. * * @note @@ -512,10 +686,28 @@ ******************************************************************************/ void EMU_MemPwrDown(uint32_t blocks) { -#if defined(_EMU_MEMCTRL_RESETVALUE) - EFM_ASSERT(blocks <= _EMU_MEMCTRL_MASK); +#if defined( _EMU_MEMCTRL_POWERDOWN_MASK ) + EFM_ASSERT(blocks <= (_EMU_MEMCTRL_POWERDOWN_MASK + >> _EMU_MEMCTRL_POWERDOWN_SHIFT)); + EMU->MEMCTRL = blocks; +#elif defined( _EMU_MEMCTRL_RAMPOWERDOWN_MASK ) \ + && defined( _EMU_MEMCTRL_RAMHPOWERDOWN_MASK ) \ + && defined( _EMU_MEMCTRL_SEQRAMPOWERDOWN_MASK ) + EFM_ASSERT((blocks & (_EMU_MEMCTRL_RAMPOWERDOWN_MASK + | _EMU_MEMCTRL_RAMHPOWERDOWN_MASK + | _EMU_MEMCTRL_SEQRAMPOWERDOWN_MASK)) + == blocks); EMU->MEMCTRL = blocks; + +#elif defined( _EMU_MEMCTRL_RAMPOWERDOWN_MASK ) + EFM_ASSERT((blocks & _EMU_MEMCTRL_RAMPOWERDOWN_MASK) == blocks); + EMU->MEMCTRL = blocks; + +#elif defined( _EMU_RAM0CTRL_RAMPOWERDOWN_MASK ) + EFM_ASSERT((blocks & _EMU_RAM0CTRL_RAMPOWERDOWN_MASK) == blocks); + EMU->RAM0CTRL = blocks; + #else (void)blocks; #endif @@ -545,10 +737,12 @@ { /* Fetch current configuration */ cmuStatus = CMU->STATUS; +#if defined( _CMU_HFCLKSTATUS_RESETVALUE ) + cmuHfclkStatus = (uint16_t)(CMU->HFCLKSTATUS); +#endif } -#if defined( _EMU_CTRL_EMVREG_MASK ) || defined( _EMU_CTRL_EM23VREG_MASK ) /***************************************************************************//** * @brief * Update EMU module with Energy Mode 2 and 3 configuration @@ -559,15 +753,18 @@ void EMU_EM23Init(EMU_EM23Init_TypeDef *em23Init) { #if defined( _EMU_CTRL_EMVREG_MASK ) - EMU->CTRL = em23Init->em23Vreg ? (EMU->CTRL | EMU_CTRL_EMVREG) : (EMU->CTRL & ~EMU_CTRL_EMVREG); + EMU->CTRL = em23Init->em23VregFullEn ? (EMU->CTRL | EMU_CTRL_EMVREG) + : (EMU->CTRL & ~EMU_CTRL_EMVREG); #elif defined( _EMU_CTRL_EM23VREG_MASK ) - EMU->CTRL = em23Init->em23Vreg ? (EMU->CTRL | EMU_CTRL_EM23VREG) : (EMU->CTRL & ~EMU_CTRL_EM23VREG); + EMU->CTRL = em23Init->em23VregFullEn ? (EMU->CTRL | EMU_CTRL_EM23VREG) + : (EMU->CTRL & ~EMU_CTRL_EM23VREG); +#else + (void)em23Init; #endif } -#endif -#if defined( _EMU_EM4CONF_MASK ) +#if defined( _EMU_EM4CONF_MASK ) || defined( _EMU_EM4CTRL_MASK ) /***************************************************************************//** * @brief * Update EMU module with Energy Mode 4 configuration @@ -577,30 +774,49 @@ ******************************************************************************/ void EMU_EM4Init(EMU_EM4Init_TypeDef *em4Init) { +#if defined( _EMU_EM4CONF_MASK ) + /* Init for platforms with EMU->EM4CONF register */ uint32_t em4conf = EMU->EM4CONF; /* Clear fields that will be reconfigured */ - em4conf &= ~( - _EMU_EM4CONF_LOCKCONF_MASK | - _EMU_EM4CONF_OSC_MASK | - _EMU_EM4CONF_BURTCWU_MASK | - _EMU_EM4CONF_VREGEN_MASK); + em4conf &= ~(_EMU_EM4CONF_LOCKCONF_MASK + | _EMU_EM4CONF_OSC_MASK + | _EMU_EM4CONF_BURTCWU_MASK + | _EMU_EM4CONF_VREGEN_MASK); /* Configure new settings */ - em4conf |= ( - (em4Init->lockConfig << _EMU_EM4CONF_LOCKCONF_SHIFT) | - (em4Init->osc) | - (em4Init->buRtcWakeup << _EMU_EM4CONF_BURTCWU_SHIFT) | - (em4Init->vreg << _EMU_EM4CONF_VREGEN_SHIFT)); + em4conf |= (em4Init->lockConfig << _EMU_EM4CONF_LOCKCONF_SHIFT) + | (em4Init->osc) + | (em4Init->buRtcWakeup << _EMU_EM4CONF_BURTCWU_SHIFT) + | (em4Init->vreg << _EMU_EM4CONF_VREGEN_SHIFT); /* Apply configuration. Note that lock can be set after this stage. */ EMU->EM4CONF = em4conf; + +#elif defined( _EMU_EM4CTRL_MASK ) + /* Init for platforms with EMU->EM4CTRL register */ + + uint32_t em4ctrl = EMU->EM4CTRL; + + em4ctrl &= ~(_EMU_EM4CTRL_RETAINLFXO_MASK + | _EMU_EM4CTRL_RETAINLFRCO_MASK + | _EMU_EM4CTRL_RETAINULFRCO_MASK + | _EMU_EM4CTRL_EM4STATE_MASK + | _EMU_EM4CTRL_EM4IORETMODE_MASK); + + em4ctrl |= (em4Init->retainLfxo ? EMU_EM4CTRL_RETAINLFXO : 0) + | (em4Init->retainLfrco ? EMU_EM4CTRL_RETAINLFRCO : 0) + | (em4Init->retainUlfrco ? EMU_EM4CTRL_RETAINULFRCO : 0) + | (em4Init->em4State ? EMU_EM4CTRL_EM4STATE_EM4H : 0) + | (em4Init->pinRetentionMode); + + EMU->EM4CTRL = em4ctrl; +#endif } #endif #if defined( BU_PRESENT ) - /***************************************************************************//** * @brief * Configure Backup Power Domain settings @@ -613,16 +829,15 @@ uint32_t reg; /* Set power connection configuration */ - reg = EMU->PWRCONF & ~( - _EMU_PWRCONF_PWRRES_MASK| - _EMU_PWRCONF_VOUTSTRONG_MASK| - _EMU_PWRCONF_VOUTMED_MASK| - _EMU_PWRCONF_VOUTWEAK_MASK); + reg = EMU->PWRCONF & ~(_EMU_PWRCONF_PWRRES_MASK + | _EMU_PWRCONF_VOUTSTRONG_MASK + | _EMU_PWRCONF_VOUTMED_MASK + | _EMU_PWRCONF_VOUTWEAK_MASK); - reg |= (bupdInit->resistor| - (bupdInit->voutStrong << _EMU_PWRCONF_VOUTSTRONG_SHIFT)| - (bupdInit->voutMed << _EMU_PWRCONF_VOUTMED_SHIFT)| - (bupdInit->voutWeak << _EMU_PWRCONF_VOUTWEAK_SHIFT)); + reg |= bupdInit->resistor + | (bupdInit->voutStrong << _EMU_PWRCONF_VOUTSTRONG_SHIFT) + | (bupdInit->voutMed << _EMU_PWRCONF_VOUTMED_SHIFT) + | (bupdInit->voutWeak << _EMU_PWRCONF_VOUTWEAK_SHIFT); EMU->PWRCONF = reg; @@ -637,18 +852,17 @@ EMU->BUACT = reg; /* Set power control configuration */ - reg = EMU->BUCTRL & ~( - _EMU_BUCTRL_PROBE_MASK| - _EMU_BUCTRL_BODCAL_MASK| - _EMU_BUCTRL_STATEN_MASK| - _EMU_BUCTRL_EN_MASK); + reg = EMU->BUCTRL & ~(_EMU_BUCTRL_PROBE_MASK + | _EMU_BUCTRL_BODCAL_MASK + | _EMU_BUCTRL_STATEN_MASK + | _EMU_BUCTRL_EN_MASK); /* Note use of ->enable to both enable BUPD, use BU_VIN pin input and release reset */ - reg |= (bupdInit->probe| - (bupdInit->bodCal << _EMU_BUCTRL_BODCAL_SHIFT)| - (bupdInit->statusPinEnable << _EMU_BUCTRL_STATEN_SHIFT)| - (bupdInit->enable << _EMU_BUCTRL_EN_SHIFT)); + reg |= bupdInit->probe + | (bupdInit->bodCal << _EMU_BUCTRL_BODCAL_SHIFT) + | (bupdInit->statusPinEnable << _EMU_BUCTRL_STATEN_SHIFT) + | (bupdInit->enable << _EMU_BUCTRL_EN_SHIFT); /* Enable configuration */ EMU->BUCTRL = reg; @@ -657,7 +871,7 @@ EMU_BUPinEnable(bupdInit->enable); /* If enable is true, release BU reset, if not keep reset asserted */ - BITBAND_Peripheral(&(RMU->CTRL), _RMU_CTRL_BURSTEN_SHIFT, !bupdInit->enable); + BUS_RegBitWrite(&(RMU->CTRL), _RMU_CTRL_BURSTEN_SHIFT, !bupdInit->enable); } @@ -671,16 +885,19 @@ ******************************************************************************/ void EMU_BUThresholdSet(EMU_BODMode_TypeDef mode, uint32_t value) { + EFM_ASSERT(value<8); EFM_ASSERT(value<=(_EMU_BUACT_BUEXTHRES_MASK>>_EMU_BUACT_BUEXTHRES_SHIFT)); switch(mode) { - case emuBODMode_Active: - EMU->BUACT = (EMU->BUACT & ~(_EMU_BUACT_BUEXTHRES_MASK))|(value<<_EMU_BUACT_BUEXTHRES_SHIFT); - break; - case emuBODMode_Inactive: - EMU->BUINACT = (EMU->BUINACT & ~(_EMU_BUINACT_BUENTHRES_MASK))|(value<<_EMU_BUINACT_BUENTHRES_SHIFT); - break; + case emuBODMode_Active: + EMU->BUACT = (EMU->BUACT & ~_EMU_BUACT_BUEXTHRES_MASK) + | (value<<_EMU_BUACT_BUEXTHRES_SHIFT); + break; + case emuBODMode_Inactive: + EMU->BUINACT = (EMU->BUINACT & ~_EMU_BUINACT_BUENTHRES_MASK) + | (value<<_EMU_BUINACT_BUENTHRES_SHIFT); + break; } } @@ -695,22 +912,894 @@ ******************************************************************************/ void EMU_BUThresRangeSet(EMU_BODMode_TypeDef mode, uint32_t value) { + EFM_ASSERT(value < 4); EFM_ASSERT(value<=(_EMU_BUACT_BUEXRANGE_MASK>>_EMU_BUACT_BUEXRANGE_SHIFT)); switch(mode) { - case emuBODMode_Active: - EMU->BUACT = (EMU->BUACT & ~(_EMU_BUACT_BUEXRANGE_MASK))|(value<<_EMU_BUACT_BUEXRANGE_SHIFT); - break; - case emuBODMode_Inactive: - EMU->BUINACT = (EMU->BUINACT & ~(_EMU_BUINACT_BUENRANGE_MASK))|(value<<_EMU_BUINACT_BUENRANGE_SHIFT); - break; + case emuBODMode_Active: + EMU->BUACT = (EMU->BUACT & ~_EMU_BUACT_BUEXRANGE_MASK) + | (value<<_EMU_BUACT_BUEXRANGE_SHIFT); + break; + case emuBODMode_Inactive: + EMU->BUINACT = (EMU->BUINACT & ~_EMU_BUINACT_BUENRANGE_MASK) + | (value<<_EMU_BUINACT_BUENRANGE_SHIFT); + break; + } +} +#endif + + +#if defined( _EMU_DCDCCTRL_MASK ) + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +/***************************************************************************//** + * @brief + * Load DCDC calibration constants from DI page. Const means calibration + * data that does not change depending on other configuration parameters. + * + * @return + * False if calibration registers are locked + ******************************************************************************/ +static bool ConstCalibrationLoad(void) +{ + uint32_t val; + volatile uint32_t *reg; + + /* DI calib data in flash */ + volatile uint32_t* const diCal_EMU_DCDCLNFREQCTRL = (volatile uint32_t *)(0x0FE08038); + volatile uint32_t* const diCal_EMU_DCDCLNVCTRL = (volatile uint32_t *)(0x0FE08040); + volatile uint32_t* const diCal_EMU_DCDCLPCTRL = (volatile uint32_t *)(0x0FE08048); + volatile uint32_t* const diCal_EMU_DCDCLPVCTRL = (volatile uint32_t *)(0x0FE08050); + volatile uint32_t* const diCal_EMU_DCDCTRIM0 = (volatile uint32_t *)(0x0FE08058); + volatile uint32_t* const diCal_EMU_DCDCTRIM1 = (volatile uint32_t *)(0x0FE08060); + + if (DEVINFO->DCDCLPVCTRL0 != UINT_MAX) + { + val = *(diCal_EMU_DCDCLNFREQCTRL + 1); + reg = (volatile uint32_t *)*diCal_EMU_DCDCLNFREQCTRL; + *reg = val; + + val = *(diCal_EMU_DCDCLNVCTRL + 1); + reg = (volatile uint32_t *)*diCal_EMU_DCDCLNVCTRL; + *reg = val; + + val = *(diCal_EMU_DCDCLPCTRL + 1); + reg = (volatile uint32_t *)*diCal_EMU_DCDCLPCTRL; + *reg = val; + + val = *(diCal_EMU_DCDCLPVCTRL + 1); + reg = (volatile uint32_t *)*diCal_EMU_DCDCLPVCTRL; + *reg = val; + + val = *(diCal_EMU_DCDCTRIM0 + 1); + reg = (volatile uint32_t *)*diCal_EMU_DCDCTRIM0; + *reg = val; + + val = *(diCal_EMU_DCDCTRIM1 + 1); + reg = (volatile uint32_t *)*diCal_EMU_DCDCTRIM1; + *reg = val; + + return true; + } + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; +} + + +/***************************************************************************//** + * @brief + * Set recommended and validated current optimization settings + * + ******************************************************************************/ +void ValidatedConfigSet(void) +{ +#define EMU_DCDCSMCTRL (* (volatile uint32_t *)(EMU_BASE + 0x44)) + + uint32_t dcdcTiming; + SYSTEM_PartFamily_TypeDef family; + SYSTEM_ChipRevision_TypeDef rev; + + /* Enable duty cycling of the bias */ + EMU->DCDCLPCTRL |= EMU_DCDCLPCTRL_LPVREFDUTYEN; + + /* Set low-noise RCO for EFM32 and EFR32 */ +#if defined( _EFR_DEVICE ) + /* 7MHz is recommended for all EFR32 parts with DCDC */ + EMU->DCDCLNFREQCTRL = (EMU->DCDCLNFREQCTRL & ~_EMU_DCDCLNFREQCTRL_RCOBAND_MASK) + | (EMU_DcdcLnRcoBand_7MHz << _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT); +#else + /* 3MHz is recommended for all EFM32 parts with DCDC */ + EMU->DCDCLNFREQCTRL = (EMU->DCDCLNFREQCTRL & ~_EMU_DCDCLNFREQCTRL_RCOBAND_MASK) + | (EMU_DcdcLnRcoBand_3MHz << _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT); +#endif + + EMU->DCDCTIMING &= ~_EMU_DCDCTIMING_DUTYSCALE_MASK; + + family = SYSTEM_GetFamily(); + SYSTEM_ChipRevisionGet(&rev); + if ((((family >= systemPartFamilyMighty1P) + && (family <= systemPartFamilyFlex1V)) + || (family == systemPartFamilyEfm32Pearl1B) + || (family == systemPartFamilyEfm32Jade1B)) + && ((rev.major == 1) && (rev.minor < 3)) + && (errataFixDcdcHsState == errataFixDcdcHsInit)) + { + /* LPCMPWAITDIS = 1 */ + EMU_DCDCSMCTRL |= 1; + + dcdcTiming = EMU->DCDCTIMING; + dcdcTiming &= ~(_EMU_DCDCTIMING_LPINITWAIT_MASK + |_EMU_DCDCTIMING_LNWAIT_MASK + |_EMU_DCDCTIMING_BYPWAIT_MASK); + + dcdcTiming |= ((180 << _EMU_DCDCTIMING_LPINITWAIT_SHIFT) + | (12 << _EMU_DCDCTIMING_LNWAIT_SHIFT) + | (180 << _EMU_DCDCTIMING_BYPWAIT_SHIFT)); + EMU->DCDCTIMING = dcdcTiming; + + errataFixDcdcHsState = errataFixDcdcHsTrimSet; } } + +/***************************************************************************//** + * @brief + * Calculate and update EMU->DCDCMISCCTRL for maximum DCDC current based + * on the slice configuration and user set maximum. + ******************************************************************************/ +static void maxCurrentUpdate(void) +{ + uint32_t lncLimImSel; + uint32_t lpcLimImSel; + uint32_t pFetCnt; + + pFetCnt = (EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_PFETCNT_MASK) + >> _EMU_DCDCMISCCTRL_PFETCNT_SHIFT; + + /* Equation from Reference Manual section 11.5.20, in the register + field description for LNCLIMILIMSEL and LPCLIMILIMSEL. */ + lncLimImSel = (dcdcMaxCurrent_mA / (5 * (pFetCnt + 1))) - 1; + /* 80mA as recommended in Application Note AN0948 */ + lpcLimImSel = (80 / (5 * (pFetCnt + 1))) - 1; + + lncLimImSel <<= _EMU_DCDCMISCCTRL_LNCLIMILIMSEL_SHIFT; + lpcLimImSel <<= _EMU_DCDCMISCCTRL_LPCLIMILIMSEL_SHIFT; + EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_EMU_DCDCMISCCTRL_LNCLIMILIMSEL_MASK + | _EMU_DCDCMISCCTRL_LPCLIMILIMSEL_MASK)) + | (lncLimImSel | lpcLimImSel); +} + + +/***************************************************************************//** + * @brief + * Set static variable that holds the user set maximum current. Update + * DCDC configuration. + * + * @param[in] mAmaxCurrent + * Maximum allowed current drawn by the DCDC from VREGVDD in mA. + ******************************************************************************/ +static void maxCurrentSet(uint32_t mAmaxCurrent) +{ + dcdcMaxCurrent_mA = mAmaxCurrent; + maxCurrentUpdate(); +} + + +/***************************************************************************//** + * @brief + * Load EMU_DCDCLPCTRL_LPCMPHYSSEL depending on LP bias, LP feedback + * attenuation and DEVINFOREV. + * + * @param[in] attSet + * LP feedback attenuation. + * @param[in] lpCmpBias + * lpCmpBias selection + ******************************************************************************/ +static bool LpCmpHystCalibrationLoad(bool lpAttenuation, uint32_t lpCmpBias) +{ + uint8_t devinfoRev; + uint32_t lpcmpHystSel; + + /* Get calib data revision */ + devinfoRev = SYSTEM_GetDevinfoRev(); + + /* Load LPATT indexed calibration data */ + if (devinfoRev < 4) + { + lpcmpHystSel = DEVINFO->DCDCLPCMPHYSSEL0; + + if (lpAttenuation) + { + lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT1_MASK) + >> _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT1_SHIFT; + } + else + { + lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT0_MASK) + >> _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT0_SHIFT; + } + } + /* devinfoRev >= 4 + Load LPCMPBIAS indexed calibration data */ + else + { + lpcmpHystSel = DEVINFO->DCDCLPCMPHYSSEL1; + switch (lpCmpBias) + { + case _EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS0: + lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS0_MASK) + >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS0_SHIFT; + break; + + case _EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS1: + lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS1_MASK) + >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS1_SHIFT; + break; + + case _EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS2: + lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS2_MASK) + >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS2_SHIFT; + break; + + case _EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS3: + lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS3_MASK) + >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS3_SHIFT; + break; + + default: + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; + } + } + + /* Make sure the sel value is within the field range. */ + lpcmpHystSel <<= _EMU_DCDCLPCTRL_LPCMPHYSSEL_SHIFT; + if (lpcmpHystSel & ~_EMU_DCDCLPCTRL_LPCMPHYSSEL_MASK) + { + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; + } + EMU->DCDCLPCTRL = (EMU->DCDCLPCTRL & ~_EMU_DCDCLPCTRL_LPCMPHYSSEL_MASK) | lpcmpHystSel; + + return true; +} + + +/** @endcond */ + +/***************************************************************************//** + * @brief + * Set DCDC regulator operating mode + * + * @param[in] dcdcMode + * DCDC mode + ******************************************************************************/ +void EMU_DCDCModeSet(EMU_DcdcMode_TypeDef dcdcMode) +{ + while(EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY); + BUS_RegBitWrite(&EMU->DCDCCLIMCTRL, _EMU_DCDCCLIMCTRL_BYPLIMEN_SHIFT, dcdcMode == emuDcdcMode_Bypass ? 0 : 1); + EMU->DCDCCTRL = (EMU->DCDCCTRL & ~_EMU_DCDCCTRL_DCDCMODE_MASK) | dcdcMode; +} + + +/***************************************************************************//** + * @brief + * Configure DCDC regulator + * + * @note + * Use the function EMU_DCDCPowerDown() to if the power circuit is configured + * for NODCDC as decribed in Section 11.3.4.3 in the Reference Manual. + * + * @param[in] dcdcInit + * DCDC initialization structure + * + * @return + * True if initialization parameters are valid + ******************************************************************************/ +bool EMU_DCDCInit(EMU_DCDCInit_TypeDef *dcdcInit) +{ + uint32_t lpCmpBiasSel; + + /* Set external power configuration. This enables writing to the other + DCDC registers. */ + EMU->PWRCFG = dcdcInit->powerConfig; + + /* EMU->PWRCFG is write-once and POR reset only. Check that + we could set the desired power configuration. */ + if ((EMU->PWRCFG & _EMU_PWRCFG_PWRCFG_MASK) != dcdcInit->powerConfig) + { + /* If this assert triggers unexpectedly, please power cycle the + kit to reset the power configuration. */ + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; + } + + /* Load DCDC calibration data from the DI page */ + ConstCalibrationLoad(); + + /* Check current parameters */ + EFM_ASSERT(dcdcInit->maxCurrent_mA <= 200); + EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= dcdcInit->maxCurrent_mA); + + /* DCDC low-noise supports max 200mA */ + if (dcdcInit->dcdcMode == emuDcdcMode_LowNoise) + { + EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= 200); + } + + /* EM2, 3 and 4 current above 100uA is not supported */ + EFM_ASSERT(dcdcInit->em234LoadCurrent_uA <= 100); + + /* Decode LP comparator bias for EM0/1 and EM2/3 */ + lpCmpBiasSel = EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS1; + if (dcdcInit->em234LoadCurrent_uA <= 10) + { + lpCmpBiasSel = EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS0; + } + + /* Set DCDC low-power mode comparator bias selection */ + EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_EMU_DCDCMISCCTRL_LPCMPBIAS_MASK + | _EMU_DCDCMISCCTRL_LNFORCECCM_MASK)) + | ((uint32_t)lpCmpBiasSel + | (uint32_t)dcdcInit->lnTransientMode); + + /* Set recommended and validated current optimization settings */ + ValidatedConfigSet(); + + /* Set the maximum current that the DCDC can draw from the power source */ + maxCurrentSet(dcdcInit->maxCurrent_mA); + + /* Optimize LN slice based on given load current estimate */ + EMU_DCDCOptimizeSlice(dcdcInit->em01LoadCurrent_mA); + + /* Set DCDC output voltage */ + dcdcOutput_mVout = dcdcInit->mVout; + if (!EMU_DCDCOutputVoltageSet(dcdcOutput_mVout, true, true)) + { + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; + } + + /* Set EM0 DCDC operating mode. Output voltage set in EMU_DCDCOutputVoltageSet() + above takes effect if mode is changed from bypass here. */ + EMU_DCDCModeSet(dcdcInit->dcdcMode); + + /* Select analog peripheral power supply */ + BUS_RegBitWrite(&EMU->PWRCTRL, _EMU_PWRCTRL_ANASW_SHIFT, dcdcInit->anaPeripheralPower ? 1 : 0); + + return true; +} + + +/***************************************************************************//** + * @brief + * Set DCDC output voltage + * + * @param[in] mV + * Target DCDC output voltage in mV + * + * @return + * True if the mV parameter is valid + ******************************************************************************/ +bool EMU_DCDCOutputVoltageSet(uint32_t mV, + bool setLpVoltage, + bool setLnVoltage) +{ +#if defined( _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_MASK ) + + bool validOutVoltage; + uint8_t lnMode; + bool attSet; + uint32_t attMask; + uint32_t vrefLow = 0; + uint32_t vrefHigh = 0; + uint32_t vrefVal = 0; + uint32_t mVlow = 0; + uint32_t mVhigh = 0; + uint32_t vrefShift; + uint32_t lpcmpBias; + volatile uint32_t* ctrlReg; + + /* Check that the set voltage is within valid range. + Voltages are obtained from the datasheet. */ + validOutVoltage = false; + if ((EMU->PWRCFG & _EMU_PWRCFG_PWRCFG_MASK) == EMU_PWRCFG_PWRCFG_DCDCTODVDD) + { + validOutVoltage = ((mV >= PWRCFG_DCDCTODVDD_VMIN) + && (mV <= PWRCFG_DCDCTODVDD_VMAX)); + } + + if (!validOutVoltage) + { + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; + } + + /* Populate both LP and LN registers, set control reg pointer and VREF shift. */ + for (lnMode = 0; lnMode <= 1; lnMode++) + { + if (((lnMode == 0) && !setLpVoltage) + || ((lnMode == 1) && !setLnVoltage)) + { + continue; + } + + ctrlReg = (lnMode ? &EMU->DCDCLNVCTRL : &EMU->DCDCLPVCTRL); + vrefShift = (lnMode ? _EMU_DCDCLNVCTRL_LNVREF_SHIFT + : _EMU_DCDCLPVCTRL_LPVREF_SHIFT); + + /* Set attenuation to use */ + attSet = (mV > 1800); + if (attSet) + { + mVlow = 1800; + mVhigh = 3000; + attMask = (lnMode ? EMU_DCDCLNVCTRL_LNATT : EMU_DCDCLPVCTRL_LPATT); + } + else + { + mVlow = 1200; + mVhigh = 1800; + attMask = 0; + } + + /* Get 2-point calib data from DEVINFO, calculate trimming and set voltege */ + if (lnMode) + { + /* Set low-noise DCDC output voltage tuning */ + if (attSet) + { + vrefLow = DEVINFO->DCDCLNVCTRL0; + vrefHigh = (vrefLow & _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_MASK) + >> _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_SHIFT; + vrefLow = (vrefLow & _DEVINFO_DCDCLNVCTRL0_1V8LNATT1_MASK) + >> _DEVINFO_DCDCLNVCTRL0_1V8LNATT1_SHIFT; + } + else + { + vrefLow = DEVINFO->DCDCLNVCTRL0; + vrefHigh = (vrefLow & _DEVINFO_DCDCLNVCTRL0_1V8LNATT0_MASK) + >> _DEVINFO_DCDCLNVCTRL0_1V8LNATT0_SHIFT; + vrefLow = (vrefLow & _DEVINFO_DCDCLNVCTRL0_1V2LNATT0_MASK) + >> _DEVINFO_DCDCLNVCTRL0_1V2LNATT0_SHIFT; + } + } + else + { + /* Set low-power DCDC output voltage tuning */ + + /* Get LPCMPBIAS and make sure masks are not overlayed */ + lpcmpBias = EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LPCMPBIAS_MASK; + EFM_ASSERT(!(_EMU_DCDCMISCCTRL_LPCMPBIAS_MASK & attMask)); + switch (attMask | lpcmpBias) + { + case EMU_DCDCLPVCTRL_LPATT | EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS0: + vrefLow = DEVINFO->DCDCLPVCTRL2; + vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS0_MASK) + >> _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS0_SHIFT; + vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS0_MASK) + >> _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS0_SHIFT; + break; + + case EMU_DCDCLPVCTRL_LPATT | EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS1: + vrefLow = DEVINFO->DCDCLPVCTRL2; + vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS1_MASK) + >> _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS1_SHIFT; + vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS1_MASK) + >> _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS1_SHIFT; + break; + + case EMU_DCDCLPVCTRL_LPATT | EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS2: + vrefLow = DEVINFO->DCDCLPVCTRL3; + vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS2_MASK) + >> _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS2_SHIFT; + vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS2_MASK) + >> _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS2_SHIFT; + break; + + case EMU_DCDCLPVCTRL_LPATT | EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS3: + vrefLow = DEVINFO->DCDCLPVCTRL3; + vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS3_MASK) + >> _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS3_SHIFT; + vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS3_MASK) + >> _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS3_SHIFT; + break; + + case EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS0: + vrefLow = DEVINFO->DCDCLPVCTRL0; + vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS0_MASK) + >> _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS0_SHIFT; + vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS0_MASK) + >> _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS0_SHIFT; + break; + + case EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS1: + vrefLow = DEVINFO->DCDCLPVCTRL0; + vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS1_MASK) + >> _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS1_SHIFT; + vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS1_MASK) + >> _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS1_SHIFT; + break; + + case EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS2: + vrefLow = DEVINFO->DCDCLPVCTRL1; + vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS2_MASK) + >> _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS2_SHIFT; + vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS2_MASK) + >> _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS2_SHIFT; + break; + + case EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS3: + vrefLow = DEVINFO->DCDCLPVCTRL1; + vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS3_MASK) + >> _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS3_SHIFT; + vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS3_MASK) + >> _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS3_SHIFT; + break; + + default: + EFM_ASSERT(false); + break; + } + + /* Load LP comparator hysteresis calibration */ + if(!(LpCmpHystCalibrationLoad(attSet, lpcmpBias >> _EMU_DCDCMISCCTRL_LPCMPBIAS_SHIFT))) + { + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; + } + } /* Low-nise / low-power mode */ + + + /* Check for valid 2-point trim values */ + if ((vrefLow == 0xFF) && (vrefHigh == 0xFF)) + { + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; + } + + /* Calculate and set voltage trim */ + vrefVal = ((mV - mVlow) * (vrefHigh - vrefLow)) / (mVhigh - mVlow); + vrefVal += vrefLow; + + /* Range check */ + if ((vrefVal > vrefHigh) || (vrefVal < vrefLow)) + { + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; + } + + /* Update DCDCLNVCTRL/DCDCLPVCTRL */ + *ctrlReg = (vrefVal << vrefShift) | attMask; + } +#endif + return true; +} + + +/***************************************************************************//** + * @brief + * Optimize DCDC slice count based on the estimated average load current + * in EM0 + * + * @param[in] mAEm0LoadCurrent + * Estimated average EM0 load current in mA. + ******************************************************************************/ +void EMU_DCDCOptimizeSlice(uint32_t mAEm0LoadCurrent) +{ + uint32_t sliceCount = 0; + uint32_t rcoBand = (EMU->DCDCLNFREQCTRL & _EMU_DCDCLNFREQCTRL_RCOBAND_MASK) + >> _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT; + + /* Set recommended slice count */ + if ((EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK) && (rcoBand >= EMU_DcdcLnRcoBand_5MHz)) + { + if (mAEm0LoadCurrent < 20) + { + sliceCount = 4; + } + else if ((mAEm0LoadCurrent >= 20) && (mAEm0LoadCurrent < 40)) + { + sliceCount = 8; + } + else + { + sliceCount = 16; + } + } + else if ((!(EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK)) && (rcoBand <= EMU_DcdcLnRcoBand_4MHz)) + { + if (mAEm0LoadCurrent < 10) + { + sliceCount = 4; + } + else if ((mAEm0LoadCurrent >= 10) && (mAEm0LoadCurrent < 20)) + { + sliceCount = 8; + } + else + { + sliceCount = 16; + } + } + else if ((EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK) && (rcoBand <= EMU_DcdcLnRcoBand_4MHz)) + { + if (mAEm0LoadCurrent < 40) + { + sliceCount = 8; + } + else + { + sliceCount = 16; + } + } + else + { + /* This configuration is not recommended. EMU_DCDCInit() applies a recommended + configuration. */ + EFM_ASSERT(false); + } + + /* The selected silices are PSLICESEL + 1 */ + sliceCount--; + + /* Apply slice count to both N and P slice */ + sliceCount = (sliceCount << _EMU_DCDCMISCCTRL_PFETCNT_SHIFT + | sliceCount << _EMU_DCDCMISCCTRL_NFETCNT_SHIFT); + EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_EMU_DCDCMISCCTRL_PFETCNT_MASK + | _EMU_DCDCMISCCTRL_NFETCNT_MASK)) + | sliceCount; + + /* Update current limit configuration as it depends on the slice configuration. */ + maxCurrentUpdate(); +} + +/***************************************************************************//** + * @brief + * Set DCDC Low-noise RCO band. + * + * @param[in] band + * RCO band to set. + ******************************************************************************/ +void EMU_DCDCLnRcoBandSet(EMU_DcdcLnRcoBand_TypeDef band) +{ + EMU->DCDCLNFREQCTRL = (EMU->DCDCLNFREQCTRL & ~_EMU_DCDCLNFREQCTRL_RCOBAND_MASK) + | (band << _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT); +} + +/***************************************************************************//** + * @brief + * Power off the DCDC regulator. + * + * @details + * This function powers off the DCDC controller. This function should only be + * used if the external power circuit is wired for no DCDC. If the external power + * circuit is wired for DCDC usage, then use EMU_DCDCInit() and set the + * DCDC in bypass mode to disable DCDC. + * + * @return + * Return false if the DCDC could not be disabled. + ******************************************************************************/ +bool EMU_DCDCPowerOff(void) +{ + /* Set power configuration to hard bypass */ + EMU->PWRCFG = 0xF; + if ((EMU->PWRCFG & _EMU_PWRCFG_PWRCFG_MASK) != 0xF) + { + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; + } + + /* Set DCDC to OFF and disable LP in EM2/3/4 */ + EMU->DCDCCTRL = EMU_DCDCCTRL_DCDCMODE_OFF; + return true; +} #endif +#if defined( EMU_STATUS_VMONRDY ) +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ +__STATIC_INLINE uint32_t vmonMilliVoltToCoarseThreshold(int mV) +{ + return (mV - 1200) / 200; +} + +__STATIC_INLINE uint32_t vmonMilliVoltToFineThreshold(int mV, uint32_t coarseThreshold) +{ + return (mV - 1200 - (coarseThreshold * 200)) / 20; +} +/** @endcond */ + +/***************************************************************************//** + * @brief + * Initialize VMON channel. + * + * @details + * Initialize a VMON channel without hysteresis. If the channel supports + * separate rise and fall triggers, both thresholds will be set to the same + * value. + * + * @param[in] vmonInit + * VMON initialization struct + ******************************************************************************/ +void EMU_VmonInit(EMU_VmonInit_TypeDef *vmonInit) +{ + uint32_t thresholdCoarse, thresholdFine; + EFM_ASSERT((vmonInit->threshold >= 1200) && (vmonInit->threshold <= 3980)); + + thresholdCoarse = vmonMilliVoltToCoarseThreshold(vmonInit->threshold); + thresholdFine = vmonMilliVoltToFineThreshold(vmonInit->threshold, thresholdCoarse); + + switch(vmonInit->channel) + { + case emuVmonChannel_AVDD: + EMU->VMONAVDDCTRL = (thresholdCoarse << _EMU_VMONAVDDCTRL_RISETHRESCOARSE_SHIFT) + | (thresholdFine << _EMU_VMONAVDDCTRL_RISETHRESFINE_SHIFT) + | (thresholdCoarse << _EMU_VMONAVDDCTRL_FALLTHRESCOARSE_SHIFT) + | (thresholdFine << _EMU_VMONAVDDCTRL_FALLTHRESFINE_SHIFT) + | (vmonInit->riseWakeup ? EMU_VMONAVDDCTRL_RISEWU : 0) + | (vmonInit->fallWakeup ? EMU_VMONAVDDCTRL_FALLWU : 0) + | (vmonInit->enable ? EMU_VMONAVDDCTRL_EN : 0); + break; + case emuVmonChannel_ALTAVDD: + EMU->VMONALTAVDDCTRL = (thresholdCoarse << _EMU_VMONALTAVDDCTRL_THRESCOARSE_SHIFT) + | (thresholdFine << _EMU_VMONALTAVDDCTRL_THRESFINE_SHIFT) + | (vmonInit->riseWakeup ? EMU_VMONALTAVDDCTRL_RISEWU : 0) + | (vmonInit->fallWakeup ? EMU_VMONALTAVDDCTRL_FALLWU : 0) + | (vmonInit->enable ? EMU_VMONALTAVDDCTRL_EN : 0); + break; + case emuVmonChannel_DVDD: + EMU->VMONDVDDCTRL = (thresholdCoarse << _EMU_VMONDVDDCTRL_THRESCOARSE_SHIFT) + | (thresholdFine << _EMU_VMONDVDDCTRL_THRESFINE_SHIFT) + | (vmonInit->riseWakeup ? EMU_VMONDVDDCTRL_RISEWU : 0) + | (vmonInit->fallWakeup ? EMU_VMONDVDDCTRL_FALLWU : 0) + | (vmonInit->enable ? EMU_VMONDVDDCTRL_EN : 0); + break; + case emuVmonChannel_IOVDD0: + EMU->VMONIO0CTRL = (thresholdCoarse << _EMU_VMONIO0CTRL_THRESCOARSE_SHIFT) + | (thresholdFine << _EMU_VMONIO0CTRL_THRESFINE_SHIFT) + | (vmonInit->retDisable ? EMU_VMONIO0CTRL_RETDIS : 0) + | (vmonInit->riseWakeup ? EMU_VMONIO0CTRL_RISEWU : 0) + | (vmonInit->fallWakeup ? EMU_VMONIO0CTRL_FALLWU : 0) + | (vmonInit->enable ? EMU_VMONIO0CTRL_EN : 0); + break; + default: + EFM_ASSERT(false); + return; + } +} + +/***************************************************************************//** + * @brief + * Initialize VMON channel with hysteresis (separate rise and fall triggers). + * + * @details + * Initialize a VMON channel which supports hysteresis. The AVDD channel is + * the only channel to support separate rise and fall triggers. + * + * @param[in] vmonInit + * VMON Hysteresis initialization struct + ******************************************************************************/ +void EMU_VmonHystInit(EMU_VmonHystInit_TypeDef *vmonInit) +{ + uint32_t riseThresholdCoarse, riseThresholdFine, fallThresholdCoarse, fallThresholdFine; + /* VMON supports voltages between 1200 mV and 3980 mV (inclusive) in 20 mV increments */ + EFM_ASSERT((vmonInit->riseThreshold >= 1200) && (vmonInit->riseThreshold < 4000)); + EFM_ASSERT((vmonInit->fallThreshold >= 1200) && (vmonInit->fallThreshold < 4000)); + /* Fall threshold has to be lower than rise threshold */ + EFM_ASSERT(vmonInit->fallThreshold <= vmonInit->riseThreshold); + + riseThresholdCoarse = vmonMilliVoltToCoarseThreshold(vmonInit->riseThreshold); + riseThresholdFine = vmonMilliVoltToFineThreshold(vmonInit->riseThreshold, riseThresholdCoarse); + fallThresholdCoarse = vmonMilliVoltToCoarseThreshold(vmonInit->fallThreshold); + fallThresholdFine = vmonMilliVoltToFineThreshold(vmonInit->fallThreshold, fallThresholdCoarse); + + switch(vmonInit->channel) + { + case emuVmonChannel_AVDD: + EMU->VMONAVDDCTRL = (riseThresholdCoarse << _EMU_VMONAVDDCTRL_RISETHRESCOARSE_SHIFT) + | (riseThresholdFine << _EMU_VMONAVDDCTRL_RISETHRESFINE_SHIFT) + | (fallThresholdCoarse << _EMU_VMONAVDDCTRL_FALLTHRESCOARSE_SHIFT) + | (fallThresholdFine << _EMU_VMONAVDDCTRL_FALLTHRESFINE_SHIFT) + | (vmonInit->riseWakeup ? EMU_VMONAVDDCTRL_RISEWU : 0) + | (vmonInit->fallWakeup ? EMU_VMONAVDDCTRL_FALLWU : 0) + | (vmonInit->enable ? EMU_VMONAVDDCTRL_EN : 0); + break; + default: + EFM_ASSERT(false); + return; + } +} + +/***************************************************************************//** + * @brief + * Enable or disable a VMON channel + * + * @param[in] channel + * VMON channel to enable/disable + * + * @param[in] enable + * Whether to enable or disable + ******************************************************************************/ +void EMU_VmonEnable(EMU_VmonChannel_TypeDef channel, bool enable) +{ + uint32_t volatile * reg; + uint32_t bit; + + switch(channel) + { + case emuVmonChannel_AVDD: + reg = &(EMU->VMONAVDDCTRL); + bit = _EMU_VMONAVDDCTRL_EN_SHIFT; + break; + case emuVmonChannel_ALTAVDD: + reg = &(EMU->VMONALTAVDDCTRL); + bit = _EMU_VMONALTAVDDCTRL_EN_SHIFT; + break; + case emuVmonChannel_DVDD: + reg = &(EMU->VMONDVDDCTRL); + bit = _EMU_VMONDVDDCTRL_EN_SHIFT; + break; + case emuVmonChannel_IOVDD0: + reg = &(EMU->VMONIO0CTRL); + bit = _EMU_VMONIO0CTRL_EN_SHIFT; + break; + default: + EFM_ASSERT(false); + return; + } + + BUS_RegBitWrite(reg, bit, enable); +} + +/***************************************************************************//** + * @brief + * Get the status of a voltage monitor channel. + * + * @param[in] channel + * VMON channel to get status for + * + * @return + * Status of the selected VMON channel. True if channel is triggered. + ******************************************************************************/ +bool EMU_VmonChannelStatusGet(EMU_VmonChannel_TypeDef channel) +{ + uint32_t bit; + switch(channel) + { + case emuVmonChannel_AVDD: + bit = _EMU_STATUS_VMONAVDD_SHIFT; + break; + case emuVmonChannel_ALTAVDD: + bit = _EMU_STATUS_VMONALTAVDD_SHIFT; + break; + case emuVmonChannel_DVDD: + bit = _EMU_STATUS_VMONDVDD_SHIFT; + break; + case emuVmonChannel_IOVDD0: + bit = _EMU_STATUS_VMONIO0_SHIFT; + break; + default: + EFM_ASSERT(false); + bit = 0; + } + + return BUS_RegBitRead(&EMU->STATUS, bit); +} +#endif /* EMU_STATUS_VMONRDY */ + /** @} (end addtogroup EMU) */ /** @} (end addtogroup EM_Library) */ #endif /* __EM_EMU_H */