]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_EFM32_Gecko_Starter_Kit_Simplicity_Studio/Source/SilLabs_Code/emlib/em_emu.c
Add Pearl Gecko demo.
[freertos] / FreeRTOS / Demo / CORTEX_EFM32_Gecko_Starter_Kit_Simplicity_Studio / Source / SilLabs_Code / emlib / em_emu.c
1 /***************************************************************************//**\r
2  * @file em_emu.c\r
3  * @brief Energy Management Unit (EMU) Peripheral API\r
4  * @version 4.2.1\r
5  *******************************************************************************\r
6  * @section License\r
7  * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>\r
8  *******************************************************************************\r
9  *\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
13  *\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
19  *\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
26  *\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
30  *\r
31  ******************************************************************************/\r
32 \r
33 #include <limits.h>\r
34 \r
35 #include "em_emu.h"\r
36 #if defined( EMU_PRESENT ) && ( EMU_COUNT > 0 )\r
37 \r
38 #include "em_cmu.h"\r
39 #include "em_system.h"\r
40 #include "em_assert.h"\r
41 \r
42 /***************************************************************************//**\r
43  * @addtogroup EM_Library\r
44  * @{\r
45  ******************************************************************************/\r
46 \r
47 /***************************************************************************//**\r
48  * @addtogroup EMU\r
49  * @brief Energy Management Unit (EMU) Peripheral API\r
50  * @{\r
51  ******************************************************************************/\r
52 \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
57 #endif\r
58 #if (CMU_STATUS_HFXOENS != CMU_OSCENCMD_HFXOEN)\r
59 #error Conflict in HFXOENS and HFXOEN bitpositions\r
60 #endif\r
61 #if (CMU_STATUS_LFRCOENS != CMU_OSCENCMD_LFRCOEN)\r
62 #error Conflict in LFRCOENS and LFRCOEN bitpositions\r
63 #endif\r
64 #if (CMU_STATUS_LFXOENS != CMU_OSCENCMD_LFXOEN)\r
65 #error Conflict in LFXOENS and LFXOEN bitpositions\r
66 #endif\r
67 \r
68 \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
75 \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
80 \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
85 \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
90 \r
91 #else\r
92 /* Zero Gecko and future families are not affected by errata EMU_E107 */\r
93 #endif\r
94 \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
98 #endif\r
99 /** @endcond */\r
100 \r
101 \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
106 typedef enum\r
107 {\r
108   errataFixDcdcHsInit,\r
109   errataFixDcdcHsTrimSet,\r
110   errataFixDcdcHsLnWaitDone\r
111 } errataFixDcdcHs_TypeDef;\r
112 errataFixDcdcHs_TypeDef errataFixDcdcHsState = errataFixDcdcHsInit;\r
113 #endif\r
114 \r
115 /*******************************************************************************\r
116  **************************   LOCAL VARIABLES   ********************************\r
117  ******************************************************************************/\r
118 \r
119 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */\r
120 /**\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
128  */\r
129 static uint32_t cmuStatus;\r
130 #if defined( _CMU_HFCLKSTATUS_RESETVALUE )\r
131 static uint16_t cmuHfclkStatus;\r
132 #endif\r
133 #if defined( _EMU_DCDCCTRL_MASK )\r
134 static uint16_t dcdcMaxCurrent_mA;\r
135 static uint16_t dcdcOutput_mVout;\r
136 #endif\r
137 \r
138 /** @endcond */\r
139 \r
140 \r
141 /*******************************************************************************\r
142  **************************   LOCAL FUNCTIONS   ********************************\r
143  ******************************************************************************/\r
144 \r
145 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */\r
146 \r
147 /***************************************************************************//**\r
148  * @brief\r
149  *   Restore oscillators and core clock after having been in EM2 or EM3.\r
150  ******************************************************************************/\r
151 static void emuRestore(void)\r
152 {\r
153   uint32_t oscEnCmd;\r
154   uint32_t cmuLocked;\r
155 \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
158 \r
159   /* CMU registers may be locked */\r
160   cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;\r
161   CMU_Unlock();\r
162 \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
167   oscEnCmd = 0;\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
175 #endif\r
176   CMU->OSCENCMD = oscEnCmd;\r
177 \r
178 \r
179 #if defined( _CMU_HFCLKSTATUS_RESETVALUE )\r
180   /* Restore oscillator used for clocking core */\r
181   switch (cmuHfclkStatus & _CMU_HFCLKSTATUS_SELECTED_MASK)\r
182   {\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
189       {\r
190         /* Wait for LFRCO to stabilize */\r
191         while (!(CMU->STATUS & CMU_STATUS_LFRCORDY))\r
192           ;\r
193         CMU->HFCLKSEL = CMU_HFCLKSEL_HF_LFRCO;\r
194       }\r
195       else\r
196       {\r
197         EFM_ASSERT(0);\r
198       }\r
199       break;\r
200 \r
201     case CMU_HFCLKSTATUS_SELECTED_LFXO:\r
202       /* Wait for LFXO to stabilize */\r
203       while (!(CMU->STATUS & CMU_STATUS_LFXORDY))\r
204         ;\r
205       CMU->HFCLKSEL = CMU_HFCLKSEL_HF_LFXO;\r
206       break;\r
207 \r
208     case CMU_HFCLKSTATUS_SELECTED_HFXO:\r
209       /* Wait for HFXO to stabilize */\r
210       while (!(CMU->STATUS & CMU_STATUS_HFXORDY))\r
211         ;\r
212       CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFXO;\r
213       break;\r
214 \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
218       break;\r
219   }\r
220 #else\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
226 #endif\r
227                       | CMU_STATUS_LFXOSEL))\r
228   {\r
229     case CMU_STATUS_LFRCOSEL:\r
230       /* Wait for LFRCO to stabilize */\r
231       while (!(CMU->STATUS & CMU_STATUS_LFRCORDY))\r
232         ;\r
233       CMU->CMD = CMU_CMD_HFCLKSEL_LFRCO;\r
234       break;\r
235 \r
236     case CMU_STATUS_LFXOSEL:\r
237       /* Wait for LFXO to stabilize */\r
238       while (!(CMU->STATUS & CMU_STATUS_LFXORDY))\r
239         ;\r
240       CMU->CMD = CMU_CMD_HFCLKSEL_LFXO;\r
241       break;\r
242 \r
243     case CMU_STATUS_HFXOSEL:\r
244       /* Wait for HFXO to stabilize */\r
245       while (!(CMU->STATUS & CMU_STATUS_HFXORDY))\r
246         ;\r
247       CMU->CMD = CMU_CMD_HFCLKSEL_HFXO;\r
248       break;\r
249 \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
254         ;\r
255       CMU->CMD = _CMU_CMD_HFCLKSEL_USHFRCODIV2;\r
256       break;\r
257 #endif\r
258 \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
262       break;\r
263   }\r
264 \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
268   {\r
269     CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS;\r
270   }\r
271 #endif\r
272   /* Restore CMU register locking */\r
273   if (cmuLocked)\r
274   {\r
275     CMU_Lock();\r
276   }\r
277 }\r
278 \r
279 \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
283 {\r
284   /* SYSTEM_ChipRevisionGet could have been used here, but we would like a\r
285    * faster implementation in this case.\r
286    */\r
287   uint16_t majorMinorRev;\r
288 \r
289   /* CHIP MAJOR bit [3:0] */\r
290   majorMinorRev = ((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK)\r
291                    >> _ROMTABLE_PID0_REVMAJOR_SHIFT)\r
292                   << 8;\r
293   /* CHIP MINOR bit [7:4] */\r
294   majorMinorRev |= ((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK)\r
295                     >> _ROMTABLE_PID2_REVMINORMSB_SHIFT)\r
296                    << 4;\r
297   /* CHIP MINOR bit [3:0] */\r
298   majorMinorRev |= (ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK)\r
299                    >> _ROMTABLE_PID3_REVMINORLSB_SHIFT;\r
300 \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
309 #else\r
310   /* Zero Gecko and future families are not affected by errata EMU_E107 */\r
311   return false;\r
312 #endif\r
313 }\r
314 #endif\r
315 \r
316 \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
323 {\r
324   uint32_t tmp;\r
325   static uint32_t emuDcdcMiscCtrlReg;\r
326 \r
327   if (lpModeSet)\r
328   {\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
336   }\r
337   else\r
338   {\r
339     EMU->DCDCMISCCTRL = emuDcdcMiscCtrlReg;\r
340     maxCurrentUpdate();\r
341   }\r
342 }\r
343 \r
344 void dcdcHsFixLnBlock(void)\r
345 {\r
346 #define EMU_DCDCSTATUS  (* (volatile uint32_t *)(EMU_BASE + 0x7C))\r
347   if (errataFixDcdcHsState == errataFixDcdcHsTrimSet)\r
348   {\r
349     /* Wait for LNRUNNING */\r
350     if ((EMU->DCDCCTRL & ~_EMU_DCDCCTRL_DCDCMODE_MASK) == EMU_DCDCCTRL_DCDCMODE_LOWNOISE)\r
351     {\r
352       while (!(EMU_DCDCSTATUS & (0x1 << 16)));\r
353     }\r
354     errataFixDcdcHsState = errataFixDcdcHsLnWaitDone;\r
355   }\r
356 }\r
357 #endif\r
358 \r
359 \r
360 /** @endcond */\r
361 \r
362 \r
363 /*******************************************************************************\r
364  **************************   GLOBAL FUNCTIONS   *******************************\r
365  ******************************************************************************/\r
366 \r
367 /***************************************************************************//**\r
368  * @brief\r
369  *   Enter energy mode 2 (EM2).\r
370  *\r
371  * @details\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
376  *\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
383  *\r
384  * @note\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
391  * @par\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
395  *   upon return.\r
396  * @par\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
400  * @par\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
405  *\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
409  * @par\r
410  *   The @p restore option should only be used if all clock control is done\r
411  *   via the CMU API.\r
412  ******************************************************************************/\r
413 void EMU_EnterEM2(bool restore)\r
414 {\r
415 #if defined( ERRATA_FIX_EMU_E107_EN )\r
416   bool errataFixEmuE107En;\r
417   uint32_t nonWicIntEn[2];\r
418 #endif\r
419 \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
425 #endif\r
426 \r
427   /* Enter Cortex deep sleep mode */\r
428   SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;\r
429 \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
435   {\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
441 #endif\r
442   }\r
443 #endif\r
444 \r
445 #if defined( _EMU_DCDCCTRL_MASK )\r
446   dcdcFetCntSet(true);\r
447   dcdcHsFixLnBlock();\r
448 #endif\r
449 \r
450   __WFI();\r
451 \r
452 #if defined( _EMU_DCDCCTRL_MASK )\r
453   dcdcFetCntSet(false);\r
454 #endif\r
455 \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
459   {\r
460     NVIC->ISER[0] = nonWicIntEn[0];\r
461 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))\r
462     NVIC->ISER[1] = nonWicIntEn[1];\r
463 #endif\r
464   }\r
465 #endif\r
466 \r
467   /* Restore oscillators/clocks if specified */\r
468   if (restore)\r
469   {\r
470     emuRestore();\r
471   }\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
478 #else\r
479   else if (!(cmuStatus & CMU_STATUS_HFRCOSEL))\r
480 #endif\r
481   {\r
482     SystemCoreClockUpdate();\r
483   }\r
484 }\r
485 \r
486 \r
487 /***************************************************************************//**\r
488  * @brief\r
489  *   Enter energy mode 3 (EM3).\r
490  *\r
491  * @details\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
497  *\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
504  *\r
505  * @note\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
512  * @par\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
517  * @par\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
521  *\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
525  * @par\r
526  *   The @p restore option should only be used if all clock control is done\r
527  *   via the CMU API.\r
528  ******************************************************************************/\r
529 void EMU_EnterEM3(bool restore)\r
530 {\r
531   uint32_t cmuLocked;\r
532 \r
533 #if defined( ERRATA_FIX_EMU_E107_EN )\r
534   bool errataFixEmuE107En;\r
535   uint32_t nonWicIntEn[2];\r
536 #endif\r
537 \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
543 #endif\r
544 \r
545   /* CMU registers may be locked */\r
546   cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;\r
547   CMU_Unlock();\r
548 \r
549   /* Disable LF oscillators */\r
550   CMU->OSCENCMD = CMU_OSCENCMD_LFXODIS | CMU_OSCENCMD_LFRCODIS;\r
551 \r
552   /* Restore CMU register locking */\r
553   if (cmuLocked)\r
554   {\r
555     CMU_Lock();\r
556   }\r
557 \r
558   /* Enter Cortex deep sleep mode */\r
559   SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;\r
560 \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
566   {\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
572 #endif\r
573 \r
574   }\r
575 #endif\r
576 \r
577 #if defined( _EMU_DCDCCTRL_MASK )\r
578   dcdcFetCntSet(true);\r
579   dcdcHsFixLnBlock();\r
580 #endif\r
581 \r
582   __WFI();\r
583 \r
584 #if defined( _EMU_DCDCCTRL_MASK )\r
585   dcdcFetCntSet(false);\r
586 #endif\r
587 \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
591   {\r
592     NVIC->ISER[0] = nonWicIntEn[0];\r
593 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))\r
594     NVIC->ISER[1] = nonWicIntEn[1];\r
595 #endif\r
596   }\r
597 #endif\r
598 \r
599   /* Restore oscillators/clocks if specified */\r
600   if (restore)\r
601   {\r
602     emuRestore();\r
603   }\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
610 #else\r
611   else if (!(cmuStatus & CMU_STATUS_HFRCOSEL))\r
612 #endif\r
613   {\r
614     SystemCoreClockUpdate();\r
615   }\r
616 }\r
617 \r
618 \r
619 /***************************************************************************//**\r
620  * @brief\r
621  *   Enter energy mode 4 (EM4).\r
622  *\r
623  * @note\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
627 {\r
628   int i;\r
629 \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
635 #else\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
640 #endif\r
641 \r
642   /* Make sure register write lock is disabled */\r
643   EMU_Unlock();\r
644 \r
645 #if defined( ERRATA_FIX_EMU_E108_EN )\r
646   /* Fix for errata EMU_E108 - High Current Consumption on EM4 Entry. */\r
647   __disable_irq();\r
648   *(volatile uint32_t *)0x400C80E4 = 0;\r
649 #endif\r
650 \r
651 #if defined( _EMU_DCDCCTRL_MASK )\r
652   dcdcFetCntSet(true);\r
653   dcdcHsFixLnBlock();\r
654 #endif\r
655 \r
656   for (i = 0; i < 4; i++)\r
657   {\r
658 #if defined( _EMU_EM4CTRL_EM4ENTRY_SHIFT )\r
659     EMU->EM4CTRL = em4seq2;\r
660     EMU->EM4CTRL = em4seq3;\r
661   }\r
662   EMU->EM4CTRL = em4seq2;\r
663 #else\r
664     EMU->CTRL = em4seq2;\r
665     EMU->CTRL = em4seq3;\r
666   }\r
667   EMU->CTRL = em4seq2;\r
668 #endif\r
669 }\r
670 \r
671 \r
672 /***************************************************************************//**\r
673  * @brief\r
674  *   Power down memory block.\r
675  *\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
681  *\r
682  * @note\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
688 {\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
693 \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
700              == blocks);\r
701   EMU->MEMCTRL = blocks;\r
702 \r
703 #elif defined( _EMU_MEMCTRL_RAMPOWERDOWN_MASK )\r
704   EFM_ASSERT((blocks & _EMU_MEMCTRL_RAMPOWERDOWN_MASK) == blocks);\r
705   EMU->MEMCTRL = blocks;\r
706 \r
707 #elif defined( _EMU_RAM0CTRL_RAMPOWERDOWN_MASK )\r
708   EFM_ASSERT((blocks & _EMU_RAM0CTRL_RAMPOWERDOWN_MASK) == blocks);\r
709   EMU->RAM0CTRL = blocks;\r
710 \r
711 #else\r
712   (void)blocks;\r
713 #endif\r
714 }\r
715 \r
716 \r
717 /***************************************************************************//**\r
718  * @brief\r
719  *   Update EMU module with CMU oscillator selection/enable status.\r
720  *\r
721  * @details\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
725  *   SW API.\r
726  *\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
730  *\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
734  *   up-to-date.\r
735  ******************************************************************************/\r
736 void EMU_UpdateOscConfig(void)\r
737 {\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
742 #endif\r
743 }\r
744 \r
745 \r
746 /***************************************************************************//**\r
747  * @brief\r
748  *   Update EMU module with Energy Mode 2 and 3 configuration\r
749  *\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
754 {\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
761 #else\r
762   (void)em23Init;\r
763 #endif\r
764 }\r
765 \r
766 \r
767 #if defined( _EMU_EM4CONF_MASK ) || defined( _EMU_EM4CTRL_MASK )\r
768 /***************************************************************************//**\r
769  * @brief\r
770  *   Update EMU module with Energy Mode 4 configuration\r
771  *\r
772  * @param[in] em4Init\r
773  *    Energy Mode 4 configuration structure\r
774  ******************************************************************************/\r
775 void EMU_EM4Init(EMU_EM4Init_TypeDef *em4Init)\r
776 {\r
777 #if defined( _EMU_EM4CONF_MASK )\r
778   /* Init for platforms with EMU->EM4CONF register */\r
779   uint32_t em4conf = EMU->EM4CONF;\r
780 \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
786 \r
787   /* Configure new settings */\r
788   em4conf |= (em4Init->lockConfig << _EMU_EM4CONF_LOCKCONF_SHIFT)\r
789              | (em4Init->osc)\r
790              | (em4Init->buRtcWakeup << _EMU_EM4CONF_BURTCWU_SHIFT)\r
791              | (em4Init->vreg << _EMU_EM4CONF_VREGEN_SHIFT);\r
792 \r
793   /* Apply configuration. Note that lock can be set after this stage. */\r
794   EMU->EM4CONF = em4conf;\r
795 \r
796 #elif defined( _EMU_EM4CTRL_MASK )\r
797   /* Init for platforms with EMU->EM4CTRL register */\r
798 \r
799   uint32_t em4ctrl = EMU->EM4CTRL;\r
800 \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
806 \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
812 \r
813   EMU->EM4CTRL = em4ctrl;\r
814 #endif\r
815 }\r
816 #endif\r
817 \r
818 \r
819 #if defined( BU_PRESENT )\r
820 /***************************************************************************//**\r
821  * @brief\r
822  *   Configure Backup Power Domain settings\r
823  *\r
824  * @param[in] bupdInit\r
825  *   Backup power domain initialization structure\r
826  ******************************************************************************/\r
827 void EMU_BUPDInit(EMU_BUPDInit_TypeDef *bupdInit)\r
828 {\r
829   uint32_t reg;\r
830 \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
836 \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
841 \r
842   EMU->PWRCONF = reg;\r
843 \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
848 \r
849   /* Set backup domain active mode configuration */\r
850   reg = EMU->BUACT & ~(_EMU_BUACT_PWRCON_MASK);\r
851   reg |= (bupdInit->activePower);\r
852   EMU->BUACT = reg;\r
853 \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
859 \r
860   /* Note use of ->enable to both enable BUPD, use BU_VIN pin input and\r
861      release reset */\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
866 \r
867   /* Enable configuration */\r
868   EMU->BUCTRL = reg;\r
869 \r
870   /* If enable is true, enable BU_VIN input power pin, if not disable it  */\r
871   EMU_BUPinEnable(bupdInit->enable);\r
872 \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
875 }\r
876 \r
877 \r
878 /***************************************************************************//**\r
879  * @brief\r
880  *   Configure Backup Power Domain BOD Threshold value\r
881  * @note\r
882  *   These values are precalibrated\r
883  * @param[in] mode Active or Inactive mode\r
884  * @param[in] value\r
885  ******************************************************************************/\r
886 void EMU_BUThresholdSet(EMU_BODMode_TypeDef mode, uint32_t value)\r
887 {\r
888   EFM_ASSERT(value<8);\r
889   EFM_ASSERT(value<=(_EMU_BUACT_BUEXTHRES_MASK>>_EMU_BUACT_BUEXTHRES_SHIFT));\r
890 \r
891   switch(mode)\r
892   {\r
893     case emuBODMode_Active:\r
894       EMU->BUACT = (EMU->BUACT & ~_EMU_BUACT_BUEXTHRES_MASK)\r
895                    | (value<<_EMU_BUACT_BUEXTHRES_SHIFT);\r
896       break;\r
897     case emuBODMode_Inactive:\r
898       EMU->BUINACT = (EMU->BUINACT & ~_EMU_BUINACT_BUENTHRES_MASK)\r
899                      | (value<<_EMU_BUINACT_BUENTHRES_SHIFT);\r
900       break;\r
901   }\r
902 }\r
903 \r
904 \r
905 /***************************************************************************//**\r
906  * @brief\r
907  *  Configure Backup Power Domain BOD Threshold Range\r
908  * @note\r
909  *  These values are precalibrated\r
910  * @param[in] mode Active or Inactive mode\r
911  * @param[in] value\r
912  ******************************************************************************/\r
913 void EMU_BUThresRangeSet(EMU_BODMode_TypeDef mode, uint32_t value)\r
914 {\r
915   EFM_ASSERT(value < 4);\r
916   EFM_ASSERT(value<=(_EMU_BUACT_BUEXRANGE_MASK>>_EMU_BUACT_BUEXRANGE_SHIFT));\r
917 \r
918   switch(mode)\r
919   {\r
920     case emuBODMode_Active:\r
921       EMU->BUACT = (EMU->BUACT & ~_EMU_BUACT_BUEXRANGE_MASK)\r
922                    | (value<<_EMU_BUACT_BUEXRANGE_SHIFT);\r
923       break;\r
924     case emuBODMode_Inactive:\r
925       EMU->BUINACT = (EMU->BUINACT & ~_EMU_BUINACT_BUENRANGE_MASK)\r
926                      | (value<<_EMU_BUINACT_BUENRANGE_SHIFT);\r
927       break;\r
928   }\r
929 }\r
930 #endif\r
931 \r
932 \r
933 #if defined( _EMU_DCDCCTRL_MASK )\r
934 \r
935 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */\r
936 \r
937 /***************************************************************************//**\r
938  * @brief\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
941  *\r
942  * @return\r
943  *   False if calibration registers are locked\r
944  ******************************************************************************/\r
945 static bool ConstCalibrationLoad(void)\r
946 {\r
947   uint32_t val;\r
948   volatile uint32_t *reg;\r
949 \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
957 \r
958   if (DEVINFO->DCDCLPVCTRL0 != UINT_MAX)\r
959   {\r
960     val = *(diCal_EMU_DCDCLNFREQCTRL + 1);\r
961     reg = (volatile uint32_t *)*diCal_EMU_DCDCLNFREQCTRL;\r
962     *reg = val;\r
963 \r
964     val = *(diCal_EMU_DCDCLNVCTRL + 1);\r
965     reg = (volatile uint32_t *)*diCal_EMU_DCDCLNVCTRL;\r
966     *reg = val;\r
967 \r
968     val = *(diCal_EMU_DCDCLPCTRL + 1);\r
969     reg = (volatile uint32_t *)*diCal_EMU_DCDCLPCTRL;\r
970     *reg = val;\r
971 \r
972     val = *(diCal_EMU_DCDCLPVCTRL + 1);\r
973     reg = (volatile uint32_t *)*diCal_EMU_DCDCLPVCTRL;\r
974     *reg = val;\r
975 \r
976     val = *(diCal_EMU_DCDCTRIM0 + 1);\r
977     reg = (volatile uint32_t *)*diCal_EMU_DCDCTRIM0;\r
978     *reg = val;\r
979 \r
980     val = *(diCal_EMU_DCDCTRIM1 + 1);\r
981     reg = (volatile uint32_t *)*diCal_EMU_DCDCTRIM1;\r
982     *reg = val;\r
983 \r
984     return true;\r
985   }\r
986   EFM_ASSERT(false);\r
987   /* Return when assertions are disabled */\r
988   return false;\r
989 }\r
990 \r
991 \r
992 /***************************************************************************//**\r
993  * @brief\r
994  *   Set recommended and validated current optimization settings\r
995  *\r
996  ******************************************************************************/\r
997 void ValidatedConfigSet(void)\r
998 {\r
999 #define EMU_DCDCSMCTRL  (* (volatile uint32_t *)(EMU_BASE + 0x44))\r
1000 \r
1001   uint32_t dcdcTiming;\r
1002   SYSTEM_PartFamily_TypeDef family;\r
1003   SYSTEM_ChipRevision_TypeDef rev;\r
1004 \r
1005   /* Enable duty cycling of the bias */\r
1006   EMU->DCDCLPCTRL |= EMU_DCDCLPCTRL_LPVREFDUTYEN;\r
1007 \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
1013 #else\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
1017 #endif\r
1018 \r
1019   EMU->DCDCTIMING &= ~_EMU_DCDCTIMING_DUTYSCALE_MASK;\r
1020 \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
1029   {\r
1030     /* LPCMPWAITDIS = 1 */\r
1031     EMU_DCDCSMCTRL |= 1;\r
1032 \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
1037 \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
1042 \r
1043     errataFixDcdcHsState = errataFixDcdcHsTrimSet;\r
1044   }\r
1045 }\r
1046 \r
1047 \r
1048 /***************************************************************************//**\r
1049  * @brief\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
1054 {\r
1055   uint32_t lncLimImSel;\r
1056   uint32_t lpcLimImSel;\r
1057   uint32_t pFetCnt;\r
1058 \r
1059   pFetCnt = (EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_PFETCNT_MASK)\r
1060              >> _EMU_DCDCMISCCTRL_PFETCNT_SHIFT;\r
1061 \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
1067 \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
1073 }\r
1074 \r
1075 \r
1076 /***************************************************************************//**\r
1077  * @brief\r
1078  *   Set static variable that holds the user set maximum current. Update\r
1079  *   DCDC configuration.\r
1080  *\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
1085 {\r
1086   dcdcMaxCurrent_mA = mAmaxCurrent;\r
1087   maxCurrentUpdate();\r
1088 }\r
1089 \r
1090 \r
1091 /***************************************************************************//**\r
1092  * @brief\r
1093  *   Load EMU_DCDCLPCTRL_LPCMPHYSSEL depending on LP bias, LP feedback\r
1094  *   attenuation and DEVINFOREV.\r
1095  *\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
1102 {\r
1103   uint8_t devinfoRev;\r
1104   uint32_t lpcmpHystSel;\r
1105 \r
1106   /* Get calib data revision */\r
1107   devinfoRev = SYSTEM_GetDevinfoRev();\r
1108 \r
1109   /* Load LPATT indexed calibration data */\r
1110   if (devinfoRev < 4)\r
1111   {\r
1112     lpcmpHystSel = DEVINFO->DCDCLPCMPHYSSEL0;\r
1113 \r
1114     if (lpAttenuation)\r
1115     {\r
1116       lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT1_MASK)\r
1117                       >> _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT1_SHIFT;\r
1118     }\r
1119     else\r
1120     {\r
1121       lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT0_MASK)\r
1122                       >> _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT0_SHIFT;\r
1123     }\r
1124   }\r
1125   /* devinfoRev >= 4\r
1126      Load LPCMPBIAS indexed calibration data */\r
1127   else\r
1128   {\r
1129     lpcmpHystSel = DEVINFO->DCDCLPCMPHYSSEL1;\r
1130     switch (lpCmpBias)\r
1131     {\r
1132       case _EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS0:\r
1133         lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS0_MASK)\r
1134                         >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS0_SHIFT;\r
1135         break;\r
1136 \r
1137       case _EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS1:\r
1138         lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS1_MASK)\r
1139                         >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS1_SHIFT;\r
1140         break;\r
1141 \r
1142       case _EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS2:\r
1143         lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS2_MASK)\r
1144                         >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS2_SHIFT;\r
1145         break;\r
1146 \r
1147       case _EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS3:\r
1148         lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS3_MASK)\r
1149                         >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS3_SHIFT;\r
1150         break;\r
1151 \r
1152       default:\r
1153         EFM_ASSERT(false);\r
1154         /* Return when assertions are disabled */\r
1155         return false;\r
1156     }\r
1157   }\r
1158 \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
1162   {\r
1163     EFM_ASSERT(false);\r
1164     /* Return when assertions are disabled */\r
1165     return false;\r
1166   }\r
1167   EMU->DCDCLPCTRL = (EMU->DCDCLPCTRL & ~_EMU_DCDCLPCTRL_LPCMPHYSSEL_MASK) | lpcmpHystSel;\r
1168 \r
1169   return true;\r
1170 }\r
1171 \r
1172 \r
1173 /** @endcond */\r
1174 \r
1175 /***************************************************************************//**\r
1176  * @brief\r
1177  *   Set DCDC regulator operating mode\r
1178  *\r
1179  * @param[in] dcdcMode\r
1180  *   DCDC mode\r
1181  ******************************************************************************/\r
1182 void EMU_DCDCModeSet(EMU_DcdcMode_TypeDef dcdcMode)\r
1183 {\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
1187 }\r
1188 \r
1189 \r
1190 /***************************************************************************//**\r
1191  * @brief\r
1192  *   Configure DCDC regulator\r
1193  *\r
1194  * @note\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
1197  *\r
1198  * @param[in] dcdcInit\r
1199  *   DCDC initialization structure\r
1200  *\r
1201  * @return\r
1202  *   True if initialization parameters are valid\r
1203  ******************************************************************************/\r
1204 bool EMU_DCDCInit(EMU_DCDCInit_TypeDef *dcdcInit)\r
1205 {\r
1206   uint32_t lpCmpBiasSel;\r
1207 \r
1208   /* Set external power configuration. This enables writing to the other\r
1209      DCDC registers. */\r
1210   EMU->PWRCFG = dcdcInit->powerConfig;\r
1211 \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
1215   {\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
1220     return false;\r
1221   }\r
1222 \r
1223   /* Load DCDC calibration data from the DI page */\r
1224   ConstCalibrationLoad();\r
1225 \r
1226   /* Check current parameters */\r
1227   EFM_ASSERT(dcdcInit->maxCurrent_mA <= 200);\r
1228   EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= dcdcInit->maxCurrent_mA);\r
1229 \r
1230   /* DCDC low-noise supports max 200mA */\r
1231   if (dcdcInit->dcdcMode == emuDcdcMode_LowNoise)\r
1232   {\r
1233     EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= 200);\r
1234   }\r
1235 \r
1236   /* EM2, 3 and 4 current above 100uA is not supported */\r
1237   EFM_ASSERT(dcdcInit->em234LoadCurrent_uA <= 100);\r
1238 \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
1242   {\r
1243     lpCmpBiasSel  = EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS0;\r
1244   }\r
1245 \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
1251 \r
1252   /* Set recommended and validated current optimization settings */\r
1253   ValidatedConfigSet();\r
1254 \r
1255   /* Set the maximum current that the DCDC can draw from the power source */\r
1256   maxCurrentSet(dcdcInit->maxCurrent_mA);\r
1257 \r
1258   /* Optimize LN slice based on given load current estimate */\r
1259   EMU_DCDCOptimizeSlice(dcdcInit->em01LoadCurrent_mA);\r
1260 \r
1261   /* Set DCDC output voltage */\r
1262   dcdcOutput_mVout = dcdcInit->mVout;\r
1263   if (!EMU_DCDCOutputVoltageSet(dcdcOutput_mVout, true, true))\r
1264   {\r
1265     EFM_ASSERT(false);\r
1266     /* Return when assertions are disabled */\r
1267     return false;\r
1268   }\r
1269 \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
1273 \r
1274   /* Select analog peripheral power supply */\r
1275   BUS_RegBitWrite(&EMU->PWRCTRL, _EMU_PWRCTRL_ANASW_SHIFT, dcdcInit->anaPeripheralPower ? 1 : 0);\r
1276 \r
1277   return true;\r
1278 }\r
1279 \r
1280 \r
1281 /***************************************************************************//**\r
1282  * @brief\r
1283  *   Set DCDC output voltage\r
1284  *\r
1285  * @param[in] mV\r
1286  *   Target DCDC output voltage in mV\r
1287  *\r
1288  * @return\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
1294 {\r
1295 #if defined( _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_MASK )\r
1296 \r
1297   bool validOutVoltage;\r
1298   uint8_t lnMode;\r
1299   bool attSet;\r
1300   uint32_t attMask;\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
1309 \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
1314   {\r
1315     validOutVoltage = ((mV >= PWRCFG_DCDCTODVDD_VMIN)\r
1316                        && (mV <= PWRCFG_DCDCTODVDD_VMAX));\r
1317   }\r
1318 \r
1319   if (!validOutVoltage)\r
1320   {\r
1321     EFM_ASSERT(false);\r
1322     /* Return when assertions are disabled */\r
1323     return false;\r
1324   }\r
1325 \r
1326   /* Populate both LP and LN registers, set control reg pointer and VREF shift. */\r
1327   for (lnMode = 0; lnMode <= 1; lnMode++)\r
1328   {\r
1329     if (((lnMode == 0) && !setLpVoltage)\r
1330         || ((lnMode == 1) && !setLnVoltage))\r
1331     {\r
1332       continue;\r
1333     }\r
1334 \r
1335     ctrlReg   = (lnMode ? &EMU->DCDCLNVCTRL : &EMU->DCDCLPVCTRL);\r
1336     vrefShift = (lnMode ? _EMU_DCDCLNVCTRL_LNVREF_SHIFT\r
1337                         : _EMU_DCDCLPVCTRL_LPVREF_SHIFT);\r
1338 \r
1339     /* Set attenuation to use */\r
1340     attSet = (mV > 1800);\r
1341     if (attSet)\r
1342     {\r
1343       mVlow = 1800;\r
1344       mVhigh = 3000;\r
1345       attMask = (lnMode ? EMU_DCDCLNVCTRL_LNATT : EMU_DCDCLPVCTRL_LPATT);\r
1346     }\r
1347     else\r
1348     {\r
1349       mVlow = 1200;\r
1350       mVhigh = 1800;\r
1351       attMask = 0;\r
1352     }\r
1353 \r
1354     /* Get 2-point calib data from DEVINFO, calculate trimming and set voltege */\r
1355     if (lnMode)\r
1356     {\r
1357       /* Set low-noise DCDC output voltage tuning */\r
1358       if (attSet)\r
1359       {\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
1365       }\r
1366       else\r
1367       {\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
1373       }\r
1374     }\r
1375     else\r
1376     {\r
1377       /* Set low-power DCDC output voltage tuning */\r
1378 \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
1383       {\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
1390           break;\r
1391 \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
1398           break;\r
1399 \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
1406           break;\r
1407 \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
1414           break;\r
1415 \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
1422           break;\r
1423 \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
1430           break;\r
1431 \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
1438           break;\r
1439 \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
1446           break;\r
1447 \r
1448         default:\r
1449           EFM_ASSERT(false);\r
1450           break;\r
1451       }\r
1452 \r
1453       /* Load LP comparator hysteresis calibration */\r
1454       if(!(LpCmpHystCalibrationLoad(attSet, lpcmpBias >> _EMU_DCDCMISCCTRL_LPCMPBIAS_SHIFT)))\r
1455       {\r
1456         EFM_ASSERT(false);\r
1457         /* Return when assertions are disabled */\r
1458         return false;\r
1459       }\r
1460     } /* Low-nise / low-power mode */\r
1461 \r
1462 \r
1463     /* Check for valid 2-point trim values */\r
1464     if ((vrefLow == 0xFF) && (vrefHigh == 0xFF))\r
1465     {\r
1466       EFM_ASSERT(false);\r
1467       /* Return when assertions are disabled */\r
1468       return false;\r
1469     }\r
1470 \r
1471     /* Calculate and set voltage trim */\r
1472     vrefVal = ((mV - mVlow) * (vrefHigh - vrefLow))  / (mVhigh - mVlow);\r
1473     vrefVal += vrefLow;\r
1474 \r
1475     /* Range check */\r
1476     if ((vrefVal > vrefHigh) || (vrefVal < vrefLow))\r
1477     {\r
1478       EFM_ASSERT(false);\r
1479       /* Return when assertions are disabled */\r
1480       return false;\r
1481     }\r
1482 \r
1483     /* Update DCDCLNVCTRL/DCDCLPVCTRL */\r
1484     *ctrlReg = (vrefVal << vrefShift) | attMask;\r
1485   }\r
1486 #endif\r
1487   return true;\r
1488 }\r
1489 \r
1490 \r
1491 /***************************************************************************//**\r
1492  * @brief\r
1493  *   Optimize DCDC slice count based on the estimated average load current\r
1494  *   in EM0\r
1495  *\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
1500 {\r
1501   uint32_t sliceCount = 0;\r
1502   uint32_t rcoBand = (EMU->DCDCLNFREQCTRL & _EMU_DCDCLNFREQCTRL_RCOBAND_MASK)\r
1503                       >> _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT;\r
1504 \r
1505   /* Set recommended slice count */\r
1506   if ((EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK) && (rcoBand >= EMU_DcdcLnRcoBand_5MHz))\r
1507   {\r
1508     if (mAEm0LoadCurrent < 20)\r
1509     {\r
1510       sliceCount = 4;\r
1511     }\r
1512     else if ((mAEm0LoadCurrent >= 20) && (mAEm0LoadCurrent < 40))\r
1513     {\r
1514       sliceCount = 8;\r
1515     }\r
1516     else\r
1517     {\r
1518       sliceCount = 16;\r
1519     }\r
1520   }\r
1521   else if ((!(EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK)) && (rcoBand <= EMU_DcdcLnRcoBand_4MHz))\r
1522   {\r
1523     if (mAEm0LoadCurrent < 10)\r
1524     {\r
1525       sliceCount = 4;\r
1526     }\r
1527     else if ((mAEm0LoadCurrent >= 10) && (mAEm0LoadCurrent < 20))\r
1528     {\r
1529       sliceCount = 8;\r
1530     }\r
1531     else\r
1532     {\r
1533       sliceCount = 16;\r
1534     }\r
1535   }\r
1536   else if ((EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK) && (rcoBand <= EMU_DcdcLnRcoBand_4MHz))\r
1537   {\r
1538     if (mAEm0LoadCurrent < 40)\r
1539     {\r
1540       sliceCount = 8;\r
1541     }\r
1542     else\r
1543     {\r
1544       sliceCount = 16;\r
1545     }\r
1546   }\r
1547   else\r
1548   {\r
1549     /* This configuration is not recommended. EMU_DCDCInit() applies a recommended\r
1550        configuration. */\r
1551     EFM_ASSERT(false);\r
1552   }\r
1553 \r
1554   /* The selected silices are PSLICESEL + 1 */\r
1555   sliceCount--;\r
1556 \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
1562                       | sliceCount;\r
1563 \r
1564   /* Update current limit configuration as it depends on the slice configuration. */\r
1565   maxCurrentUpdate();\r
1566 }\r
1567 \r
1568 /***************************************************************************//**\r
1569  * @brief\r
1570  *   Set DCDC Low-noise RCO band.\r
1571  *\r
1572  * @param[in] band\r
1573  *   RCO band to set.\r
1574  ******************************************************************************/\r
1575 void EMU_DCDCLnRcoBandSet(EMU_DcdcLnRcoBand_TypeDef band)\r
1576 {\r
1577   EMU->DCDCLNFREQCTRL = (EMU->DCDCLNFREQCTRL & ~_EMU_DCDCLNFREQCTRL_RCOBAND_MASK)\r
1578                          | (band << _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT);\r
1579 }\r
1580 \r
1581 /***************************************************************************//**\r
1582  * @brief\r
1583  *   Power off the DCDC regulator.\r
1584  *\r
1585  * @details\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
1590  *\r
1591  * @return\r
1592  *   Return false if the DCDC could not be disabled.\r
1593  ******************************************************************************/\r
1594 bool EMU_DCDCPowerOff(void)\r
1595 {\r
1596   /* Set power configuration to hard bypass */\r
1597   EMU->PWRCFG = 0xF;\r
1598   if ((EMU->PWRCFG & _EMU_PWRCFG_PWRCFG_MASK) != 0xF)\r
1599   {\r
1600     EFM_ASSERT(false);\r
1601     /* Return when assertions are disabled */\r
1602     return false;\r
1603   }\r
1604 \r
1605   /* Set DCDC to OFF and disable LP in EM2/3/4 */\r
1606   EMU->DCDCCTRL = EMU_DCDCCTRL_DCDCMODE_OFF;\r
1607   return true;\r
1608 }\r
1609 #endif\r
1610 \r
1611 \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
1615 {\r
1616   return (mV - 1200) / 200;\r
1617 }\r
1618 \r
1619 __STATIC_INLINE uint32_t vmonMilliVoltToFineThreshold(int mV, uint32_t coarseThreshold)\r
1620 {\r
1621   return (mV - 1200 - (coarseThreshold * 200)) / 20;\r
1622 }\r
1623 /** @endcond */\r
1624 \r
1625 /***************************************************************************//**\r
1626  * @brief\r
1627  *   Initialize VMON channel.\r
1628  *\r
1629  * @details\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
1632  *   value.\r
1633  *\r
1634  * @param[in] vmonInit\r
1635  *   VMON initialization struct\r
1636  ******************************************************************************/\r
1637 void EMU_VmonInit(EMU_VmonInit_TypeDef *vmonInit)\r
1638 {\r
1639   uint32_t thresholdCoarse, thresholdFine;\r
1640   EFM_ASSERT((vmonInit->threshold >= 1200) && (vmonInit->threshold <= 3980));\r
1641 \r
1642   thresholdCoarse = vmonMilliVoltToCoarseThreshold(vmonInit->threshold);\r
1643   thresholdFine = vmonMilliVoltToFineThreshold(vmonInit->threshold, thresholdCoarse);\r
1644 \r
1645   switch(vmonInit->channel)\r
1646   {\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
1655     break;\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
1662     break;\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
1669     break;\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
1677     break;\r
1678   default:\r
1679     EFM_ASSERT(false);\r
1680     return;\r
1681   }\r
1682 }\r
1683 \r
1684 /***************************************************************************//**\r
1685  * @brief\r
1686  *   Initialize VMON channel with hysteresis (separate rise and fall triggers).\r
1687  *\r
1688  * @details\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
1691  *\r
1692  * @param[in] vmonInit\r
1693  *   VMON Hysteresis initialization struct\r
1694  ******************************************************************************/\r
1695 void EMU_VmonHystInit(EMU_VmonHystInit_TypeDef *vmonInit)\r
1696 {\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
1703 \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
1708 \r
1709   switch(vmonInit->channel)\r
1710   {\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
1719     break;\r
1720   default:\r
1721     EFM_ASSERT(false);\r
1722     return;\r
1723   }\r
1724 }\r
1725 \r
1726 /***************************************************************************//**\r
1727  * @brief\r
1728  *   Enable or disable a VMON channel\r
1729  *\r
1730  * @param[in] channel\r
1731  *   VMON channel to enable/disable\r
1732  *\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
1737 {\r
1738   uint32_t volatile * reg;\r
1739   uint32_t bit;\r
1740 \r
1741   switch(channel)\r
1742   {\r
1743   case emuVmonChannel_AVDD:\r
1744     reg = &(EMU->VMONAVDDCTRL);\r
1745     bit = _EMU_VMONAVDDCTRL_EN_SHIFT;\r
1746     break;\r
1747   case emuVmonChannel_ALTAVDD:\r
1748     reg = &(EMU->VMONALTAVDDCTRL);\r
1749     bit = _EMU_VMONALTAVDDCTRL_EN_SHIFT;\r
1750     break;\r
1751   case emuVmonChannel_DVDD:\r
1752     reg = &(EMU->VMONDVDDCTRL);\r
1753     bit = _EMU_VMONDVDDCTRL_EN_SHIFT;\r
1754     break;\r
1755   case emuVmonChannel_IOVDD0:\r
1756     reg = &(EMU->VMONIO0CTRL);\r
1757     bit = _EMU_VMONIO0CTRL_EN_SHIFT;\r
1758     break;\r
1759   default:\r
1760     EFM_ASSERT(false);\r
1761     return;\r
1762   }\r
1763 \r
1764   BUS_RegBitWrite(reg, bit, enable);\r
1765 }\r
1766 \r
1767 /***************************************************************************//**\r
1768  * @brief\r
1769  *   Get the status of a voltage monitor channel.\r
1770  *\r
1771  * @param[in] channel\r
1772  *   VMON channel to get status for\r
1773  *\r
1774  * @return\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
1778 {\r
1779   uint32_t bit;\r
1780   switch(channel)\r
1781   {\r
1782   case emuVmonChannel_AVDD:\r
1783     bit = _EMU_STATUS_VMONAVDD_SHIFT;\r
1784     break;\r
1785   case emuVmonChannel_ALTAVDD:\r
1786     bit = _EMU_STATUS_VMONALTAVDD_SHIFT;\r
1787     break;\r
1788   case emuVmonChannel_DVDD:\r
1789     bit = _EMU_STATUS_VMONDVDD_SHIFT;\r
1790     break;\r
1791   case emuVmonChannel_IOVDD0:\r
1792     bit = _EMU_STATUS_VMONIO0_SHIFT;\r
1793     break;\r
1794   default:\r
1795     EFM_ASSERT(false);\r
1796     bit = 0;\r
1797   }\r
1798 \r
1799   return BUS_RegBitRead(&EMU->STATUS, bit);\r
1800 }\r
1801 #endif /* EMU_STATUS_VMONRDY */\r
1802 \r
1803 /** @} (end addtogroup EMU) */\r
1804 /** @} (end addtogroup EM_Library) */\r
1805 #endif /* __EM_EMU_H */\r