1 /***************************************************************************//**
\r
3 * @brief Energy Management Unit (EMU) Peripheral API
\r
5 *******************************************************************************
\r
7 * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
\r
8 *******************************************************************************
\r
10 * Permission is granted to anyone to use this software for any purpose,
\r
11 * including commercial applications, and to alter it and redistribute it
\r
12 * freely, subject to the following restrictions:
\r
14 * 1. The origin of this software must not be misrepresented; you must not
\r
15 * claim that you wrote the original software.
\r
16 * 2. Altered source versions must be plainly marked as such, and must not be
\r
17 * misrepresented as being the original software.
\r
18 * 3. This notice may not be removed or altered from any source distribution.
\r
20 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
\r
21 * obligation to support this Software. Silicon Labs is providing the
\r
22 * Software "AS IS", with no express or implied warranties of any kind,
\r
23 * including, but not limited to, any implied warranties of merchantability
\r
24 * or fitness for any particular purpose or warranties against infringement
\r
25 * of any proprietary rights of a third party.
\r
27 * Silicon Labs will not be liable for any consequential, incidental, or
\r
28 * special damages, or any other relief, or for any claim by any third party,
\r
29 * arising from your use of this Software.
\r
31 ******************************************************************************/
\r
36 #if defined( EMU_PRESENT ) && ( EMU_COUNT > 0 )
\r
39 #include "em_system.h"
\r
40 #include "em_assert.h"
\r
42 /***************************************************************************//**
\r
43 * @addtogroup EM_Library
\r
45 ******************************************************************************/
\r
47 /***************************************************************************//**
\r
49 * @brief Energy Management Unit (EMU) Peripheral API
\r
51 ******************************************************************************/
\r
53 /* Consistency check, since restoring assumes similar bitpositions in */
\r
54 /* CMU OSCENCMD and STATUS regs */
\r
55 #if (CMU_STATUS_AUXHFRCOENS != CMU_OSCENCMD_AUXHFRCOEN)
\r
56 #error Conflict in AUXHFRCOENS and AUXHFRCOEN bitpositions
\r
58 #if (CMU_STATUS_HFXOENS != CMU_OSCENCMD_HFXOEN)
\r
59 #error Conflict in HFXOENS and HFXOEN bitpositions
\r
61 #if (CMU_STATUS_LFRCOENS != CMU_OSCENCMD_LFRCOEN)
\r
62 #error Conflict in LFRCOENS and LFRCOEN bitpositions
\r
64 #if (CMU_STATUS_LFXOENS != CMU_OSCENCMD_LFXOEN)
\r
65 #error Conflict in LFXOENS and LFXOEN bitpositions
\r
69 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
\r
70 /* Fix for errata EMU_E107 - non-WIC interrupt masks. */
\r
71 #if defined( _EFM32_GECKO_FAMILY )
\r
72 #define ERRATA_FIX_EMU_E107_EN
\r
73 #define NON_WIC_INT_MASK_0 (~(0x0dfc0323U))
\r
74 #define NON_WIC_INT_MASK_1 (~(0x0U))
\r
76 #elif defined( _EFM32_TINY_FAMILY )
\r
77 #define ERRATA_FIX_EMU_E107_EN
\r
78 #define NON_WIC_INT_MASK_0 (~(0x001be323U))
\r
79 #define NON_WIC_INT_MASK_1 (~(0x0U))
\r
81 #elif defined( _EFM32_GIANT_FAMILY )
\r
82 #define ERRATA_FIX_EMU_E107_EN
\r
83 #define NON_WIC_INT_MASK_0 (~(0xff020e63U))
\r
84 #define NON_WIC_INT_MASK_1 (~(0x00000046U))
\r
86 #elif defined( _EFM32_WONDER_FAMILY )
\r
87 #define ERRATA_FIX_EMU_E107_EN
\r
88 #define NON_WIC_INT_MASK_0 (~(0xff020e63U))
\r
89 #define NON_WIC_INT_MASK_1 (~(0x00000046U))
\r
92 /* Zero Gecko and future families are not affected by errata EMU_E107 */
\r
95 /* Fix for errata EMU_E108 - High Current Consumption on EM4 Entry. */
\r
96 #if defined( _EFM32_HAPPY_FAMILY )
\r
97 #define ERRATA_FIX_EMU_E108_EN
\r
102 #if defined( _EMU_DCDCCTRL_MASK )
\r
103 /* DCDCTODVDD output range min/max */
\r
104 #define PWRCFG_DCDCTODVDD_VMIN 1200
\r
105 #define PWRCFG_DCDCTODVDD_VMAX 3000
\r
108 errataFixDcdcHsInit,
\r
109 errataFixDcdcHsTrimSet,
\r
110 errataFixDcdcHsLnWaitDone
\r
111 } errataFixDcdcHs_TypeDef;
\r
112 errataFixDcdcHs_TypeDef errataFixDcdcHsState = errataFixDcdcHsInit;
\r
115 /*******************************************************************************
\r
116 ************************** LOCAL VARIABLES ********************************
\r
117 ******************************************************************************/
\r
119 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
\r
121 * CMU configured oscillator selection and oscillator enable status. When a
\r
122 * user configures oscillators, this varaiable shall shadow the configuration.
\r
123 * It is used by the EMU module in order to be able to restore the oscillator
\r
124 * config after having been in certain energy modes (since HW may automatically
\r
125 * alter config when going into an energy mode). It is the responsibility of
\r
126 * the CMU module to keep it up-to-date (or a user if not using the CMU API
\r
127 * for oscillator control).
\r
129 static uint32_t cmuStatus;
\r
130 #if defined( _CMU_HFCLKSTATUS_RESETVALUE )
\r
131 static uint16_t cmuHfclkStatus;
\r
133 #if defined( _EMU_DCDCCTRL_MASK )
\r
134 static uint16_t dcdcMaxCurrent_mA;
\r
135 static uint16_t dcdcOutput_mVout;
\r
141 /*******************************************************************************
\r
142 ************************** LOCAL FUNCTIONS ********************************
\r
143 ******************************************************************************/
\r
145 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
\r
147 /***************************************************************************//**
\r
149 * Restore oscillators and core clock after having been in EM2 or EM3.
\r
150 ******************************************************************************/
\r
151 static void emuRestore(void)
\r
154 uint32_t cmuLocked;
\r
156 /* Although we could use the CMU API for most of the below handling, we */
\r
157 /* would like this function to be as efficient as possible. */
\r
159 /* CMU registers may be locked */
\r
160 cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
\r
163 /* AUXHFRCO are automatically disabled (except if using debugger). */
\r
164 /* HFRCO, USHFRCO and HFXO are automatically disabled. */
\r
165 /* LFRCO/LFXO may be disabled by SW in EM3. */
\r
166 /* Restore according to status prior to entering energy mode. */
\r
168 oscEnCmd |= ((cmuStatus & CMU_STATUS_HFRCOENS) ? CMU_OSCENCMD_HFRCOEN : 0);
\r
169 oscEnCmd |= ((cmuStatus & CMU_STATUS_AUXHFRCOENS) ? CMU_OSCENCMD_AUXHFRCOEN : 0);
\r
170 oscEnCmd |= ((cmuStatus & CMU_STATUS_LFRCOENS) ? CMU_OSCENCMD_LFRCOEN : 0);
\r
171 oscEnCmd |= ((cmuStatus & CMU_STATUS_HFXOENS) ? CMU_OSCENCMD_HFXOEN : 0);
\r
172 oscEnCmd |= ((cmuStatus & CMU_STATUS_LFXOENS) ? CMU_OSCENCMD_LFXOEN : 0);
\r
173 #if defined( _CMU_STATUS_USHFRCOENS_MASK )
\r
174 oscEnCmd |= ((cmuStatus & CMU_STATUS_USHFRCOENS) ? CMU_OSCENCMD_USHFRCOEN : 0);
\r
176 CMU->OSCENCMD = oscEnCmd;
\r
179 #if defined( _CMU_HFCLKSTATUS_RESETVALUE )
\r
180 /* Restore oscillator used for clocking core */
\r
181 switch (cmuHfclkStatus & _CMU_HFCLKSTATUS_SELECTED_MASK)
\r
183 case CMU_HFCLKSTATUS_SELECTED_LFRCO:
\r
184 /* HFRCO could only be selected if the autostart HFXO feature is not
\r
185 * enabled, otherwise the HFXO would be started and selected automatically.
\r
186 * Note: this error hook helps catching erroneous oscillator configurations,
\r
187 * when the AUTOSTARTSELEM0EM1 is set in CMU_HFXOCTRL. */
\r
188 if (!(CMU->HFXOCTRL & CMU_HFXOCTRL_AUTOSTARTSELEM0EM1))
\r
190 /* Wait for LFRCO to stabilize */
\r
191 while (!(CMU->STATUS & CMU_STATUS_LFRCORDY))
\r
193 CMU->HFCLKSEL = CMU_HFCLKSEL_HF_LFRCO;
\r
201 case CMU_HFCLKSTATUS_SELECTED_LFXO:
\r
202 /* Wait for LFXO to stabilize */
\r
203 while (!(CMU->STATUS & CMU_STATUS_LFXORDY))
\r
205 CMU->HFCLKSEL = CMU_HFCLKSEL_HF_LFXO;
\r
208 case CMU_HFCLKSTATUS_SELECTED_HFXO:
\r
209 /* Wait for HFXO to stabilize */
\r
210 while (!(CMU->STATUS & CMU_STATUS_HFXORDY))
\r
212 CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFXO;
\r
215 default: /* CMU_HFCLKSTATUS_SELECTED_HFRCO */
\r
216 /* If core clock was HFRCO core clock, it is automatically restored to */
\r
217 /* state prior to entering energy mode. No need for further action. */
\r
221 switch (cmuStatus & (CMU_STATUS_HFRCOSEL
\r
222 | CMU_STATUS_HFXOSEL
\r
223 | CMU_STATUS_LFRCOSEL
\r
224 #if defined( CMU_STATUS_USHFRCODIV2SEL )
\r
225 | CMU_STATUS_USHFRCODIV2SEL
\r
227 | CMU_STATUS_LFXOSEL))
\r
229 case CMU_STATUS_LFRCOSEL:
\r
230 /* Wait for LFRCO to stabilize */
\r
231 while (!(CMU->STATUS & CMU_STATUS_LFRCORDY))
\r
233 CMU->CMD = CMU_CMD_HFCLKSEL_LFRCO;
\r
236 case CMU_STATUS_LFXOSEL:
\r
237 /* Wait for LFXO to stabilize */
\r
238 while (!(CMU->STATUS & CMU_STATUS_LFXORDY))
\r
240 CMU->CMD = CMU_CMD_HFCLKSEL_LFXO;
\r
243 case CMU_STATUS_HFXOSEL:
\r
244 /* Wait for HFXO to stabilize */
\r
245 while (!(CMU->STATUS & CMU_STATUS_HFXORDY))
\r
247 CMU->CMD = CMU_CMD_HFCLKSEL_HFXO;
\r
250 #if defined( CMU_STATUS_USHFRCODIV2SEL )
\r
251 case CMU_STATUS_USHFRCODIV2SEL:
\r
252 /* Wait for USHFRCO to stabilize */
\r
253 while (!(CMU->STATUS & CMU_STATUS_USHFRCORDY))
\r
255 CMU->CMD = _CMU_CMD_HFCLKSEL_USHFRCODIV2;
\r
259 default: /* CMU_STATUS_HFRCOSEL */
\r
260 /* If core clock was HFRCO core clock, it is automatically restored to */
\r
261 /* state prior to entering energy mode. No need for further action. */
\r
265 /* If HFRCO was disabled before entering Energy Mode, turn it off again */
\r
266 /* as it is automatically enabled by wake up */
\r
267 if ( ! (cmuStatus & CMU_STATUS_HFRCOENS) )
\r
269 CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS;
\r
272 /* Restore CMU register locking */
\r
280 #if defined( ERRATA_FIX_EMU_E107_EN )
\r
281 /* Get enable conditions for errata EMU_E107 fix. */
\r
282 static __INLINE bool getErrataFixEmuE107En(void)
\r
284 /* SYSTEM_ChipRevisionGet could have been used here, but we would like a
\r
285 * faster implementation in this case.
\r
287 uint16_t majorMinorRev;
\r
289 /* CHIP MAJOR bit [3:0] */
\r
290 majorMinorRev = ((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK)
\r
291 >> _ROMTABLE_PID0_REVMAJOR_SHIFT)
\r
293 /* CHIP MINOR bit [7:4] */
\r
294 majorMinorRev |= ((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK)
\r
295 >> _ROMTABLE_PID2_REVMINORMSB_SHIFT)
\r
297 /* CHIP MINOR bit [3:0] */
\r
298 majorMinorRev |= (ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK)
\r
299 >> _ROMTABLE_PID3_REVMINORLSB_SHIFT;
\r
301 #if defined( _EFM32_GECKO_FAMILY )
\r
302 return (majorMinorRev <= 0x0103);
\r
303 #elif defined( _EFM32_TINY_FAMILY )
\r
304 return (majorMinorRev <= 0x0102);
\r
305 #elif defined( _EFM32_GIANT_FAMILY )
\r
306 return (majorMinorRev <= 0x0103) || (majorMinorRev == 0x0204);
\r
307 #elif defined( _EFM32_WONDER_FAMILY )
\r
308 return (majorMinorRev == 0x0100);
\r
310 /* Zero Gecko and future families are not affected by errata EMU_E107 */
\r
317 #if defined( _EMU_DCDCCTRL_MASK )
\r
318 /* LP prepare / LN restore P/NFET count */
\r
319 static void maxCurrentUpdate(void);
\r
320 #define DCDC_LP_PFET_CNT 7
\r
321 #define DCDC_LP_NFET_CNT 15
\r
322 void dcdcFetCntSet(bool lpModeSet)
\r
325 static uint32_t emuDcdcMiscCtrlReg;
\r
329 emuDcdcMiscCtrlReg = EMU->DCDCMISCCTRL;
\r
330 tmp = EMU->DCDCMISCCTRL
\r
331 & ~(_EMU_DCDCMISCCTRL_PFETCNT_MASK | _EMU_DCDCMISCCTRL_NFETCNT_MASK);
\r
332 tmp |= (DCDC_LP_PFET_CNT << _EMU_DCDCMISCCTRL_PFETCNT_SHIFT)
\r
333 | (DCDC_LP_NFET_CNT << _EMU_DCDCMISCCTRL_NFETCNT_SHIFT);
\r
334 EMU->DCDCMISCCTRL = tmp;
\r
335 maxCurrentUpdate();
\r
339 EMU->DCDCMISCCTRL = emuDcdcMiscCtrlReg;
\r
340 maxCurrentUpdate();
\r
344 void dcdcHsFixLnBlock(void)
\r
346 #define EMU_DCDCSTATUS (* (volatile uint32_t *)(EMU_BASE + 0x7C))
\r
347 if (errataFixDcdcHsState == errataFixDcdcHsTrimSet)
\r
349 /* Wait for LNRUNNING */
\r
350 if ((EMU->DCDCCTRL & ~_EMU_DCDCCTRL_DCDCMODE_MASK) == EMU_DCDCCTRL_DCDCMODE_LOWNOISE)
\r
352 while (!(EMU_DCDCSTATUS & (0x1 << 16)));
\r
354 errataFixDcdcHsState = errataFixDcdcHsLnWaitDone;
\r
363 /*******************************************************************************
\r
364 ************************** GLOBAL FUNCTIONS *******************************
\r
365 ******************************************************************************/
\r
367 /***************************************************************************//**
\r
369 * Enter energy mode 2 (EM2).
\r
372 * When entering EM2, the high frequency clocks are disabled, ie HFXO, HFRCO
\r
373 * and AUXHFRCO (for AUXHFRCO, see exception note below). When re-entering
\r
374 * EM0, HFRCO is re-enabled and the core will be clocked by the configured
\r
375 * HFRCO band. This ensures a quick wakeup from EM2.
\r
377 * However, prior to entering EM2, the core may have been using another
\r
378 * oscillator than HFRCO. The @p restore parameter gives the user the option
\r
379 * to restore all HF oscillators according to state prior to entering EM2,
\r
380 * as well as the clock used to clock the core. This restore procedure is
\r
381 * handled by SW. However, since handled by SW, it will not be restored
\r
382 * before completing the interrupt function(s) waking up the core!
\r
385 * If restoring core clock to use the HFXO oscillator, which has been
\r
386 * disabled during EM2 mode, this function will stall until the oscillator
\r
387 * has stabilized. Stalling time can be reduced by adding interrupt
\r
388 * support detecting stable oscillator, and an asynchronous switch to the
\r
389 * original oscillator. See CMU documentation. Such a feature is however
\r
390 * outside the scope of the implementation in this function.
\r
392 * If HFXO is re-enabled by this function, and NOT used to clock the core,
\r
393 * this function will not wait for HFXO to stabilize. This must be considered
\r
394 * by the application if trying to use features relying on that oscillator
\r
397 * If a debugger is attached, the AUXHFRCO will not be disabled if enabled
\r
398 * upon entering EM2. It will thus remain enabled when returning to EM0
\r
399 * regardless of the @p restore parameter.
\r
401 * If HFXO autostart and select is enabled by using CMU_HFXOAutostartEnable(),
\r
402 * the starting and selecting of the core clocks will be identical to the user
\r
403 * independently of the value of the @p restore parameter when waking up on
\r
404 * the wakeup sources corresponding to the autostart and select setting.
\r
406 * @param[in] restore
\r
407 * @li true - restore oscillators and clocks, see function details.
\r
408 * @li false - do not restore oscillators and clocks, see function details.
\r
410 * The @p restore option should only be used if all clock control is done
\r
412 ******************************************************************************/
\r
413 void EMU_EnterEM2(bool restore)
\r
415 #if defined( ERRATA_FIX_EMU_E107_EN )
\r
416 bool errataFixEmuE107En;
\r
417 uint32_t nonWicIntEn[2];
\r
420 /* Auto-update CMU status just in case before entering energy mode. */
\r
421 /* This variable is normally kept up-to-date by the CMU API. */
\r
422 cmuStatus = CMU->STATUS;
\r
423 #if defined( _CMU_HFCLKSTATUS_RESETVALUE )
\r
424 cmuHfclkStatus = (uint16_t)(CMU->HFCLKSTATUS);
\r
427 /* Enter Cortex deep sleep mode */
\r
428 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
\r
430 /* Fix for errata EMU_E107 - store non-WIC interrupt enable flags.
\r
431 Disable the enabled non-WIC interrupts. */
\r
432 #if defined( ERRATA_FIX_EMU_E107_EN )
\r
433 errataFixEmuE107En = getErrataFixEmuE107En();
\r
434 if (errataFixEmuE107En)
\r
436 nonWicIntEn[0] = NVIC->ISER[0] & NON_WIC_INT_MASK_0;
\r
437 NVIC->ICER[0] = nonWicIntEn[0];
\r
438 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
\r
439 nonWicIntEn[1] = NVIC->ISER[1] & NON_WIC_INT_MASK_1;
\r
440 NVIC->ICER[1] = nonWicIntEn[1];
\r
445 #if defined( _EMU_DCDCCTRL_MASK )
\r
446 dcdcFetCntSet(true);
\r
447 dcdcHsFixLnBlock();
\r
452 #if defined( _EMU_DCDCCTRL_MASK )
\r
453 dcdcFetCntSet(false);
\r
456 /* Fix for errata EMU_E107 - restore state of non-WIC interrupt enable flags. */
\r
457 #if defined( ERRATA_FIX_EMU_E107_EN )
\r
458 if (errataFixEmuE107En)
\r
460 NVIC->ISER[0] = nonWicIntEn[0];
\r
461 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
\r
462 NVIC->ISER[1] = nonWicIntEn[1];
\r
467 /* Restore oscillators/clocks if specified */
\r
472 /* If not restoring, and original clock was not HFRCO, we have to */
\r
473 /* update CMSIS core clock variable since core clock has changed */
\r
474 /* to using HFRCO. */
\r
475 #if defined( _CMU_HFCLKSTATUS_RESETVALUE )
\r
476 else if ((cmuHfclkStatus & _CMU_HFCLKSTATUS_SELECTED_MASK)
\r
477 != CMU_HFCLKSTATUS_SELECTED_HFRCO)
\r
479 else if (!(cmuStatus & CMU_STATUS_HFRCOSEL))
\r
482 SystemCoreClockUpdate();
\r
487 /***************************************************************************//**
\r
489 * Enter energy mode 3 (EM3).
\r
492 * When entering EM3, the high frequency clocks are disabled by HW, ie HFXO,
\r
493 * HFRCO and AUXHFRCO (for AUXHFRCO, see exception note below). In addition,
\r
494 * the low frequency clocks, ie LFXO and LFRCO are disabled by SW. When
\r
495 * re-entering EM0, HFRCO is re-enabled and the core will be clocked by the
\r
496 * configured HFRCO band. This ensures a quick wakeup from EM3.
\r
498 * However, prior to entering EM3, the core may have been using another
\r
499 * oscillator than HFRCO. The @p restore parameter gives the user the option
\r
500 * to restore all HF/LF oscillators according to state prior to entering EM3,
\r
501 * as well as the clock used to clock the core. This restore procedure is
\r
502 * handled by SW. However, since handled by SW, it will not be restored
\r
503 * before completing the interrupt function(s) waking up the core!
\r
506 * If restoring core clock to use an oscillator other than HFRCO, this
\r
507 * function will stall until the oscillator has stabilized. Stalling time
\r
508 * can be reduced by adding interrupt support detecting stable oscillator,
\r
509 * and an asynchronous switch to the original oscillator. See CMU
\r
510 * documentation. Such a feature is however outside the scope of the
\r
511 * implementation in this function.
\r
513 * If HFXO/LFXO/LFRCO are re-enabled by this function, and NOT used to clock
\r
514 * the core, this function will not wait for those oscillators to stabilize.
\r
515 * This must be considered by the application if trying to use features
\r
516 * relying on those oscillators upon return.
\r
518 * If a debugger is attached, the AUXHFRCO will not be disabled if enabled
\r
519 * upon entering EM3. It will thus remain enabled when returning to EM0
\r
520 * regardless of the @p restore parameter.
\r
522 * @param[in] restore
\r
523 * @li true - restore oscillators and clocks, see function details.
\r
524 * @li false - do not restore oscillators and clocks, see function details.
\r
526 * The @p restore option should only be used if all clock control is done
\r
528 ******************************************************************************/
\r
529 void EMU_EnterEM3(bool restore)
\r
531 uint32_t cmuLocked;
\r
533 #if defined( ERRATA_FIX_EMU_E107_EN )
\r
534 bool errataFixEmuE107En;
\r
535 uint32_t nonWicIntEn[2];
\r
538 /* Auto-update CMU status just in case before entering energy mode. */
\r
539 /* This variable is normally kept up-to-date by the CMU API. */
\r
540 cmuStatus = CMU->STATUS;
\r
541 #if defined( _CMU_HFCLKSTATUS_RESETVALUE )
\r
542 cmuHfclkStatus = (uint16_t)(CMU->HFCLKSTATUS);
\r
545 /* CMU registers may be locked */
\r
546 cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
\r
549 /* Disable LF oscillators */
\r
550 CMU->OSCENCMD = CMU_OSCENCMD_LFXODIS | CMU_OSCENCMD_LFRCODIS;
\r
552 /* Restore CMU register locking */
\r
558 /* Enter Cortex deep sleep mode */
\r
559 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
\r
561 /* Fix for errata EMU_E107 - store non-WIC interrupt enable flags.
\r
562 Disable the enabled non-WIC interrupts. */
\r
563 #if defined( ERRATA_FIX_EMU_E107_EN )
\r
564 errataFixEmuE107En = getErrataFixEmuE107En();
\r
565 if (errataFixEmuE107En)
\r
567 nonWicIntEn[0] = NVIC->ISER[0] & NON_WIC_INT_MASK_0;
\r
568 NVIC->ICER[0] = nonWicIntEn[0];
\r
569 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
\r
570 nonWicIntEn[1] = NVIC->ISER[1] & NON_WIC_INT_MASK_1;
\r
571 NVIC->ICER[1] = nonWicIntEn[1];
\r
577 #if defined( _EMU_DCDCCTRL_MASK )
\r
578 dcdcFetCntSet(true);
\r
579 dcdcHsFixLnBlock();
\r
584 #if defined( _EMU_DCDCCTRL_MASK )
\r
585 dcdcFetCntSet(false);
\r
588 /* Fix for errata EMU_E107 - restore state of non-WIC interrupt enable flags. */
\r
589 #if defined( ERRATA_FIX_EMU_E107_EN )
\r
590 if (errataFixEmuE107En)
\r
592 NVIC->ISER[0] = nonWicIntEn[0];
\r
593 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
\r
594 NVIC->ISER[1] = nonWicIntEn[1];
\r
599 /* Restore oscillators/clocks if specified */
\r
604 /* If not restoring, and original clock was not HFRCO, we have to */
\r
605 /* update CMSIS core clock variable since core clock has changed */
\r
606 /* to using HFRCO. */
\r
607 #if defined( _CMU_HFCLKSTATUS_RESETVALUE )
\r
608 else if ((cmuHfclkStatus & _CMU_HFCLKSTATUS_SELECTED_MASK)
\r
609 != CMU_HFCLKSTATUS_SELECTED_HFRCO)
\r
611 else if (!(cmuStatus & CMU_STATUS_HFRCOSEL))
\r
614 SystemCoreClockUpdate();
\r
619 /***************************************************************************//**
\r
621 * Enter energy mode 4 (EM4).
\r
624 * Only a power on reset or external reset pin can wake the device from EM4.
\r
625 ******************************************************************************/
\r
626 void EMU_EnterEM4(void)
\r
630 #if defined( _EMU_EM4CTRL_EM4ENTRY_SHIFT )
\r
631 uint32_t em4seq2 = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4ENTRY_MASK)
\r
632 | (2 << _EMU_EM4CTRL_EM4ENTRY_SHIFT);
\r
633 uint32_t em4seq3 = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4ENTRY_MASK)
\r
634 | (3 << _EMU_EM4CTRL_EM4ENTRY_SHIFT);
\r
636 uint32_t em4seq2 = (EMU->CTRL & ~_EMU_CTRL_EM4CTRL_MASK)
\r
637 | (2 << _EMU_CTRL_EM4CTRL_SHIFT);
\r
638 uint32_t em4seq3 = (EMU->CTRL & ~_EMU_CTRL_EM4CTRL_MASK)
\r
639 | (3 << _EMU_CTRL_EM4CTRL_SHIFT);
\r
642 /* Make sure register write lock is disabled */
\r
645 #if defined( ERRATA_FIX_EMU_E108_EN )
\r
646 /* Fix for errata EMU_E108 - High Current Consumption on EM4 Entry. */
\r
648 *(volatile uint32_t *)0x400C80E4 = 0;
\r
651 #if defined( _EMU_DCDCCTRL_MASK )
\r
652 dcdcFetCntSet(true);
\r
653 dcdcHsFixLnBlock();
\r
656 for (i = 0; i < 4; i++)
\r
658 #if defined( _EMU_EM4CTRL_EM4ENTRY_SHIFT )
\r
659 EMU->EM4CTRL = em4seq2;
\r
660 EMU->EM4CTRL = em4seq3;
\r
662 EMU->EM4CTRL = em4seq2;
\r
664 EMU->CTRL = em4seq2;
\r
665 EMU->CTRL = em4seq3;
\r
667 EMU->CTRL = em4seq2;
\r
672 /***************************************************************************//**
\r
674 * Power down memory block.
\r
676 * @param[in] blocks
\r
677 * Specifies a logical OR of bits indicating memory blocks to power down.
\r
678 * Bit 0 selects block 1, bit 1 selects block 2, etc. Memory block 0 cannot
\r
679 * be disabled. Please refer to the reference manual for available
\r
680 * memory blocks for a device.
\r
683 * Only a reset can make the specified memory block(s) available for use
\r
684 * after having been powered down. Function will be void for devices not
\r
685 * supporting this feature.
\r
686 ******************************************************************************/
\r
687 void EMU_MemPwrDown(uint32_t blocks)
\r
689 #if defined( _EMU_MEMCTRL_POWERDOWN_MASK )
\r
690 EFM_ASSERT(blocks <= (_EMU_MEMCTRL_POWERDOWN_MASK
\r
691 >> _EMU_MEMCTRL_POWERDOWN_SHIFT));
\r
692 EMU->MEMCTRL = blocks;
\r
694 #elif defined( _EMU_MEMCTRL_RAMPOWERDOWN_MASK ) \
\r
695 && defined( _EMU_MEMCTRL_RAMHPOWERDOWN_MASK ) \
\r
696 && defined( _EMU_MEMCTRL_SEQRAMPOWERDOWN_MASK )
\r
697 EFM_ASSERT((blocks & (_EMU_MEMCTRL_RAMPOWERDOWN_MASK
\r
698 | _EMU_MEMCTRL_RAMHPOWERDOWN_MASK
\r
699 | _EMU_MEMCTRL_SEQRAMPOWERDOWN_MASK))
\r
701 EMU->MEMCTRL = blocks;
\r
703 #elif defined( _EMU_MEMCTRL_RAMPOWERDOWN_MASK )
\r
704 EFM_ASSERT((blocks & _EMU_MEMCTRL_RAMPOWERDOWN_MASK) == blocks);
\r
705 EMU->MEMCTRL = blocks;
\r
707 #elif defined( _EMU_RAM0CTRL_RAMPOWERDOWN_MASK )
\r
708 EFM_ASSERT((blocks & _EMU_RAM0CTRL_RAMPOWERDOWN_MASK) == blocks);
\r
709 EMU->RAM0CTRL = blocks;
\r
717 /***************************************************************************//**
\r
719 * Update EMU module with CMU oscillator selection/enable status.
\r
722 * When entering EM2 and EM3, the HW may change the core clock oscillator
\r
723 * used, as well as disabling some oscillators. The user may optionally select
\r
724 * to restore the oscillators after waking up from EM2 and EM3 through the
\r
727 * However, in order to support this in a safe way, the EMU module must
\r
728 * be kept up-to-date on the actual selected configuration. The CMU
\r
729 * module must keep the EMU module up-to-date.
\r
731 * This function is mainly intended for internal use by the CMU module,
\r
732 * but if the applications changes oscillator configurations without
\r
733 * using the CMU API, this function can be used to keep the EMU module
\r
735 ******************************************************************************/
\r
736 void EMU_UpdateOscConfig(void)
\r
738 /* Fetch current configuration */
\r
739 cmuStatus = CMU->STATUS;
\r
740 #if defined( _CMU_HFCLKSTATUS_RESETVALUE )
\r
741 cmuHfclkStatus = (uint16_t)(CMU->HFCLKSTATUS);
\r
746 /***************************************************************************//**
\r
748 * Update EMU module with Energy Mode 2 and 3 configuration
\r
750 * @param[in] em23Init
\r
751 * Energy Mode 2 and 3 configuration structure
\r
752 ******************************************************************************/
\r
753 void EMU_EM23Init(EMU_EM23Init_TypeDef *em23Init)
\r
755 #if defined( _EMU_CTRL_EMVREG_MASK )
\r
756 EMU->CTRL = em23Init->em23VregFullEn ? (EMU->CTRL | EMU_CTRL_EMVREG)
\r
757 : (EMU->CTRL & ~EMU_CTRL_EMVREG);
\r
758 #elif defined( _EMU_CTRL_EM23VREG_MASK )
\r
759 EMU->CTRL = em23Init->em23VregFullEn ? (EMU->CTRL | EMU_CTRL_EM23VREG)
\r
760 : (EMU->CTRL & ~EMU_CTRL_EM23VREG);
\r
767 #if defined( _EMU_EM4CONF_MASK ) || defined( _EMU_EM4CTRL_MASK )
\r
768 /***************************************************************************//**
\r
770 * Update EMU module with Energy Mode 4 configuration
\r
772 * @param[in] em4Init
\r
773 * Energy Mode 4 configuration structure
\r
774 ******************************************************************************/
\r
775 void EMU_EM4Init(EMU_EM4Init_TypeDef *em4Init)
\r
777 #if defined( _EMU_EM4CONF_MASK )
\r
778 /* Init for platforms with EMU->EM4CONF register */
\r
779 uint32_t em4conf = EMU->EM4CONF;
\r
781 /* Clear fields that will be reconfigured */
\r
782 em4conf &= ~(_EMU_EM4CONF_LOCKCONF_MASK
\r
783 | _EMU_EM4CONF_OSC_MASK
\r
784 | _EMU_EM4CONF_BURTCWU_MASK
\r
785 | _EMU_EM4CONF_VREGEN_MASK);
\r
787 /* Configure new settings */
\r
788 em4conf |= (em4Init->lockConfig << _EMU_EM4CONF_LOCKCONF_SHIFT)
\r
790 | (em4Init->buRtcWakeup << _EMU_EM4CONF_BURTCWU_SHIFT)
\r
791 | (em4Init->vreg << _EMU_EM4CONF_VREGEN_SHIFT);
\r
793 /* Apply configuration. Note that lock can be set after this stage. */
\r
794 EMU->EM4CONF = em4conf;
\r
796 #elif defined( _EMU_EM4CTRL_MASK )
\r
797 /* Init for platforms with EMU->EM4CTRL register */
\r
799 uint32_t em4ctrl = EMU->EM4CTRL;
\r
801 em4ctrl &= ~(_EMU_EM4CTRL_RETAINLFXO_MASK
\r
802 | _EMU_EM4CTRL_RETAINLFRCO_MASK
\r
803 | _EMU_EM4CTRL_RETAINULFRCO_MASK
\r
804 | _EMU_EM4CTRL_EM4STATE_MASK
\r
805 | _EMU_EM4CTRL_EM4IORETMODE_MASK);
\r
807 em4ctrl |= (em4Init->retainLfxo ? EMU_EM4CTRL_RETAINLFXO : 0)
\r
808 | (em4Init->retainLfrco ? EMU_EM4CTRL_RETAINLFRCO : 0)
\r
809 | (em4Init->retainUlfrco ? EMU_EM4CTRL_RETAINULFRCO : 0)
\r
810 | (em4Init->em4State ? EMU_EM4CTRL_EM4STATE_EM4H : 0)
\r
811 | (em4Init->pinRetentionMode);
\r
813 EMU->EM4CTRL = em4ctrl;
\r
819 #if defined( BU_PRESENT )
\r
820 /***************************************************************************//**
\r
822 * Configure Backup Power Domain settings
\r
824 * @param[in] bupdInit
\r
825 * Backup power domain initialization structure
\r
826 ******************************************************************************/
\r
827 void EMU_BUPDInit(EMU_BUPDInit_TypeDef *bupdInit)
\r
831 /* Set power connection configuration */
\r
832 reg = EMU->PWRCONF & ~(_EMU_PWRCONF_PWRRES_MASK
\r
833 | _EMU_PWRCONF_VOUTSTRONG_MASK
\r
834 | _EMU_PWRCONF_VOUTMED_MASK
\r
835 | _EMU_PWRCONF_VOUTWEAK_MASK);
\r
837 reg |= bupdInit->resistor
\r
838 | (bupdInit->voutStrong << _EMU_PWRCONF_VOUTSTRONG_SHIFT)
\r
839 | (bupdInit->voutMed << _EMU_PWRCONF_VOUTMED_SHIFT)
\r
840 | (bupdInit->voutWeak << _EMU_PWRCONF_VOUTWEAK_SHIFT);
\r
842 EMU->PWRCONF = reg;
\r
844 /* Set backup domain inactive mode configuration */
\r
845 reg = EMU->BUINACT & ~(_EMU_BUINACT_PWRCON_MASK);
\r
846 reg |= (bupdInit->inactivePower);
\r
847 EMU->BUINACT = reg;
\r
849 /* Set backup domain active mode configuration */
\r
850 reg = EMU->BUACT & ~(_EMU_BUACT_PWRCON_MASK);
\r
851 reg |= (bupdInit->activePower);
\r
854 /* Set power control configuration */
\r
855 reg = EMU->BUCTRL & ~(_EMU_BUCTRL_PROBE_MASK
\r
856 | _EMU_BUCTRL_BODCAL_MASK
\r
857 | _EMU_BUCTRL_STATEN_MASK
\r
858 | _EMU_BUCTRL_EN_MASK);
\r
860 /* Note use of ->enable to both enable BUPD, use BU_VIN pin input and
\r
862 reg |= bupdInit->probe
\r
863 | (bupdInit->bodCal << _EMU_BUCTRL_BODCAL_SHIFT)
\r
864 | (bupdInit->statusPinEnable << _EMU_BUCTRL_STATEN_SHIFT)
\r
865 | (bupdInit->enable << _EMU_BUCTRL_EN_SHIFT);
\r
867 /* Enable configuration */
\r
870 /* If enable is true, enable BU_VIN input power pin, if not disable it */
\r
871 EMU_BUPinEnable(bupdInit->enable);
\r
873 /* If enable is true, release BU reset, if not keep reset asserted */
\r
874 BUS_RegBitWrite(&(RMU->CTRL), _RMU_CTRL_BURSTEN_SHIFT, !bupdInit->enable);
\r
878 /***************************************************************************//**
\r
880 * Configure Backup Power Domain BOD Threshold value
\r
882 * These values are precalibrated
\r
883 * @param[in] mode Active or Inactive mode
\r
885 ******************************************************************************/
\r
886 void EMU_BUThresholdSet(EMU_BODMode_TypeDef mode, uint32_t value)
\r
888 EFM_ASSERT(value<8);
\r
889 EFM_ASSERT(value<=(_EMU_BUACT_BUEXTHRES_MASK>>_EMU_BUACT_BUEXTHRES_SHIFT));
\r
893 case emuBODMode_Active:
\r
894 EMU->BUACT = (EMU->BUACT & ~_EMU_BUACT_BUEXTHRES_MASK)
\r
895 | (value<<_EMU_BUACT_BUEXTHRES_SHIFT);
\r
897 case emuBODMode_Inactive:
\r
898 EMU->BUINACT = (EMU->BUINACT & ~_EMU_BUINACT_BUENTHRES_MASK)
\r
899 | (value<<_EMU_BUINACT_BUENTHRES_SHIFT);
\r
905 /***************************************************************************//**
\r
907 * Configure Backup Power Domain BOD Threshold Range
\r
909 * These values are precalibrated
\r
910 * @param[in] mode Active or Inactive mode
\r
912 ******************************************************************************/
\r
913 void EMU_BUThresRangeSet(EMU_BODMode_TypeDef mode, uint32_t value)
\r
915 EFM_ASSERT(value < 4);
\r
916 EFM_ASSERT(value<=(_EMU_BUACT_BUEXRANGE_MASK>>_EMU_BUACT_BUEXRANGE_SHIFT));
\r
920 case emuBODMode_Active:
\r
921 EMU->BUACT = (EMU->BUACT & ~_EMU_BUACT_BUEXRANGE_MASK)
\r
922 | (value<<_EMU_BUACT_BUEXRANGE_SHIFT);
\r
924 case emuBODMode_Inactive:
\r
925 EMU->BUINACT = (EMU->BUINACT & ~_EMU_BUINACT_BUENRANGE_MASK)
\r
926 | (value<<_EMU_BUINACT_BUENRANGE_SHIFT);
\r
933 #if defined( _EMU_DCDCCTRL_MASK )
\r
935 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
\r
937 /***************************************************************************//**
\r
939 * Load DCDC calibration constants from DI page. Const means calibration
\r
940 * data that does not change depending on other configuration parameters.
\r
943 * False if calibration registers are locked
\r
944 ******************************************************************************/
\r
945 static bool ConstCalibrationLoad(void)
\r
948 volatile uint32_t *reg;
\r
950 /* DI calib data in flash */
\r
951 volatile uint32_t* const diCal_EMU_DCDCLNFREQCTRL = (volatile uint32_t *)(0x0FE08038);
\r
952 volatile uint32_t* const diCal_EMU_DCDCLNVCTRL = (volatile uint32_t *)(0x0FE08040);
\r
953 volatile uint32_t* const diCal_EMU_DCDCLPCTRL = (volatile uint32_t *)(0x0FE08048);
\r
954 volatile uint32_t* const diCal_EMU_DCDCLPVCTRL = (volatile uint32_t *)(0x0FE08050);
\r
955 volatile uint32_t* const diCal_EMU_DCDCTRIM0 = (volatile uint32_t *)(0x0FE08058);
\r
956 volatile uint32_t* const diCal_EMU_DCDCTRIM1 = (volatile uint32_t *)(0x0FE08060);
\r
958 if (DEVINFO->DCDCLPVCTRL0 != UINT_MAX)
\r
960 val = *(diCal_EMU_DCDCLNFREQCTRL + 1);
\r
961 reg = (volatile uint32_t *)*diCal_EMU_DCDCLNFREQCTRL;
\r
964 val = *(diCal_EMU_DCDCLNVCTRL + 1);
\r
965 reg = (volatile uint32_t *)*diCal_EMU_DCDCLNVCTRL;
\r
968 val = *(diCal_EMU_DCDCLPCTRL + 1);
\r
969 reg = (volatile uint32_t *)*diCal_EMU_DCDCLPCTRL;
\r
972 val = *(diCal_EMU_DCDCLPVCTRL + 1);
\r
973 reg = (volatile uint32_t *)*diCal_EMU_DCDCLPVCTRL;
\r
976 val = *(diCal_EMU_DCDCTRIM0 + 1);
\r
977 reg = (volatile uint32_t *)*diCal_EMU_DCDCTRIM0;
\r
980 val = *(diCal_EMU_DCDCTRIM1 + 1);
\r
981 reg = (volatile uint32_t *)*diCal_EMU_DCDCTRIM1;
\r
987 /* Return when assertions are disabled */
\r
992 /***************************************************************************//**
\r
994 * Set recommended and validated current optimization settings
\r
996 ******************************************************************************/
\r
997 void ValidatedConfigSet(void)
\r
999 #define EMU_DCDCSMCTRL (* (volatile uint32_t *)(EMU_BASE + 0x44))
\r
1001 uint32_t dcdcTiming;
\r
1002 SYSTEM_PartFamily_TypeDef family;
\r
1003 SYSTEM_ChipRevision_TypeDef rev;
\r
1005 /* Enable duty cycling of the bias */
\r
1006 EMU->DCDCLPCTRL |= EMU_DCDCLPCTRL_LPVREFDUTYEN;
\r
1008 /* Set low-noise RCO for EFM32 and EFR32 */
\r
1009 #if defined( _EFR_DEVICE )
\r
1010 /* 7MHz is recommended for all EFR32 parts with DCDC */
\r
1011 EMU->DCDCLNFREQCTRL = (EMU->DCDCLNFREQCTRL & ~_EMU_DCDCLNFREQCTRL_RCOBAND_MASK)
\r
1012 | (EMU_DcdcLnRcoBand_7MHz << _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT);
\r
1014 /* 3MHz is recommended for all EFM32 parts with DCDC */
\r
1015 EMU->DCDCLNFREQCTRL = (EMU->DCDCLNFREQCTRL & ~_EMU_DCDCLNFREQCTRL_RCOBAND_MASK)
\r
1016 | (EMU_DcdcLnRcoBand_3MHz << _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT);
\r
1019 EMU->DCDCTIMING &= ~_EMU_DCDCTIMING_DUTYSCALE_MASK;
\r
1021 family = SYSTEM_GetFamily();
\r
1022 SYSTEM_ChipRevisionGet(&rev);
\r
1023 if ((((family >= systemPartFamilyMighty1P)
\r
1024 && (family <= systemPartFamilyFlex1V))
\r
1025 || (family == systemPartFamilyEfm32Pearl1B)
\r
1026 || (family == systemPartFamilyEfm32Jade1B))
\r
1027 && ((rev.major == 1) && (rev.minor < 3))
\r
1028 && (errataFixDcdcHsState == errataFixDcdcHsInit))
\r
1030 /* LPCMPWAITDIS = 1 */
\r
1031 EMU_DCDCSMCTRL |= 1;
\r
1033 dcdcTiming = EMU->DCDCTIMING;
\r
1034 dcdcTiming &= ~(_EMU_DCDCTIMING_LPINITWAIT_MASK
\r
1035 |_EMU_DCDCTIMING_LNWAIT_MASK
\r
1036 |_EMU_DCDCTIMING_BYPWAIT_MASK);
\r
1038 dcdcTiming |= ((180 << _EMU_DCDCTIMING_LPINITWAIT_SHIFT)
\r
1039 | (12 << _EMU_DCDCTIMING_LNWAIT_SHIFT)
\r
1040 | (180 << _EMU_DCDCTIMING_BYPWAIT_SHIFT));
\r
1041 EMU->DCDCTIMING = dcdcTiming;
\r
1043 errataFixDcdcHsState = errataFixDcdcHsTrimSet;
\r
1048 /***************************************************************************//**
\r
1050 * Calculate and update EMU->DCDCMISCCTRL for maximum DCDC current based
\r
1051 * on the slice configuration and user set maximum.
\r
1052 ******************************************************************************/
\r
1053 static void maxCurrentUpdate(void)
\r
1055 uint32_t lncLimImSel;
\r
1056 uint32_t lpcLimImSel;
\r
1059 pFetCnt = (EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_PFETCNT_MASK)
\r
1060 >> _EMU_DCDCMISCCTRL_PFETCNT_SHIFT;
\r
1062 /* Equation from Reference Manual section 11.5.20, in the register
\r
1063 field description for LNCLIMILIMSEL and LPCLIMILIMSEL. */
\r
1064 lncLimImSel = (dcdcMaxCurrent_mA / (5 * (pFetCnt + 1))) - 1;
\r
1065 /* 80mA as recommended in Application Note AN0948 */
\r
1066 lpcLimImSel = (80 / (5 * (pFetCnt + 1))) - 1;
\r
1068 lncLimImSel <<= _EMU_DCDCMISCCTRL_LNCLIMILIMSEL_SHIFT;
\r
1069 lpcLimImSel <<= _EMU_DCDCMISCCTRL_LPCLIMILIMSEL_SHIFT;
\r
1070 EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_EMU_DCDCMISCCTRL_LNCLIMILIMSEL_MASK
\r
1071 | _EMU_DCDCMISCCTRL_LPCLIMILIMSEL_MASK))
\r
1072 | (lncLimImSel | lpcLimImSel);
\r
1076 /***************************************************************************//**
\r
1078 * Set static variable that holds the user set maximum current. Update
\r
1079 * DCDC configuration.
\r
1081 * @param[in] mAmaxCurrent
\r
1082 * Maximum allowed current drawn by the DCDC from VREGVDD in mA.
\r
1083 ******************************************************************************/
\r
1084 static void maxCurrentSet(uint32_t mAmaxCurrent)
\r
1086 dcdcMaxCurrent_mA = mAmaxCurrent;
\r
1087 maxCurrentUpdate();
\r
1091 /***************************************************************************//**
\r
1093 * Load EMU_DCDCLPCTRL_LPCMPHYSSEL depending on LP bias, LP feedback
\r
1094 * attenuation and DEVINFOREV.
\r
1096 * @param[in] attSet
\r
1097 * LP feedback attenuation.
\r
1098 * @param[in] lpCmpBias
\r
1099 * lpCmpBias selection
\r
1100 ******************************************************************************/
\r
1101 static bool LpCmpHystCalibrationLoad(bool lpAttenuation, uint32_t lpCmpBias)
\r
1103 uint8_t devinfoRev;
\r
1104 uint32_t lpcmpHystSel;
\r
1106 /* Get calib data revision */
\r
1107 devinfoRev = SYSTEM_GetDevinfoRev();
\r
1109 /* Load LPATT indexed calibration data */
\r
1110 if (devinfoRev < 4)
\r
1112 lpcmpHystSel = DEVINFO->DCDCLPCMPHYSSEL0;
\r
1114 if (lpAttenuation)
\r
1116 lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT1_MASK)
\r
1117 >> _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT1_SHIFT;
\r
1121 lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT0_MASK)
\r
1122 >> _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT0_SHIFT;
\r
1125 /* devinfoRev >= 4
\r
1126 Load LPCMPBIAS indexed calibration data */
\r
1129 lpcmpHystSel = DEVINFO->DCDCLPCMPHYSSEL1;
\r
1130 switch (lpCmpBias)
\r
1132 case _EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS0:
\r
1133 lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS0_MASK)
\r
1134 >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS0_SHIFT;
\r
1137 case _EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS1:
\r
1138 lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS1_MASK)
\r
1139 >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS1_SHIFT;
\r
1142 case _EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS2:
\r
1143 lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS2_MASK)
\r
1144 >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS2_SHIFT;
\r
1147 case _EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS3:
\r
1148 lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS3_MASK)
\r
1149 >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS3_SHIFT;
\r
1153 EFM_ASSERT(false);
\r
1154 /* Return when assertions are disabled */
\r
1159 /* Make sure the sel value is within the field range. */
\r
1160 lpcmpHystSel <<= _EMU_DCDCLPCTRL_LPCMPHYSSEL_SHIFT;
\r
1161 if (lpcmpHystSel & ~_EMU_DCDCLPCTRL_LPCMPHYSSEL_MASK)
\r
1163 EFM_ASSERT(false);
\r
1164 /* Return when assertions are disabled */
\r
1167 EMU->DCDCLPCTRL = (EMU->DCDCLPCTRL & ~_EMU_DCDCLPCTRL_LPCMPHYSSEL_MASK) | lpcmpHystSel;
\r
1175 /***************************************************************************//**
\r
1177 * Set DCDC regulator operating mode
\r
1179 * @param[in] dcdcMode
\r
1181 ******************************************************************************/
\r
1182 void EMU_DCDCModeSet(EMU_DcdcMode_TypeDef dcdcMode)
\r
1184 while(EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY);
\r
1185 BUS_RegBitWrite(&EMU->DCDCCLIMCTRL, _EMU_DCDCCLIMCTRL_BYPLIMEN_SHIFT, dcdcMode == emuDcdcMode_Bypass ? 0 : 1);
\r
1186 EMU->DCDCCTRL = (EMU->DCDCCTRL & ~_EMU_DCDCCTRL_DCDCMODE_MASK) | dcdcMode;
\r
1190 /***************************************************************************//**
\r
1192 * Configure DCDC regulator
\r
1195 * Use the function EMU_DCDCPowerDown() to if the power circuit is configured
\r
1196 * for NODCDC as decribed in Section 11.3.4.3 in the Reference Manual.
\r
1198 * @param[in] dcdcInit
\r
1199 * DCDC initialization structure
\r
1202 * True if initialization parameters are valid
\r
1203 ******************************************************************************/
\r
1204 bool EMU_DCDCInit(EMU_DCDCInit_TypeDef *dcdcInit)
\r
1206 uint32_t lpCmpBiasSel;
\r
1208 /* Set external power configuration. This enables writing to the other
\r
1209 DCDC registers. */
\r
1210 EMU->PWRCFG = dcdcInit->powerConfig;
\r
1212 /* EMU->PWRCFG is write-once and POR reset only. Check that
\r
1213 we could set the desired power configuration. */
\r
1214 if ((EMU->PWRCFG & _EMU_PWRCFG_PWRCFG_MASK) != dcdcInit->powerConfig)
\r
1216 /* If this assert triggers unexpectedly, please power cycle the
\r
1217 kit to reset the power configuration. */
\r
1218 EFM_ASSERT(false);
\r
1219 /* Return when assertions are disabled */
\r
1223 /* Load DCDC calibration data from the DI page */
\r
1224 ConstCalibrationLoad();
\r
1226 /* Check current parameters */
\r
1227 EFM_ASSERT(dcdcInit->maxCurrent_mA <= 200);
\r
1228 EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= dcdcInit->maxCurrent_mA);
\r
1230 /* DCDC low-noise supports max 200mA */
\r
1231 if (dcdcInit->dcdcMode == emuDcdcMode_LowNoise)
\r
1233 EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= 200);
\r
1236 /* EM2, 3 and 4 current above 100uA is not supported */
\r
1237 EFM_ASSERT(dcdcInit->em234LoadCurrent_uA <= 100);
\r
1239 /* Decode LP comparator bias for EM0/1 and EM2/3 */
\r
1240 lpCmpBiasSel = EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS1;
\r
1241 if (dcdcInit->em234LoadCurrent_uA <= 10)
\r
1243 lpCmpBiasSel = EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS0;
\r
1246 /* Set DCDC low-power mode comparator bias selection */
\r
1247 EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_EMU_DCDCMISCCTRL_LPCMPBIAS_MASK
\r
1248 | _EMU_DCDCMISCCTRL_LNFORCECCM_MASK))
\r
1249 | ((uint32_t)lpCmpBiasSel
\r
1250 | (uint32_t)dcdcInit->lnTransientMode);
\r
1252 /* Set recommended and validated current optimization settings */
\r
1253 ValidatedConfigSet();
\r
1255 /* Set the maximum current that the DCDC can draw from the power source */
\r
1256 maxCurrentSet(dcdcInit->maxCurrent_mA);
\r
1258 /* Optimize LN slice based on given load current estimate */
\r
1259 EMU_DCDCOptimizeSlice(dcdcInit->em01LoadCurrent_mA);
\r
1261 /* Set DCDC output voltage */
\r
1262 dcdcOutput_mVout = dcdcInit->mVout;
\r
1263 if (!EMU_DCDCOutputVoltageSet(dcdcOutput_mVout, true, true))
\r
1265 EFM_ASSERT(false);
\r
1266 /* Return when assertions are disabled */
\r
1270 /* Set EM0 DCDC operating mode. Output voltage set in EMU_DCDCOutputVoltageSet()
\r
1271 above takes effect if mode is changed from bypass here. */
\r
1272 EMU_DCDCModeSet(dcdcInit->dcdcMode);
\r
1274 /* Select analog peripheral power supply */
\r
1275 BUS_RegBitWrite(&EMU->PWRCTRL, _EMU_PWRCTRL_ANASW_SHIFT, dcdcInit->anaPeripheralPower ? 1 : 0);
\r
1281 /***************************************************************************//**
\r
1283 * Set DCDC output voltage
\r
1286 * Target DCDC output voltage in mV
\r
1289 * True if the mV parameter is valid
\r
1290 ******************************************************************************/
\r
1291 bool EMU_DCDCOutputVoltageSet(uint32_t mV,
\r
1292 bool setLpVoltage,
\r
1293 bool setLnVoltage)
\r
1295 #if defined( _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_MASK )
\r
1297 bool validOutVoltage;
\r
1301 uint32_t vrefLow = 0;
\r
1302 uint32_t vrefHigh = 0;
\r
1303 uint32_t vrefVal = 0;
\r
1304 uint32_t mVlow = 0;
\r
1305 uint32_t mVhigh = 0;
\r
1306 uint32_t vrefShift;
\r
1307 uint32_t lpcmpBias;
\r
1308 volatile uint32_t* ctrlReg;
\r
1310 /* Check that the set voltage is within valid range.
\r
1311 Voltages are obtained from the datasheet. */
\r
1312 validOutVoltage = false;
\r
1313 if ((EMU->PWRCFG & _EMU_PWRCFG_PWRCFG_MASK) == EMU_PWRCFG_PWRCFG_DCDCTODVDD)
\r
1315 validOutVoltage = ((mV >= PWRCFG_DCDCTODVDD_VMIN)
\r
1316 && (mV <= PWRCFG_DCDCTODVDD_VMAX));
\r
1319 if (!validOutVoltage)
\r
1321 EFM_ASSERT(false);
\r
1322 /* Return when assertions are disabled */
\r
1326 /* Populate both LP and LN registers, set control reg pointer and VREF shift. */
\r
1327 for (lnMode = 0; lnMode <= 1; lnMode++)
\r
1329 if (((lnMode == 0) && !setLpVoltage)
\r
1330 || ((lnMode == 1) && !setLnVoltage))
\r
1335 ctrlReg = (lnMode ? &EMU->DCDCLNVCTRL : &EMU->DCDCLPVCTRL);
\r
1336 vrefShift = (lnMode ? _EMU_DCDCLNVCTRL_LNVREF_SHIFT
\r
1337 : _EMU_DCDCLPVCTRL_LPVREF_SHIFT);
\r
1339 /* Set attenuation to use */
\r
1340 attSet = (mV > 1800);
\r
1345 attMask = (lnMode ? EMU_DCDCLNVCTRL_LNATT : EMU_DCDCLPVCTRL_LPATT);
\r
1354 /* Get 2-point calib data from DEVINFO, calculate trimming and set voltege */
\r
1357 /* Set low-noise DCDC output voltage tuning */
\r
1360 vrefLow = DEVINFO->DCDCLNVCTRL0;
\r
1361 vrefHigh = (vrefLow & _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_MASK)
\r
1362 >> _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_SHIFT;
\r
1363 vrefLow = (vrefLow & _DEVINFO_DCDCLNVCTRL0_1V8LNATT1_MASK)
\r
1364 >> _DEVINFO_DCDCLNVCTRL0_1V8LNATT1_SHIFT;
\r
1368 vrefLow = DEVINFO->DCDCLNVCTRL0;
\r
1369 vrefHigh = (vrefLow & _DEVINFO_DCDCLNVCTRL0_1V8LNATT0_MASK)
\r
1370 >> _DEVINFO_DCDCLNVCTRL0_1V8LNATT0_SHIFT;
\r
1371 vrefLow = (vrefLow & _DEVINFO_DCDCLNVCTRL0_1V2LNATT0_MASK)
\r
1372 >> _DEVINFO_DCDCLNVCTRL0_1V2LNATT0_SHIFT;
\r
1377 /* Set low-power DCDC output voltage tuning */
\r
1379 /* Get LPCMPBIAS and make sure masks are not overlayed */
\r
1380 lpcmpBias = EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LPCMPBIAS_MASK;
\r
1381 EFM_ASSERT(!(_EMU_DCDCMISCCTRL_LPCMPBIAS_MASK & attMask));
\r
1382 switch (attMask | lpcmpBias)
\r
1384 case EMU_DCDCLPVCTRL_LPATT | EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS0:
\r
1385 vrefLow = DEVINFO->DCDCLPVCTRL2;
\r
1386 vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS0_MASK)
\r
1387 >> _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS0_SHIFT;
\r
1388 vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS0_MASK)
\r
1389 >> _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS0_SHIFT;
\r
1392 case EMU_DCDCLPVCTRL_LPATT | EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS1:
\r
1393 vrefLow = DEVINFO->DCDCLPVCTRL2;
\r
1394 vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS1_MASK)
\r
1395 >> _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS1_SHIFT;
\r
1396 vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS1_MASK)
\r
1397 >> _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS1_SHIFT;
\r
1400 case EMU_DCDCLPVCTRL_LPATT | EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS2:
\r
1401 vrefLow = DEVINFO->DCDCLPVCTRL3;
\r
1402 vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS2_MASK)
\r
1403 >> _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS2_SHIFT;
\r
1404 vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS2_MASK)
\r
1405 >> _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS2_SHIFT;
\r
1408 case EMU_DCDCLPVCTRL_LPATT | EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS3:
\r
1409 vrefLow = DEVINFO->DCDCLPVCTRL3;
\r
1410 vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS3_MASK)
\r
1411 >> _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS3_SHIFT;
\r
1412 vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS3_MASK)
\r
1413 >> _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS3_SHIFT;
\r
1416 case EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS0:
\r
1417 vrefLow = DEVINFO->DCDCLPVCTRL0;
\r
1418 vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS0_MASK)
\r
1419 >> _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS0_SHIFT;
\r
1420 vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS0_MASK)
\r
1421 >> _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS0_SHIFT;
\r
1424 case EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS1:
\r
1425 vrefLow = DEVINFO->DCDCLPVCTRL0;
\r
1426 vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS1_MASK)
\r
1427 >> _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS1_SHIFT;
\r
1428 vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS1_MASK)
\r
1429 >> _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS1_SHIFT;
\r
1432 case EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS2:
\r
1433 vrefLow = DEVINFO->DCDCLPVCTRL1;
\r
1434 vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS2_MASK)
\r
1435 >> _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS2_SHIFT;
\r
1436 vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS2_MASK)
\r
1437 >> _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS2_SHIFT;
\r
1440 case EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS3:
\r
1441 vrefLow = DEVINFO->DCDCLPVCTRL1;
\r
1442 vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS3_MASK)
\r
1443 >> _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS3_SHIFT;
\r
1444 vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS3_MASK)
\r
1445 >> _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS3_SHIFT;
\r
1449 EFM_ASSERT(false);
\r
1453 /* Load LP comparator hysteresis calibration */
\r
1454 if(!(LpCmpHystCalibrationLoad(attSet, lpcmpBias >> _EMU_DCDCMISCCTRL_LPCMPBIAS_SHIFT)))
\r
1456 EFM_ASSERT(false);
\r
1457 /* Return when assertions are disabled */
\r
1460 } /* Low-nise / low-power mode */
\r
1463 /* Check for valid 2-point trim values */
\r
1464 if ((vrefLow == 0xFF) && (vrefHigh == 0xFF))
\r
1466 EFM_ASSERT(false);
\r
1467 /* Return when assertions are disabled */
\r
1471 /* Calculate and set voltage trim */
\r
1472 vrefVal = ((mV - mVlow) * (vrefHigh - vrefLow)) / (mVhigh - mVlow);
\r
1473 vrefVal += vrefLow;
\r
1476 if ((vrefVal > vrefHigh) || (vrefVal < vrefLow))
\r
1478 EFM_ASSERT(false);
\r
1479 /* Return when assertions are disabled */
\r
1483 /* Update DCDCLNVCTRL/DCDCLPVCTRL */
\r
1484 *ctrlReg = (vrefVal << vrefShift) | attMask;
\r
1491 /***************************************************************************//**
\r
1493 * Optimize DCDC slice count based on the estimated average load current
\r
1496 * @param[in] mAEm0LoadCurrent
\r
1497 * Estimated average EM0 load current in mA.
\r
1498 ******************************************************************************/
\r
1499 void EMU_DCDCOptimizeSlice(uint32_t mAEm0LoadCurrent)
\r
1501 uint32_t sliceCount = 0;
\r
1502 uint32_t rcoBand = (EMU->DCDCLNFREQCTRL & _EMU_DCDCLNFREQCTRL_RCOBAND_MASK)
\r
1503 >> _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT;
\r
1505 /* Set recommended slice count */
\r
1506 if ((EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK) && (rcoBand >= EMU_DcdcLnRcoBand_5MHz))
\r
1508 if (mAEm0LoadCurrent < 20)
\r
1512 else if ((mAEm0LoadCurrent >= 20) && (mAEm0LoadCurrent < 40))
\r
1521 else if ((!(EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK)) && (rcoBand <= EMU_DcdcLnRcoBand_4MHz))
\r
1523 if (mAEm0LoadCurrent < 10)
\r
1527 else if ((mAEm0LoadCurrent >= 10) && (mAEm0LoadCurrent < 20))
\r
1536 else if ((EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK) && (rcoBand <= EMU_DcdcLnRcoBand_4MHz))
\r
1538 if (mAEm0LoadCurrent < 40)
\r
1549 /* This configuration is not recommended. EMU_DCDCInit() applies a recommended
\r
1551 EFM_ASSERT(false);
\r
1554 /* The selected silices are PSLICESEL + 1 */
\r
1557 /* Apply slice count to both N and P slice */
\r
1558 sliceCount = (sliceCount << _EMU_DCDCMISCCTRL_PFETCNT_SHIFT
\r
1559 | sliceCount << _EMU_DCDCMISCCTRL_NFETCNT_SHIFT);
\r
1560 EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_EMU_DCDCMISCCTRL_PFETCNT_MASK
\r
1561 | _EMU_DCDCMISCCTRL_NFETCNT_MASK))
\r
1564 /* Update current limit configuration as it depends on the slice configuration. */
\r
1565 maxCurrentUpdate();
\r
1568 /***************************************************************************//**
\r
1570 * Set DCDC Low-noise RCO band.
\r
1573 * RCO band to set.
\r
1574 ******************************************************************************/
\r
1575 void EMU_DCDCLnRcoBandSet(EMU_DcdcLnRcoBand_TypeDef band)
\r
1577 EMU->DCDCLNFREQCTRL = (EMU->DCDCLNFREQCTRL & ~_EMU_DCDCLNFREQCTRL_RCOBAND_MASK)
\r
1578 | (band << _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT);
\r
1581 /***************************************************************************//**
\r
1583 * Power off the DCDC regulator.
\r
1586 * This function powers off the DCDC controller. This function should only be
\r
1587 * used if the external power circuit is wired for no DCDC. If the external power
\r
1588 * circuit is wired for DCDC usage, then use EMU_DCDCInit() and set the
\r
1589 * DCDC in bypass mode to disable DCDC.
\r
1592 * Return false if the DCDC could not be disabled.
\r
1593 ******************************************************************************/
\r
1594 bool EMU_DCDCPowerOff(void)
\r
1596 /* Set power configuration to hard bypass */
\r
1597 EMU->PWRCFG = 0xF;
\r
1598 if ((EMU->PWRCFG & _EMU_PWRCFG_PWRCFG_MASK) != 0xF)
\r
1600 EFM_ASSERT(false);
\r
1601 /* Return when assertions are disabled */
\r
1605 /* Set DCDC to OFF and disable LP in EM2/3/4 */
\r
1606 EMU->DCDCCTRL = EMU_DCDCCTRL_DCDCMODE_OFF;
\r
1612 #if defined( EMU_STATUS_VMONRDY )
\r
1613 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
\r
1614 __STATIC_INLINE uint32_t vmonMilliVoltToCoarseThreshold(int mV)
\r
1616 return (mV - 1200) / 200;
\r
1619 __STATIC_INLINE uint32_t vmonMilliVoltToFineThreshold(int mV, uint32_t coarseThreshold)
\r
1621 return (mV - 1200 - (coarseThreshold * 200)) / 20;
\r
1625 /***************************************************************************//**
\r
1627 * Initialize VMON channel.
\r
1630 * Initialize a VMON channel without hysteresis. If the channel supports
\r
1631 * separate rise and fall triggers, both thresholds will be set to the same
\r
1634 * @param[in] vmonInit
\r
1635 * VMON initialization struct
\r
1636 ******************************************************************************/
\r
1637 void EMU_VmonInit(EMU_VmonInit_TypeDef *vmonInit)
\r
1639 uint32_t thresholdCoarse, thresholdFine;
\r
1640 EFM_ASSERT((vmonInit->threshold >= 1200) && (vmonInit->threshold <= 3980));
\r
1642 thresholdCoarse = vmonMilliVoltToCoarseThreshold(vmonInit->threshold);
\r
1643 thresholdFine = vmonMilliVoltToFineThreshold(vmonInit->threshold, thresholdCoarse);
\r
1645 switch(vmonInit->channel)
\r
1647 case emuVmonChannel_AVDD:
\r
1648 EMU->VMONAVDDCTRL = (thresholdCoarse << _EMU_VMONAVDDCTRL_RISETHRESCOARSE_SHIFT)
\r
1649 | (thresholdFine << _EMU_VMONAVDDCTRL_RISETHRESFINE_SHIFT)
\r
1650 | (thresholdCoarse << _EMU_VMONAVDDCTRL_FALLTHRESCOARSE_SHIFT)
\r
1651 | (thresholdFine << _EMU_VMONAVDDCTRL_FALLTHRESFINE_SHIFT)
\r
1652 | (vmonInit->riseWakeup ? EMU_VMONAVDDCTRL_RISEWU : 0)
\r
1653 | (vmonInit->fallWakeup ? EMU_VMONAVDDCTRL_FALLWU : 0)
\r
1654 | (vmonInit->enable ? EMU_VMONAVDDCTRL_EN : 0);
\r
1656 case emuVmonChannel_ALTAVDD:
\r
1657 EMU->VMONALTAVDDCTRL = (thresholdCoarse << _EMU_VMONALTAVDDCTRL_THRESCOARSE_SHIFT)
\r
1658 | (thresholdFine << _EMU_VMONALTAVDDCTRL_THRESFINE_SHIFT)
\r
1659 | (vmonInit->riseWakeup ? EMU_VMONALTAVDDCTRL_RISEWU : 0)
\r
1660 | (vmonInit->fallWakeup ? EMU_VMONALTAVDDCTRL_FALLWU : 0)
\r
1661 | (vmonInit->enable ? EMU_VMONALTAVDDCTRL_EN : 0);
\r
1663 case emuVmonChannel_DVDD:
\r
1664 EMU->VMONDVDDCTRL = (thresholdCoarse << _EMU_VMONDVDDCTRL_THRESCOARSE_SHIFT)
\r
1665 | (thresholdFine << _EMU_VMONDVDDCTRL_THRESFINE_SHIFT)
\r
1666 | (vmonInit->riseWakeup ? EMU_VMONDVDDCTRL_RISEWU : 0)
\r
1667 | (vmonInit->fallWakeup ? EMU_VMONDVDDCTRL_FALLWU : 0)
\r
1668 | (vmonInit->enable ? EMU_VMONDVDDCTRL_EN : 0);
\r
1670 case emuVmonChannel_IOVDD0:
\r
1671 EMU->VMONIO0CTRL = (thresholdCoarse << _EMU_VMONIO0CTRL_THRESCOARSE_SHIFT)
\r
1672 | (thresholdFine << _EMU_VMONIO0CTRL_THRESFINE_SHIFT)
\r
1673 | (vmonInit->retDisable ? EMU_VMONIO0CTRL_RETDIS : 0)
\r
1674 | (vmonInit->riseWakeup ? EMU_VMONIO0CTRL_RISEWU : 0)
\r
1675 | (vmonInit->fallWakeup ? EMU_VMONIO0CTRL_FALLWU : 0)
\r
1676 | (vmonInit->enable ? EMU_VMONIO0CTRL_EN : 0);
\r
1679 EFM_ASSERT(false);
\r
1684 /***************************************************************************//**
\r
1686 * Initialize VMON channel with hysteresis (separate rise and fall triggers).
\r
1689 * Initialize a VMON channel which supports hysteresis. The AVDD channel is
\r
1690 * the only channel to support separate rise and fall triggers.
\r
1692 * @param[in] vmonInit
\r
1693 * VMON Hysteresis initialization struct
\r
1694 ******************************************************************************/
\r
1695 void EMU_VmonHystInit(EMU_VmonHystInit_TypeDef *vmonInit)
\r
1697 uint32_t riseThresholdCoarse, riseThresholdFine, fallThresholdCoarse, fallThresholdFine;
\r
1698 /* VMON supports voltages between 1200 mV and 3980 mV (inclusive) in 20 mV increments */
\r
1699 EFM_ASSERT((vmonInit->riseThreshold >= 1200) && (vmonInit->riseThreshold < 4000));
\r
1700 EFM_ASSERT((vmonInit->fallThreshold >= 1200) && (vmonInit->fallThreshold < 4000));
\r
1701 /* Fall threshold has to be lower than rise threshold */
\r
1702 EFM_ASSERT(vmonInit->fallThreshold <= vmonInit->riseThreshold);
\r
1704 riseThresholdCoarse = vmonMilliVoltToCoarseThreshold(vmonInit->riseThreshold);
\r
1705 riseThresholdFine = vmonMilliVoltToFineThreshold(vmonInit->riseThreshold, riseThresholdCoarse);
\r
1706 fallThresholdCoarse = vmonMilliVoltToCoarseThreshold(vmonInit->fallThreshold);
\r
1707 fallThresholdFine = vmonMilliVoltToFineThreshold(vmonInit->fallThreshold, fallThresholdCoarse);
\r
1709 switch(vmonInit->channel)
\r
1711 case emuVmonChannel_AVDD:
\r
1712 EMU->VMONAVDDCTRL = (riseThresholdCoarse << _EMU_VMONAVDDCTRL_RISETHRESCOARSE_SHIFT)
\r
1713 | (riseThresholdFine << _EMU_VMONAVDDCTRL_RISETHRESFINE_SHIFT)
\r
1714 | (fallThresholdCoarse << _EMU_VMONAVDDCTRL_FALLTHRESCOARSE_SHIFT)
\r
1715 | (fallThresholdFine << _EMU_VMONAVDDCTRL_FALLTHRESFINE_SHIFT)
\r
1716 | (vmonInit->riseWakeup ? EMU_VMONAVDDCTRL_RISEWU : 0)
\r
1717 | (vmonInit->fallWakeup ? EMU_VMONAVDDCTRL_FALLWU : 0)
\r
1718 | (vmonInit->enable ? EMU_VMONAVDDCTRL_EN : 0);
\r
1721 EFM_ASSERT(false);
\r
1726 /***************************************************************************//**
\r
1728 * Enable or disable a VMON channel
\r
1730 * @param[in] channel
\r
1731 * VMON channel to enable/disable
\r
1733 * @param[in] enable
\r
1734 * Whether to enable or disable
\r
1735 ******************************************************************************/
\r
1736 void EMU_VmonEnable(EMU_VmonChannel_TypeDef channel, bool enable)
\r
1738 uint32_t volatile * reg;
\r
1743 case emuVmonChannel_AVDD:
\r
1744 reg = &(EMU->VMONAVDDCTRL);
\r
1745 bit = _EMU_VMONAVDDCTRL_EN_SHIFT;
\r
1747 case emuVmonChannel_ALTAVDD:
\r
1748 reg = &(EMU->VMONALTAVDDCTRL);
\r
1749 bit = _EMU_VMONALTAVDDCTRL_EN_SHIFT;
\r
1751 case emuVmonChannel_DVDD:
\r
1752 reg = &(EMU->VMONDVDDCTRL);
\r
1753 bit = _EMU_VMONDVDDCTRL_EN_SHIFT;
\r
1755 case emuVmonChannel_IOVDD0:
\r
1756 reg = &(EMU->VMONIO0CTRL);
\r
1757 bit = _EMU_VMONIO0CTRL_EN_SHIFT;
\r
1760 EFM_ASSERT(false);
\r
1764 BUS_RegBitWrite(reg, bit, enable);
\r
1767 /***************************************************************************//**
\r
1769 * Get the status of a voltage monitor channel.
\r
1771 * @param[in] channel
\r
1772 * VMON channel to get status for
\r
1775 * Status of the selected VMON channel. True if channel is triggered.
\r
1776 ******************************************************************************/
\r
1777 bool EMU_VmonChannelStatusGet(EMU_VmonChannel_TypeDef channel)
\r
1782 case emuVmonChannel_AVDD:
\r
1783 bit = _EMU_STATUS_VMONAVDD_SHIFT;
\r
1785 case emuVmonChannel_ALTAVDD:
\r
1786 bit = _EMU_STATUS_VMONALTAVDD_SHIFT;
\r
1788 case emuVmonChannel_DVDD:
\r
1789 bit = _EMU_STATUS_VMONDVDD_SHIFT;
\r
1791 case emuVmonChannel_IOVDD0:
\r
1792 bit = _EMU_STATUS_VMONIO0_SHIFT;
\r
1795 EFM_ASSERT(false);
\r
1799 return BUS_RegBitRead(&EMU->STATUS, bit);
\r
1801 #endif /* EMU_STATUS_VMONRDY */
\r
1803 /** @} (end addtogroup EMU) */
\r
1804 /** @} (end addtogroup EM_Library) */
\r
1805 #endif /* __EM_EMU_H */
\r