EFM32 Gecko Software Documentation  efm32g-doc-5.1.2
em_emu.c
Go to the documentation of this file.
1 /***************************************************************************/
33 #include <limits.h>
34 
35 #include "em_emu.h"
36 #if defined( EMU_PRESENT ) && ( EMU_COUNT > 0 )
37 
38 #include "em_cmu.h"
39 #include "em_system.h"
40 #include "em_common.h"
41 #include "em_assert.h"
42 
43 /***************************************************************************/
48 /***************************************************************************/
58 /* Consistency check, since restoring assumes similar bitpositions in */
59 /* CMU OSCENCMD and STATUS regs */
60 #if (CMU_STATUS_AUXHFRCOENS != CMU_OSCENCMD_AUXHFRCOEN)
61 #error Conflict in AUXHFRCOENS and AUXHFRCOEN bitpositions
62 #endif
63 #if (CMU_STATUS_HFXOENS != CMU_OSCENCMD_HFXOEN)
64 #error Conflict in HFXOENS and HFXOEN bitpositions
65 #endif
66 #if (CMU_STATUS_LFRCOENS != CMU_OSCENCMD_LFRCOEN)
67 #error Conflict in LFRCOENS and LFRCOEN bitpositions
68 #endif
69 #if (CMU_STATUS_LFXOENS != CMU_OSCENCMD_LFXOEN)
70 #error Conflict in LFXOENS and LFXOEN bitpositions
71 #endif
72 
74 #if defined( _SILICON_LABS_32B_SERIES_0 )
75 /* Fix for errata EMU_E107 - non-WIC interrupt masks.
76  * Zero Gecko and future families are not affected by errata EMU_E107 */
77 #if defined( _EFM32_GECKO_FAMILY )
78 #define ERRATA_FIX_EMU_E107_EN
79 #define NON_WIC_INT_MASK_0 (~(0x0dfc0323U))
80 #define NON_WIC_INT_MASK_1 (~(0x0U))
81 
82 #elif defined( _EFM32_TINY_FAMILY )
83 #define ERRATA_FIX_EMU_E107_EN
84 #define NON_WIC_INT_MASK_0 (~(0x001be323U))
85 #define NON_WIC_INT_MASK_1 (~(0x0U))
86 
87 #elif defined( _EFM32_GIANT_FAMILY )
88 #define ERRATA_FIX_EMU_E107_EN
89 #define NON_WIC_INT_MASK_0 (~(0xff020e63U))
90 #define NON_WIC_INT_MASK_1 (~(0x00000046U))
91 
92 #elif defined( _EFM32_WONDER_FAMILY )
93 #define ERRATA_FIX_EMU_E107_EN
94 #define NON_WIC_INT_MASK_0 (~(0xff020e63U))
95 #define NON_WIC_INT_MASK_1 (~(0x00000046U))
96 
97 #endif
98 #endif
99 
100 /* Fix for errata EMU_E108 - High Current Consumption on EM4 Entry. */
101 #if defined(_SILICON_LABS_32B_SERIES_0) && defined( _EFM32_HAPPY_FAMILY )
102 #define ERRATA_FIX_EMU_E108_EN
103 #endif
104 
105 /* Fix for errata EMU_E208 - Occasional Full Reset After Exiting EM4H */
106 #if defined( _SILICON_LABS_GECKO_INTERNAL_SDID_80 )
107 #define ERRATA_FIX_EMU_E208_EN
108 #endif
109 
110 /* Enable FETCNT tuning errata fix */
111 #if defined( _SILICON_LABS_GECKO_INTERNAL_SDID_80 )
112 #define ERRATA_FIX_DCDC_FETCNT_SET_EN
113 #endif
114 
115 /* Enable LN handshake errata fix */
116 #if defined( _SILICON_LABS_GECKO_INTERNAL_SDID_80 )
117 #define ERRATA_FIX_DCDC_LNHS_BLOCK_EN
118 typedef enum
119 {
120  errataFixDcdcHsInit,
121  errataFixDcdcHsTrimSet,
122  errataFixDcdcHsBypassLn,
123  errataFixDcdcHsLnWaitDone
124 } errataFixDcdcHs_TypeDef;
125 static errataFixDcdcHs_TypeDef errataFixDcdcHsState = errataFixDcdcHsInit;
126 #endif
127 
128 /* Used to figure out if a memory address is inside or outside of a RAM block.
129  * A memory address is inside a RAM block if the address is greater than the
130  * RAM block address. */
131 #define ADDRESS_NOT_IN_BLOCK(addr, block) ((addr) <= (block))
132 
133 /* RAM Block layout for various device families. Note that some devices
134  * have special layout in RAM0. */
135 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_84)
136 #define RAM1_BLOCKS 2
137 #define RAM1_BLOCK_SIZE 0x10000 // 64 kB blocks
138 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_89)
139 #define RAM0_BLOCKS 2
140 #define RAM0_BLOCK_SIZE 0x4000
141 #define RAM1_BLOCKS 2
142 #define RAM1_BLOCK_SIZE 0x4000 // 16 kB blocks
143 #elif defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_GIANT_FAMILY)
144 #define RAM0_BLOCKS 4
145 #define RAM0_BLOCK_SIZE 0x8000 // 32 kB blocks
146 #elif defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_GECKO_FAMILY)
147 #define RAM0_BLOCKS 4
148 #define RAM0_BLOCK_SIZE 0x1000 // 4 kB blocks
149 #endif
150 
151 #if defined(_SILICON_LABS_32B_SERIES_0)
152 /* RAM_MEM_END on Gecko devices have a value larger than the SRAM_SIZE */
153 #define RAM0_END (SRAM_BASE + SRAM_SIZE - 1)
154 #else
155 #define RAM0_END RAM_MEM_END
156 #endif
157 
161 #if defined( _EMU_DCDCCTRL_MASK )
162 /* DCDCTODVDD output range min/max */
163 #if !defined(PWRCFG_DCDCTODVDD_VMIN)
164 #define PWRCFG_DCDCTODVDD_VMIN 1800
165 #endif
166 #if !defined(PWRCFG_DCDCTODVDD_VMAX)
167 #define PWRCFG_DCDCTODVDD_VMAX 3000
168 #endif
169 #endif
170 
171 /*******************************************************************************
172  *************************** LOCAL VARIABLES ********************************
173  ******************************************************************************/
174 
177 /* Static user configuration */
178 #if defined( _EMU_DCDCCTRL_MASK )
179 static uint16_t dcdcMaxCurrent_mA;
180 static uint16_t dcdcEm01LoadCurrent_mA;
181 static EMU_DcdcLnReverseCurrentControl_TypeDef dcdcReverseCurrentControl;
182 #endif
183 #if defined( _EMU_CMD_EM01VSCALE0_MASK )
184 static EMU_EM01Init_TypeDef vScaleEM01Config = {false};
185 #endif
186 
189 /*******************************************************************************
190  ************************** LOCAL FUNCTIONS ********************************
191  ******************************************************************************/
192 
195 #if defined( _EMU_CMD_EM01VSCALE0_MASK )
196 /* Convert from level to EM0 and 1 command bit */
197 __STATIC_INLINE uint32_t vScaleEM01Cmd(EMU_VScaleEM01_TypeDef level)
198 {
199  return EMU_CMD_EM01VSCALE0 << (_EMU_STATUS_VSCALE_VSCALE0 - (uint32_t)level);
200 }
201 #endif
202 
203 /***************************************************************************/
214 typedef enum
215 {
216  emState_Save, /* Save EMU and CMU state */
217  emState_Restore, /* Restore and unlock */
218 } emState_TypeDef;
219 
220 static void emState(emState_TypeDef action)
221 {
222  uint32_t oscEnCmd;
223  uint32_t cmuLocked;
224  static uint32_t cmuStatus;
225  static CMU_Select_TypeDef hfClock;
226 #if defined( _EMU_CMD_EM01VSCALE0_MASK )
227  static uint8_t vScaleStatus;
228 #endif
229 
230 
231  /* Save or update state */
232  if (action == emState_Save)
233  {
234  /* Save configuration. */
235  cmuStatus = CMU->STATUS;
236  hfClock = CMU_ClockSelectGet(cmuClock_HF);
237 #if defined( _EMU_CMD_EM01VSCALE0_MASK )
238  /* Save vscale */
239  EMU_VScaleWait();
240  vScaleStatus = (uint8_t)((EMU->STATUS & _EMU_STATUS_VSCALE_MASK)
241  >> _EMU_STATUS_VSCALE_SHIFT);
242 #endif
243  }
244  else if (action == emState_Restore) /* Restore state */
245  {
246  /* Apply saved configuration. */
247 #if defined( _EMU_CMD_EM01VSCALE0_MASK )
248  /* Restore EM0 and 1 voltage scaling level. EMU_VScaleWait() is called later,
249  just before HF clock select is set. */
250  EMU->CMD = vScaleEM01Cmd((EMU_VScaleEM01_TypeDef)vScaleStatus);
251 #endif
252 
253  /* CMU registers may be locked */
254  cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
255  CMU_Unlock();
256 
257  /* AUXHFRCO are automatically disabled (except if using debugger). */
258  /* HFRCO, USHFRCO and HFXO are automatically disabled. */
259  /* LFRCO/LFXO may be disabled by SW in EM3. */
260  /* Restore according to status prior to entering energy mode. */
261  oscEnCmd = 0;
262  oscEnCmd |= ((cmuStatus & CMU_STATUS_HFRCOENS) ? CMU_OSCENCMD_HFRCOEN : 0);
263  oscEnCmd |= ((cmuStatus & CMU_STATUS_AUXHFRCOENS) ? CMU_OSCENCMD_AUXHFRCOEN : 0);
264  oscEnCmd |= ((cmuStatus & CMU_STATUS_LFRCOENS) ? CMU_OSCENCMD_LFRCOEN : 0);
265  oscEnCmd |= ((cmuStatus & CMU_STATUS_HFXOENS) ? CMU_OSCENCMD_HFXOEN : 0);
266  oscEnCmd |= ((cmuStatus & CMU_STATUS_LFXOENS) ? CMU_OSCENCMD_LFXOEN : 0);
267 #if defined( _CMU_STATUS_USHFRCOENS_MASK )
268  oscEnCmd |= ((cmuStatus & CMU_STATUS_USHFRCOENS) ? CMU_OSCENCMD_USHFRCOEN : 0);
269 #endif
270  CMU->OSCENCMD = oscEnCmd;
271 
272 #if defined( _EMU_STATUS_VSCALE_MASK )
273  /* Wait for upscale to complete and then restore selected clock */
274  EMU_VScaleWait();
275 #endif
276 
277  if (hfClock != cmuSelect_HFRCO)
278  {
280  }
281 
282  /* If HFRCO was disabled before entering Energy Mode, turn it off again */
283  /* as it is automatically enabled by wake up */
284  if ( ! (cmuStatus & CMU_STATUS_HFRCOENS) )
285  {
286  CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS;
287  }
288 
289  /* Restore CMU register locking */
290  if (cmuLocked)
291  {
292  CMU_Lock();
293  }
294  }
295 }
296 
297 
298 #if defined( ERRATA_FIX_EMU_E107_EN )
299 /* Get enable conditions for errata EMU_E107 fix. */
300 __STATIC_INLINE bool getErrataFixEmuE107En(void)
301 {
302  /* SYSTEM_ChipRevisionGet could have been used here, but we would like a
303  * faster implementation in this case.
304  */
305  uint16_t majorMinorRev;
306 
307  /* CHIP MAJOR bit [3:0] */
308  majorMinorRev = ((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK)
310  << 8;
311  /* CHIP MINOR bit [7:4] */
312  majorMinorRev |= ((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK)
314  << 4;
315  /* CHIP MINOR bit [3:0] */
316  majorMinorRev |= (ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK)
318 
319 #if defined( _EFM32_GECKO_FAMILY )
320  return (majorMinorRev <= 0x0103);
321 #elif defined( _EFM32_TINY_FAMILY )
322  return (majorMinorRev <= 0x0102);
323 #elif defined( _EFM32_GIANT_FAMILY )
324  return (majorMinorRev <= 0x0103) || (majorMinorRev == 0x0204);
325 #elif defined( _EFM32_WONDER_FAMILY )
326  return (majorMinorRev == 0x0100);
327 #else
328  /* Zero Gecko and future families are not affected by errata EMU_E107 */
329  return false;
330 #endif
331 }
332 #endif
333 
334 /* LP prepare / LN restore P/NFET count */
335 #define DCDC_LP_PFET_CNT 7
336 #define DCDC_LP_NFET_CNT 7
337 #if defined( ERRATA_FIX_DCDC_FETCNT_SET_EN )
338 static void currentLimitersUpdate(void);
339 static void dcdcFetCntSet(bool lpModeSet)
340 {
341  uint32_t tmp;
342  static uint32_t emuDcdcMiscCtrlReg;
343 
344  if (lpModeSet)
345  {
346  emuDcdcMiscCtrlReg = EMU->DCDCMISCCTRL;
347  tmp = EMU->DCDCMISCCTRL
348  & ~(_EMU_DCDCMISCCTRL_PFETCNT_MASK | _EMU_DCDCMISCCTRL_NFETCNT_MASK);
349  tmp |= (DCDC_LP_PFET_CNT << _EMU_DCDCMISCCTRL_PFETCNT_SHIFT)
350  | (DCDC_LP_NFET_CNT << _EMU_DCDCMISCCTRL_NFETCNT_SHIFT);
351  EMU->DCDCMISCCTRL = tmp;
352  currentLimitersUpdate();
353  }
354  else
355  {
356  EMU->DCDCMISCCTRL = emuDcdcMiscCtrlReg;
357  currentLimitersUpdate();
358  }
359 }
360 #endif
361 
362 #if defined( ERRATA_FIX_DCDC_LNHS_BLOCK_EN )
363 static void dcdcHsFixLnBlock(void)
364 {
365 #define EMU_DCDCSTATUS (* (volatile uint32_t *)(EMU_BASE + 0x7C))
366  if ((errataFixDcdcHsState == errataFixDcdcHsTrimSet)
367  || (errataFixDcdcHsState == errataFixDcdcHsBypassLn))
368  {
369  /* Wait for LNRUNNING */
370  if ((EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK) == EMU_DCDCCTRL_DCDCMODE_LOWNOISE)
371  {
372  while (!(EMU_DCDCSTATUS & (0x1 << 16)));
373  }
374  errataFixDcdcHsState = errataFixDcdcHsLnWaitDone;
375  }
376 }
377 #endif
378 
379 
380 #if defined( _EMU_CTRL_EM23VSCALE_MASK )
381 /* Configure EMU and CMU for EM2 and 3 voltage downscale */
382 static void vScaleDownEM23Setup(void)
383 {
384  uint32_t hfSrcClockFrequency;
385 
386  EMU_VScaleEM23_TypeDef scaleEM23Voltage =
387  (EMU_VScaleEM23_TypeDef)((EMU->CTRL & _EMU_CTRL_EM23VSCALE_MASK)
388  >> _EMU_CTRL_EM23VSCALE_SHIFT);
389 
390  EMU_VScaleEM01_TypeDef currentEM01Voltage =
391  (EMU_VScaleEM01_TypeDef)((EMU->STATUS & _EMU_STATUS_VSCALE_MASK)
392  >> _EMU_STATUS_VSCALE_SHIFT);
393 
394  /* Wait until previous scaling is done. */
395  EMU_VScaleWait();
396 
397  /* Inverse coding. */
398  if ((uint32_t)scaleEM23Voltage > (uint32_t)currentEM01Voltage)
399  {
400  /* Set safe clock and wait-states. */
401  if (scaleEM23Voltage == emuVScaleEM23_LowPower)
402  {
403  hfSrcClockFrequency = CMU_ClockDivGet(cmuClock_HF) * CMU_ClockFreqGet(cmuClock_HF);
404  /* Set default low power voltage HFRCO band as HF clock. */
405  if (hfSrcClockFrequency > CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX)
406  {
407  CMU_HFRCOBandSet(cmuHFRCOFreq_19M0Hz);
408  }
410  }
411  else
412  {
413  /* Other voltage scaling levels are not currently supported. */
414  EFM_ASSERT(false);
415  }
416  }
417  else
418  {
419  /* Same voltage or hardware will scale to min(EMU_CTRL_EM23VSCALE, EMU_STATUS_VSCALE) */
420  }
421 }
422 #endif
423 
426 /*******************************************************************************
427  ************************** GLOBAL FUNCTIONS *******************************
428  ******************************************************************************/
429 
430 /***************************************************************************/
480 void EMU_EnterEM2(bool restore)
481 {
482 #if defined( ERRATA_FIX_EMU_E107_EN )
483  bool errataFixEmuE107En;
484  uint32_t nonWicIntEn[2];
485 #endif
486 
487  /* Save EMU and CMU state requiring restore on EM2 exit. */
488  emState(emState_Save);
489 
490 #if defined( _EMU_CTRL_EM23VSCALE_MASK )
491  vScaleDownEM23Setup();
492 #endif
493 
494  /* Enter Cortex deep sleep mode */
495  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
496 
497  /* Fix for errata EMU_E107 - store non-WIC interrupt enable flags.
498  Disable the enabled non-WIC interrupts. */
499 #if defined( ERRATA_FIX_EMU_E107_EN )
500  errataFixEmuE107En = getErrataFixEmuE107En();
501  if (errataFixEmuE107En)
502  {
503  nonWicIntEn[0] = NVIC->ISER[0] & NON_WIC_INT_MASK_0;
504  NVIC->ICER[0] = nonWicIntEn[0];
505 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
506  nonWicIntEn[1] = NVIC->ISER[1] & NON_WIC_INT_MASK_1;
507  NVIC->ICER[1] = nonWicIntEn[1];
508 #endif
509  }
510 #endif
511 
512 #if defined( ERRATA_FIX_DCDC_FETCNT_SET_EN )
513  dcdcFetCntSet(true);
514 #endif
515 #if defined( ERRATA_FIX_DCDC_LNHS_BLOCK_EN )
516  dcdcHsFixLnBlock();
517 #endif
518 
519  __WFI();
520 
521 #if defined( ERRATA_FIX_DCDC_FETCNT_SET_EN )
522  dcdcFetCntSet(false);
523 #endif
524 
525  /* Fix for errata EMU_E107 - restore state of non-WIC interrupt enable flags. */
526 #if defined( ERRATA_FIX_EMU_E107_EN )
527  if (errataFixEmuE107En)
528  {
529  NVIC->ISER[0] = nonWicIntEn[0];
530 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
531  NVIC->ISER[1] = nonWicIntEn[1];
532 #endif
533  }
534 #endif
535 
536  /* Restore oscillators/clocks and voltage scaling if supported. */
537  if (restore)
538  {
539  emState(emState_Restore);
540  }
541  else
542  {
543  /* If not restoring, and original clock was not HFRCO, we have to */
544  /* update CMSIS core clock variable since HF clock has changed */
545  /* to HFRCO. */
547  }
548 }
549 
550 
551 /***************************************************************************/
597 void EMU_EnterEM3(bool restore)
598 {
599  uint32_t cmuLocked;
600 
601 #if defined( ERRATA_FIX_EMU_E107_EN )
602  bool errataFixEmuE107En;
603  uint32_t nonWicIntEn[2];
604 #endif
605 
606  /* Save EMU and CMU state requiring restore on EM2 exit. */
607  emState(emState_Save);
608 
609 #if defined( _EMU_CTRL_EM23VSCALE_MASK )
610  vScaleDownEM23Setup();
611 #endif
612 
613  /* CMU registers may be locked */
614  cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
615  CMU_Unlock();
616 
617  /* Disable LF oscillators */
619 
620  /* Restore CMU register locking */
621  if (cmuLocked)
622  {
623  CMU_Lock();
624  }
625 
626  /* Enter Cortex deep sleep mode */
627  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
628 
629  /* Fix for errata EMU_E107 - store non-WIC interrupt enable flags.
630  Disable the enabled non-WIC interrupts. */
631 #if defined( ERRATA_FIX_EMU_E107_EN )
632  errataFixEmuE107En = getErrataFixEmuE107En();
633  if (errataFixEmuE107En)
634  {
635  nonWicIntEn[0] = NVIC->ISER[0] & NON_WIC_INT_MASK_0;
636  NVIC->ICER[0] = nonWicIntEn[0];
637 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
638  nonWicIntEn[1] = NVIC->ISER[1] & NON_WIC_INT_MASK_1;
639  NVIC->ICER[1] = nonWicIntEn[1];
640 #endif
641  }
642 #endif
643 
644 #if defined( ERRATA_FIX_DCDC_FETCNT_SET_EN )
645  dcdcFetCntSet(true);
646 #endif
647 #if defined( ERRATA_FIX_DCDC_LNHS_BLOCK_EN )
648  dcdcHsFixLnBlock();
649 #endif
650 
651  __WFI();
652 
653 #if defined( ERRATA_FIX_DCDC_FETCNT_SET_EN )
654  dcdcFetCntSet(false);
655 #endif
656 
657  /* Fix for errata EMU_E107 - restore state of non-WIC interrupt enable flags. */
658 #if defined( ERRATA_FIX_EMU_E107_EN )
659  if (errataFixEmuE107En)
660  {
661  NVIC->ISER[0] = nonWicIntEn[0];
662 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
663  NVIC->ISER[1] = nonWicIntEn[1];
664 #endif
665  }
666 #endif
667 
668  /* Restore oscillators/clocks and voltage scaling if supported. */
669  if (restore)
670  {
671  emState(emState_Restore);
672  }
673  else
674  {
675  /* If not restoring, and original clock was not HFRCO, we have to */
676  /* update CMSIS core clock variable since HF clock has changed */
677  /* to HFRCO. */
679  }
680 }
681 
682 
683 /***************************************************************************/
692 void EMU_Restore(void)
693 {
694  emState(emState_Restore);
695 }
696 
697 
698 /***************************************************************************/
705 void EMU_EnterEM4(void)
706 {
707  int i;
708 
709 #if defined( _EMU_EM4CTRL_EM4ENTRY_SHIFT )
710  uint32_t em4seq2 = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4ENTRY_MASK)
711  | (2 << _EMU_EM4CTRL_EM4ENTRY_SHIFT);
712  uint32_t em4seq3 = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4ENTRY_MASK)
713  | (3 << _EMU_EM4CTRL_EM4ENTRY_SHIFT);
714 #else
715  uint32_t em4seq2 = (EMU->CTRL & ~_EMU_CTRL_EM4CTRL_MASK)
716  | (2 << _EMU_CTRL_EM4CTRL_SHIFT);
717  uint32_t em4seq3 = (EMU->CTRL & ~_EMU_CTRL_EM4CTRL_MASK)
718  | (3 << _EMU_CTRL_EM4CTRL_SHIFT);
719 #endif
720 
721  /* Make sure register write lock is disabled */
722  EMU_Unlock();
723 
724 #if defined( _EMU_EM4CTRL_MASK )
725  if ((EMU->EM4CTRL & _EMU_EM4CTRL_EM4STATE_MASK) == EMU_EM4CTRL_EM4STATE_EM4S)
726  {
727  uint32_t dcdcMode = EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK;
728  if (dcdcMode == EMU_DCDCCTRL_DCDCMODE_LOWNOISE
729  || dcdcMode == EMU_DCDCCTRL_DCDCMODE_LOWPOWER)
730  {
731  /* DCDC is not supported in EM4S so we switch DCDC to bypass mode before
732  * entering EM4S */
733  EMU_DCDCModeSet(emuDcdcMode_Bypass);
734  }
735  }
736 #endif
737 
738 #if defined( _EMU_EM4CTRL_MASK ) && defined( ERRATA_FIX_EMU_E208_EN )
739  if (EMU->EM4CTRL & EMU_EM4CTRL_EM4STATE_EM4H)
740  {
741  /* Fix for errata EMU_E208 - Occasional Full Reset After Exiting EM4H.
742  * Full description of errata fix can be found in the errata document. */
743  __disable_irq();
744  *(volatile uint32_t *)(EMU_BASE + 0x190) = 0x0000ADE8UL;
745  *(volatile uint32_t *)(EMU_BASE + 0x198) |= (0x1UL << 7);
746  *(volatile uint32_t *)(EMU_BASE + 0x88) |= (0x1UL << 8);
747  }
748 #endif
749 
750 #if defined( ERRATA_FIX_EMU_E108_EN )
751  /* Fix for errata EMU_E108 - High Current Consumption on EM4 Entry. */
752  __disable_irq();
753  *(volatile uint32_t *)0x400C80E4 = 0;
754 #endif
755 
756 #if defined( ERRATA_FIX_DCDC_FETCNT_SET_EN )
757  dcdcFetCntSet(true);
758 #endif
759 #if defined( ERRATA_FIX_DCDC_LNHS_BLOCK_EN )
760  dcdcHsFixLnBlock();
761 #endif
762 
763  for (i = 0; i < 4; i++)
764  {
765 #if defined( _EMU_EM4CTRL_EM4ENTRY_SHIFT )
766  EMU->EM4CTRL = em4seq2;
767  EMU->EM4CTRL = em4seq3;
768  }
769  EMU->EM4CTRL = em4seq2;
770 #else
771  EMU->CTRL = em4seq2;
772  EMU->CTRL = em4seq3;
773  }
774  EMU->CTRL = em4seq2;
775 #endif
776 }
777 
778 #if defined( _EMU_EM4CTRL_MASK )
779 /***************************************************************************/
787 void EMU_EnterEM4H(void)
788 {
789  BUS_RegBitWrite(&EMU->EM4CTRL, _EMU_EM4CTRL_EM4STATE_SHIFT, 1);
790  EMU_EnterEM4();
791 }
792 
793 /***************************************************************************/
801 void EMU_EnterEM4S(void)
802 {
803  BUS_RegBitWrite(&EMU->EM4CTRL, _EMU_EM4CTRL_EM4STATE_SHIFT, 0);
804  EMU_EnterEM4();
805 }
806 #endif
807 
808 /***************************************************************************/
825 void EMU_MemPwrDown(uint32_t blocks)
826 {
827 #if defined( _EMU_MEMCTRL_MASK )
828  EMU->MEMCTRL = blocks & _EMU_MEMCTRL_MASK;
829 #elif defined( _EMU_RAM0CTRL_MASK )
830  EMU->RAM0CTRL = blocks & _EMU_RAM0CTRL_MASK;
831 #else
832  (void)blocks;
833 #endif
834 }
835 
836 /***************************************************************************/
870 void EMU_RamPowerDown(uint32_t start, uint32_t end)
871 {
872  uint32_t mask = 0;
873 
874  if (end == 0)
875  {
876  end = SRAM_BASE + SRAM_SIZE;
877  }
878 
879  // Check to see if something in RAM0 can be powered down
880  if (end > RAM0_END)
881  {
882 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_84) // EFM32xG12 and EFR32xG12
883  // Block 0 is 16 kB and cannot be powered off
884  mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20004000) << 0; // Block 1, 16 kB
885  mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20008000) << 1; // Block 2, 16 kB
886  mask |= ADDRESS_NOT_IN_BLOCK(start, 0x2000C000) << 2; // Block 3, 16 kB
887  mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20010000) << 3; // Block 4, 64 kB
888 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80) // EFM32xG1 and EFR32xG1
889  // Block 0 is 4 kB and cannot be powered off
890  mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20001000) << 0; // Block 1, 4 kB
891  mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20002000) << 1; // Block 2, 8 kB
892  mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20004000) << 2; // Block 3, 8 kB
893  mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20006000) << 3; // Block 4, 7 kB
894 #elif defined(RAM0_BLOCKS)
895  // These platforms have equally sized RAM blocks
896  for (int i = 1; i < RAM0_BLOCKS; i++)
897  {
898  mask |= ADDRESS_NOT_IN_BLOCK(start, RAM_MEM_BASE + (i * RAM0_BLOCK_SIZE)) << (i - 1);
899  }
900 #endif
901  }
902 
903  // Power down the selected blocks
904 #if defined( _EMU_MEMCTRL_MASK )
905  EMU->MEMCTRL = EMU->MEMCTRL | mask;
906 #elif defined( _EMU_RAM0CTRL_MASK )
907  EMU->RAM0CTRL = EMU->RAM0CTRL | mask;
908 #else
909  // These devices are unable to power down RAM blocks
910  (void) mask;
911  (void) start;
912 #endif
913 
914 #if defined(RAM1_MEM_END)
915  mask = 0;
916  if (end > RAM1_MEM_END)
917  {
918  for (int i = 0; i < RAM1_BLOCKS; i++)
919  {
920  mask |= ADDRESS_NOT_IN_BLOCK(start, RAM1_MEM_BASE + (i * RAM1_BLOCK_SIZE)) << i;
921  }
922  }
923  EMU->RAM1CTRL |= mask;
924 #endif
925 }
926 
927 #if defined(_EMU_EM23PERNORETAINCTRL_MASK)
928 /***************************************************************************/
943 void EMU_PeripheralRetention(EMU_PeripheralRetention_TypeDef periMask, bool enable)
944 {
945  EFM_ASSERT(!enable);
946  EMU->EM23PERNORETAINCTRL = periMask & emuPeripheralRetention_ALL;
947 }
948 #endif
949 
950 
951 /***************************************************************************/
959 {
960  emState(emState_Save);
961 }
962 
963 
964 #if defined( _EMU_CMD_EM01VSCALE0_MASK )
965 /***************************************************************************/
979 void EMU_VScaleEM01ByClock(uint32_t clockFrequency, bool wait)
980 {
981  uint32_t hfSrcClockFrequency;
982  uint32_t hfPresc = 1U + ((CMU->HFPRESC & _CMU_HFPRESC_PRESC_MASK)
983  >> _CMU_HFPRESC_PRESC_SHIFT);
984 
985  /* VSCALE frequency is HFSRCCLK */
986  if (clockFrequency == 0)
987  {
988  hfSrcClockFrequency = SystemHFClockGet() * hfPresc;
989  }
990  else
991  {
992  hfSrcClockFrequency = clockFrequency;
993  }
994 
995  /* Apply EM0 and 1 voltage scaling command. */
996  if (vScaleEM01Config.vScaleEM01LowPowerVoltageEnable
997  && (hfSrcClockFrequency < CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX))
998  {
999  EMU->CMD = vScaleEM01Cmd(emuVScaleEM01_LowPower);
1000  }
1001  else
1002  {
1003  EMU->CMD = vScaleEM01Cmd(emuVScaleEM01_HighPerformance);
1004  }
1005 
1006  if (wait)
1007  {
1008  EMU_VScaleWait();
1009  }
1010 }
1011 #endif
1012 
1013 
1014 #if defined( _EMU_CMD_EM01VSCALE0_MASK )
1015 /***************************************************************************/
1033 void EMU_VScaleEM01(EMU_VScaleEM01_TypeDef voltage, bool wait)
1034 {
1035  uint32_t hfSrcClockFrequency;
1036  uint32_t hfPresc = 1U + ((CMU->HFPRESC & _CMU_HFPRESC_PRESC_MASK)
1037  >> _CMU_HFPRESC_PRESC_SHIFT);
1038  hfSrcClockFrequency = SystemHFClockGet() * hfPresc;
1039 
1040  if (voltage == emuVScaleEM01_LowPower)
1041  {
1042  EFM_ASSERT(hfSrcClockFrequency <= CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX);
1043  }
1044 
1045  EMU->CMD = vScaleEM01Cmd(voltage);
1046  if (wait)
1047  {
1048  EMU_VScaleWait();
1049  }
1050 }
1051 #endif
1052 
1053 
1054 #if defined( _EMU_CMD_EM01VSCALE0_MASK )
1055 /***************************************************************************/
1062 void EMU_EM01Init(const EMU_EM01Init_TypeDef *em01Init)
1063 {
1064  vScaleEM01Config.vScaleEM01LowPowerVoltageEnable =
1065  em01Init->vScaleEM01LowPowerVoltageEnable;
1066  EMU_VScaleEM01ByClock(0, true);
1067 }
1068 #endif
1069 
1070 
1071 /***************************************************************************/
1078 void EMU_EM23Init(const EMU_EM23Init_TypeDef *em23Init)
1079 {
1080 #if defined( _EMU_CTRL_EMVREG_MASK )
1081  EMU->CTRL = em23Init->em23VregFullEn ? (EMU->CTRL | EMU_CTRL_EMVREG)
1082  : (EMU->CTRL & ~EMU_CTRL_EMVREG);
1083 #elif defined( _EMU_CTRL_EM23VREG_MASK )
1084  EMU->CTRL = em23Init->em23VregFullEn ? (EMU->CTRL | EMU_CTRL_EM23VREG)
1085  : (EMU->CTRL & ~EMU_CTRL_EM23VREG);
1086 #else
1087  (void)em23Init;
1088 #endif
1089 
1090 #if defined( _EMU_CTRL_EM23VSCALE_MASK )
1091  EMU->CTRL = (EMU->CTRL & ~_EMU_CTRL_EM23VSCALE_MASK)
1092  | (em23Init->vScaleEM23Voltage << _EMU_CTRL_EM23VSCALE_SHIFT);
1093 #endif
1094 }
1095 
1096 
1097 #if defined( _EMU_EM4CONF_MASK ) || defined( _EMU_EM4CTRL_MASK )
1098 /***************************************************************************/
1105 void EMU_EM4Init(const EMU_EM4Init_TypeDef *em4Init)
1106 {
1107 #if defined( _EMU_EM4CONF_MASK )
1108  /* Init for platforms with EMU->EM4CONF register */
1109  uint32_t em4conf = EMU->EM4CONF;
1110 
1111  /* Clear fields that will be reconfigured */
1112  em4conf &= ~(_EMU_EM4CONF_LOCKCONF_MASK
1113  | _EMU_EM4CONF_OSC_MASK
1114  | _EMU_EM4CONF_BURTCWU_MASK
1115  | _EMU_EM4CONF_VREGEN_MASK);
1116 
1117  /* Configure new settings */
1118  em4conf |= (em4Init->lockConfig << _EMU_EM4CONF_LOCKCONF_SHIFT)
1119  | (em4Init->osc)
1120  | (em4Init->buRtcWakeup << _EMU_EM4CONF_BURTCWU_SHIFT)
1121  | (em4Init->vreg << _EMU_EM4CONF_VREGEN_SHIFT);
1122 
1123  /* Apply configuration. Note that lock can be set after this stage. */
1124  EMU->EM4CONF = em4conf;
1125 
1126 #elif defined( _EMU_EM4CTRL_MASK )
1127  /* Init for platforms with EMU->EM4CTRL register */
1128 
1129  uint32_t em4ctrl = EMU->EM4CTRL;
1130 
1131  em4ctrl &= ~(_EMU_EM4CTRL_RETAINLFXO_MASK
1132  | _EMU_EM4CTRL_RETAINLFRCO_MASK
1133  | _EMU_EM4CTRL_RETAINULFRCO_MASK
1134  | _EMU_EM4CTRL_EM4STATE_MASK
1135  | _EMU_EM4CTRL_EM4IORETMODE_MASK);
1136 
1137  em4ctrl |= (em4Init->retainLfxo ? EMU_EM4CTRL_RETAINLFXO : 0)
1138  | (em4Init->retainLfrco ? EMU_EM4CTRL_RETAINLFRCO : 0)
1139  | (em4Init->retainUlfrco ? EMU_EM4CTRL_RETAINULFRCO : 0)
1140  | (em4Init->em4State ? EMU_EM4CTRL_EM4STATE_EM4H : 0)
1141  | (em4Init->pinRetentionMode);
1142 
1143  EMU->EM4CTRL = em4ctrl;
1144 #endif
1145 
1146 #if defined( _EMU_CTRL_EM4HVSCALE_MASK )
1147  EMU->CTRL = (EMU->CTRL & ~_EMU_CTRL_EM4HVSCALE_MASK)
1148  | (em4Init->vScaleEM4HVoltage << _EMU_CTRL_EM4HVSCALE_SHIFT);
1149 #endif
1150 }
1151 #endif
1152 
1153 
1154 #if defined( BU_PRESENT )
1155 /***************************************************************************/
1162 void EMU_BUPDInit(const EMU_BUPDInit_TypeDef *bupdInit)
1163 {
1164  uint32_t reg;
1165 
1166  /* Set power connection configuration */
1167  reg = EMU->PWRCONF & ~(_EMU_PWRCONF_PWRRES_MASK
1168  | _EMU_PWRCONF_VOUTSTRONG_MASK
1169  | _EMU_PWRCONF_VOUTMED_MASK
1170  | _EMU_PWRCONF_VOUTWEAK_MASK);
1171 
1172  reg |= bupdInit->resistor
1173  | (bupdInit->voutStrong << _EMU_PWRCONF_VOUTSTRONG_SHIFT)
1174  | (bupdInit->voutMed << _EMU_PWRCONF_VOUTMED_SHIFT)
1175  | (bupdInit->voutWeak << _EMU_PWRCONF_VOUTWEAK_SHIFT);
1176 
1177  EMU->PWRCONF = reg;
1178 
1179  /* Set backup domain inactive mode configuration */
1180  reg = EMU->BUINACT & ~(_EMU_BUINACT_PWRCON_MASK);
1181  reg |= (bupdInit->inactivePower);
1182  EMU->BUINACT = reg;
1183 
1184  /* Set backup domain active mode configuration */
1185  reg = EMU->BUACT & ~(_EMU_BUACT_PWRCON_MASK);
1186  reg |= (bupdInit->activePower);
1187  EMU->BUACT = reg;
1188 
1189  /* Set power control configuration */
1190  reg = EMU->BUCTRL & ~(_EMU_BUCTRL_PROBE_MASK
1191  | _EMU_BUCTRL_BODCAL_MASK
1192  | _EMU_BUCTRL_STATEN_MASK
1193  | _EMU_BUCTRL_EN_MASK);
1194 
1195  /* Note use of ->enable to both enable BUPD, use BU_VIN pin input and
1196  release reset */
1197  reg |= bupdInit->probe
1198  | (bupdInit->bodCal << _EMU_BUCTRL_BODCAL_SHIFT)
1199  | (bupdInit->statusPinEnable << _EMU_BUCTRL_STATEN_SHIFT)
1200  | (bupdInit->enable << _EMU_BUCTRL_EN_SHIFT);
1201 
1202  /* Enable configuration */
1203  EMU->BUCTRL = reg;
1204 
1205  /* If enable is true, enable BU_VIN input power pin, if not disable it */
1206  EMU_BUPinEnable(bupdInit->enable);
1207 
1208  /* If enable is true, release BU reset, if not keep reset asserted */
1209  BUS_RegBitWrite(&(RMU->CTRL), _RMU_CTRL_BURSTEN_SHIFT, !bupdInit->enable);
1210 }
1211 
1212 
1213 /***************************************************************************/
1221 void EMU_BUThresholdSet(EMU_BODMode_TypeDef mode, uint32_t value)
1222 {
1223  EFM_ASSERT(value<8);
1224  EFM_ASSERT(value<=(_EMU_BUACT_BUEXTHRES_MASK>>_EMU_BUACT_BUEXTHRES_SHIFT));
1225 
1226  switch(mode)
1227  {
1228  case emuBODMode_Active:
1229  EMU->BUACT = (EMU->BUACT & ~_EMU_BUACT_BUEXTHRES_MASK)
1230  | (value<<_EMU_BUACT_BUEXTHRES_SHIFT);
1231  break;
1232  case emuBODMode_Inactive:
1233  EMU->BUINACT = (EMU->BUINACT & ~_EMU_BUINACT_BUENTHRES_MASK)
1234  | (value<<_EMU_BUINACT_BUENTHRES_SHIFT);
1235  break;
1236  }
1237 }
1238 
1239 
1240 /***************************************************************************/
1248 void EMU_BUThresRangeSet(EMU_BODMode_TypeDef mode, uint32_t value)
1249 {
1250  EFM_ASSERT(value < 4);
1251  EFM_ASSERT(value<=(_EMU_BUACT_BUEXRANGE_MASK>>_EMU_BUACT_BUEXRANGE_SHIFT));
1252 
1253  switch(mode)
1254  {
1255  case emuBODMode_Active:
1256  EMU->BUACT = (EMU->BUACT & ~_EMU_BUACT_BUEXRANGE_MASK)
1257  | (value<<_EMU_BUACT_BUEXRANGE_SHIFT);
1258  break;
1259  case emuBODMode_Inactive:
1260  EMU->BUINACT = (EMU->BUINACT & ~_EMU_BUINACT_BUENRANGE_MASK)
1261  | (value<<_EMU_BUINACT_BUENRANGE_SHIFT);
1262  break;
1263  }
1264 }
1265 #endif
1266 
1267 
1269 #if defined( _EMU_DCDCCTRL_MASK )
1270 /* Translate fields with different names across platform generations to common names. */
1271 #if defined( _EMU_DCDCMISCCTRL_LPCMPBIAS_MASK )
1272 #define _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_MASK _EMU_DCDCMISCCTRL_LPCMPBIAS_MASK
1273 #define _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT _EMU_DCDCMISCCTRL_LPCMPBIAS_SHIFT
1274 #elif defined( _EMU_DCDCMISCCTRL_LPCMPBIASEM234H_MASK )
1275 #define _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_MASK _EMU_DCDCMISCCTRL_LPCMPBIASEM234H_MASK
1276 #define _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT _EMU_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT
1277 #endif
1278 #if defined( _EMU_DCDCLPCTRL_LPCMPHYSSEL_MASK )
1279 #define _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK _EMU_DCDCLPCTRL_LPCMPHYSSEL_MASK
1280 #define _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_SHIFT _EMU_DCDCLPCTRL_LPCMPHYSSEL_SHIFT
1281 #elif defined( _EMU_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK )
1282 #define _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK _EMU_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK
1283 #define _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_SHIFT _EMU_DCDCLPCTRL_LPCMPHYSSELEM234H_SHIFT
1284 #endif
1285 
1286 /* Internal DCDC trim modes. */
1287 typedef enum
1288 {
1289  dcdcTrimMode_EM234H_LP = 0,
1290 #if defined( _EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK )
1291  dcdcTrimMode_EM01_LP,
1292 #endif
1293  dcdcTrimMode_LN,
1294 } dcdcTrimMode_TypeDef;
1295 
1296 /***************************************************************************/
1304 static bool dcdcConstCalibrationLoad(void)
1305 {
1306 #if defined( _SILICON_LABS_GECKO_INTERNAL_SDID_80 )
1307  uint32_t val;
1308  volatile uint32_t *reg;
1309 
1310  /* DI calib data in flash */
1311  volatile uint32_t* const diCal_EMU_DCDCLNFREQCTRL = (volatile uint32_t *)(0x0FE08038);
1312  volatile uint32_t* const diCal_EMU_DCDCLNVCTRL = (volatile uint32_t *)(0x0FE08040);
1313  volatile uint32_t* const diCal_EMU_DCDCLPCTRL = (volatile uint32_t *)(0x0FE08048);
1314  volatile uint32_t* const diCal_EMU_DCDCLPVCTRL = (volatile uint32_t *)(0x0FE08050);
1315  volatile uint32_t* const diCal_EMU_DCDCTRIM0 = (volatile uint32_t *)(0x0FE08058);
1316  volatile uint32_t* const diCal_EMU_DCDCTRIM1 = (volatile uint32_t *)(0x0FE08060);
1317 
1318  if (DEVINFO->DCDCLPVCTRL0 != UINT_MAX)
1319  {
1320  val = *(diCal_EMU_DCDCLNFREQCTRL + 1);
1321  reg = (volatile uint32_t *)*diCal_EMU_DCDCLNFREQCTRL;
1322  *reg = val;
1323 
1324  val = *(diCal_EMU_DCDCLNVCTRL + 1);
1325  reg = (volatile uint32_t *)*diCal_EMU_DCDCLNVCTRL;
1326  *reg = val;
1327 
1328  val = *(diCal_EMU_DCDCLPCTRL + 1);
1329  reg = (volatile uint32_t *)*diCal_EMU_DCDCLPCTRL;
1330  *reg = val;
1331 
1332  val = *(diCal_EMU_DCDCLPVCTRL + 1);
1333  reg = (volatile uint32_t *)*diCal_EMU_DCDCLPVCTRL;
1334  *reg = val;
1335 
1336  val = *(diCal_EMU_DCDCTRIM0 + 1);
1337  reg = (volatile uint32_t *)*diCal_EMU_DCDCTRIM0;
1338  *reg = val;
1339 
1340  val = *(diCal_EMU_DCDCTRIM1 + 1);
1341  reg = (volatile uint32_t *)*diCal_EMU_DCDCTRIM1;
1342  *reg = val;
1343 
1344  return true;
1345  }
1346  EFM_ASSERT(false);
1347  /* Return when assertions are disabled */
1348  return false;
1349 
1350 #else
1351  return true;
1352 #endif
1353 }
1354 
1355 
1356 /***************************************************************************/
1361 static void dcdcValidatedConfigSet(void)
1362 {
1363 /* Disable LP mode hysterysis in the state machine control */
1364 #define EMU_DCDCMISCCTRL_LPCMPHYSDIS (0x1UL << 1)
1365 /* Comparator threshold on the high side */
1366 #define EMU_DCDCMISCCTRL_LPCMPHYSHI (0x1UL << 2)
1367 #define EMU_DCDCSMCTRL (* (volatile uint32_t *)(EMU_BASE + 0x44))
1368 
1369  uint32_t lnForceCcm;
1370 
1371 #if defined( _SILICON_LABS_GECKO_INTERNAL_SDID_80 )
1372  uint32_t dcdcTiming;
1374 #endif
1375 
1376  /* Enable duty cycling of the bias */
1377  EMU->DCDCLPCTRL |= EMU_DCDCLPCTRL_LPVREFDUTYEN;
1378 
1379  /* Set low-noise RCO for LNFORCECCM configuration
1380  * LNFORCECCM is default 1 for EFR32
1381  * LNFORCECCM is default 0 for EFM32
1382  */
1383  lnForceCcm = BUS_RegBitRead(&EMU->DCDCMISCCTRL, _EMU_DCDCMISCCTRL_LNFORCECCM_SHIFT);
1384  if (lnForceCcm)
1385  {
1386  /* 7MHz is recommended for LNFORCECCM = 1 */
1387  EMU_DCDCLnRcoBandSet(emuDcdcLnRcoBand_7MHz);
1388  }
1389  else
1390  {
1391  /* 3MHz is recommended for LNFORCECCM = 0 */
1392  EMU_DCDCLnRcoBandSet(emuDcdcLnRcoBand_3MHz);
1393  }
1394 
1395 #if defined( _SILICON_LABS_GECKO_INTERNAL_SDID_80 )
1396  EMU->DCDCTIMING &= ~_EMU_DCDCTIMING_DUTYSCALE_MASK;
1397  EMU->DCDCMISCCTRL |= EMU_DCDCMISCCTRL_LPCMPHYSDIS
1398  | EMU_DCDCMISCCTRL_LPCMPHYSHI;
1399 
1400  SYSTEM_ChipRevisionGet(&rev);
1401  if ((rev.major == 1)
1402  && (rev.minor < 3)
1403  && (errataFixDcdcHsState == errataFixDcdcHsInit))
1404  {
1405  /* LPCMPWAITDIS = 1 */
1406  EMU_DCDCSMCTRL |= 1;
1407 
1408  dcdcTiming = EMU->DCDCTIMING;
1409  dcdcTiming &= ~(_EMU_DCDCTIMING_LPINITWAIT_MASK
1410  |_EMU_DCDCTIMING_LNWAIT_MASK
1411  |_EMU_DCDCTIMING_BYPWAIT_MASK);
1412 
1413  dcdcTiming |= ((180 << _EMU_DCDCTIMING_LPINITWAIT_SHIFT)
1414  | (12 << _EMU_DCDCTIMING_LNWAIT_SHIFT)
1415  | (180 << _EMU_DCDCTIMING_BYPWAIT_SHIFT));
1416  EMU->DCDCTIMING = dcdcTiming;
1417 
1418  errataFixDcdcHsState = errataFixDcdcHsTrimSet;
1419  }
1420 #endif
1421 }
1422 
1423 
1424 /***************************************************************************/
1431 static void currentLimitersUpdate(void)
1432 {
1433  uint32_t lncLimSel;
1434  uint32_t zdetLimSel;
1435  uint32_t pFetCnt;
1436  uint16_t maxReverseCurrent_mA;
1437 
1438  /* 80mA as recommended peak in Application Note AN0948.
1439  The peak current is the average current plus 50% of the current ripple.
1440  Hence, a 14mA average current is recommended in LP mode. Since LP PFETCNT is also
1441  a constant, we get lpcLimImSel = 1. The following calculation is provided
1442  for documentation only. */
1443  const uint32_t lpcLim = (((14 + 40) + ((14 + 40) / 2))
1444  / (5 * (DCDC_LP_PFET_CNT + 1)))
1445  - 1;
1446  const uint32_t lpcLimSel = lpcLim << _EMU_DCDCMISCCTRL_LPCLIMILIMSEL_SHIFT;
1447 
1448  /* Get enabled PFETs */
1449  pFetCnt = (EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_PFETCNT_MASK)
1450  >> _EMU_DCDCMISCCTRL_PFETCNT_SHIFT;
1451 
1452  /* Compute LN current limiter threshold from nominal user input current and
1453  LN PFETCNT as described in the register description for
1454  EMU_DCDCMISCCTRL_LNCLIMILIMSEL. */
1455  lncLimSel = (((dcdcMaxCurrent_mA + 40) + ((dcdcMaxCurrent_mA + 40) / 2))
1456  / (5 * (pFetCnt + 1)))
1457  - 1;
1458 
1459  /* Saturate the register field value */
1460  lncLimSel = SL_MIN(lncLimSel,
1461  _EMU_DCDCMISCCTRL_LNCLIMILIMSEL_MASK
1462  >> _EMU_DCDCMISCCTRL_LNCLIMILIMSEL_SHIFT);
1463 
1464  lncLimSel <<= _EMU_DCDCMISCCTRL_LNCLIMILIMSEL_SHIFT;
1465 
1466  /* Check for overflow */
1467  EFM_ASSERT((lncLimSel & ~_EMU_DCDCMISCCTRL_LNCLIMILIMSEL_MASK) == 0x0);
1468  EFM_ASSERT((lpcLimSel & ~_EMU_DCDCMISCCTRL_LPCLIMILIMSEL_MASK) == 0x0);
1469 
1470  EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_EMU_DCDCMISCCTRL_LNCLIMILIMSEL_MASK
1471  | _EMU_DCDCMISCCTRL_LPCLIMILIMSEL_MASK))
1472  | (lncLimSel | lpcLimSel);
1473 
1474 
1475  /* Compute reverse current limit threshold for the zero detector from user input
1476  maximum reverse current and LN PFETCNT as described in the register description
1477  for EMU_DCDCZDETCTRL_ZDETILIMSEL. */
1478  if (dcdcReverseCurrentControl >= 0)
1479  {
1480  /* If dcdcReverseCurrentControl < 0, then EMU_DCDCZDETCTRL_ZDETILIMSEL is "don't care" */
1481  maxReverseCurrent_mA = (uint16_t)dcdcReverseCurrentControl;
1482 
1483  zdetLimSel = ( ((maxReverseCurrent_mA + 40) + ((maxReverseCurrent_mA + 40) / 2))
1484  / ((2 * (pFetCnt + 1)) + ((pFetCnt + 1) / 2)) );
1485  /* Saturate the register field value */
1486  zdetLimSel = SL_MIN(zdetLimSel,
1487  _EMU_DCDCZDETCTRL_ZDETILIMSEL_MASK
1488  >> _EMU_DCDCZDETCTRL_ZDETILIMSEL_SHIFT);
1489 
1490  zdetLimSel <<= _EMU_DCDCZDETCTRL_ZDETILIMSEL_SHIFT;
1491 
1492  /* Check for overflow */
1493  EFM_ASSERT((zdetLimSel & ~_EMU_DCDCZDETCTRL_ZDETILIMSEL_MASK) == 0x0);
1494 
1495  EMU->DCDCZDETCTRL = (EMU->DCDCZDETCTRL & ~_EMU_DCDCZDETCTRL_ZDETILIMSEL_MASK)
1496  | zdetLimSel;
1497  }
1498 }
1499 
1500 
1501 /***************************************************************************/
1512 static void userCurrentLimitsSet(uint32_t maxCurrent_mA,
1513  EMU_DcdcLnReverseCurrentControl_TypeDef reverseCurrentControl)
1514 {
1515  dcdcMaxCurrent_mA = maxCurrent_mA;
1516  dcdcReverseCurrentControl = reverseCurrentControl;
1517 }
1518 
1519 
1520 /***************************************************************************/
1527 static void compCtrlSet(EMU_DcdcLnCompCtrl_TypeDef comp)
1528 {
1529  switch (comp)
1530  {
1531  case emuDcdcLnCompCtrl_1u0F:
1532  EMU->DCDCLNCOMPCTRL = 0x57204077UL;
1533  break;
1534 
1535  case emuDcdcLnCompCtrl_4u7F:
1536  EMU->DCDCLNCOMPCTRL = 0xB7102137UL;
1537  break;
1538 
1539  default:
1540  EFM_ASSERT(false);
1541  break;
1542  }
1543 }
1544 
1545 /***************************************************************************/
1557 static bool lpCmpHystCalibrationLoad(bool lpAttenuation,
1558  uint8_t lpCmpBias,
1559  dcdcTrimMode_TypeDef trimMode)
1560 {
1561  uint32_t lpcmpHystSel;
1562 
1563  /* Get calib data revision */
1564 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
1565  uint8_t devinfoRev = SYSTEM_GetDevinfoRev();
1566 
1567  /* Load LPATT indexed calibration data */
1568  if (devinfoRev < 4)
1569 #else
1570  /* Format change not present of newer families. */
1571  if (false)
1572 #endif
1573  {
1574  lpcmpHystSel = DEVINFO->DCDCLPCMPHYSSEL0;
1575 
1576  if (lpAttenuation)
1577  {
1578  lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT1_MASK)
1579  >> _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT1_SHIFT;
1580  }
1581  else
1582  {
1583  lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT0_MASK)
1584  >> _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT0_SHIFT;
1585  }
1586  }
1587  else
1588  {
1589  /* devinfoRev >= 4: load LPCMPBIAS indexed calibration data */
1590  lpcmpHystSel = DEVINFO->DCDCLPCMPHYSSEL1;
1591  switch (lpCmpBias)
1592  {
1593  case 0:
1594  lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS0_MASK)
1595  >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS0_SHIFT;
1596  break;
1597 
1598  case 1:
1599  lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS1_MASK)
1600  >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS1_SHIFT;
1601  break;
1602 
1603  case 2:
1604  lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS2_MASK)
1605  >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS2_SHIFT;
1606  break;
1607 
1608  case 3:
1609  lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS3_MASK)
1610  >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS3_SHIFT;
1611  break;
1612 
1613  default:
1614  EFM_ASSERT(false);
1615  /* Return when assertions are disabled */
1616  return false;
1617  }
1618  }
1619 
1620  /* Set trims */
1621  if (trimMode == dcdcTrimMode_EM234H_LP)
1622  {
1623  /* Make sure the sel value is within the field range. */
1624  lpcmpHystSel <<= _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_SHIFT;
1625  if (lpcmpHystSel & ~_GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK)
1626  {
1627  EFM_ASSERT(false);
1628  /* Return when assertions are disabled */
1629  return false;
1630  }
1631  EMU->DCDCLPCTRL = (EMU->DCDCLPCTRL & ~_GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK) | lpcmpHystSel;
1632  }
1633 
1634 #if defined( _EMU_DCDCLPEM01CFG_LPCMPHYSSELEM01_MASK )
1635  if (trimMode == dcdcTrimMode_EM01_LP)
1636  {
1637  /* Make sure the sel value is within the field range. */
1638  lpcmpHystSel <<= _EMU_DCDCLPEM01CFG_LPCMPHYSSELEM01_SHIFT;
1639  if (lpcmpHystSel & ~_EMU_DCDCLPEM01CFG_LPCMPHYSSELEM01_MASK)
1640  {
1641  EFM_ASSERT(false);
1642  /* Return when assertions are disabled */
1643  return false;
1644  }
1645  EMU->DCDCLPEM01CFG = (EMU->DCDCLPEM01CFG & ~_EMU_DCDCLPEM01CFG_LPCMPHYSSELEM01_MASK) | lpcmpHystSel;
1646  }
1647 #endif
1648 
1649  return true;
1650 }
1651 
1652 
1653 /***************************************************************************/
1666 static void lpGetDevinfoVrefLowHigh(uint32_t *vrefL,
1667  uint32_t *vrefH,
1668  bool lpAttenuation,
1669  uint8_t lpcmpBias)
1670 {
1671  uint32_t vrefLow = 0;
1672  uint32_t vrefHigh = 0;
1673 
1674  /* Find VREF high and low in DEVINFO indexed by LPCMPBIAS (lpcmpBias)
1675  and LPATT (lpAttenuation) */
1676  uint32_t switchVal = (lpcmpBias << 8) | (lpAttenuation ? 1 : 0);
1677  switch (switchVal)
1678  {
1679  case ((0 << 8) | 1):
1680  vrefLow = DEVINFO->DCDCLPVCTRL2;
1681  vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS0_MASK)
1682  >> _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS0_SHIFT;
1683  vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS0_MASK)
1684  >> _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS0_SHIFT;
1685  break;
1686 
1687  case ((1 << 8) | 1):
1688  vrefLow = DEVINFO->DCDCLPVCTRL2;
1689  vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS1_MASK)
1690  >> _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS1_SHIFT;
1691  vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS1_MASK)
1692  >> _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS1_SHIFT;
1693  break;
1694 
1695  case ((2 << 8) | 1):
1696  vrefLow = DEVINFO->DCDCLPVCTRL3;
1697  vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS2_MASK)
1698  >> _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS2_SHIFT;
1699  vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS2_MASK)
1700  >> _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS2_SHIFT;
1701  break;
1702 
1703  case ((3 << 8) | 1):
1704  vrefLow = DEVINFO->DCDCLPVCTRL3;
1705  vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS3_MASK)
1706  >> _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS3_SHIFT;
1707  vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS3_MASK)
1708  >> _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS3_SHIFT;
1709  break;
1710 
1711  case ((0 << 8) | 0):
1712  vrefLow = DEVINFO->DCDCLPVCTRL0;
1713  vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS0_MASK)
1714  >> _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS0_SHIFT;
1715  vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS0_MASK)
1716  >> _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS0_SHIFT;
1717  break;
1718 
1719  case ((1 << 8) | 0):
1720  vrefLow = DEVINFO->DCDCLPVCTRL0;
1721  vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS1_MASK)
1722  >> _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS1_SHIFT;
1723  vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS1_MASK)
1724  >> _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS1_SHIFT;
1725  break;
1726 
1727  case ((2 << 8) | 0):
1728  vrefLow = DEVINFO->DCDCLPVCTRL1;
1729  vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS2_MASK)
1730  >> _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS2_SHIFT;
1731  vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS2_MASK)
1732  >> _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS2_SHIFT;
1733  break;
1734 
1735  case ((3 << 8) | 0):
1736  vrefLow = DEVINFO->DCDCLPVCTRL1;
1737  vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS3_MASK)
1738  >> _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS3_SHIFT;
1739  vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS3_MASK)
1740  >> _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS3_SHIFT;
1741  break;
1742 
1743  default:
1744  EFM_ASSERT(false);
1745  break;
1746  }
1747  *vrefL = vrefLow;
1748  *vrefH = vrefHigh;
1749 }
1750 
1753 /***************************************************************************/
1760 void EMU_DCDCModeSet(EMU_DcdcMode_TypeDef dcdcMode)
1761 {
1762  uint32_t currentDcdcMode = (EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK);
1763 
1764  if ((EMU_DcdcMode_TypeDef)currentDcdcMode == dcdcMode)
1765  {
1766  /* Mode already set - do nothing */
1767  return;
1768  }
1769 
1770 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
1771 
1772  while(EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY);
1773  /* Configure bypass current limiter */
1774  BUS_RegBitWrite(&EMU->DCDCCLIMCTRL, _EMU_DCDCCLIMCTRL_BYPLIMEN_SHIFT, dcdcMode == emuDcdcMode_Bypass ? 0 : 1);
1775 
1776  /* Fix for errata DCDC_E203 */
1777  if (((EMU_DcdcMode_TypeDef)currentDcdcMode == emuDcdcMode_Bypass)
1778  && (dcdcMode == emuDcdcMode_LowNoise))
1779  {
1780  errataFixDcdcHsState = errataFixDcdcHsBypassLn;
1781  }
1782 
1783 #else
1784 
1785  /* Fix for errata DCDC_E204 */
1786  if (((currentDcdcMode == EMU_DCDCCTRL_DCDCMODE_OFF) || (currentDcdcMode == EMU_DCDCCTRL_DCDCMODE_BYPASS))
1787  && ((dcdcMode == emuDcdcMode_LowPower) || (dcdcMode == emuDcdcMode_LowNoise)))
1788  {
1789  /* Always start in LOWNOISE mode and then switch to LOWPOWER mode once LOWNOISE startup is complete. */
1790  EMU_IntClear(EMU_IFC_DCDCLNRUNNING);
1791  while(EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY);
1792  EMU->DCDCCTRL = (EMU->DCDCCTRL & ~_EMU_DCDCCTRL_DCDCMODE_MASK) | EMU_DCDCCTRL_DCDCMODE_LOWNOISE;
1793  while(!(EMU_IntGet() & EMU_IF_DCDCLNRUNNING));
1794  }
1795 #endif
1796 
1797  /* Set user requested mode. */
1798  while(EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY);
1799  EMU->DCDCCTRL = (EMU->DCDCCTRL & ~_EMU_DCDCCTRL_DCDCMODE_MASK) | dcdcMode;
1800 }
1801 
1802 
1803 /***************************************************************************/
1813 void EMU_DCDCConductionModeSet(EMU_DcdcConductionMode_TypeDef conductionMode, bool rcoDefaultSet)
1814 {
1815  EMU_DcdcMode_TypeDef currentDcdcMode
1816  = (EMU_DcdcMode_TypeDef)(EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK);
1817  EMU_DcdcLnRcoBand_TypeDef rcoBand
1818  = (EMU_DcdcLnRcoBand_TypeDef)((EMU->DCDCLNFREQCTRL & _EMU_DCDCLNFREQCTRL_RCOBAND_MASK)
1819  >> _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT);
1820 
1821  /* Set bypass mode and wait for bypass mode to settle before
1822  EMU_DCDCMISCCTRL_LNFORCECCM is set. Restore current DCDC mode. */
1823  EMU_IntClear(EMU_IFC_DCDCINBYPASS);
1824  EMU_DCDCModeSet(emuDcdcMode_Bypass);
1825  while(EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY);
1826  while(!(EMU_IntGet() & EMU_IF_DCDCINBYPASS));
1827  if (conductionMode == emuDcdcConductionMode_DiscontinuousLN)
1828  {
1829  EMU->DCDCMISCCTRL &= ~ EMU_DCDCMISCCTRL_LNFORCECCM;
1830  if (rcoDefaultSet)
1831  {
1832  EMU_DCDCLnRcoBandSet(emuDcdcLnRcoBand_3MHz);
1833  }
1834  else
1835  {
1836  /* emuDcdcConductionMode_DiscontinuousLN supports up to 4MHz LN RCO. */
1837  EFM_ASSERT(rcoBand <= emuDcdcLnRcoBand_4MHz);
1838  }
1839  }
1840  else
1841  {
1842  EMU->DCDCMISCCTRL |= EMU_DCDCMISCCTRL_LNFORCECCM;
1843  if (rcoDefaultSet)
1844  {
1845  EMU_DCDCLnRcoBandSet(emuDcdcLnRcoBand_7MHz);
1846  }
1847  }
1848  EMU_DCDCModeSet(currentDcdcMode);
1849  /* Update slice configuration as it depends on conduction mode and RCO band. */
1850  EMU_DCDCOptimizeSlice(dcdcEm01LoadCurrent_mA);
1851 }
1852 
1853 
1854 /***************************************************************************/
1869 bool EMU_DCDCInit(const EMU_DCDCInit_TypeDef *dcdcInit)
1870 {
1871  uint32_t lpCmpBiasSelEM234H;
1872 
1873 #if defined(_EMU_PWRCFG_MASK)
1874  /* Set external power configuration. This enables writing to the other
1875  DCDC registers. */
1876  EMU->PWRCFG = EMU_PWRCFG_PWRCFG_DCDCTODVDD;
1877 
1878  /* EMU->PWRCFG is write-once and POR reset only. Check that
1879  we could set the desired power configuration. */
1880  if ((EMU->PWRCFG & _EMU_PWRCFG_PWRCFG_MASK) != EMU_PWRCFG_PWRCFG_DCDCTODVDD)
1881  {
1882  /* If this assert triggers unexpectedly, please power cycle the
1883  kit to reset the power configuration. */
1884  EFM_ASSERT(false);
1885  /* Return when assertions are disabled */
1886  return false;
1887  }
1888 #endif
1889 
1890  /* Load DCDC calibration data from the DI page */
1891  dcdcConstCalibrationLoad();
1892 
1893  /* Check current parameters */
1894  EFM_ASSERT(dcdcInit->maxCurrent_mA <= 200);
1895  EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= dcdcInit->maxCurrent_mA);
1896  EFM_ASSERT(dcdcInit->reverseCurrentControl <= 200);
1897 
1898  if (dcdcInit->dcdcMode == emuDcdcMode_LowNoise)
1899  {
1900  /* DCDC low-noise supports max 200mA */
1901  EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= 200);
1902  }
1903 #if (_SILICON_LABS_GECKO_INTERNAL_SDID != 80)
1904  else if (dcdcInit->dcdcMode == emuDcdcMode_LowPower)
1905  {
1906  /* Up to 10mA is supported for EM01-LP mode. */
1907  EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= 10);
1908  }
1909 #endif
1910 
1911  /* EM2/3/4 current above 10mA is not supported */
1912  EFM_ASSERT(dcdcInit->em234LoadCurrent_uA <= 10000);
1913 
1914  if (dcdcInit->em234LoadCurrent_uA < 75)
1915  {
1916  lpCmpBiasSelEM234H = 0;
1917  }
1918  else if (dcdcInit->em234LoadCurrent_uA < 500)
1919  {
1920  lpCmpBiasSelEM234H = 1 << _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT;
1921  }
1922  else if (dcdcInit->em234LoadCurrent_uA < 2500)
1923  {
1924  lpCmpBiasSelEM234H = 2 << _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT;
1925  }
1926  else
1927  {
1928  lpCmpBiasSelEM234H = 3 << _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT;
1929  }
1930 
1931  /* ==== THESE NEXT STEPS ARE STRONGLY ORDER DEPENDENT ==== */
1932 
1933  /* Set DCDC low-power mode comparator bias selection */
1934 
1935  /* 1. Set DCDC low-power mode comparator bias selection and forced CCM
1936  => Updates DCDCMISCCTRL_LNFORCECCM */
1937  EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_MASK
1938  | _EMU_DCDCMISCCTRL_LNFORCECCM_MASK))
1939  | ((uint32_t)lpCmpBiasSelEM234H
1940  | (dcdcInit->reverseCurrentControl >= 0 ?
1941  EMU_DCDCMISCCTRL_LNFORCECCM : 0));
1942 #if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
1943  /* Only 10mA EM01-LP current is supported */
1944  EMU->DCDCLPEM01CFG = (EMU->DCDCLPEM01CFG & ~_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
1945  | EMU_DCDCLPEM01CFG_LPCMPBIASEM01_BIAS3;
1946 #endif
1947 
1948  /* 2. Set recommended and validated current optimization settings
1949  <= Depends on LNFORCECCM
1950  => Updates DCDCLNFREQCTRL_RCOBAND */
1951  dcdcValidatedConfigSet();
1952 
1953  /* 3. Updated static currents and limits user data.
1954  Limiters are updated in EMU_DCDCOptimizeSlice() */
1955  userCurrentLimitsSet(dcdcInit->maxCurrent_mA,
1956  dcdcInit->reverseCurrentControl);
1957  dcdcEm01LoadCurrent_mA = dcdcInit->em01LoadCurrent_mA;
1958 
1959  /* 4. Optimize LN slice based on given user input load current
1960  <= Depends on DCDCMISCCTRL_LNFORCECCM and DCDCLNFREQCTRL_RCOBAND
1961  <= Depends on dcdcInit->maxCurrent_mA and dcdcInit->reverseCurrentControl
1962  => Updates DCDCMISCCTRL_P/NFETCNT
1963  => Updates DCDCMISCCTRL_LNCLIMILIMSEL and DCDCMISCCTRL_LPCLIMILIMSEL
1964  => Updates DCDCZDETCTRL_ZDETILIMSEL */
1965  EMU_DCDCOptimizeSlice(dcdcInit->em01LoadCurrent_mA);
1966 
1967  /* ======================================================= */
1968 
1969  /* Set DCDC low noise mode compensator control register. */
1970  compCtrlSet(dcdcInit->dcdcLnCompCtrl);
1971 
1972  /* Set DCDC output voltage */
1973  if (!EMU_DCDCOutputVoltageSet(dcdcInit->mVout, true, true))
1974  {
1975  EFM_ASSERT(false);
1976  /* Return when assertions are disabled */
1977  return false;
1978  }
1979 
1980 #if ( _SILICON_LABS_GECKO_INTERNAL_SDID == 80 )
1981  /* Select analog peripheral power supply. This must be done before
1982  DCDC mode is set for all EFM32xG1 and EFR32xG1 devices. */
1983  BUS_RegBitWrite(&EMU->PWRCTRL,
1984  _EMU_PWRCTRL_ANASW_SHIFT,
1985  dcdcInit->anaPeripheralPower ? 1 : 0);
1986 #endif
1987 
1988 #if defined(_EMU_PWRCTRL_REGPWRSEL_MASK)
1989  /* Select DVDD as input to the digital regulator. The switch to DVDD will take
1990  effect once the DCDC output is stable. */
1991  EMU->PWRCTRL |= EMU_PWRCTRL_REGPWRSEL_DVDD;
1992 #endif
1993 
1994  /* Set EM0 DCDC operating mode. Output voltage set in
1995  EMU_DCDCOutputVoltageSet() above takes effect if mode
1996  is changed from bypass/off mode. */
1997  EMU_DCDCModeSet(dcdcInit->dcdcMode);
1998 
1999 #if ( _SILICON_LABS_GECKO_INTERNAL_SDID != 80 )
2000  /* Select analog peripheral power supply. This must be done after
2001  DCDC mode is set for all devices other than EFM32xG1 and EFR32xG1. */
2002  BUS_RegBitWrite(&EMU->PWRCTRL,
2003  _EMU_PWRCTRL_ANASW_SHIFT,
2004  dcdcInit->anaPeripheralPower ? 1 : 0);
2005 #endif
2006 
2007  return true;
2008 }
2009 
2010 /***************************************************************************/
2020 bool EMU_DCDCOutputVoltageSet(uint32_t mV,
2021  bool setLpVoltage,
2022  bool setLnVoltage)
2023 {
2024 #if defined( _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_MASK )
2025 
2026 #define DCDC_TRIM_MODES ((uint8_t)dcdcTrimMode_LN + 1)
2027  bool validOutVoltage;
2028  bool attenuationSet;
2029  uint32_t mVlow = 0;
2030  uint32_t mVhigh = 0;
2031  uint32_t mVdiff;
2032  uint32_t vrefVal[DCDC_TRIM_MODES] = {0};
2033  uint32_t vrefLow[DCDC_TRIM_MODES] = {0};
2034  uint32_t vrefHigh[DCDC_TRIM_MODES] = {0};
2035  uint8_t lpcmpBias[DCDC_TRIM_MODES] = {0};
2036 
2037  /* Check that the set voltage is within valid range.
2038  Voltages are obtained from the datasheet. */
2039  validOutVoltage = ((mV >= PWRCFG_DCDCTODVDD_VMIN)
2040  && (mV <= PWRCFG_DCDCTODVDD_VMAX));
2041 
2042  if (!validOutVoltage)
2043  {
2044  EFM_ASSERT(false);
2045  /* Return when assertions are disabled */
2046  return false;
2047  }
2048 
2049  /* Set attenuation to use and low/high range. */
2050  attenuationSet = (mV > 1800);
2051  if (attenuationSet)
2052  {
2053  mVlow = 1800;
2054  mVhigh = 3000;
2055  mVdiff = mVhigh - mVlow;
2056  }
2057  else
2058  {
2059  mVlow = 1200;
2060  mVhigh = 1800;
2061  mVdiff = mVhigh - mVlow;
2062  }
2063 
2064  /* Get 2-point calib data from DEVINFO */
2065 
2066  /* LN mode */
2067  if (attenuationSet)
2068  {
2069  vrefLow[dcdcTrimMode_LN] = DEVINFO->DCDCLNVCTRL0;
2070  vrefHigh[dcdcTrimMode_LN] = (vrefLow[dcdcTrimMode_LN] & _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_MASK)
2071  >> _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_SHIFT;
2072  vrefLow[dcdcTrimMode_LN] = (vrefLow[dcdcTrimMode_LN] & _DEVINFO_DCDCLNVCTRL0_1V8LNATT1_MASK)
2073  >> _DEVINFO_DCDCLNVCTRL0_1V8LNATT1_SHIFT;
2074  }
2075  else
2076  {
2077  vrefLow[dcdcTrimMode_LN] = DEVINFO->DCDCLNVCTRL0;
2078  vrefHigh[dcdcTrimMode_LN] = (vrefLow[dcdcTrimMode_LN] & _DEVINFO_DCDCLNVCTRL0_1V8LNATT0_MASK)
2079  >> _DEVINFO_DCDCLNVCTRL0_1V8LNATT0_SHIFT;
2080  vrefLow[dcdcTrimMode_LN] = (vrefLow[dcdcTrimMode_LN] & _DEVINFO_DCDCLNVCTRL0_1V2LNATT0_MASK)
2081  >> _DEVINFO_DCDCLNVCTRL0_1V2LNATT0_SHIFT;
2082  }
2083 
2084 
2085  /* LP EM234H mode */
2086  lpcmpBias[dcdcTrimMode_EM234H_LP] = (EMU->DCDCMISCCTRL & _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_MASK)
2087  >> _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT;
2088  lpGetDevinfoVrefLowHigh(&vrefLow[dcdcTrimMode_EM234H_LP],
2089  &vrefHigh[dcdcTrimMode_EM234H_LP],
2090  attenuationSet,
2091  lpcmpBias[dcdcTrimMode_EM234H_LP]);
2092 
2093 #if defined( _EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK )
2094  /* LP EM01 mode */
2095  lpcmpBias[dcdcTrimMode_EM01_LP] = (EMU->DCDCLPEM01CFG & _EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
2096  >> _EMU_DCDCLPEM01CFG_LPCMPBIASEM01_SHIFT;
2097  lpGetDevinfoVrefLowHigh(&vrefLow[dcdcTrimMode_EM01_LP],
2098  &vrefHigh[dcdcTrimMode_EM01_LP],
2099  attenuationSet,
2100  lpcmpBias[dcdcTrimMode_EM01_LP]);
2101 #endif
2102 
2103 
2104  /* Calculate output voltage trims */
2105  vrefVal[dcdcTrimMode_LN] = ((mV - mVlow) * (vrefHigh[dcdcTrimMode_LN] - vrefLow[dcdcTrimMode_LN]))
2106  / mVdiff;
2107  vrefVal[dcdcTrimMode_LN] += vrefLow[dcdcTrimMode_LN];
2108 
2109  vrefVal[dcdcTrimMode_EM234H_LP] = ((mV - mVlow) * (vrefHigh[dcdcTrimMode_EM234H_LP] - vrefLow[dcdcTrimMode_EM234H_LP]))
2110  / mVdiff;
2111  vrefVal[dcdcTrimMode_EM234H_LP] += vrefLow[dcdcTrimMode_EM234H_LP];
2112 
2113 #if defined( _EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK )
2114  vrefVal[dcdcTrimMode_EM01_LP] = ((mV - mVlow) * (vrefHigh[dcdcTrimMode_EM01_LP] - vrefLow[dcdcTrimMode_EM01_LP]))
2115  / mVdiff;
2116  vrefVal[dcdcTrimMode_EM01_LP] += vrefLow[dcdcTrimMode_EM01_LP];
2117 #endif
2118 
2119  /* Range checks */
2120  if ((vrefVal[dcdcTrimMode_LN] > vrefHigh[dcdcTrimMode_LN])
2121  || (vrefVal[dcdcTrimMode_LN] < vrefLow[dcdcTrimMode_LN])
2122 #if defined( _EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK )
2123  || (vrefVal[dcdcTrimMode_EM01_LP] > vrefHigh[dcdcTrimMode_EM01_LP])
2124  || (vrefVal[dcdcTrimMode_EM01_LP] < vrefLow[dcdcTrimMode_EM01_LP])
2125 #endif
2126  || (vrefVal[dcdcTrimMode_EM234H_LP] > vrefHigh[dcdcTrimMode_EM234H_LP])
2127  || (vrefVal[dcdcTrimMode_EM234H_LP] < vrefLow[dcdcTrimMode_EM234H_LP]))
2128  {
2129  EFM_ASSERT(false);
2130  /* Return when assertions are disabled */
2131  return false;
2132  }
2133 
2134  /* Update output voltage tuning for LN and LP modes. */
2135  if (setLnVoltage)
2136  {
2137  EMU->DCDCLNVCTRL = (EMU->DCDCLNVCTRL & ~(_EMU_DCDCLNVCTRL_LNVREF_MASK | _EMU_DCDCLNVCTRL_LNATT_MASK))
2138  | (vrefVal[dcdcTrimMode_LN] << _EMU_DCDCLNVCTRL_LNVREF_SHIFT)
2139  | (attenuationSet ? EMU_DCDCLNVCTRL_LNATT : 0);
2140  }
2141 
2142  if (setLpVoltage)
2143  {
2144  /* Load LP EM234H comparator hysteresis calibration */
2145  if(!(lpCmpHystCalibrationLoad(attenuationSet, lpcmpBias[dcdcTrimMode_EM234H_LP], dcdcTrimMode_EM234H_LP)))
2146  {
2147  EFM_ASSERT(false);
2148  /* Return when assertions are disabled */
2149  return false;
2150  }
2151 
2152 #if defined( _EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK )
2153  /* Load LP EM234H comparator hysteresis calibration */
2154  if(!(lpCmpHystCalibrationLoad(attenuationSet, lpcmpBias[dcdcTrimMode_EM01_LP], dcdcTrimMode_EM01_LP)))
2155  {
2156  EFM_ASSERT(false);
2157  /* Return when assertions are disabled */
2158  return false;
2159  }
2160 
2161  /* LP VREF is that max of trims for EM01 and EM234H. */
2162  vrefVal[dcdcTrimMode_EM234H_LP] = SL_MAX(vrefVal[dcdcTrimMode_EM234H_LP], vrefVal[dcdcTrimMode_EM01_LP]);
2163 #endif
2164 
2165  /* Don't exceed max available code as specified in the reference manual for EMU_DCDCLPVCTRL. */
2166  vrefVal[dcdcTrimMode_EM234H_LP] = SL_MIN(vrefVal[dcdcTrimMode_EM234H_LP], 0xE7U);
2167  EMU->DCDCLPVCTRL = (EMU->DCDCLPVCTRL & ~(_EMU_DCDCLPVCTRL_LPVREF_MASK | _EMU_DCDCLPVCTRL_LPATT_MASK))
2168  | (vrefVal[dcdcTrimMode_EM234H_LP] << _EMU_DCDCLPVCTRL_LPVREF_SHIFT)
2169  | (attenuationSet ? EMU_DCDCLPVCTRL_LPATT : 0);
2170  }
2171 #endif
2172  return true;
2173 }
2174 
2175 
2176 /***************************************************************************/
2184 void EMU_DCDCOptimizeSlice(uint32_t em0LoadCurrent_mA)
2185 {
2186  uint32_t sliceCount = 0;
2187  uint32_t rcoBand = (EMU->DCDCLNFREQCTRL & _EMU_DCDCLNFREQCTRL_RCOBAND_MASK)
2188  >> _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT;
2189 
2190  /* Set recommended slice count */
2191  if ((EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK) && (rcoBand >= emuDcdcLnRcoBand_5MHz))
2192  {
2193  if (em0LoadCurrent_mA < 20)
2194  {
2195  sliceCount = 4;
2196  }
2197  else if ((em0LoadCurrent_mA >= 20) && (em0LoadCurrent_mA < 40))
2198  {
2199  sliceCount = 8;
2200  }
2201  else
2202  {
2203  sliceCount = 16;
2204  }
2205  }
2206  else if ((!(EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK)) && (rcoBand <= emuDcdcLnRcoBand_4MHz))
2207  {
2208  if (em0LoadCurrent_mA < 10)
2209  {
2210  sliceCount = 4;
2211  }
2212  else if ((em0LoadCurrent_mA >= 10) && (em0LoadCurrent_mA < 20))
2213  {
2214  sliceCount = 8;
2215  }
2216  else
2217  {
2218  sliceCount = 16;
2219  }
2220  }
2221  else if ((EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK) && (rcoBand <= emuDcdcLnRcoBand_4MHz))
2222  {
2223  if (em0LoadCurrent_mA < 40)
2224  {
2225  sliceCount = 8;
2226  }
2227  else
2228  {
2229  sliceCount = 16;
2230  }
2231  }
2232  else
2233  {
2234  /* This configuration is not recommended. EMU_DCDCInit() applies a recommended
2235  configuration. */
2236  EFM_ASSERT(false);
2237  }
2238 
2239  /* The selected slices are PSLICESEL + 1 */
2240  sliceCount--;
2241 
2242  /* Apply slice count to both N and P slice */
2243  sliceCount = (sliceCount << _EMU_DCDCMISCCTRL_PFETCNT_SHIFT
2244  | sliceCount << _EMU_DCDCMISCCTRL_NFETCNT_SHIFT);
2245  EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_EMU_DCDCMISCCTRL_PFETCNT_MASK
2246  | _EMU_DCDCMISCCTRL_NFETCNT_MASK))
2247  | sliceCount;
2248 
2249  /* Update current limiters */
2250  currentLimitersUpdate();
2251 }
2252 
2253 /***************************************************************************/
2260 void EMU_DCDCLnRcoBandSet(EMU_DcdcLnRcoBand_TypeDef band)
2261 {
2262  uint32_t forcedCcm;
2263  forcedCcm = BUS_RegBitRead(&EMU->DCDCMISCCTRL, _EMU_DCDCMISCCTRL_LNFORCECCM_SHIFT);
2264 
2265  /* DCM mode supports up to 4MHz LN RCO. */
2266  EFM_ASSERT((!forcedCcm && band <= emuDcdcLnRcoBand_4MHz) || forcedCcm);
2267 
2268  EMU->DCDCLNFREQCTRL = (EMU->DCDCLNFREQCTRL & ~_EMU_DCDCLNFREQCTRL_RCOBAND_MASK)
2269  | (band << _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT);
2270 
2271  /* Update slice configuration as this depends on the RCO band. */
2272  EMU_DCDCOptimizeSlice(dcdcEm01LoadCurrent_mA);
2273 }
2274 
2275 /***************************************************************************/
2289 {
2290  bool dcdcModeSet;
2291 
2292 #if defined(_EMU_PWRCFG_MASK)
2293  /* Set DCDCTODVDD only to enable write access to EMU->DCDCCTRL */
2294  EMU->PWRCFG = EMU_PWRCFG_PWRCFG_DCDCTODVDD;
2295 #endif
2296 
2297  /* Select DVDD as input to the digital regulator */
2298 #if defined(EMU_PWRCTRL_IMMEDIATEPWRSWITCH)
2299  EMU->PWRCTRL |= EMU_PWRCTRL_REGPWRSEL_DVDD | EMU_PWRCTRL_IMMEDIATEPWRSWITCH;
2300 #elif defined(EMU_PWRCTRL_REGPWRSEL_DVDD)
2301  EMU->PWRCTRL |= EMU_PWRCTRL_REGPWRSEL_DVDD;
2302 #endif
2303 
2304  /* Set DCDC to OFF and disable LP in EM2/3/4. Verify that the required
2305  mode could be set. */
2306  while(EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY);
2307  EMU->DCDCCTRL = EMU_DCDCCTRL_DCDCMODE_OFF;
2308 
2309  dcdcModeSet = (EMU->DCDCCTRL == EMU_DCDCCTRL_DCDCMODE_OFF);
2310  EFM_ASSERT(dcdcModeSet);
2311 
2312  return dcdcModeSet;
2313 }
2314 #endif
2315 
2316 
2317 #if defined( EMU_STATUS_VMONRDY )
2318 
2319 __STATIC_INLINE uint32_t vmonMilliVoltToCoarseThreshold(int mV)
2320 {
2321  return (mV - 1200) / 200;
2322 }
2323 
2324 __STATIC_INLINE uint32_t vmonMilliVoltToFineThreshold(int mV, uint32_t coarseThreshold)
2325 {
2326  return (mV - 1200 - (coarseThreshold * 200)) / 20;
2327 }
2330 /***************************************************************************/
2342 void EMU_VmonInit(const EMU_VmonInit_TypeDef *vmonInit)
2343 {
2344  uint32_t thresholdCoarse, thresholdFine;
2345  EFM_ASSERT((vmonInit->threshold >= 1200) && (vmonInit->threshold <= 3980));
2346 
2347  thresholdCoarse = vmonMilliVoltToCoarseThreshold(vmonInit->threshold);
2348  thresholdFine = vmonMilliVoltToFineThreshold(vmonInit->threshold, thresholdCoarse);
2349 
2350  switch(vmonInit->channel)
2351  {
2352  case emuVmonChannel_AVDD:
2353  EMU->VMONAVDDCTRL = (thresholdCoarse << _EMU_VMONAVDDCTRL_RISETHRESCOARSE_SHIFT)
2354  | (thresholdFine << _EMU_VMONAVDDCTRL_RISETHRESFINE_SHIFT)
2355  | (thresholdCoarse << _EMU_VMONAVDDCTRL_FALLTHRESCOARSE_SHIFT)
2356  | (thresholdFine << _EMU_VMONAVDDCTRL_FALLTHRESFINE_SHIFT)
2357  | (vmonInit->riseWakeup ? EMU_VMONAVDDCTRL_RISEWU : 0)
2358  | (vmonInit->fallWakeup ? EMU_VMONAVDDCTRL_FALLWU : 0)
2359  | (vmonInit->enable ? EMU_VMONAVDDCTRL_EN : 0);
2360  break;
2361  case emuVmonChannel_ALTAVDD:
2362  EMU->VMONALTAVDDCTRL = (thresholdCoarse << _EMU_VMONALTAVDDCTRL_THRESCOARSE_SHIFT)
2363  | (thresholdFine << _EMU_VMONALTAVDDCTRL_THRESFINE_SHIFT)
2364  | (vmonInit->riseWakeup ? EMU_VMONALTAVDDCTRL_RISEWU : 0)
2365  | (vmonInit->fallWakeup ? EMU_VMONALTAVDDCTRL_FALLWU : 0)
2366  | (vmonInit->enable ? EMU_VMONALTAVDDCTRL_EN : 0);
2367  break;
2368  case emuVmonChannel_DVDD:
2369  EMU->VMONDVDDCTRL = (thresholdCoarse << _EMU_VMONDVDDCTRL_THRESCOARSE_SHIFT)
2370  | (thresholdFine << _EMU_VMONDVDDCTRL_THRESFINE_SHIFT)
2371  | (vmonInit->riseWakeup ? EMU_VMONDVDDCTRL_RISEWU : 0)
2372  | (vmonInit->fallWakeup ? EMU_VMONDVDDCTRL_FALLWU : 0)
2373  | (vmonInit->enable ? EMU_VMONDVDDCTRL_EN : 0);
2374  break;
2375  case emuVmonChannel_IOVDD0:
2376  EMU->VMONIO0CTRL = (thresholdCoarse << _EMU_VMONIO0CTRL_THRESCOARSE_SHIFT)
2377  | (thresholdFine << _EMU_VMONIO0CTRL_THRESFINE_SHIFT)
2378  | (vmonInit->retDisable ? EMU_VMONIO0CTRL_RETDIS : 0)
2379  | (vmonInit->riseWakeup ? EMU_VMONIO0CTRL_RISEWU : 0)
2380  | (vmonInit->fallWakeup ? EMU_VMONIO0CTRL_FALLWU : 0)
2381  | (vmonInit->enable ? EMU_VMONIO0CTRL_EN : 0);
2382  break;
2383  default:
2384  EFM_ASSERT(false);
2385  return;
2386  }
2387 }
2388 
2389 /***************************************************************************/
2400 void EMU_VmonHystInit(const EMU_VmonHystInit_TypeDef *vmonInit)
2401 {
2402  uint32_t riseThresholdCoarse, riseThresholdFine, fallThresholdCoarse, fallThresholdFine;
2403  /* VMON supports voltages between 1200 mV and 3980 mV (inclusive) in 20 mV increments */
2404  EFM_ASSERT((vmonInit->riseThreshold >= 1200) && (vmonInit->riseThreshold < 4000));
2405  EFM_ASSERT((vmonInit->fallThreshold >= 1200) && (vmonInit->fallThreshold < 4000));
2406  /* Fall threshold has to be lower than rise threshold */
2407  EFM_ASSERT(vmonInit->fallThreshold <= vmonInit->riseThreshold);
2408 
2409  riseThresholdCoarse = vmonMilliVoltToCoarseThreshold(vmonInit->riseThreshold);
2410  riseThresholdFine = vmonMilliVoltToFineThreshold(vmonInit->riseThreshold, riseThresholdCoarse);
2411  fallThresholdCoarse = vmonMilliVoltToCoarseThreshold(vmonInit->fallThreshold);
2412  fallThresholdFine = vmonMilliVoltToFineThreshold(vmonInit->fallThreshold, fallThresholdCoarse);
2413 
2414  switch(vmonInit->channel)
2415  {
2416  case emuVmonChannel_AVDD:
2417  EMU->VMONAVDDCTRL = (riseThresholdCoarse << _EMU_VMONAVDDCTRL_RISETHRESCOARSE_SHIFT)
2418  | (riseThresholdFine << _EMU_VMONAVDDCTRL_RISETHRESFINE_SHIFT)
2419  | (fallThresholdCoarse << _EMU_VMONAVDDCTRL_FALLTHRESCOARSE_SHIFT)
2420  | (fallThresholdFine << _EMU_VMONAVDDCTRL_FALLTHRESFINE_SHIFT)
2421  | (vmonInit->riseWakeup ? EMU_VMONAVDDCTRL_RISEWU : 0)
2422  | (vmonInit->fallWakeup ? EMU_VMONAVDDCTRL_FALLWU : 0)
2423  | (vmonInit->enable ? EMU_VMONAVDDCTRL_EN : 0);
2424  break;
2425  default:
2426  EFM_ASSERT(false);
2427  return;
2428  }
2429 }
2430 
2431 /***************************************************************************/
2441 void EMU_VmonEnable(EMU_VmonChannel_TypeDef channel, bool enable)
2442 {
2443  uint32_t volatile * reg;
2444  uint32_t bit;
2445 
2446  switch(channel)
2447  {
2448  case emuVmonChannel_AVDD:
2449  reg = &(EMU->VMONAVDDCTRL);
2450  bit = _EMU_VMONAVDDCTRL_EN_SHIFT;
2451  break;
2452  case emuVmonChannel_ALTAVDD:
2453  reg = &(EMU->VMONALTAVDDCTRL);
2454  bit = _EMU_VMONALTAVDDCTRL_EN_SHIFT;
2455  break;
2456  case emuVmonChannel_DVDD:
2457  reg = &(EMU->VMONDVDDCTRL);
2458  bit = _EMU_VMONDVDDCTRL_EN_SHIFT;
2459  break;
2460  case emuVmonChannel_IOVDD0:
2461  reg = &(EMU->VMONIO0CTRL);
2462  bit = _EMU_VMONIO0CTRL_EN_SHIFT;
2463  break;
2464  default:
2465  EFM_ASSERT(false);
2466  return;
2467  }
2468 
2469  BUS_RegBitWrite(reg, bit, enable);
2470 }
2471 
2472 /***************************************************************************/
2482 bool EMU_VmonChannelStatusGet(EMU_VmonChannel_TypeDef channel)
2483 {
2484  uint32_t bit;
2485  switch(channel)
2486  {
2487  case emuVmonChannel_AVDD:
2488  bit = _EMU_STATUS_VMONAVDD_SHIFT;
2489  break;
2490  case emuVmonChannel_ALTAVDD:
2491  bit = _EMU_STATUS_VMONALTAVDD_SHIFT;
2492  break;
2493  case emuVmonChannel_DVDD:
2494  bit = _EMU_STATUS_VMONDVDD_SHIFT;
2495  break;
2496  case emuVmonChannel_IOVDD0:
2497  bit = _EMU_STATUS_VMONIO0_SHIFT;
2498  break;
2499  default:
2500  EFM_ASSERT(false);
2501  bit = 0;
2502  }
2503 
2504  return BUS_RegBitRead(&EMU->STATUS, bit);
2505 }
2506 #endif /* EMU_STATUS_VMONRDY */
2507 
2508 #if defined( _SILICON_LABS_GECKO_INTERNAL_SDID_80 )
2509 /***************************************************************************/
2522 void EMU_SetBiasMode(EMU_BiasMode_TypeDef mode)
2523 {
2524 #define EMU_TESTLOCK (*(volatile uint32_t *) (EMU_BASE + 0x190))
2525 #define EMU_BIASCONF (*(volatile uint32_t *) (EMU_BASE + 0x164))
2526 #define EMU_BIASTESTCTRL (*(volatile uint32_t *) (EMU_BASE + 0x19C))
2527 #define CMU_ULFRCOCTRL (*(volatile uint32_t *) (CMU_BASE + 0x03C))
2528 
2529  uint32_t freq = 0x2u;
2530  bool emuTestLocked = false;
2531 
2532  if (mode == emuBiasMode_1KHz)
2533  {
2534  freq = 0x0u;
2535  }
2536 
2537  if (EMU_TESTLOCK == 0x1u)
2538  {
2539  emuTestLocked = true;
2540  EMU_TESTLOCK = 0xADE8u;
2541  }
2542 
2543  if (mode == emuBiasMode_Continuous)
2544  {
2545  EMU_BIASCONF &= ~0x74u;
2546  }
2547  else
2548  {
2549  EMU_BIASCONF |= 0x74u;
2550  }
2551 
2552  EMU_BIASTESTCTRL |= 0x8u;
2553  CMU_ULFRCOCTRL = (CMU_ULFRCOCTRL & ~0xC00u)
2554  | ((freq & 0x3u) << 10u);
2555  EMU_BIASTESTCTRL &= ~0x8u;
2556 
2557  if (emuTestLocked)
2558  {
2559  EMU_TESTLOCK = 0u;
2560  }
2561 }
2562 #endif
2563 
2566 #endif /* __EM_EMU_H */
Clock management unit (CMU) API.
void CMU_ClockSelectSet(CMU_Clock_TypeDef clock, CMU_Select_TypeDef ref)
Select reference clock/oscillator used for a clock branch.
Definition: em_cmu.c:2521
#define CMU_STATUS_HFXOENS
Definition: efm32g_cmu.h:440
bool EMU_DCDCInit(const EMU_DCDCInit_TypeDef *dcdcInit)
Configure DCDC regulator.
Definition: em_emu.c:1869
__STATIC_INLINE void CMU_Lock(void)
Lock the CMU in order to protect some of its registers against unintended modification.
Definition: em_cmu.h:1433
bool EMU_DCDCPowerOff(void)
Power off the DCDC regulator.
Definition: em_emu.c:2288
Emlib peripheral API "assert" implementation.
void EMU_EnterEM4(void)
Enter energy mode 4 (EM4).
Definition: em_emu.c:705
void SYSTEM_ChipRevisionGet(SYSTEM_ChipRevision_TypeDef *rev)
Get chip major/minor revision.
Definition: em_system.c:58
#define CMU_STATUS_HFRCOENS
Definition: efm32g_cmu.h:430
void EMU_MemPwrDown(uint32_t blocks)
Power down memory block.
Definition: em_emu.c:825
#define SRAM_SIZE
#define CMU_OSCENCMD_AUXHFRCOEN
Definition: efm32g_cmu.h:347
CMU_Select_TypeDef
Definition: em_cmu.h:962
#define CMU_LOCK_LOCKKEY_LOCKED
Definition: efm32g_cmu.h:1036
#define CMU_STATUS_LFRCOENS
Definition: efm32g_cmu.h:460
void EMU_EnterEM3(bool restore)
Enter energy mode 3 (EM3).
Definition: em_emu.c:597
void EMU_EnterEM2(bool restore)
Enter energy mode 2 (EM2).
Definition: em_emu.c:480
bool EMU_DCDCOutputVoltageSet(uint32_t mV, bool setLpVoltage, bool setLnVoltage)
Set DCDC output voltage.
Definition: em_emu.c:2020
#define EMU_CTRL_EMVREG
Definition: efm32g_emu.h:58
#define CMU_OSCENCMD_HFRCODIS
Definition: efm32g_cmu.h:332
#define _ROMTABLE_PID0_REVMAJOR_MASK
#define DEVINFO
__STATIC_INLINE unsigned int BUS_RegBitRead(volatile const uint32_t *addr, unsigned int bit)
Perform a single-bit read operation on a peripheral register.
Definition: em_bus.h:187
#define _ROMTABLE_PID2_REVMINORMSB_SHIFT
#define _ROMTABLE_PID0_REVMAJOR_SHIFT
#define EMU
General purpose utilities.
__STATIC_INLINE void EMU_Unlock(void)
Unlock the EMU so that writing to locked registers again is possible.
Definition: em_emu.h:926
void EMU_Restore(void)
Restore CMU HF clock select state, oscillator enable and voltage scaling (if available) after EMU_Ent...
Definition: em_emu.c:692
void EMU_DCDCOptimizeSlice(uint32_t em0LoadCurrent_mA)
Optimize DCDC slice count based on the estimated average load current in EM0.
Definition: em_emu.c:2184
#define _ROMTABLE_PID2_REVMINORMSB_MASK
#define RMU
#define EMU_BASE
EMU_BODMode_TypeDef
Definition: em_emu.h:121
void EMU_RamPowerDown(uint32_t start, uint32_t end)
Power down RAM memory blocks.
Definition: em_emu.c:870
#define CMU_OSCENCMD_LFRCOEN
Definition: efm32g_cmu.h:357
uint32_t SystemHFClockGet(void)
Get the current HFCLK frequency.
#define CMU_STATUS_LFXOENS
Definition: efm32g_cmu.h:470
#define CMU_OSCENCMD_LFRCODIS
Definition: efm32g_cmu.h:362
void EMU_DCDCLnRcoBandSet(EMU_DcdcLnRcoBand_TypeDef band)
Set DCDC Low-noise RCO band.
Definition: em_emu.c:2260
void EMU_DCDCConductionModeSet(EMU_DcdcConductionMode_TypeDef conductionMode, bool rcoDefaultSet)
Set DCDC LN regulator conduction mode.
Definition: em_emu.c:1813
#define CMU_OSCENCMD_LFXOEN
Definition: efm32g_cmu.h:367
#define ROMTABLE
#define CMU_OSCENCMD_HFRCOEN
Definition: efm32g_cmu.h:327
#define _EMU_CTRL_EM4CTRL_MASK
Definition: efm32g_emu.h:73
#define CMU_OSCENCMD_HFXOEN
Definition: efm32g_cmu.h:337
void EMU_EM23Init(const EMU_EM23Init_TypeDef *em23Init)
Update EMU module with Energy Mode 2 and 3 configuration.
Definition: em_emu.c:1078
Energy management unit (EMU) peripheral API.
void EMU_DCDCModeSet(EMU_DcdcMode_TypeDef dcdcMode)
Set DCDC regulator operating mode.
Definition: em_emu.c:1760
#define CMU
#define _ROMTABLE_PID3_REVMINORLSB_MASK
#define _EMU_MEMCTRL_MASK
Definition: efm32g_emu.h:79
#define _EMU_CTRL_EM4CTRL_SHIFT
Definition: efm32g_emu.h:72
#define SL_MIN(a, b)
Macro for getting minimum value. No sideeffects, a and b are evaluated once only. ...
Definition: em_common.h:137
System API.
#define CMU_OSCENCMD_LFXODIS
Definition: efm32g_cmu.h:372
#define SL_MAX(a, b)
Macro for getting maximum value. No sideeffects, a and b are evaluated once only. ...
Definition: em_common.h:140
#define CMU_STATUS_AUXHFRCOENS
Definition: efm32g_cmu.h:450
#define SRAM_BASE
static __INLINE void SystemCoreClockUpdate(void)
Update CMSIS SystemCoreClock variable.
#define _ROMTABLE_PID3_REVMINORLSB_SHIFT
__STATIC_INLINE void BUS_RegBitWrite(volatile uint32_t *addr, unsigned int bit, unsigned int val)
Perform a single-bit write operation on a peripheral register.
Definition: em_bus.h:148
#define RAM_MEM_BASE
void CMU_HFRCOBandSet(CMU_HFRCOBand_TypeDef band)
Set HFRCO band and the tuning value based on the value in the calibration table made during productio...
Definition: em_cmu.c:3049
uint32_t CMU_ClockFreqGet(CMU_Clock_TypeDef clock)
Get clock frequency for a clock point.
Definition: em_cmu.c:1550
void EMU_UpdateOscConfig(void)
Update EMU module with CMU oscillator selection/enable status.
Definition: em_emu.c:958
__STATIC_INLINE void CMU_Unlock(void)
Unlock the CMU so that writing to locked registers again is possible.
Definition: em_cmu.h:1489
CMU_ClkDiv_TypeDef CMU_ClockDivGet(CMU_Clock_TypeDef clock)
Get clock divisor/prescaler.
Definition: em_cmu.c:1112
CMU_Select_TypeDef CMU_ClockSelectGet(CMU_Clock_TypeDef clock)
Get currently selected reference clock used for a clock branch.
Definition: em_cmu.c:2146