1 /***************************************************************************//**
2 * @file
3 * @brief Energy Management Unit (EMU) Peripheral API
4 *******************************************************************************
5 * # License
6 * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
7 *******************************************************************************
8 *
9 * SPDX-License-Identifier: Zlib
10 *
11 * The licensor of this software is Silicon Laboratories Inc.
12 *
13 * This software is provided 'as-is', without any express or implied
14 * warranty. In no event will the authors be held liable for any damages
15 * arising from the use of this software.
16 *
17 * Permission is granted to anyone to use this software for any purpose,
18 * including commercial applications, and to alter it and redistribute it
19 * freely, subject to the following restrictions:
20 *
21 * 1. The origin of this software must not be misrepresented; you must not
22 * claim that you wrote the original software. If you use this software
23 * in a product, an acknowledgment in the product documentation would be
24 * appreciated but is not required.
25 * 2. Altered source versions must be plainly marked as such, and must not be
26 * misrepresented as being the original software.
27 * 3. This notice may not be removed or altered from any source distribution.
28 *
29 ******************************************************************************/
30
31 #include <limits.h>
32
33 #include "em_emu.h"
34 #if defined(EMU_PRESENT) && (EMU_COUNT > 0)
35
36 #include "sl_assert.h"
37 #include "em_cmu.h"
38 #include "sl_common.h"
39 #include "em_core.h"
40 #include "em_system.h"
41 #include "em_ramfunc.h"
42 #if defined(SYSCFG_PRESENT)
43 #include "em_syscfg.h"
44 #endif
45 /* Consistency check, since restoring assumes similar bit positions in */
46 /* CMU OSCENCMD and STATUS regs. */
47 #if defined(CMU_STATUS_AUXHFRCOENS) && (CMU_STATUS_AUXHFRCOENS != CMU_OSCENCMD_AUXHFRCOEN)
48 #error Conflict in AUXHFRCOENS and AUXHFRCOEN bitpositions
49 #endif
50 #if defined(CMU_STATUS_HFXOENS) && (CMU_STATUS_HFXOENS != CMU_OSCENCMD_HFXOEN)
51 #error Conflict in HFXOENS and HFXOEN bitpositions
52 #endif
53 #if defined(CMU_STATUS_LFRCOENS) && (CMU_STATUS_LFRCOENS != CMU_OSCENCMD_LFRCOEN)
54 #error Conflict in LFRCOENS and LFRCOEN bitpositions
55 #endif
56 #if defined(CMU_STATUS_LFXOENS) && (CMU_STATUS_LFXOENS != CMU_OSCENCMD_LFXOEN)
57 #error Conflict in LFXOENS and LFXOEN bitpositions
58 #endif
59
60 /*******************************************************************************
61 ****************************** DEFINES ************************************
62 ******************************************************************************/
63 #if defined(_SILICON_LABS_32B_SERIES_0)
64 /* Fix for errata EMU_E107 - non-WIC interrupt masks. */
65 #if defined(_EFM32_GECKO_FAMILY)
66 #define ERRATA_FIX_EMU_E107_ENABLE
67 #define NON_WIC_INT_MASK_0 (~(0x0dfc0323U))
68 #define NON_WIC_INT_MASK_1 (~(0x0U))
69
70 #elif defined(_EFM32_TINY_FAMILY)
71 #define ERRATA_FIX_EMU_E107_ENABLE
72 #define NON_WIC_INT_MASK_0 (~(0x001be323U))
73 #define NON_WIC_INT_MASK_1 (~(0x0U))
74
75 #elif defined(_EFM32_GIANT_FAMILY)
76 #define ERRATA_FIX_EMU_E107_ENABLE
77 #define NON_WIC_INT_MASK_0 (~(0xff020e63U))
78 #define NON_WIC_INT_MASK_1 (~(0x00000046U))
79
80 #elif defined(_EFM32_WONDER_FAMILY)
81 #define ERRATA_FIX_EMU_E107_ENABLE
82 #define NON_WIC_INT_MASK_0 (~(0xff020e63U))
83 #define NON_WIC_INT_MASK_1 (~(0x00000046U))
84
85 #elif defined(_EFM32_ZERO_FAMILY)
86 #define ERRATA_FIX_EMU_E107_ENABLE
87 #define NON_WIC_INT_MASK_0 (~(0x00005c6bU))
88 #define NON_WIC_INT_MASK_1 (~(0x00000000U))
89
90 #elif defined(_EFM32_HAPPY_FAMILY)
91 #define ERRATA_FIX_EMU_E107_ENABLE
92 #define NON_WIC_INT_MASK_0 (~(0x00085c6bU))
93 #define NON_WIC_INT_MASK_1 (~(0x00000000U))
94
95 #endif
96 #endif
97
98 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_74) \
99 || (defined(_SILICON_LABS_32B_SERIES_0) \
100 && (defined(_EFM32_HAPPY_FAMILY) || defined(_EFM32_ZERO_FAMILY)))
101 // Fix for errata EMU_E110 - Potential Hard Fault when Exiting EM2.
102 #define ERRATA_FIX_EMU_E110_ENABLE
103 #endif
104
105 /* Fix for errata EMU_E108 - High Current Consumption on EM4 Entry. */
106 #if defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_HAPPY_FAMILY)
107 #define ERRATA_FIX_EMU_E108_ENABLE
108 #endif
109
110 /* Fix for errata EMU_E208 - Occasional Full Reset After Exiting EM4H. */
111 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
112 #define ERRATA_FIX_EMU_E208_ENABLE
113 #endif
114
115 /* Enable FETCNT tuning errata fix. */
116 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
117 #define ERRATA_FIX_DCDC_FETCNT_SET_ENABLE
118 #endif
119
120 /* Enable LN handshake errata fix. */
121 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
122 #define ERRATA_FIX_DCDC_LNHS_BLOCK_ENABLE
123 typedef enum {
124 errataFixDcdcHsInit,
125 errataFixDcdcHsTrimSet,
126 errataFixDcdcHsBypassLn,
127 errataFixDcdcHsLnWaitDone
128 } errataFixDcdcHs_TypeDef;
129 static errataFixDcdcHs_TypeDef errataFixDcdcHsState = errataFixDcdcHsInit;
130 #endif
131
132 /* Fix for errata for EFM32GG11 and EFM32TG11. If a device is entering EM4S
133 * while powering the analog peripherals from DVDD, firmware must switch
134 * over to powering the analog peripherals from AVDD and delay the EM4S entry
135 * with 30 us. */
136 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_100) \
137 || defined(_SILICON_LABS_GECKO_INTERNAL_SDID_103)
138 #define ERRATA_FIX_EM4S_DELAY_ENTRY
139 #endif
140
141 #if defined(_SILICON_LABS_32B_SERIES_1) \
142 && !defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80) \
143 && !defined(ERRATA_FIX_EMU_E220_DECBOD_IGNORE)
144 /* EMU_E220 DECBOD Errata fix. DECBOD Reset can occur
145 * during voltage scaling after EM2/3 wakeup. */
146 #define ERRATA_FIX_EMU_E220_DECBOD_ENABLE
147 #define EMU_PORBOD (*(volatile uint32_t *) (EMU_BASE + 0x14C))
148 #define EMU_PORBOD_GMC_CALIB_DISABLE (0x1UL << 31)
149 #endif
150
151 /* Used to figure out if a memory address is inside or outside of a RAM block.
152 * A memory address is inside a RAM block if the address is greater than the
153 * RAM block address. */
154 #define ADDRESS_NOT_IN_BLOCK(addr, block) ((addr) <= (block) ? 1UL : 0UL)
155
156 /* RAM Block layout for various device families. Note that some devices
157 * have special layout in RAM0 and some devices have a special RAM block
158 * at the end of their block layout. */
159 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_84)
160 #define RAM1_BLOCKS 2U
161 #define RAM1_BLOCK_SIZE 0x10000U // 64 kB blocks
162 #define RAM2_BLOCKS 1U
163 #define RAM2_BLOCK_SIZE 0x800U // 2 kB block
164 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_89)
165 #define RAM0_BLOCKS 2U
166 #define RAM0_BLOCK_SIZE 0x4000U
167 #define RAM1_BLOCKS 2U
168 #define RAM1_BLOCK_SIZE 0x4000U // 16 kB blocks
169 #define RAM2_BLOCKS 1U
170 #define RAM2_BLOCK_SIZE 0x800U // 2 kB block
171 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_95)
172 #define RAM0_BLOCKS 1U
173 #define RAM0_BLOCK_SIZE 0x4000U // 16 kB block
174 #define RAM1_BLOCKS 1U
175 #define RAM1_BLOCK_SIZE 0x4000U // 16 kB block
176 #define RAM2_BLOCKS 1U
177 #define RAM2_BLOCK_SIZE 0x800U // 2 kB block
178 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_103)
179 #define RAM0_BLOCKS 4U
180 #define RAM0_BLOCK_SIZE 0x2000U // 8 kB blocks
181 #elif defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_GIANT_FAMILY)
182 #define RAM0_BLOCKS 4U
183 #define RAM0_BLOCK_SIZE 0x8000U // 32 kB blocks
184 #elif defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_GECKO_FAMILY)
185 #define RAM0_BLOCKS 4U
186 #define RAM0_BLOCK_SIZE 0x1000U // 4 kB blocks
187 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_100)
188 #define RAM0_BLOCKS 8U
189 #define RAM0_BLOCK_SIZE 0x4000U // 16 kB blocks
190 #define RAM1_BLOCKS 8U
191 #define RAM1_BLOCK_SIZE 0x4000U // 16 kB blocks
192 #define RAM2_BLOCKS 4U
193 #define RAM2_BLOCK_SIZE 0x10000U // 64 kB blocks
194 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_106)
195 #define RAM0_BLOCKS 4U
196 #define RAM0_BLOCK_SIZE 0x4000U // 16 kB blocks
197 #define RAM1_BLOCKS 4U
198 #define RAM1_BLOCK_SIZE 0x4000U // 16 kB blocks
199 #define RAM2_BLOCKS 4U
200 #define RAM2_BLOCK_SIZE 0x4000U // 16 kB blocks
201 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
202 #define RAM0_BLOCKS 6U
203 #define RAM0_BLOCK_SIZE 0x4000U // 16 kB blocks
204 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3)
205 #define RAM0_BLOCKS 4U
206 #define RAM0_BLOCK_SIZE 0x4000U // 16 kB blocks
207 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)
208 #define RAM0_BLOCKS 16U
209 #define RAM0_BLOCK_SIZE 0x4000U // 16 kB blocks
210 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)
211 #define RAM0_BLOCKS 16U
212 #define RAM0_BLOCK_SIZE 0x8000U // 32 kB blocks
213 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
214 #define RAM0_BLOCKS 16U
215 #define RAM0_BLOCK_SIZE 0x4000U // 16 kB blocks
216 #endif
217
218 #if defined(_SILICON_LABS_32B_SERIES_0)
219 /* RAM_MEM_END on Gecko devices have a value larger than the SRAM_SIZE. */
220 #define RAM0_END (SRAM_BASE + SRAM_SIZE - 1)
221 #else
222 #define RAM0_END RAM_MEM_END
223 #endif
224
225 #if defined(CMU_STATUS_HFXOSHUNTOPTRDY)
226 #define HFXO_STATUS_READY_FLAGS (CMU_STATUS_HFXOPEAKDETRDY | CMU_STATUS_HFXOSHUNTOPTRDY)
227 #elif defined(CMU_STATUS_HFXOPEAKDETRDY)
228 #define HFXO_STATUS_READY_FLAGS (CMU_STATUS_HFXOPEAKDETRDY)
229 #endif
230
231 #if defined(EMU_SERIES1_DCDC_BUCK_PRESENT)
232 #if !defined(PWRCFG_DCDCTODVDD_VMIN)
233 /** DCDCTODVDD output range maximum. */
234 #define PWRCFG_DCDCTODVDD_VMIN 1800U
235 #endif
236 #if !defined(PWRCFG_DCDCTODVDD_VMAX)
237 /** DCDCTODVDD output range minimum. */
238 #define PWRCFG_DCDCTODVDD_VMAX 3000U
239 #endif
240 #endif
241
242 #if defined(ERRATA_FIX_DCDC_FETCNT_SET_ENABLE) || defined(EMU_SERIES1_DCDC_BUCK_PRESENT)
243 #define DCDC_LP_PFET_CNT 7
244 #define DCDC_LP_NFET_CNT 7
245 #endif
246
247 #if defined(ERRATA_FIX_DCDC_LNHS_BLOCK_ENABLE)
248 #define EMU_DCDCSTATUS (*(volatile uint32_t *)(EMU_BASE + 0x7C))
249 #endif
250
251 #if defined(EMU_SERIES1_DCDC_BUCK_PRESENT)
252 /* Translate fields with different names across platform generations to common names. */
253 #if defined(_EMU_DCDCMISCCTRL_LPCMPBIAS_MASK)
254 #define _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_MASK _EMU_DCDCMISCCTRL_LPCMPBIAS_MASK
255 #define _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT _EMU_DCDCMISCCTRL_LPCMPBIAS_SHIFT
256 #elif defined(_EMU_DCDCMISCCTRL_LPCMPBIASEM234H_MASK)
257 #define _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_MASK _EMU_DCDCMISCCTRL_LPCMPBIASEM234H_MASK
258 #define _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT _EMU_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT
259 #endif
260 #if defined(_EMU_DCDCLPCTRL_LPCMPHYSSEL_MASK)
261 #define _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK _EMU_DCDCLPCTRL_LPCMPHYSSEL_MASK
262 #define _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_SHIFT _EMU_DCDCLPCTRL_LPCMPHYSSEL_SHIFT
263 #elif defined(_EMU_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK)
264 #define _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK _EMU_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK
265 #define _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_SHIFT _EMU_DCDCLPCTRL_LPCMPHYSSELEM234H_SHIFT
266 #endif
267
268 /* Disable LP mode hysteresis in the state machine control. */
269 #define EMU_DCDCMISCCTRL_LPCMPHYSDIS (0x1UL << 1)
270 /* Comparator threshold on the high side. */
271 #define EMU_DCDCMISCCTRL_LPCMPHYSHI (0x1UL << 2)
272 #define EMU_DCDCSMCTRL (*(volatile uint32_t *)(EMU_BASE + 0x44))
273
274 #define DCDC_TRIM_MODES ((uint8_t)dcdcTrimMode_LN + 1)
275 #endif
276
277 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
278 #define EMU_TESTLOCK (*(volatile uint32_t *) (EMU_BASE + 0x190))
279 #define EMU_BIASCONF (*(volatile uint32_t *) (EMU_BASE + 0x164))
280 #define EMU_BIASTESTCTRL (*(volatile uint32_t *) (EMU_BASE + 0x19C))
281 #define CMU_ULFRCOCTRL (*(volatile uint32_t *) (CMU_BASE + 0x03C))
282 #endif
283
284 #if defined(_EMU_TEMP_TEMP_MASK)
285 /* As the energy mode at which a temperature measurement was taken at is
286 * not known, the chosen constant for the TEMPCO calculation is midway between
287 * the EM0/EM1 constant and the EM2/EM3/EM4 constant.
288 */
289 #define EMU_TEMPCO_CONST (0.273f)
290 #endif
291
292 #define EMU_EM4_ENTRY_WAIT_LOOPS 200
293
294 /*******************************************************************************
295 *************************** LOCAL VARIABLES ********************************
296 ******************************************************************************/
297
298 /* Static user configuration. */
299 #if defined(EMU_SERIES1_DCDC_BUCK_PRESENT)
300 static uint16_t dcdcMaxCurrent_mA;
301 static uint16_t dcdcEm01LoadCurrent_mA;
302 static EMU_DcdcLnReverseCurrentControl_TypeDef dcdcReverseCurrentControl;
303 #endif
304 #if defined(EMU_VSCALE_EM01_PRESENT)
305 static EMU_EM01Init_TypeDef vScaleEM01Config = { false };
306 #endif
307
308 /*******************************************************************************
309 ************************** LOCAL FUNCTIONS ********************************
310 ******************************************************************************/
311
312 #if defined(EMU_VSCALE_EM01_PRESENT)
313 /* Convert from level to EM0/1 command bit */
vScaleEM01Cmd(EMU_VScaleEM01_TypeDef level)314 __STATIC_INLINE uint32_t vScaleEM01Cmd(EMU_VScaleEM01_TypeDef level)
315 {
316 #if defined(_SILICON_LABS_32B_SERIES_2)
317 return EMU_CMD_EM01VSCALE1 << ((uint32_t)level - _EMU_STATUS_VSCALE_VSCALE1);
318 #else
319 return EMU_CMD_EM01VSCALE0 << (_EMU_STATUS_VSCALE_VSCALE0 - (uint32_t)level);
320 #endif
321 }
322 #endif
323
324 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_205) \
325 || defined(ERRATA_FIX_EMU_E110_ENABLE)
326 SL_RAMFUNC_DECLARATOR static void __attribute__ ((noinline)) ramWFI(void);
327 SL_RAMFUNC_DEFINITION_BEGIN
ramWFI(void)328 static void __attribute__ ((noinline)) ramWFI(void)
329 {
330 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_205)
331 __WFI(); // Enter EM2 or EM3
332 if (CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk) {
333 for (volatile int i = 0; i < 6; i++) {
334 } // Dummy wait loop ...
335 }
336
337 #else
338 __WFI(); // Enter EM2 or EM3
339 *(volatile uint32_t*)4; // Clear faulty read data after wakeup
340 #endif
341 }
342 SL_RAMFUNC_DEFINITION_END
343 #endif
344
345 #if defined(ERRATA_FIX_EMU_E220_DECBOD_ENABLE)
346 SL_RAMFUNC_DECLARATOR static void __attribute__ ((noinline)) ramWFI(void);
347 SL_RAMFUNC_DEFINITION_BEGIN
ramWFI(void)348 static void __attribute__ ((noinline)) ramWFI(void)
349 {
350 /* Second part of EMU_E220 DECBOD Errata fix. Calibration needs to be disabled
351 * quickly when coming out of EM2/EM3. Ram execution is needed to meet timing.
352 * Calibration is re-enabled after voltage scaling completes. */
353 uint32_t temp = EMU_PORBOD | EMU_PORBOD_GMC_CALIB_DISABLE;
354 __WFI();
355 EMU_PORBOD = temp;
356 }
357 SL_RAMFUNC_DEFINITION_END
358 #endif
359
360 #if (_SILICON_LABS_32B_SERIES < 2)
361 /***************************************************************************//**
362 * @brief
363 * Save/restore/update oscillator, core clock and voltage scaling configuration on
364 * EM2 or EM3 entry/exit.
365 *
366 * @details
367 * Hardware may automatically change the oscillator and the voltage scaling configuration
368 * when going into or out of an energy mode. Static data in this function keeps track of
369 * such configuration bits and is used to restore state if needed.
370 *
371 ******************************************************************************/
372 typedef enum {
373 emState_Save, /* Save EMU and CMU state. */
374 emState_Restore, /* Restore and unlock. */
375 } emState_TypeDef;
376
emState(emState_TypeDef action)377 static void emState(emState_TypeDef action)
378 {
379 uint32_t oscEnCmd;
380 uint32_t cmuLocked;
381 static uint32_t cmuStatus;
382 static CMU_Select_TypeDef hfClock;
383 #if defined(EMU_VSCALE_PRESENT)
384 static uint8_t vScaleStatus;
385 static uint32_t hfrcoCtrl;
386 #endif
387
388 /* Save or update state. */
389 if (action == emState_Save) {
390 /* Save configuration. */
391 cmuStatus = CMU->STATUS;
392 hfClock = CMU_ClockSelectGet(cmuClock_HF);
393 #if defined(EMU_VSCALE_PRESENT)
394 /* Save vscale. */
395 EMU_VScaleWait();
396 vScaleStatus = (uint8_t)((EMU->STATUS & _EMU_STATUS_VSCALE_MASK)
397 >> _EMU_STATUS_VSCALE_SHIFT);
398 hfrcoCtrl = CMU->HFRCOCTRL;
399 #endif
400 } else { /* Restore state. */
401 /* Apply saved configuration. */
402 #if defined(EMU_VSCALE_PRESENT)
403 #if defined(_SILICON_LABS_32B_SERIES_1)
404 if (EMU_LDOStatusGet() == true)
405 /* Restore voltage scaling level if LDO regulator is on. */
406 #endif
407 {
408 /* Restore EM0 and 1 voltage scaling level.
409 @ref EMU_VScaleWait() is called later,
410 just before HF clock select is set. */
411 EMU->CMD = vScaleEM01Cmd((EMU_VScaleEM01_TypeDef)vScaleStatus);
412 }
413 #endif
414 /* CMU registers may be locked. */
415 cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
416 CMU_Unlock();
417
418 #if defined(_CMU_OSCENCMD_MASK)
419 /* AUXHFRCO are automatically disabled (except if using debugger). */
420 /* HFRCO, USHFRCO and HFXO are automatically disabled. */
421 /* LFRCO/LFXO may be disabled by SW in EM3. */
422 /* Restore according to status prior to entering energy mode. */
423 oscEnCmd = 0;
424 oscEnCmd |= (cmuStatus & CMU_STATUS_HFRCOENS) != 0U
425 ? CMU_OSCENCMD_HFRCOEN : 0U;
426 oscEnCmd |= (cmuStatus & CMU_STATUS_AUXHFRCOENS) != 0U
427 ? CMU_OSCENCMD_AUXHFRCOEN : 0U;
428 oscEnCmd |= (cmuStatus & CMU_STATUS_LFRCOENS) != 0U
429 ? CMU_OSCENCMD_LFRCOEN : 0U;
430 oscEnCmd |= (cmuStatus & CMU_STATUS_HFXOENS) != 0U
431 ? CMU_OSCENCMD_HFXOEN : 0U;
432 oscEnCmd |= (cmuStatus & CMU_STATUS_LFXOENS) != 0U
433 ? CMU_OSCENCMD_LFXOEN : 0U;
434 #if defined(_CMU_STATUS_USHFRCOENS_MASK)
435 oscEnCmd |= (cmuStatus & CMU_STATUS_USHFRCOENS) != 0U
436 ? CMU_OSCENCMD_USHFRCOEN : 0U;
437 #endif
438 CMU->OSCENCMD = oscEnCmd;
439 #endif
440
441 #if defined(_EMU_STATUS_VSCALE_MASK)
442 /* Wait for upscale to complete and then restore selected clock. */
443 EMU_VScaleWait();
444 if ((EMU->CTRL & _EMU_CTRL_EM23VSCALEAUTOWSEN_MASK) != 0U) {
445 /* Restore HFRCO frequency which was automatically adjusted by hardware. */
446 while ((CMU->SYNCBUSY & CMU_SYNCBUSY_HFRCOBSY) != 0U) {
447 }
448 CMU->HFRCOCTRL = hfrcoCtrl;
449 if (hfClock == cmuSelect_HFRCO) {
450 /* Optimize wait state after EM2/EM3 wakeup because hardware has
451 * modified them. */
452 CMU_UpdateWaitStates(SystemHfrcoFreq, (int)EMU_VScaleGet());
453 }
454 }
455 #endif
456
457 switch (hfClock) {
458 case cmuSelect_LFXO:
459 CMU_CLOCK_SELECT_SET(HF, LFXO);
460 break;
461 case cmuSelect_LFRCO:
462 CMU_CLOCK_SELECT_SET(HF, LFRCO);
463 break;
464 case cmuSelect_HFXO:
465 CMU_CLOCK_SELECT_SET(HF, HFXO);
466 break;
467 #if defined(CMU_CMD_HFCLKSEL_USHFRCODIV2)
468 case cmuSelect_USHFRCODIV2:
469 CMU_CLOCK_SELECT_SET(HF, USHFRCODIV2);
470 break;
471 #endif
472 #if defined(CMU_HFCLKSTATUS_SELECTED_HFRCODIV2)
473 case cmuSelect_HFRCODIV2:
474 CMU_CLOCK_SELECT_SET(HF, HFRCODIV2);
475 break;
476 #endif
477 #if defined(CMU_HFCLKSTATUS_SELECTED_CLKIN0)
478 case cmuSelect_CLKIN0:
479 CMU_CLOCK_SELECT_SET(HF, CLKIN0);
480 break;
481 #endif
482 #if defined(CMU_HFCLKSTATUS_SELECTED_USHFRCO)
483 case cmuSelect_USHFRCO:
484 CMU_CLOCK_SELECT_SET(HF, USHFRCO);
485 break;
486 #endif
487 }
488
489 #if defined(_CMU_OSCENCMD_MASK)
490 /* If HFRCO was disabled before entering Energy Mode, turn it off again */
491 /* as it is automatically enabled by wake up */
492 if ((cmuStatus & CMU_STATUS_HFRCOENS) == 0U) {
493 CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS;
494 }
495 #endif
496
497 /* Restore CMU register locking */
498 if (cmuLocked != 0U) {
499 CMU_Lock();
500 }
501 }
502 }
503 #endif
504
505 #if defined(ERRATA_FIX_EMU_E107_ENABLE)
506 /* Get enable conditions for errata EMU_E107 fix. */
getErrataFixEmuE107En(void)507 __STATIC_INLINE bool getErrataFixEmuE107En(void)
508 {
509 #if defined(_EFM32_HAPPY_FAMILY) \
510 || defined(_EFM32_TINY_FAMILY) \
511 || defined(_EFM32_WONDER_FAMILY) \
512 || defined(_EFM32_ZERO_FAMILY)
513 // all revisions have the errata
514 return true;
515 #else
516 /* SYSTEM_ChipRevisionGet() could have been used here, but a faster implementation
517 * would be needed in this case.
518 */
519 uint16_t majorMinorRev;
520
521 /* CHIP MAJOR bit [3:0]. */
522 majorMinorRev = ((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK)
523 >> _ROMTABLE_PID0_REVMAJOR_SHIFT)
524 << 8;
525 /* CHIP MINOR bit [7:4]. */
526 majorMinorRev |= ((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK)
527 >> _ROMTABLE_PID2_REVMINORMSB_SHIFT)
528 << 4;
529 /* CHIP MINOR bit [3:0]. */
530 majorMinorRev |= (ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK)
531 >> _ROMTABLE_PID3_REVMINORLSB_SHIFT;
532
533 #if defined(_EFM32_GECKO_FAMILY)
534 // all GECKO revisions except Revision E have the errata
535 return (majorMinorRev <= 0x0103);
536 #elif defined(_EFM32_GIANT_FAMILY)
537 // all LEOPARD GECKO (Major = 0x01 Or 0x02) revisions have the errata
538 // all GIANT GECKO (Major = 0x01) revisions except Revision E have the errata
539 return (majorMinorRev <= 0x0103) || (majorMinorRev == 0x0204) || (majorMinorRev == 0x0205);
540 #else
541 /* Invalid configuration. */
542 EFM_ASSERT(false);
543 /* Return when assertions are disabled. */
544 return false;
545 #endif
546 #endif /* #if defined(_EFM32_ZERO_FAMILY) || defined(_EFM32_HAPPY_FAMILY) #else */
547 }
548 #endif /* #if defined(ERRATA_FIX_EMU_E107_ENABLE) */
549
550 #if defined(ERRATA_FIX_EMU_E110_ENABLE)
551 /* Get enable conditions for errata EMU_E110 fix. */
getErrataFixEmuE110En(void)552 __STATIC_INLINE bool getErrataFixEmuE110En(void)
553 {
554 /* SYSTEM_ChipRevisionGet() could have been used here, but a faster implementation
555 * would be needed in this case.
556 */
557 uint16_t majorMinorRev;
558
559 /* CHIP MAJOR bit [3:0]. */
560 majorMinorRev = ((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK)
561 >> _ROMTABLE_PID0_REVMAJOR_SHIFT)
562 << 8;
563 /* CHIP MINOR bit [7:4]. */
564 majorMinorRev |= ((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK)
565 >> _ROMTABLE_PID2_REVMINORMSB_SHIFT)
566 << 4;
567 /* CHIP MINOR bit [3:0]. */
568 majorMinorRev |= (ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK)
569 >> _ROMTABLE_PID3_REVMINORLSB_SHIFT;
570
571 #if defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_ZERO_FAMILY)
572 return (majorMinorRev == 0x0100);
573 #elif defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_HAPPY_FAMILY)
574 return ((majorMinorRev == 0x0100 || majorMinorRev == 0x0101));
575 #elif defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_WONDER_FAMILY)
576 return (majorMinorRev == 0x0100);
577 #elif defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_GIANT_FAMILY)
578 return (majorMinorRev == 0x0204);
579 #else
580 /* Invalid configuration. */
581 EFM_ASSERT(false);
582 /* Return when assertions are disabled. */
583 return false;
584 #endif
585 }
586 #endif /* #if defined(ERRATA_FIX_EMU_E110_ENABLE) */
587
588 /* LP prepare / LN restore P/NFET count. */
589 #if defined(ERRATA_FIX_DCDC_FETCNT_SET_ENABLE)
590 static void currentLimitersUpdate(void);
dcdcFetCntSet(bool lpModeSet)591 static void dcdcFetCntSet(bool lpModeSet)
592 {
593 uint32_t tmp;
594 static uint32_t emuDcdcMiscCtrlReg;
595
596 if (lpModeSet) {
597 emuDcdcMiscCtrlReg = EMU->DCDCMISCCTRL;
598 tmp = EMU->DCDCMISCCTRL
599 & ~(_EMU_DCDCMISCCTRL_PFETCNT_MASK | _EMU_DCDCMISCCTRL_NFETCNT_MASK);
600 tmp |= (DCDC_LP_PFET_CNT << _EMU_DCDCMISCCTRL_PFETCNT_SHIFT)
601 | (DCDC_LP_NFET_CNT << _EMU_DCDCMISCCTRL_NFETCNT_SHIFT);
602 EMU->DCDCMISCCTRL = tmp;
603 currentLimitersUpdate();
604 } else {
605 EMU->DCDCMISCCTRL = emuDcdcMiscCtrlReg;
606 currentLimitersUpdate();
607 }
608 }
609 #endif
610
611 #if defined(ERRATA_FIX_DCDC_LNHS_BLOCK_ENABLE)
dcdcHsFixLnBlock(void)612 static void dcdcHsFixLnBlock(void)
613 {
614 if ((errataFixDcdcHsState == errataFixDcdcHsTrimSet)
615 || (errataFixDcdcHsState == errataFixDcdcHsBypassLn)) {
616 /* Wait for LNRUNNING */
617 if ((EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK) == EMU_DCDCCTRL_DCDCMODE_LOWNOISE) {
618 while (!(EMU_DCDCSTATUS & (0x1 << 16))) {
619 }
620 }
621 errataFixDcdcHsState = errataFixDcdcHsLnWaitDone;
622 }
623 }
624 #endif
625
626 #if defined(_EMU_CTRL_EM23VSCALE_MASK) && defined(EMU_CTRL_EM23VSCALEAUTOWSEN)
627 /* Configure EMU and CMU for EM2 and 3 voltage downscale. */
vScaleDownEM23Setup(void)628 static void vScaleDownEM23Setup(void)
629 {
630 #if defined(_SILICON_LABS_32B_SERIES_1)
631 if (EMU_LDOStatusGet() == false) {
632 /* Skip voltage scaling if the LDO regulator is turned off. */
633 return;
634 }
635 #endif
636
637 /* Wait until previous scaling is done. */
638 EMU_VScaleWait();
639
640 uint32_t em23vs = (EMU->CTRL & _EMU_CTRL_EM23VSCALE_MASK) >> _EMU_CTRL_EM23VSCALE_SHIFT;
641 uint32_t em01vs = (EMU->STATUS & _EMU_STATUS_VSCALE_MASK) >> _EMU_STATUS_VSCALE_SHIFT;
642
643 /* Inverse coding. */
644 if (em23vs > em01vs) {
645 EMU->CTRL |= EMU_CTRL_EM23VSCALEAUTOWSEN;
646 #if defined(_MSC_RAMCTRL_RAMWSEN_MASK)
647 /* Set RAM wait states for safe EM2 wakeup. */
648 BUS_RegMaskedSet(&MSC->RAMCTRL, (MSC_RAMCTRL_RAMWSEN
649 | MSC_RAMCTRL_RAM1WSEN
650 | MSC_RAMCTRL_RAM2WSEN));
651 #endif
652 } else {
653 EMU->CTRL &= ~EMU_CTRL_EM23VSCALEAUTOWSEN;
654 }
655 }
656
657 /* Handle automatic HFRCO adjustment that may have occurred during EM2/EM3. */
vScaleAfterWakeup(void)658 static void vScaleAfterWakeup(void)
659 {
660 if ((EMU->CTRL & EMU_CTRL_EM23VSCALEAUTOWSEN) != 0U) {
661 /* The hardware may have updated the HFRCOCTRL register during EM2/EM3
662 * entry if voltage scaling in EM2/EM3 is enabled. The hardware would
663 * then update the HFRCO frequency to 19 MHz automatically. */
664 uint32_t freqRange = (CMU->HFRCOCTRL & _CMU_HFRCOCTRL_FREQRANGE_MASK)
665 >> _CMU_HFRCOCTRL_FREQRANGE_SHIFT;
666 if (freqRange == 0x08U) {
667 SystemHfrcoFreq = 19000000;
668 }
669 }
670 }
671 #endif
672
673 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
674 typedef enum {
675 dpllState_Save, /* Save DPLL state. */
676 dpllState_Restore, /* Restore DPLL. */
677 } dpllState_TypeDef;
678
679 /* Save or restore and relock DPLL. */
dpllState(dpllState_TypeDef action)680 static void dpllState(dpllState_TypeDef action)
681 {
682 CMU_ClkDiv_TypeDef div;
683 static uint32_t dpllRefClk = CMU_DPLLREFCLKCTRL_CLKSEL_DISABLED;
684
685 if (action == dpllState_Save) {
686 dpllRefClk = CMU_DPLLREFCLKCTRL_CLKSEL_DISABLED;
687 CMU->CLKEN0_SET = CMU_CLKEN0_DPLL0;
688 if (DPLL0->EN == DPLL_EN_EN) {
689 /* DPLL is in use, save reference clock selection. */
690 dpllRefClk = CMU->DPLLREFCLKCTRL;
691 }
692 } else { /* Restore */
693 if ((dpllRefClk != CMU_DPLLREFCLKCTRL_CLKSEL_DISABLED)
694 && (DPLL0->EN != DPLL_EN_EN)) {
695 /* Restore DPLL reference clock selection. */
696 CMU->DPLLREFCLKCTRL = dpllRefClk;
697 /* Only wait for DPLL lock if HFRCODPLL is used as SYSCLK. */
698 if (CMU_ClockSelectGet(cmuClock_SYSCLK) == cmuSelect_HFRCODPLL) {
699 /* Set HCLK prescaler to safe value to avoid overclocking while locking. */
700 div = CMU_ClockDivGet(cmuClock_HCLK);
701 if (div == 1U) {
702 CMU_ClockDivSet(cmuClock_HCLK, 2U);
703 }
704
705 /* Relock DPLL and wait for ready. */
706 DPLL0->IF_CLR = DPLL_IF_LOCK | DPLL_IF_LOCKFAILLOW | DPLL_IF_LOCKFAILHIGH;
707 DPLL0->EN_SET = DPLL_EN_EN;
708 while ((DPLL0->IF & DPLL_IF_LOCK) == 0U) {
709 }
710
711 /* Restore HCLK prescaler. */
712 if (div == 1U) {
713 CMU_ClockDivSet(cmuClock_HCLK, 1U);
714 }
715 } else {
716 /* Relock DPLL and exit without waiting for ready. */
717 DPLL0->EN_SET = DPLL_EN_EN;
718 }
719 }
720 }
721 }
722 #endif
723
724 /*******************************************************************************
725 ************************** GLOBAL FUNCTIONS *******************************
726 ******************************************************************************/
727
728 /***************************************************************************//**
729 * @addtogroup emu EMU - Energy Management Unit
730 * @brief Energy Management Unit (EMU) Peripheral API
731 * @details
732 * This module contains functions to control the EMU peripheral of Silicon
733 * Labs 32-bit MCUs and SoCs. The EMU handles the different low energy modes
734 * in Silicon Labs microcontrollers.
735 * @{
736 ******************************************************************************/
737
738 #if defined(EMU_VSCALE_EM01_PRESENT)
739 /***************************************************************************//**
740 * @brief
741 * Update the EMU module with Energy Mode 0 and 1 configuration.
742 *
743 * @param[in] em01Init
744 * Energy Mode 0 and 1 configuration structure.
745 ******************************************************************************/
EMU_EM01Init(const EMU_EM01Init_TypeDef * em01Init)746 void EMU_EM01Init(const EMU_EM01Init_TypeDef *em01Init)
747 {
748 vScaleEM01Config.vScaleEM01LowPowerVoltageEnable =
749 em01Init->vScaleEM01LowPowerVoltageEnable;
750 EMU_VScaleEM01ByClock(0, true);
751 }
752 #endif
753
754 /***************************************************************************//**
755 * @brief
756 * Update the EMU module with Energy Mode 2 and 3 configuration.
757 *
758 * @param[in] em23Init
759 * Energy Mode 2 and 3 configuration structure.
760 ******************************************************************************/
EMU_EM23Init(const EMU_EM23Init_TypeDef * em23Init)761 void EMU_EM23Init(const EMU_EM23Init_TypeDef *em23Init)
762 {
763 #if defined(_EMU_CTRL_EMVREG_MASK)
764 EMU->CTRL = em23Init->em23VregFullEn ? (EMU->CTRL | EMU_CTRL_EMVREG)
765 : (EMU->CTRL & ~EMU_CTRL_EMVREG);
766 #elif defined(_EMU_CTRL_EM23VREG_MASK)
767 EMU->CTRL = em23Init->em23VregFullEn ? (EMU->CTRL | EMU_CTRL_EM23VREG)
768 : (EMU->CTRL & ~EMU_CTRL_EM23VREG);
769 #else
770 (void)em23Init;
771 #endif
772
773 #if defined(EMU_VSCALE_PRESENT)
774 EMU->CTRL = (EMU->CTRL & ~_EMU_CTRL_EM23VSCALE_MASK)
775 | ((uint32_t)em23Init->vScaleEM23Voltage << _EMU_CTRL_EM23VSCALE_SHIFT);
776 #if defined(CMU_HFXOCTRL_AUTOSTARTSELEM0EM1)
777 if (em23Init->vScaleEM23Voltage == emuVScaleEM23_LowPower) {
778 /* Voltage scaling is not compatible with HFXO auto start and select. */
779 EFM_ASSERT((CMU->HFXOCTRL & CMU_HFXOCTRL_AUTOSTARTSELEM0EM1) == 0U);
780 }
781 #endif
782 #endif
783 }
784
785 /***************************************************************************//**
786 * @brief
787 * Energy mode 2/3 pre-sleep hook function.
788 *
789 * @details
790 * This function is called by EMU_EnterEM2() and EMU_EnterEM3() functions
791 * just prior to execution of the WFI instruction. The function implementation
792 * does not perform anything, but it is SL_WEAK so that it can be re-
793 * implemented in application code if actions are needed.
794 ******************************************************************************/
EMU_EM23PresleepHook(void)795 SL_WEAK void EMU_EM23PresleepHook(void)
796 {
797 }
798
799 /***************************************************************************//**
800 * @brief
801 * EFP's Energy mode 2/3 pre-sleep hook function.
802 *
803 * @details
804 * This function is similar to @ref EMU_EM23PresleepHook() but is reserved
805 * for EFP usage.
806 *
807 * @note
808 * The function is primarily meant to be used in systems with EFP circuitry.
809 * (EFP = Energy Friendly Pmic (PMIC = Power Management IC)).
810 * In such systems there is a need to drive certain signals to EFP pins to
811 * notify about energy mode transitions.
812 ******************************************************************************/
EMU_EFPEM23PresleepHook(void)813 SL_WEAK void EMU_EFPEM23PresleepHook(void)
814 {
815 }
816
817 /***************************************************************************//**
818 * @brief
819 * Energy mode 2/3 post-sleep hook function.
820 *
821 * @details
822 * This function is called by EMU_EnterEM2() and EMU_EnterEM3() functions
823 * just after wakeup from the WFI instruction. The function implementation
824 * does not perform anything, but it is SL_WEAK so that it can be re-
825 * implemented in application code if actions are needed.
826 ******************************************************************************/
EMU_EM23PostsleepHook(void)827 SL_WEAK void EMU_EM23PostsleepHook(void)
828 {
829 }
830
831 /***************************************************************************//**
832 * @brief
833 * EFP's Energy mode 2/3 post-sleep hook function.
834 *
835 * @details
836 * This function is similar to @ref EMU_EM23PostsleepHook() but is reserved
837 * for EFP usage.
838 *
839 * @note
840 * The function is primarily meant to be used in systems with EFP circuitry.
841 * (EFP = Energy Friendly Pmic (PMIC = Power Management IC)).
842 * In such systems there is a need to drive certain signals to EFP pins to
843 * notify about energy mode transitions.
844 ******************************************************************************/
EMU_EFPEM23PostsleepHook(void)845 SL_WEAK void EMU_EFPEM23PostsleepHook(void)
846 {
847 }
848
849 /***************************************************************************//**
850 * @brief
851 * Enter energy mode 2 (EM2).
852 *
853 * @details
854 * When entering EM2, high-frequency clocks are disabled, i.e., HFXO, HFRCO
855 * and AUXHFRCO (for AUXHFRCO, see exception note below). When re-entering
856 * EM0, HFRCO is re-enabled and the core will be clocked by the configured
857 * HFRCO band. This ensures a quick wakeup from EM2.
858 *
859 * However, prior to entering EM2, the core may have been using another
860 * oscillator than HFRCO. The @p restore parameter gives the user the option
861 * to restore all HF oscillators according to state prior to entering EM2,
862 * as well as the clock used to clock the core. This restore procedure is
863 * handled by SW. However, since handled by SW, it will not be restored
864 * before completing the interrupt function(s) waking up the core!
865 *
866 * @note
867 * If restoring core clock to use the HFXO oscillator, which has been
868 * disabled during EM2 mode, this function will stall until the oscillator
869 * has stabilized. Stalling time can be reduced by adding interrupt
870 * support detecting stable oscillator, and an asynchronous switch to the
871 * original oscillator. See CMU documentation. Such a feature is however
872 * outside the scope of the implementation in this function.
873 * @note
874 * If ERRATA_FIX_EMU_E110_ENABLE is active, the core's SLEEPONEXIT feature
875 * can not be used.
876 * @par
877 * If HFXO is re-enabled by this function, and NOT used to clock the core,
878 * this function will not wait for HFXO to stabilize. This must be considered
879 * by the application if trying to use features relying on that oscillator
880 * upon return.
881 * @par
882 * If a debugger is attached, the AUXHFRCO will not be disabled if enabled
883 * upon entering EM2. It will thus remain enabled when returning to EM0
884 * regardless of the @p restore parameter.
885 * @par
886 * If HFXO autostart and select is enabled by using CMU_HFXOAutostartEnable(),
887 * the automatic starting and selecting of the core clocks will be done,
888 * regardless of the @p restore parameter, when waking up on the wakeup
889 * sources corresponding to the autostart and select setting.
890 * @par
891 * If voltage scaling is supported, the restore parameter is true and the EM0
892 * voltage scaling level is set higher than the EM2 level, then the EM0 level is
893 * also restored.
894 * @par
895 * On Series 2 Config 2 devices (EFRxG22), this function will also relock the
896 * DPLL if the DPLL is used and @p restore is true.
897 *
898 * Note that the hardware will automatically update the HFRCO frequency in the
899 * case where voltage scaling is used in EM2/EM3 and not in EM0/EM1. When the
900 * restore argument to this function is true then software will restore the
901 * original HFRCO frequency after EM2/EM3 wake up. If the restore argument is
902 * false then the HFRCO frequency is 19 MHz when coming out of EM2/EM3 and
903 * all wait states are at a safe value.
904 *
905 * @param[in] restore
906 * @li true - save and restore oscillators, clocks and voltage scaling, see
907 * function details.
908 * @li false - do not save and restore oscillators and clocks, see function
909 * details.
910 * @par
911 * The @p restore option should only be used if all clock control is done
912 * via the CMU API.
913 ******************************************************************************/
EMU_EnterEM2(bool restore)914 void EMU_EnterEM2(bool restore)
915 {
916 #if defined(ERRATA_FIX_EMU_E107_ENABLE)
917 bool errataFixEmuE107En;
918 uint32_t nonWicIntEn[2];
919 #endif
920
921 #if defined(ERRATA_FIX_EMU_E110_ENABLE)
922 bool errataFixEmuE110En;
923 #endif
924
925 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
926 if (restore) {
927 dpllState(dpllState_Save);
928 }
929 #endif
930
931 #if (_SILICON_LABS_32B_SERIES < 2)
932 /* Only save EMU and CMU state if restored on wake-up. */
933 if (restore) {
934 emState(emState_Save);
935 }
936 #endif
937
938 #if defined(_EMU_CTRL_EM23VSCALE_MASK) && defined(EMU_CTRL_EM23VSCALEAUTOWSEN)
939 vScaleDownEM23Setup();
940 #endif
941
942 /* Enter Cortex deep sleep mode. */
943 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
944
945 /* Fix for errata EMU_E107 - store non-WIC interrupt enable flags.
946 Disable the enabled non-WIC interrupts. */
947 #if defined(ERRATA_FIX_EMU_E107_ENABLE)
948 errataFixEmuE107En = getErrataFixEmuE107En();
949 if (errataFixEmuE107En) {
950 nonWicIntEn[0] = NVIC->ISER[0] & NON_WIC_INT_MASK_0;
951 NVIC->ICER[0] = nonWicIntEn[0];
952 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
953 nonWicIntEn[1] = NVIC->ISER[1] & NON_WIC_INT_MASK_1;
954 NVIC->ICER[1] = nonWicIntEn[1];
955 #endif
956 }
957 #endif
958
959 #if defined(ERRATA_FIX_DCDC_FETCNT_SET_ENABLE)
960 dcdcFetCntSet(true);
961 #endif
962 #if defined(ERRATA_FIX_DCDC_LNHS_BLOCK_ENABLE)
963 dcdcHsFixLnBlock();
964 #endif
965
966 EMU_EM23PresleepHook();
967 EMU_EFPEM23PresleepHook();
968 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_205) \
969 || defined(ERRATA_FIX_EMU_E110_ENABLE)
970 #if defined(ERRATA_FIX_EMU_E110_ENABLE)
971 errataFixEmuE110En = getErrataFixEmuE110En();
972 if (errataFixEmuE110En) {
973 #endif
974 CORE_CRITICAL_SECTION(ramWFI(); )
975 #if defined(ERRATA_FIX_EMU_E110_ENABLE)
976 } else {
977 __WFI();
978 }
979 #endif
980 #elif defined(ERRATA_FIX_EMU_E220_DECBOD_ENABLE)
981 // Apply errata fix if voltage scaling in EM2 is used.
982 if ((EMU->CTRL & EMU_CTRL_EM23VSCALEAUTOWSEN) != 0U) {
983 CORE_CRITICAL_SECTION(ramWFI(); )
984 } else {
985 __WFI();
986 }
987 #else
988 __WFI();
989 #endif
990 EMU_EFPEM23PostsleepHook();
991 EMU_EM23PostsleepHook();
992
993 #if defined(ERRATA_FIX_DCDC_FETCNT_SET_ENABLE)
994 dcdcFetCntSet(false);
995 #endif
996
997 /* Fix for errata EMU_E107 - restore state of non-WIC interrupt enable flags. */
998 #if defined(ERRATA_FIX_EMU_E107_ENABLE)
999 if (errataFixEmuE107En) {
1000 NVIC->ISER[0] = nonWicIntEn[0];
1001 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
1002 NVIC->ISER[1] = nonWicIntEn[1];
1003 #endif
1004 }
1005 #endif
1006
1007 #if (_SILICON_LABS_32B_SERIES < 2)
1008 /* Restore oscillators/clocks and voltage scaling if supported. */
1009 if (restore) {
1010 emState(emState_Restore);
1011 }
1012 #if defined(_EMU_CTRL_EM23VSCALE_MASK) && defined(EMU_CTRL_EM23VSCALEAUTOWSEN)
1013 else {
1014 vScaleAfterWakeup();
1015 }
1016 #if defined(ERRATA_FIX_EMU_E220_DECBOD_ENABLE)
1017 /* Third part of EMU_E220 DECBOD Errata fix. Calibration needs to be enabled
1018 * after voltage scaling completes. */
1019 EMU_PORBOD &= ~(EMU_PORBOD_GMC_CALIB_DISABLE);
1020 #endif
1021 #endif
1022 #endif
1023
1024 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
1025 if (restore) {
1026 dpllState(dpllState_Restore);
1027 }
1028 #endif
1029
1030 if (!restore) {
1031 /* If not restoring, and the original clock was not HFRCO, the CMSIS */
1032 /* core clock variable must be updated since HF clock has changed */
1033 /* to HFRCO. */
1034 SystemCoreClockUpdate();
1035 }
1036 }
1037
1038 /***************************************************************************//**
1039 * @brief
1040 * Enter energy mode 3 (EM3).
1041 *
1042 * @details
1043 * When entering EM3, the high-frequency clocks are disabled by hardware, i.e., HFXO,
1044 * HFRCO, and AUXHFRCO (for AUXHFRCO, see exception note below). In addition,
1045 * the low-frequency clocks, i.e., LFXO and LFRCO are disabled by software. When
1046 * re-entering EM0, HFRCO is re-enabled and the core will be clocked by the
1047 * configured HFRCO band. This ensures a quick wakeup from EM3.
1048 *
1049 * However, prior to entering EM3, the core may have been using an
1050 * oscillator other than HFRCO. The @p restore parameter gives the user the option
1051 * to restore all HF/LF oscillators according to state prior to entering EM3,
1052 * as well as the clock used to clock the core. This restore procedure is
1053 * handled by software. However, since it is handled by software, it will not be restored
1054 * before completing the interrupt function(s) waking up the core!
1055 *
1056 * @note
1057 * If restoring core clock to use an oscillator other than HFRCO, this
1058 * function will stall until the oscillator has stabilized. Stalling time
1059 * can be reduced by adding interrupt support detecting stable oscillator,
1060 * and an asynchronous switch to the original oscillator. See CMU
1061 * documentation. This feature is, however, outside the scope of the
1062 * implementation in this function.
1063 * @note
1064 * If ERRATA_FIX_EMU_E110_ENABLE is active, the core's SLEEPONEXIT feature
1065 * can't be used.
1066 * @par
1067 * If HFXO/LFXO/LFRCO are re-enabled by this function, and NOT used to clock
1068 * the core, this function will not wait for those oscillators to stabilize.
1069 * This must be considered by the application if trying to use features
1070 * relying on those oscillators upon return.
1071 * @par
1072 * If a debugger is attached, the AUXHFRCO will not be disabled if enabled
1073 * upon entering EM3. It will, therefore, remain enabled when returning to EM0
1074 * regardless of the @p restore parameter.
1075 * @par
1076 * If voltage scaling is supported, the restore parameter is true and the EM0
1077 * voltage scaling level is set higher than the EM3 level, then the EM0 level is
1078 * also restored.
1079 * @par
1080 * On Series 2 Config 2 devices (EFRxG22), this function will also relock the
1081 * DPLL if the DPLL is used and @p restore is true.
1082 *
1083 * @param[in] restore
1084 * @li true - save and restore oscillators, clocks and voltage scaling, see
1085 * function details.
1086 * @li false - do not save and restore oscillators and clocks, see function
1087 * details.
1088 * @par
1089 * The @p restore option should only be used if all clock control is done
1090 * via the CMU API.
1091 ******************************************************************************/
EMU_EnterEM3(bool restore)1092 void EMU_EnterEM3(bool restore)
1093 {
1094 #if defined(ERRATA_FIX_EMU_E107_ENABLE)
1095 bool errataFixEmuE107En;
1096 uint32_t nonWicIntEn[2];
1097 #endif
1098
1099 #if defined(ERRATA_FIX_EMU_E110_ENABLE)
1100 bool errataFixEmuE110En;
1101 #endif
1102
1103 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
1104 if (restore) {
1105 dpllState(dpllState_Save);
1106 }
1107 #endif
1108
1109 #if (_SILICON_LABS_32B_SERIES < 2)
1110 /* Only save EMU and CMU state if restored on wake-up. */
1111 if (restore) {
1112 emState(emState_Save);
1113 }
1114 #endif
1115
1116 #if defined(_EMU_CTRL_EM23VSCALE_MASK) && defined(EMU_CTRL_EM23VSCALEAUTOWSEN)
1117 vScaleDownEM23Setup();
1118 #endif
1119
1120 #if defined(_CMU_OSCENCMD_MASK)
1121 uint32_t cmuLocked;
1122 cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
1123 CMU_Unlock();
1124
1125 /* Disable LF oscillators. */
1126 CMU->OSCENCMD = CMU_OSCENCMD_LFXODIS | CMU_OSCENCMD_LFRCODIS;
1127
1128 /* Restore CMU register locking. */
1129 if (cmuLocked != 0U) {
1130 CMU_Lock();
1131 }
1132 #endif
1133
1134 /* Enter Cortex deep sleep mode. */
1135 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
1136
1137 /* Fix for errata EMU_E107 - store non-WIC interrupt enable flags.
1138 Disable the enabled non-WIC interrupts. */
1139 #if defined(ERRATA_FIX_EMU_E107_ENABLE)
1140 errataFixEmuE107En = getErrataFixEmuE107En();
1141 if (errataFixEmuE107En) {
1142 nonWicIntEn[0] = NVIC->ISER[0] & NON_WIC_INT_MASK_0;
1143 NVIC->ICER[0] = nonWicIntEn[0];
1144 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
1145 nonWicIntEn[1] = NVIC->ISER[1] & NON_WIC_INT_MASK_1;
1146 NVIC->ICER[1] = nonWicIntEn[1];
1147 #endif
1148 }
1149 #endif
1150
1151 #if defined(ERRATA_FIX_DCDC_FETCNT_SET_ENABLE)
1152 dcdcFetCntSet(true);
1153 #endif
1154 #if defined(ERRATA_FIX_DCDC_LNHS_BLOCK_ENABLE)
1155 dcdcHsFixLnBlock();
1156 #endif
1157
1158 EMU_EM23PresleepHook();
1159 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_205) \
1160 || defined(ERRATA_FIX_EMU_E110_ENABLE)
1161 #if defined(ERRATA_FIX_EMU_E110_ENABLE)
1162 errataFixEmuE110En = getErrataFixEmuE110En();
1163 if (errataFixEmuE110En) {
1164 #endif
1165 CORE_CRITICAL_SECTION(ramWFI(); )
1166 #if defined(ERRATA_FIX_EMU_E110_ENABLE)
1167 } else {
1168 __WFI();
1169 }
1170 #endif
1171 #elif defined(ERRATA_FIX_EMU_E220_DECBOD_ENABLE)
1172 // Apply errata fix if voltage scaling in EM2 is used.
1173 if ((EMU->CTRL & EMU_CTRL_EM23VSCALEAUTOWSEN) != 0U) {
1174 CORE_CRITICAL_SECTION(ramWFI(); )
1175 } else {
1176 __WFI();
1177 }
1178 #else
1179 __WFI();
1180 #endif
1181 EMU_EM23PostsleepHook();
1182
1183 #if defined(ERRATA_FIX_DCDC_FETCNT_SET_ENABLE)
1184 dcdcFetCntSet(false);
1185 #endif
1186
1187 /* Fix for errata EMU_E107 - restore state of non-WIC interrupt enable flags. */
1188 #if defined(ERRATA_FIX_EMU_E107_ENABLE)
1189 if (errataFixEmuE107En) {
1190 NVIC->ISER[0] = nonWicIntEn[0];
1191 #if (NON_WIC_INT_MASK_1 != (~(0x0U)))
1192 NVIC->ISER[1] = nonWicIntEn[1];
1193 #endif
1194 }
1195 #endif
1196
1197 #if (_SILICON_LABS_32B_SERIES < 2)
1198 /* Restore oscillators/clocks and voltage scaling if supported. */
1199 if (restore) {
1200 emState(emState_Restore);
1201 }
1202 #if defined(_EMU_CTRL_EM23VSCALE_MASK) && defined(EMU_CTRL_EM23VSCALEAUTOWSEN)
1203 else {
1204 vScaleAfterWakeup();
1205 }
1206 #if defined(ERRATA_FIX_EMU_E220_DECBOD_ENABLE)
1207 /* Third part of EMU_E220 DECBOD Errata fix. Calibration needs to be enabled
1208 * after voltage scaling completes. */
1209 EMU_PORBOD &= ~(EMU_PORBOD_GMC_CALIB_DISABLE);
1210 #endif
1211 #endif
1212 #endif
1213
1214 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
1215 if (restore) {
1216 dpllState(dpllState_Restore);
1217 }
1218 #endif
1219
1220 if (!restore) {
1221 /* If not restoring, and the original clock was not HFRCO, the CMSIS */
1222 /* core clock variable must be updated since HF clock has changed */
1223 /* to HFRCO. */
1224 SystemCoreClockUpdate();
1225 }
1226 }
1227
1228 /***************************************************************************//**
1229 * @brief
1230 * Save the CMU HF clock select state, oscillator enable, and voltage scaling
1231 * (if available) before @ref EMU_EnterEM2() or @ref EMU_EnterEM3() are called
1232 * with the restore parameter set to false. Calling this function is
1233 * equivalent to calling @ref EMU_EnterEM2() or @ref EMU_EnterEM3() with the
1234 * restore parameter set to true, but it allows the state to be saved without
1235 * going to sleep. The state can be restored manually by calling
1236 * @ref EMU_Restore().
1237 ******************************************************************************/
EMU_Save(void)1238 void EMU_Save(void)
1239 {
1240 #if (_SILICON_LABS_32B_SERIES < 2)
1241 emState(emState_Save);
1242 #endif
1243 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
1244 dpllState(dpllState_Save);
1245 #endif
1246 }
1247
1248 /***************************************************************************//**
1249 * @brief
1250 * Restore CMU HF clock select state, oscillator enable, and voltage scaling
1251 * (if available) after @ref EMU_EnterEM2() or @ref EMU_EnterEM3() are called
1252 * with the restore parameter set to false. Calling this function is
1253 * equivalent to calling @ref EMU_EnterEM2() or @ref EMU_EnterEM3() with the
1254 * restore parameter set to true, but it allows the application to evaluate the
1255 * wakeup reason before restoring state.
1256 ******************************************************************************/
EMU_Restore(void)1257 void EMU_Restore(void)
1258 {
1259 #if (_SILICON_LABS_32B_SERIES < 2)
1260 emState(emState_Restore);
1261 #endif
1262 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
1263 dpllState(dpllState_Restore);
1264 #endif
1265 }
1266
1267 #if defined(_EMU_EM4CONF_MASK) || defined(_EMU_EM4CTRL_MASK)
1268 /***************************************************************************//**
1269 * @brief
1270 * Update the EMU module with Energy Mode 4 configuration.
1271 *
1272 * @param[in] em4Init
1273 * Energy Mode 4 configuration structure.
1274 ******************************************************************************/
EMU_EM4Init(const EMU_EM4Init_TypeDef * em4Init)1275 void EMU_EM4Init(const EMU_EM4Init_TypeDef *em4Init)
1276 {
1277 #if defined(_EMU_EM4CONF_MASK)
1278 /* Initialization for platforms with EMU->EM4CONF register. */
1279 uint32_t em4conf = EMU->EM4CONF;
1280
1281 /* Clear fields that will be reconfigured. */
1282 em4conf &= ~(_EMU_EM4CONF_LOCKCONF_MASK
1283 | _EMU_EM4CONF_OSC_MASK
1284 | _EMU_EM4CONF_BURTCWU_MASK
1285 | _EMU_EM4CONF_VREGEN_MASK
1286 | _EMU_EM4CONF_BUBODRSTDIS_MASK);
1287
1288 /* Configure new settings. */
1289 em4conf |= (em4Init->lockConfig << _EMU_EM4CONF_LOCKCONF_SHIFT)
1290 | (em4Init->osc)
1291 | (em4Init->buRtcWakeup << _EMU_EM4CONF_BURTCWU_SHIFT)
1292 | (em4Init->vreg << _EMU_EM4CONF_VREGEN_SHIFT)
1293 | (em4Init->buBodRstDis << _EMU_EM4CONF_BUBODRSTDIS_SHIFT);
1294
1295 /* Apply configuration. Note that lock can be set after this stage. */
1296 EMU->EM4CONF = em4conf;
1297
1298 #elif defined(_EMU_EM4CTRL_EM4STATE_MASK)
1299 /* Initialization for platforms with EMU->EM4CTRL register and EM4H and EM4S. */
1300
1301 uint32_t em4ctrl = EMU->EM4CTRL;
1302
1303 em4ctrl &= ~(_EMU_EM4CTRL_RETAINLFXO_MASK
1304 | _EMU_EM4CTRL_RETAINLFRCO_MASK
1305 | _EMU_EM4CTRL_RETAINULFRCO_MASK
1306 | _EMU_EM4CTRL_EM4STATE_MASK
1307 | _EMU_EM4CTRL_EM4IORETMODE_MASK);
1308
1309 em4ctrl |= (em4Init->retainLfxo ? EMU_EM4CTRL_RETAINLFXO : 0U)
1310 | (em4Init->retainLfrco ? EMU_EM4CTRL_RETAINLFRCO : 0U)
1311 | (em4Init->retainUlfrco ? EMU_EM4CTRL_RETAINULFRCO : 0U)
1312 | (em4Init->em4State == emuEM4Hibernate
1313 ? EMU_EM4CTRL_EM4STATE_EM4H : 0U)
1314 | ((uint32_t)em4Init->pinRetentionMode);
1315
1316 EMU->EM4CTRL = em4ctrl;
1317 #elif defined(_EMU_EM4CTRL_MASK)
1318 EMU->EM4CTRL = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4IORETMODE_MASK)
1319 | (uint32_t)em4Init->pinRetentionMode;
1320 #endif
1321
1322 #if defined(_EMU_CTRL_EM4HVSCALE_MASK)
1323 EMU->CTRL = (EMU->CTRL & ~_EMU_CTRL_EM4HVSCALE_MASK)
1324 | ((uint32_t)em4Init->vScaleEM4HVoltage << _EMU_CTRL_EM4HVSCALE_SHIFT);
1325 #endif
1326 }
1327 #endif
1328
1329 /***************************************************************************//**
1330 * @brief
1331 * Energy mode 4 pre-sleep hook function.
1332 *
1333 * @details
1334 * This function is called by @ref EMU_EnterEM4() just prior to the sequence
1335 * of writes to put the device in EM4. The function implementation does not
1336 * perform anything, but it is SL_WEAK so that it can be re-implemented in
1337 * application code if actions are needed.
1338 ******************************************************************************/
EMU_EM4PresleepHook(void)1339 SL_WEAK void EMU_EM4PresleepHook(void)
1340 {
1341 }
1342
1343 /***************************************************************************//**
1344 * @brief
1345 * EFP's Energy mode 4 pre-sleep hook function.
1346 *
1347 * @details
1348 * This function is similar to @ref EMU_EM4PresleepHook() but is reserved for
1349 * EFP usage.
1350 *
1351 * @note
1352 * The function is primarily meant to be used in systems with EFP circuitry.
1353 * (EFP = Energy Friendly Pmic (PMIC = Power Management IC)).
1354 * In such systems there is a need to drive certain signals to EFP pins to
1355 * notify about energy mode transitions.
1356 ******************************************************************************/
EMU_EFPEM4PresleepHook(void)1357 SL_WEAK void EMU_EFPEM4PresleepHook(void)
1358 {
1359 }
1360
1361 /***************************************************************************//**
1362 * @brief
1363 * Enter energy mode 4 (EM4).
1364 *
1365 * @note
1366 * Only a power on reset or external reset pin can wake the device from EM4.
1367 ******************************************************************************/
EMU_EnterEM4(void)1368 void EMU_EnterEM4(void)
1369 {
1370 int i;
1371
1372 #if defined(_EMU_EM4CTRL_EM4ENTRY_SHIFT)
1373 uint32_t em4seq2 = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4ENTRY_MASK)
1374 | (2U << _EMU_EM4CTRL_EM4ENTRY_SHIFT);
1375 uint32_t em4seq3 = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4ENTRY_MASK)
1376 | (3U << _EMU_EM4CTRL_EM4ENTRY_SHIFT);
1377 #else
1378 uint32_t em4seq2 = (EMU->CTRL & ~_EMU_CTRL_EM4CTRL_MASK)
1379 | (2U << _EMU_CTRL_EM4CTRL_SHIFT);
1380 uint32_t em4seq3 = (EMU->CTRL & ~_EMU_CTRL_EM4CTRL_MASK)
1381 | (3U << _EMU_CTRL_EM4CTRL_SHIFT);
1382 #endif
1383
1384 /* Make sure that the register write lock is disabled. */
1385 EMU_Unlock();
1386
1387 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
1388 /* The DCDC is not supported in EM4S. EFM32xG1 and EFR32xG1 devices should
1389 * switch to bypass mode before entering EM4S. Other devices handle this
1390 * automatically at the hardware level. */
1391 if ((EMU->EM4CTRL & _EMU_EM4CTRL_EM4STATE_MASK) == EMU_EM4CTRL_EM4STATE_EM4S) {
1392 uint32_t dcdcMode = EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK;
1393 if (dcdcMode == EMU_DCDCCTRL_DCDCMODE_LOWNOISE
1394 || dcdcMode == EMU_DCDCCTRL_DCDCMODE_LOWPOWER) {
1395 EMU_DCDCModeSet(emuDcdcMode_Bypass);
1396 }
1397 }
1398 #endif
1399
1400 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG) && (_SILICON_LABS_32B_SERIES_2_CONFIG >= 2)
1401 /* Workaround for bug that may cause a Hard Fault on EM4 entry */
1402 CMU_CLOCK_SELECT_SET(SYSCLK, FSRCO);
1403 /* Switch from DCDC regulation mode to bypass mode before entering EM4. */
1404 EMU_DCDCModeSet(emuDcdcMode_Bypass);
1405 #endif
1406
1407 #if defined(_EMU_EM4CTRL_MASK) && defined(ERRATA_FIX_EMU_E208_ENABLE)
1408 if (EMU->EM4CTRL & EMU_EM4CTRL_EM4STATE_EM4H) {
1409 /* Fix for errata EMU_E208 - Occasional Full Reset After Exiting EM4H.
1410 * Full description of errata fix can be found in the errata document. */
1411 __disable_irq();
1412 *(volatile uint32_t *)(EMU_BASE + 0x190UL) = 0x0000ADE8UL;
1413 *(volatile uint32_t *)(EMU_BASE + 0x198UL) |= (0x1UL << 7);
1414 *(volatile uint32_t *)(EMU_BASE + 0x88UL) |= (0x1UL << 8);
1415 }
1416 #endif
1417
1418 #if defined(ERRATA_FIX_EMU_E108_ENABLE)
1419 /* Fix for errata EMU_E108 - High Current Consumption on EM4 Entry. */
1420 __disable_irq();
1421 *(volatile uint32_t *)0x400C80E4 = 0;
1422 #endif
1423
1424 #if defined(ERRATA_FIX_DCDC_FETCNT_SET_ENABLE)
1425 dcdcFetCntSet(true);
1426 #endif
1427 #if defined(ERRATA_FIX_DCDC_LNHS_BLOCK_ENABLE)
1428 dcdcHsFixLnBlock();
1429 #endif
1430
1431 #if defined(ERRATA_FIX_EM4S_DELAY_ENTRY)
1432 /* Fix for errata where firmware must clear ANASW and delay EM4S entry by 30 us. */
1433 if ((EMU->EM4CTRL & _EMU_EM4CTRL_EM4STATE_MASK) == EMU_EM4CTRL_EM4STATE_EM4S) {
1434 if ((EMU->PWRCTRL & _EMU_PWRCTRL_ANASW_MASK) == EMU_PWRCTRL_ANASW_DVDD) {
1435 BUS_RegMaskedClear(&EMU->PWRCTRL, _EMU_PWRCTRL_ANASW_MASK);
1436 /* Switch to 1 MHz HFRCO. This delays enough to meet the 30 us requirement
1437 * before entering EM4. */
1438 uint32_t freqCal = (DEVINFO->HFRCOCAL0 & ~_CMU_HFRCOCTRL_CLKDIV_MASK)
1439 | CMU_HFRCOCTRL_CLKDIV_DIV4;
1440 while ((CMU->SYNCBUSY & CMU_SYNCBUSY_HFRCOBSY) != 0UL) {
1441 }
1442 CMU->HFRCOCTRL = freqCal;
1443 CMU->OSCENCMD = CMU_OSCENCMD_HFRCOEN;
1444 while ((CMU->STATUS & CMU_STATUS_HFRCORDY) == 0U) {
1445 }
1446 CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFRCO;
1447 __NOP();
1448 }
1449 }
1450 #endif
1451
1452 EMU_EM4PresleepHook();
1453 EMU_EFPEM4PresleepHook();
1454
1455 for (i = 0; i < 4; i++) {
1456 #if defined(_EMU_EM4CTRL_EM4ENTRY_SHIFT)
1457 EMU->EM4CTRL = em4seq2;
1458 EMU->EM4CTRL = em4seq3;
1459 }
1460 EMU->EM4CTRL = em4seq2;
1461 #else
1462 EMU->CTRL = em4seq2;
1463 EMU->CTRL = em4seq3;
1464 }
1465 EMU->CTRL = em4seq2;
1466 #endif
1467
1468 #if defined(_DCDC_IF_EM4ERR_MASK)
1469 EFM_ASSERT((DCDC->IF & _DCDC_IF_EM4ERR_MASK) == 0);
1470 #endif
1471 }
1472
1473 /***************************************************************************//**
1474 * @brief
1475 * Enter energy mode 4 (EM4).
1476 *
1477 * @details
1478 * This function waits after the EM4 entry request to make sure the CPU
1479 * is properly shutdown or the EM4 entry failed.
1480 *
1481 * @note
1482 * Only a power on reset or external reset pin can wake the device from EM4.
1483 ******************************************************************************/
EMU_EnterEM4Wait(void)1484 void EMU_EnterEM4Wait(void)
1485 {
1486 EMU_EnterEM4();
1487
1488 // The EM4 entry waiting loop should take 4 cycles by loop minimally (Compiler dependent).
1489 // We would then wait for (EMU_EM4_ENTRY_WAIT_LOOPS * 4) clock cycles.
1490 for (uint16_t i = 0; i < EMU_EM4_ENTRY_WAIT_LOOPS; i++) {
1491 __NOP();
1492 }
1493 }
1494
1495 #if defined(_EMU_EM4CTRL_MASK)
1496 /***************************************************************************//**
1497 * @brief
1498 * Enter energy mode 4 hibernate (EM4H).
1499 *
1500 * @note
1501 * Retention of clocks and GPIO in EM4 can be configured using
1502 * @ref EMU_EM4Init before calling this function.
1503 ******************************************************************************/
EMU_EnterEM4H(void)1504 void EMU_EnterEM4H(void)
1505 {
1506 #if defined(_EMU_EM4CTRL_EM4STATE_MASK)
1507 BUS_RegBitWrite(&EMU->EM4CTRL, _EMU_EM4CTRL_EM4STATE_SHIFT, 1);
1508 #endif
1509 EMU_EnterEM4();
1510 }
1511
1512 /***************************************************************************//**
1513 * @brief
1514 * Enter energy mode 4 shutoff (EM4S).
1515 *
1516 * @note
1517 * Retention of clocks and GPIO in EM4 can be configured using
1518 * @ref EMU_EM4Init before calling this function.
1519 ******************************************************************************/
EMU_EnterEM4S(void)1520 void EMU_EnterEM4S(void)
1521 {
1522 #if defined(_EMU_EM4CTRL_EM4STATE_MASK)
1523 BUS_RegBitWrite(&EMU->EM4CTRL, _EMU_EM4CTRL_EM4STATE_SHIFT, 0);
1524 #endif
1525 EMU_EnterEM4();
1526 }
1527 #endif
1528
1529 /***************************************************************************//**
1530 * @brief
1531 * Power down memory block.
1532 *
1533 * @param[in] blocks
1534 * Specifies a logical OR of bits indicating memory blocks to power down.
1535 * Bit 0 selects block 1, bit 1 selects block 2, and so on. Memory block 0 cannot
1536 * be disabled. See the reference manual for available
1537 * memory blocks for a device.
1538 *
1539 * @note
1540 * Only a POR reset can power up the specified memory block(s) after power down.
1541 *
1542 * @deprecated
1543 * This function is deprecated, use @ref EMU_RamPowerDown() instead which
1544 * maps a user provided memory range into RAM blocks to power down.
1545 ******************************************************************************/
EMU_MemPwrDown(uint32_t blocks)1546 void EMU_MemPwrDown(uint32_t blocks)
1547 {
1548 #if defined(_EMU_MEMCTRL_MASK)
1549 EMU->MEMCTRL = blocks & _EMU_MEMCTRL_MASK;
1550 #elif defined(_EMU_RAM0CTRL_MASK)
1551 EMU->RAM0CTRL = blocks & _EMU_RAM0CTRL_MASK;
1552 #else
1553 (void)blocks;
1554 #endif
1555 }
1556
1557 /***************************************************************************//**
1558 * @brief
1559 * Power down RAM memory blocks.
1560 *
1561 * @details
1562 * This function will power down all the RAM blocks that are within a given
1563 * range. The RAM block layout is different between device families, so this
1564 * function can be used in a generic way to power down a RAM memory region
1565 * which is known to be unused.
1566 *
1567 * This function will only power down blocks which are completely enclosed
1568 * by the memory range given by [start, end).
1569 *
1570 * This is an example to power down all RAM blocks except the first
1571 * one. The first RAM block is special in that it cannot be powered down
1572 * by the hardware. The size of the first RAM block is device-specific.
1573 * See the reference manual to find the RAM block sizes.
1574 *
1575 * @code
1576 * EMU_RamPowerDown(SRAM_BASE, SRAM_BASE + SRAM_SIZE);
1577 * @endcode
1578 *
1579 * @note
1580 * Only a reset can power up the specified memory block(s) after power down
1581 * on a series 0 device. The specified memory block(s) will stay off
1582 * until a call to EMU_RamPowerUp() is done on series 1/2.
1583 *
1584 * @param[in] start
1585 * The start address of the RAM region to power down. This address is
1586 * inclusive.
1587 *
1588 * @param[in] end
1589 * The end address of the RAM region to power down. This address is
1590 * exclusive. If this parameter is 0, all RAM blocks contained in the
1591 * region from start to the upper RAM address will be powered down.
1592 ******************************************************************************/
EMU_RamPowerDown(uint32_t start,uint32_t end)1593 void EMU_RamPowerDown(uint32_t start, uint32_t end)
1594 {
1595 uint32_t mask = 0;
1596 (void) start;
1597
1598 if (end == 0U) {
1599 end = SRAM_BASE + SRAM_SIZE;
1600 }
1601
1602 // Check to see if something in RAM0 can be powered down.
1603 if (end > RAM0_END) {
1604 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_84) // EFM32xG12 and EFR32xG12
1605 // Block 0 is 16 kB and cannot be powered off.
1606 mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20004000UL) << 0; // Block 1, 16 kB
1607 mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20008000UL) << 1; // Block 2, 16 kB
1608 mask |= ADDRESS_NOT_IN_BLOCK(start, 0x2000C000UL) << 2; // Block 3, 16 kB
1609 mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20010000UL) << 3; // Block 4, 64 kB
1610 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80) // EFM32xG1 and EFR32xG1
1611 // Block 0 is 4 kB and cannot be powered off.
1612 mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20001000UL) << 0; // Block 1, 4 kB
1613 mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20002000UL) << 1; // Block 2, 8 kB
1614 mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20004000UL) << 2; // Block 3, 8 kB
1615 mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20006000UL) << 3; // Block 4, 7 kB
1616 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
1617 // Lynx has 2 blocks. We do no shut off block 0 because we dont want to disable all RAM0
1618 mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20006000UL) << 1; // Block 1, 8 kB
1619 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)
1620 // Leopard has 3 blocks. We do no shut off block 0 because we dont want to disable all RAM0
1621 mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20006000UL) << 1; // Block 1, 8 kB
1622 mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20008000UL) << 2; // Block 2, 32 kB
1623 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
1624 // These platforms have equally-sized RAM blocks and block 0 can be powered down but should not.
1625 // This condition happens when the block 0 disable bit flag is available in the retention control register.
1626 for (unsigned i = 1; i < RAM0_BLOCKS; i++) {
1627 mask |= ADDRESS_NOT_IN_BLOCK(start, RAM_MEM_BASE + (i * RAM0_BLOCK_SIZE)) << (i);
1628 }
1629 #elif defined(RAM0_BLOCKS)
1630 // These platforms have equally-sized RAM blocks and block 0 cannot be powered down.
1631 for (unsigned i = 1; i < RAM0_BLOCKS; i++) {
1632 mask |= ADDRESS_NOT_IN_BLOCK(start, RAM_MEM_BASE + (i * RAM0_BLOCK_SIZE)) << (i - 1U);
1633 }
1634 #endif
1635 }
1636
1637 // Power down the selected blocks.
1638 #if defined(_EMU_MEMCTRL_MASK)
1639 EMU->MEMCTRL = EMU->MEMCTRL | mask;
1640 #elif defined(_EMU_RAM0CTRL_MASK)
1641 EMU->RAM0CTRL = EMU->RAM0CTRL | mask;
1642 #elif defined(_SILICON_LABS_32B_SERIES_2)
1643 #if defined(CMU_CLKEN0_SYSCFG)
1644 CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
1645 #endif
1646 SYSCFG_maskDmem0RetnCtrl(mask);
1647 #else
1648 // These devices are unable to power down RAM blocks.
1649 (void) mask;
1650 (void) start;
1651 #endif
1652
1653 #if defined(RAM1_MEM_END)
1654 mask = 0;
1655 if (end > RAM1_MEM_END) {
1656 for (unsigned i = 0; i < RAM1_BLOCKS; i++) {
1657 mask |= ADDRESS_NOT_IN_BLOCK(start, RAM1_MEM_BASE + (i * RAM1_BLOCK_SIZE)) << i;
1658 }
1659 }
1660 EMU->RAM1CTRL |= mask;
1661 #endif
1662
1663 #if defined(RAM2_MEM_END)
1664 mask = 0;
1665 if (end > RAM2_MEM_END) {
1666 for (unsigned i = 0; i < RAM2_BLOCKS; i++) {
1667 mask |= ADDRESS_NOT_IN_BLOCK(start, RAM2_MEM_BASE + (i * RAM2_BLOCK_SIZE)) << i;
1668 }
1669 }
1670 EMU->RAM2CTRL |= mask;
1671 #endif
1672 }
1673
1674 /***************************************************************************//**
1675 * @brief
1676 * Power up all available RAM memory blocks.
1677 *
1678 * @details
1679 * This function will power up all the RAM blocks on a device, this means
1680 * that the RAM blocks are retained in EM2/EM3. Note that this functionality
1681 * is not supported on Series 0 devices. Only a reset will power up the RAM
1682 * blocks on a series 0 device.
1683 ******************************************************************************/
EMU_RamPowerUp(void)1684 void EMU_RamPowerUp(void)
1685 {
1686 #if defined(_EMU_RAM0CTRL_MASK)
1687 EMU->RAM0CTRL = 0x0UL;
1688 #endif
1689 #if defined(_EMU_RAM1CTRL_MASK)
1690 EMU->RAM1CTRL = 0x0UL;
1691 #endif
1692 #if defined(_EMU_RAM2CTRL_MASK)
1693 EMU->RAM2CTRL = 0x0UL;
1694 #endif
1695 #if defined(_SYSCFG_DMEM0RETNCTRL_MASK)
1696 #if defined(CMU_CLKEN0_SYSCFG)
1697 CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
1698 #endif
1699 SYSCFG_zeroDmem0RetnCtrl();
1700 #endif
1701 }
1702
1703 #if defined(_EMU_EM23PERNORETAINCTRL_MASK)
1704 /***************************************************************************//**
1705 * @brief
1706 * Set EM2 3 peripheral retention control.
1707 *
1708 * @param[in] periMask
1709 * A peripheral select mask. Use | operator to select multiple peripherals, for example
1710 * @ref emuPeripheralRetention_LEUART0 | @ref emuPeripheralRetention_VDAC0.
1711 * @param[in] enable
1712 * Peripheral retention enable (true) or disable (false).
1713 *
1714 *
1715 * @note
1716 * Only peripheral retention disable is currently supported. Peripherals are
1717 * enabled by default and can only be disabled.
1718 ******************************************************************************/
EMU_PeripheralRetention(EMU_PeripheralRetention_TypeDef periMask,bool enable)1719 void EMU_PeripheralRetention(EMU_PeripheralRetention_TypeDef periMask, bool enable)
1720 {
1721 EFM_ASSERT(!enable);
1722 EMU->EM23PERNORETAINCTRL = (uint32_t)periMask
1723 & (uint32_t)emuPeripheralRetention_ALL;
1724 }
1725 #endif
1726
1727 /***************************************************************************//**
1728 * @brief
1729 * Update EMU module with CMU oscillator selection/enable status.
1730 *
1731 * @deprecated
1732 * Oscillator status is saved in @ref EMU_EnterEM2() and @ref EMU_EnterEM3().
1733 ******************************************************************************/
EMU_UpdateOscConfig(void)1734 void EMU_UpdateOscConfig(void)
1735 {
1736 #if (_SILICON_LABS_32B_SERIES < 2)
1737 emState(emState_Save);
1738 #endif
1739 }
1740
1741 #if defined(_SILICON_LABS_32B_SERIES_2) && defined(EMU_VSCALE_EM01_PRESENT)
1742 /***************************************************************************//**
1743 * @brief
1744 * Energy mode 01 voltage scaling hook function.
1745 *
1746 * @param[in] voltage
1747 * Voltage scaling level requested.
1748 *
1749 * @details
1750 * This function is called by EMU_VScaleEM01 to let EFP know that voltage scaling
1751 * is requested.
1752 ******************************************************************************/
EMU_EFPEM01VScale(EMU_VScaleEM01_TypeDef voltage)1753 SL_WEAK void EMU_EFPEM01VScale(EMU_VScaleEM01_TypeDef voltage)
1754 {
1755 (void)voltage;
1756 }
1757 #endif
1758
1759 #if defined(EMU_VSCALE_EM01_PRESENT)
1760 /***************************************************************************//**
1761 * @brief
1762 * Voltage scale in EM0 and 1 by clock frequency.
1763 *
1764 * @param[in] clockFrequency
1765 * Use CMSIS HF clock if 0 or override to custom clock. Providing a
1766 * custom clock frequency is required if using a non-standard HFXO
1767 * frequency.
1768 * @param[in] wait
1769 * Wait for scaling to complete.
1770 *
1771 * @note
1772 * This function is primarily needed by the @ref cmu.
1773 ******************************************************************************/
EMU_VScaleEM01ByClock(uint32_t clockFrequency,bool wait)1774 void EMU_VScaleEM01ByClock(uint32_t clockFrequency, bool wait)
1775 {
1776 uint32_t hfSrcClockFrequency;
1777
1778 #if defined(_SILICON_LABS_32B_SERIES_1)
1779 if (EMU_LDOStatusGet() == false) {
1780 /* Skip voltage scaling if the LDO regulator is turned off. */
1781 return;
1782 }
1783 #endif
1784
1785 /* VSCALE frequency is HFSRCCLK. */
1786 if (clockFrequency == 0U) {
1787 #if defined(_SILICON_LABS_32B_SERIES_2)
1788 hfSrcClockFrequency = SystemSYSCLKGet();
1789 #else
1790 uint32_t hfPresc = 1U + ((CMU->HFPRESC & _CMU_HFPRESC_PRESC_MASK)
1791 >> _CMU_HFPRESC_PRESC_SHIFT);
1792 hfSrcClockFrequency = SystemHFClockGet() * hfPresc;
1793 #endif
1794 } else {
1795 hfSrcClockFrequency = clockFrequency;
1796 }
1797
1798 /* Apply EM0 and 1 voltage scaling command. */
1799 if (vScaleEM01Config.vScaleEM01LowPowerVoltageEnable
1800 && (hfSrcClockFrequency <= CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX)) {
1801 EMU_VScaleEM01(emuVScaleEM01_LowPower, wait);
1802 } else {
1803 EMU_VScaleEM01(emuVScaleEM01_HighPerformance, wait);
1804 }
1805 }
1806 #endif
1807
1808 #if defined(EMU_VSCALE_EM01_PRESENT)
1809 /***************************************************************************//**
1810 * @brief
1811 * Force voltage scaling in EM0 and 1 to a specific voltage level.
1812 *
1813 * @param[in] voltage
1814 * Target VSCALE voltage level.
1815 * @param[in] wait
1816 * Wait for scaling to complete.
1817 *
1818 * @note
1819 * This function is useful for upscaling before programming Flash from @ref msc
1820 * and downscaling after programming is done. Flash programming is only supported
1821 * at @ref emuVScaleEM01_HighPerformance.
1822 *
1823 * @note
1824 * This function ignores vScaleEM01LowPowerVoltageEnable set from @ref
1825 * EMU_EM01Init().
1826 ******************************************************************************/
EMU_VScaleEM01(EMU_VScaleEM01_TypeDef voltage,bool wait)1827 void EMU_VScaleEM01(EMU_VScaleEM01_TypeDef voltage, bool wait)
1828 {
1829 uint32_t hfFreq;
1830 uint32_t hfSrcClockFrequency;
1831
1832 #if defined(_SILICON_LABS_32B_SERIES_1)
1833 if (EMU_LDOStatusGet() == false) {
1834 /* Skip voltage scaling if the LDO regulator is turned off. */
1835 return;
1836 }
1837 #endif
1838
1839 if (EMU_VScaleGet() == voltage) {
1840 /* Voltage is already at the correct level. */
1841 return;
1842 }
1843
1844 #if defined(_SILICON_LABS_32B_SERIES_2)
1845 (void)wait;
1846 CORE_DECLARE_IRQ_STATE;
1847
1848 hfFreq = SystemSYSCLKGet();
1849 hfSrcClockFrequency = hfFreq;
1850
1851 if (voltage == emuVScaleEM01_LowPower) {
1852 EFM_ASSERT(hfSrcClockFrequency <= CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX);
1853 /* Update wait states before scaling down voltage. */
1854 CMU_UpdateWaitStates(hfFreq, VSCALE_EM01_LOW_POWER);
1855 }
1856
1857 CORE_ENTER_CRITICAL();
1858 EMU->IF_CLR = EMU_IF_VSCALEDONE;
1859 EMU_EFPEM01VScale(voltage);
1860 EMU->CMD = vScaleEM01Cmd(voltage);
1861
1862 // Note that VSCALEDONE interrupt flag must be used instead of VSCALEBUSY
1863 // because hardware does not set the VSCALEBUSY flag immediately.
1864 while (((EMU->IF & EMU_IF_VSCALEDONE) == 0U)
1865 && ((EMU->STATUS & EMU_STATUS_VSCALEFAILED) == 0U)) {
1866 EFM_ASSERT((EMU->STATUS & EMU_STATUS_VSCALEFAILED) == 0U);
1867 // Wait for VSCALE completion.
1868 // SRAM accesses will fault the core while scaling.
1869 }
1870 CORE_EXIT_CRITICAL();
1871
1872 #else
1873 uint32_t hfPresc = 1U + ((CMU->HFPRESC & _CMU_HFPRESC_PRESC_MASK)
1874 >> _CMU_HFPRESC_PRESC_SHIFT);
1875 hfFreq = SystemHFClockGet();
1876 hfSrcClockFrequency = hfFreq * hfPresc;
1877
1878 if (voltage == emuVScaleEM01_LowPower) {
1879 EFM_ASSERT(hfSrcClockFrequency <= CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX);
1880 /* Update wait states before scaling down voltage. */
1881 CMU_UpdateWaitStates(hfFreq, VSCALE_EM01_LOW_POWER);
1882 }
1883
1884 EMU->CMD = vScaleEM01Cmd(voltage);
1885
1886 if (wait) {
1887 EMU_VScaleWait();
1888 }
1889 #endif
1890
1891 if (voltage == emuVScaleEM01_HighPerformance) {
1892 /* Update wait states after scaling up voltage. */
1893 CMU_UpdateWaitStates(hfFreq, VSCALE_EM01_HIGH_PERFORMANCE);
1894 }
1895 }
1896 #endif
1897
1898 #if defined(BU_PRESENT) && defined(_SILICON_LABS_32B_SERIES_0)
1899 /***************************************************************************//**
1900 * @brief
1901 * Configure Backup Power Domain settings.
1902 *
1903 * @param[in] bupdInit
1904 * Backup power domain initialization structure.
1905 ******************************************************************************/
EMU_BUPDInit(const EMU_BUPDInit_TypeDef * bupdInit)1906 void EMU_BUPDInit(const EMU_BUPDInit_TypeDef *bupdInit)
1907 {
1908 uint32_t reg;
1909
1910 /* Set the power connection configuration. */
1911 reg = EMU->PWRCONF & ~(_EMU_PWRCONF_PWRRES_MASK
1912 | _EMU_PWRCONF_VOUTSTRONG_MASK
1913 | _EMU_PWRCONF_VOUTMED_MASK
1914 | _EMU_PWRCONF_VOUTWEAK_MASK);
1915
1916 reg |= bupdInit->resistor
1917 | (bupdInit->voutStrong << _EMU_PWRCONF_VOUTSTRONG_SHIFT)
1918 | (bupdInit->voutMed << _EMU_PWRCONF_VOUTMED_SHIFT)
1919 | (bupdInit->voutWeak << _EMU_PWRCONF_VOUTWEAK_SHIFT);
1920
1921 EMU->PWRCONF = reg;
1922
1923 /* Set the backup domain inactive mode configuration. */
1924 reg = EMU->BUINACT & ~(_EMU_BUINACT_PWRCON_MASK);
1925 reg |= (bupdInit->inactivePower);
1926 EMU->BUINACT = reg;
1927
1928 /* Set the backup domain active mode configuration. */
1929 reg = EMU->BUACT & ~(_EMU_BUACT_PWRCON_MASK);
1930 reg |= (bupdInit->activePower);
1931 EMU->BUACT = reg;
1932
1933 /* Set the power control configuration */
1934 reg = EMU->BUCTRL & ~(_EMU_BUCTRL_PROBE_MASK
1935 | _EMU_BUCTRL_BODCAL_MASK
1936 | _EMU_BUCTRL_STATEN_MASK
1937 | _EMU_BUCTRL_EN_MASK);
1938
1939 /* Note the use of ->enable to enable BUPD. Use BU_VIN pin input and
1940 release reset. */
1941 reg |= bupdInit->probe
1942 | (bupdInit->bodCal << _EMU_BUCTRL_BODCAL_SHIFT)
1943 | (bupdInit->statusPinEnable << _EMU_BUCTRL_STATEN_SHIFT)
1944 | (bupdInit->enable << _EMU_BUCTRL_EN_SHIFT);
1945
1946 /* Enable configuration. */
1947 EMU->BUCTRL = reg;
1948
1949 /* If enable is true, enable BU_VIN input power pin. If not, disable it. */
1950 EMU_BUPinEnable(bupdInit->enable);
1951
1952 /* If enable is true, release BU reset. If not, keep reset asserted. */
1953 BUS_RegBitWrite(&(RMU->CTRL), _RMU_CTRL_BURSTEN_SHIFT, !bupdInit->enable);
1954 }
1955
1956 /***************************************************************************//**
1957 * @brief
1958 * Configure the Backup Power Domain BOD Threshold value.
1959 * @note
1960 * These values are precalibrated.
1961 * @param[in] mode Active or Inactive mode
1962 * @param[in] value
1963 ******************************************************************************/
EMU_BUThresholdSet(EMU_BODMode_TypeDef mode,uint32_t value)1964 void EMU_BUThresholdSet(EMU_BODMode_TypeDef mode, uint32_t value)
1965 {
1966 EFM_ASSERT(value < 8);
1967 EFM_ASSERT(value <= (_EMU_BUACT_BUEXTHRES_MASK >> _EMU_BUACT_BUEXTHRES_SHIFT));
1968
1969 switch (mode) {
1970 case emuBODMode_Active:
1971 EMU->BUACT = (EMU->BUACT & ~_EMU_BUACT_BUEXTHRES_MASK)
1972 | (value << _EMU_BUACT_BUEXTHRES_SHIFT);
1973 break;
1974 case emuBODMode_Inactive:
1975 EMU->BUINACT = (EMU->BUINACT & ~_EMU_BUINACT_BUENTHRES_MASK)
1976 | (value << _EMU_BUINACT_BUENTHRES_SHIFT);
1977 break;
1978 }
1979 }
1980
1981 /***************************************************************************//**
1982 * @brief
1983 * Configure the Backup Power Domain BOD Threshold Range.
1984 * @note
1985 * These values are precalibrated.
1986 * @param[in] mode Active or Inactive mode
1987 * @param[in] value
1988 ******************************************************************************/
EMU_BUThresRangeSet(EMU_BODMode_TypeDef mode,uint32_t value)1989 void EMU_BUThresRangeSet(EMU_BODMode_TypeDef mode, uint32_t value)
1990 {
1991 EFM_ASSERT(value < 4);
1992 EFM_ASSERT(value <= (_EMU_BUACT_BUEXRANGE_MASK >> _EMU_BUACT_BUEXRANGE_SHIFT));
1993
1994 switch (mode) {
1995 case emuBODMode_Active:
1996 EMU->BUACT = (EMU->BUACT & ~_EMU_BUACT_BUEXRANGE_MASK)
1997 | (value << _EMU_BUACT_BUEXRANGE_SHIFT);
1998 break;
1999 case emuBODMode_Inactive:
2000 EMU->BUINACT = (EMU->BUINACT & ~_EMU_BUINACT_BUENRANGE_MASK)
2001 | (value << _EMU_BUINACT_BUENRANGE_SHIFT);
2002 break;
2003 }
2004 }
2005 #endif
2006
2007 #if defined(BU_PRESENT) && defined(_SILICON_LABS_32B_SERIES_1)
2008 /***************************************************************************//**
2009 * @brief
2010 * Configure Backup Power Domain settings.
2011 *
2012 * @param[in] buInit
2013 * Backup power domain initialization structure.
2014 ******************************************************************************/
EMU_BUInit(const EMU_BUInit_TypeDef * buInit)2015 void EMU_BUInit(const EMU_BUInit_TypeDef *buInit)
2016 {
2017 uint32_t reg = 0;
2018
2019 /* Set the backup power configuration. */
2020 reg |= (buInit->disMaxComp << _EMU_BUCTRL_DISMAXCOMP_SHIFT);
2021 reg |= (uint32_t)(buInit->inactivePwrCon);
2022 reg |= (uint32_t)(buInit->activePwrCon);
2023 reg |= (uint32_t)(buInit->pwrRes);
2024 reg |= (uint32_t)(buInit->voutRes);
2025 reg |= (buInit->buVinProbeEn << _EMU_BUCTRL_BUVINPROBEEN_SHIFT);
2026 reg |= (buInit->staEn << _EMU_BUCTRL_STATEN_SHIFT);
2027 reg |= (buInit->enable << _EMU_BUCTRL_EN_SHIFT);
2028 EMU->BUCTRL = reg;
2029 }
2030 #endif
2031
2032 #if defined(_EMU_BUCTRL_DISMAXCOMP_MASK)
2033 /***************************************************************************//**
2034 * @brief
2035 * Disable Main Backup Power Domain comparator.
2036 *
2037 * @param[in] disableMainBuComparator
2038 * True to disable main BU comparator.
2039 ******************************************************************************/
EMU_BUDisMaxCompSet(bool disableMainBuComparator)2040 void EMU_BUDisMaxCompSet(bool disableMainBuComparator)
2041 {
2042 uint32_t reg;
2043
2044 reg = EMU->BUCTRL & ~(_EMU_BUCTRL_DISMAXCOMP_MASK);
2045 reg |= (disableMainBuComparator << _EMU_BUCTRL_DISMAXCOMP_SHIFT);
2046 EMU->BUCTRL = reg;
2047 }
2048 #endif
2049
2050 #if defined(_EMU_BUCTRL_BUINACTPWRCON_MASK)
2051 /***************************************************************************//**
2052 * @brief
2053 * Configure power connection configuration when not in Backup mode.
2054 *
2055 * @param[in] inactPwrCon
2056 * Inactive power configuration.
2057 ******************************************************************************/
EMU_BUBuInactPwrConSet(EMU_BUBuInactPwrCon_TypeDef inactPwrCon)2058 void EMU_BUBuInactPwrConSet(EMU_BUBuInactPwrCon_TypeDef inactPwrCon)
2059 {
2060 uint32_t reg;
2061
2062 reg = EMU->BUCTRL & ~(_EMU_BUCTRL_BUINACTPWRCON_MASK);
2063 reg |= (uint32_t)(inactPwrCon);
2064 EMU->BUCTRL = reg;
2065 }
2066 #endif
2067
2068 #if defined(_EMU_BUCTRL_BUACTPWRCON_MASK)
2069 /***************************************************************************//**
2070 * @brief
2071 * Configure power connection configuration when in Backup mode.
2072 *
2073 * @param[in] actPwrCon
2074 * Active power configuration.
2075 ******************************************************************************/
EMU_BUBuActPwrConSet(EMU_BUBuActPwrCon_TypeDef actPwrCon)2076 void EMU_BUBuActPwrConSet(EMU_BUBuActPwrCon_TypeDef actPwrCon)
2077 {
2078 uint32_t reg;
2079
2080 reg = EMU->BUCTRL & ~(_EMU_BUCTRL_BUACTPWRCON_MASK);
2081 reg |= (uint32_t)(actPwrCon);
2082 EMU->BUCTRL = reg;
2083 }
2084 #endif
2085
2086 #if defined(_EMU_BUCTRL_PWRRES_MASK)
2087 /***************************************************************************//**
2088 * @brief
2089 * Power domain resistor selection.
2090 *
2091 * @param[in] pwrRes
2092 * Resistor selection.
2093 ******************************************************************************/
EMU_BUPwrResSet(EMU_BUPwrRes_TypeDef pwrRes)2094 void EMU_BUPwrResSet(EMU_BUPwrRes_TypeDef pwrRes)
2095 {
2096 uint32_t reg;
2097
2098 reg = EMU->BUCTRL & ~(_EMU_BUCTRL_PWRRES_MASK);
2099 reg |= (uint32_t)(pwrRes);
2100 EMU->BUCTRL = reg;
2101 }
2102 #endif
2103
2104 #if defined(_EMU_BUCTRL_VOUTRES_MASK)
2105 /***************************************************************************//**
2106 * @brief
2107 * B_VOUT resistor select.
2108 *
2109 * @param[in] resistorSel
2110 * Resistor selection.
2111 ******************************************************************************/
EMU_BUVoutResSet(EMU_BUVoutRes_TypeDef resistorSel)2112 void EMU_BUVoutResSet(EMU_BUVoutRes_TypeDef resistorSel)
2113 {
2114 uint32_t reg;
2115
2116 reg = EMU->BUCTRL & ~(_EMU_BUCTRL_VOUTRES_MASK);
2117 reg |= (uint32_t)(resistorSel);
2118 EMU->BUCTRL = reg;
2119 }
2120 #endif
2121
2122 #if defined(_EMU_BUCTRL_BUVINPROBEEN_MASK)
2123 /***************************************************************************//**
2124 * @brief
2125 * Enable BU_VIN probing
2126 *
2127 * @param[in] enable
2128 * True to enable BU_VIN probing. False to disable.
2129 ******************************************************************************/
EMU_BUBuVinProbeEnSet(bool enable)2130 void EMU_BUBuVinProbeEnSet(bool enable)
2131 {
2132 uint32_t reg;
2133
2134 reg = EMU->BUCTRL & ~(_EMU_BUCTRL_BUVINPROBEEN_MASK);
2135 reg |= (enable << _EMU_BUCTRL_BUVINPROBEEN_SHIFT);
2136 EMU->BUCTRL = reg;
2137 }
2138 #endif
2139
2140 #if defined(_EMU_BUCTRL_STATEN_MASK)
2141 /***************************************************************************//**
2142 * @brief
2143 * Enable backup mode status export.
2144 *
2145 * @param[in] enable
2146 * True to enable status export. False to disable.
2147 ******************************************************************************/
EMU_BUStatEnSet(bool enable)2148 void EMU_BUStatEnSet(bool enable)
2149 {
2150 uint32_t reg;
2151
2152 reg = EMU->BUCTRL & ~(_EMU_BUCTRL_STATEN_MASK);
2153 reg |= (enable << _EMU_BUCTRL_STATEN_SHIFT);
2154 EMU->BUCTRL = reg;
2155 }
2156 #endif
2157
2158 #if defined(_EMU_BUCTRL_EN_MASK)
2159 /***************************************************************************//**
2160 * @brief
2161 * Enable backup mode.
2162 *
2163 * @param[in] enable
2164 * True to enable backup mode. False to disable.
2165 ******************************************************************************/
EMU_BUEnableSet(bool enable)2166 void EMU_BUEnableSet(bool enable)
2167 {
2168 uint32_t reg;
2169
2170 reg = EMU->BUCTRL & ~(_EMU_BUCTRL_EN_MASK);
2171 reg |= (enable << _EMU_BUCTRL_EN_SHIFT);
2172 EMU->BUCTRL = reg;
2173 }
2174 #endif
2175
2176 #if defined(EMU_SERIES1_DCDC_BUCK_PRESENT)
2177 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
2178 /* Internal DCDC trim modes. */
2179 typedef enum {
2180 dcdcTrimMode_EM234H_LP = 0,
2181 #if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
2182 dcdcTrimMode_EM01_LP,
2183 #endif
2184 dcdcTrimMode_LN,
2185 } dcdcTrimMode_TypeDef;
2186
2187 /** @endcond */
2188
2189 /***************************************************************************//**
2190 * @brief
2191 * Load DCDC calibration constants from the DI page. A constant means that calibration
2192 * data that does not change depending on other configuration parameters.
2193 *
2194 * @return
2195 * False if calibration registers are locked.
2196 ******************************************************************************/
dcdcConstCalibrationLoad(void)2197 static bool dcdcConstCalibrationLoad(void)
2198 {
2199 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
2200 uint32_t val;
2201 volatile uint32_t *reg;
2202
2203 /* DI calibration data in Flash. */
2204 volatile uint32_t* const diCal_EMU_DCDCLNFREQCTRL = (volatile uint32_t *)(0x0FE08038);
2205 volatile uint32_t* const diCal_EMU_DCDCLNVCTRL = (volatile uint32_t *)(0x0FE08040);
2206 volatile uint32_t* const diCal_EMU_DCDCLPCTRL = (volatile uint32_t *)(0x0FE08048);
2207 volatile uint32_t* const diCal_EMU_DCDCLPVCTRL = (volatile uint32_t *)(0x0FE08050);
2208 volatile uint32_t* const diCal_EMU_DCDCTRIM0 = (volatile uint32_t *)(0x0FE08058);
2209 volatile uint32_t* const diCal_EMU_DCDCTRIM1 = (volatile uint32_t *)(0x0FE08060);
2210
2211 if (DEVINFO->DCDCLPVCTRL0 != UINT_MAX) {
2212 val = *(diCal_EMU_DCDCLNFREQCTRL + 1);
2213 reg = (volatile uint32_t *)*diCal_EMU_DCDCLNFREQCTRL;
2214 *reg = val;
2215
2216 val = *(diCal_EMU_DCDCLNVCTRL + 1);
2217 reg = (volatile uint32_t *)*diCal_EMU_DCDCLNVCTRL;
2218 *reg = val;
2219
2220 val = *(diCal_EMU_DCDCLPCTRL + 1);
2221 reg = (volatile uint32_t *)*diCal_EMU_DCDCLPCTRL;
2222 *reg = val;
2223
2224 val = *(diCal_EMU_DCDCLPVCTRL + 1);
2225 reg = (volatile uint32_t *)*diCal_EMU_DCDCLPVCTRL;
2226 *reg = val;
2227
2228 val = *(diCal_EMU_DCDCTRIM0 + 1);
2229 reg = (volatile uint32_t *)*diCal_EMU_DCDCTRIM0;
2230 *reg = val;
2231
2232 val = *(diCal_EMU_DCDCTRIM1 + 1);
2233 reg = (volatile uint32_t *)*diCal_EMU_DCDCTRIM1;
2234 *reg = val;
2235
2236 return true;
2237 }
2238 EFM_ASSERT(false);
2239 /* Return when assertions are disabled. */
2240 return false;
2241
2242 #else
2243 return true;
2244 #endif
2245 }
2246
2247 /***************************************************************************//**
2248 * @brief
2249 * Set recommended and validated current optimization and timing settings.
2250 *
2251 ******************************************************************************/
dcdcValidatedConfigSet(void)2252 static void dcdcValidatedConfigSet(void)
2253 {
2254 uint32_t lnForceCcm;
2255
2256 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
2257 uint32_t dcdcTiming;
2258 SYSTEM_ChipRevision_TypeDef rev;
2259 #endif
2260
2261 /* Enable duty cycling of the bias. */
2262 EMU->DCDCLPCTRL |= EMU_DCDCLPCTRL_LPVREFDUTYEN;
2263
2264 /* Set low-noise RCO for LNFORCECCM configuration.
2265 * LNFORCECCM is default 1 for EFR32
2266 * LNFORCECCM is default 0 for EFM32
2267 */
2268 lnForceCcm = BUS_RegBitRead(&EMU->DCDCMISCCTRL, _EMU_DCDCMISCCTRL_LNFORCECCM_SHIFT);
2269 if (lnForceCcm != 0U) {
2270 /* 7 MHz is recommended for LNFORCECCM = 1. */
2271 EMU_DCDCLnRcoBandSet(emuDcdcLnRcoBand_7MHz);
2272 } else {
2273 /* 3 MHz is recommended for LNFORCECCM = 0. */
2274 EMU_DCDCLnRcoBandSet(emuDcdcLnRcoBand_3MHz);
2275 }
2276
2277 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
2278 EMU->DCDCTIMING &= ~_EMU_DCDCTIMING_DUTYSCALE_MASK;
2279 EMU->DCDCMISCCTRL |= EMU_DCDCMISCCTRL_LPCMPHYSDIS
2280 | EMU_DCDCMISCCTRL_LPCMPHYSHI;
2281
2282 SYSTEM_ChipRevisionGet(&rev);
2283 if ((rev.major == 1)
2284 && (rev.minor < 3)
2285 && (errataFixDcdcHsState == errataFixDcdcHsInit)) {
2286 /* LPCMPWAITDIS = 1 */
2287 EMU_DCDCSMCTRL |= 1;
2288
2289 dcdcTiming = EMU->DCDCTIMING;
2290 dcdcTiming &= ~(_EMU_DCDCTIMING_LPINITWAIT_MASK
2291 | _EMU_DCDCTIMING_LNWAIT_MASK
2292 | _EMU_DCDCTIMING_BYPWAIT_MASK);
2293
2294 dcdcTiming |= ((180 << _EMU_DCDCTIMING_LPINITWAIT_SHIFT)
2295 | (12 << _EMU_DCDCTIMING_LNWAIT_SHIFT)
2296 | (180 << _EMU_DCDCTIMING_BYPWAIT_SHIFT));
2297 EMU->DCDCTIMING = dcdcTiming;
2298
2299 errataFixDcdcHsState = errataFixDcdcHsTrimSet;
2300 }
2301 #endif
2302 }
2303
2304 /***************************************************************************//**
2305 * @brief
2306 * Compute current limiters:
2307 * LNCLIMILIMSEL: LN current limiter threshold
2308 * LPCLIMILIMSEL: LP current limiter threshold
2309 * DCDCZDETCTRL: zero detector limiter threshold
2310 ******************************************************************************/
currentLimitersUpdate(void)2311 static void currentLimitersUpdate(void)
2312 {
2313 uint32_t lncLimSel;
2314 uint32_t zdetLimSel;
2315 uint32_t pFetCnt;
2316 uint16_t maxReverseCurrent_mA;
2317
2318 /* 80 mA as recommended peak in Application Note AN0948.
2319 The peak current is the average current plus 50% of the current ripple.
2320 Hence, a 14 mA average current is recommended in LP mode. Since LP PFETCNT is also
2321 a constant, lpcLimImSel = 1. The following calculation is provided
2322 for documentation only. */
2323 const uint32_t lpcLim = (((14 + 40) + ((14 + 40) / 2))
2324 / (5 * (DCDC_LP_PFET_CNT + 1)))
2325 - 1;
2326 const uint32_t lpcLimSel = lpcLim << _EMU_DCDCMISCCTRL_LPCLIMILIMSEL_SHIFT;
2327
2328 /* Get enabled PFETs. */
2329 pFetCnt = (EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_PFETCNT_MASK)
2330 >> _EMU_DCDCMISCCTRL_PFETCNT_SHIFT;
2331
2332 /* Compute the LN current limiter threshold from the nominal user input current and
2333 LN PFETCNT as described in the register description for
2334 EMU_DCDCMISCCTRL_LNCLIMILIMSEL. */
2335 lncLimSel = ((((uint32_t)dcdcMaxCurrent_mA + 40U)
2336 + (((uint32_t)dcdcMaxCurrent_mA + 40U) / 2U))
2337 / (5U * (pFetCnt + 1U)))
2338 - 1U;
2339
2340 /* Saturate the register field value. */
2341 lncLimSel = SL_MIN(lncLimSel,
2342 _EMU_DCDCMISCCTRL_LNCLIMILIMSEL_MASK
2343 >> _EMU_DCDCMISCCTRL_LNCLIMILIMSEL_SHIFT);
2344
2345 lncLimSel <<= _EMU_DCDCMISCCTRL_LNCLIMILIMSEL_SHIFT;
2346
2347 /* Check for overflow. */
2348 EFM_ASSERT((lncLimSel & ~_EMU_DCDCMISCCTRL_LNCLIMILIMSEL_MASK) == 0x0U);
2349 EFM_ASSERT((lpcLimSel & ~_EMU_DCDCMISCCTRL_LPCLIMILIMSEL_MASK) == 0x0U);
2350
2351 EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_EMU_DCDCMISCCTRL_LNCLIMILIMSEL_MASK
2352 | _EMU_DCDCMISCCTRL_LPCLIMILIMSEL_MASK))
2353 | (lncLimSel | lpcLimSel);
2354
2355 /* Compute the reverse current limit threshold for the zero detector from the user input
2356 maximum reverse current and LN PFETCNT as described in the register description
2357 for EMU_DCDCZDETCTRL_ZDETILIMSEL. */
2358 if (dcdcReverseCurrentControl >= 0) {
2359 /* If dcdcReverseCurrentControl < 0, EMU_DCDCZDETCTRL_ZDETILIMSEL is "don't care". */
2360 maxReverseCurrent_mA = (uint16_t)dcdcReverseCurrentControl;
2361
2362 zdetLimSel = ((((uint32_t)maxReverseCurrent_mA + 40U)
2363 + (((uint32_t)maxReverseCurrent_mA + 40U) / 2U))
2364 / ((2U * (pFetCnt + 1U)) + ((pFetCnt + 1U) / 2U)));
2365 /* Saturate the register field value. */
2366 zdetLimSel = SL_MIN(zdetLimSel,
2367 _EMU_DCDCZDETCTRL_ZDETILIMSEL_MASK
2368 >> _EMU_DCDCZDETCTRL_ZDETILIMSEL_SHIFT);
2369
2370 zdetLimSel <<= _EMU_DCDCZDETCTRL_ZDETILIMSEL_SHIFT;
2371
2372 /* Check for overflow. */
2373 EFM_ASSERT((zdetLimSel & ~_EMU_DCDCZDETCTRL_ZDETILIMSEL_MASK) == 0x0U);
2374
2375 EMU->DCDCZDETCTRL = (EMU->DCDCZDETCTRL & ~_EMU_DCDCZDETCTRL_ZDETILIMSEL_MASK)
2376 | zdetLimSel;
2377 }
2378 }
2379
2380 /***************************************************************************//**
2381 * @brief
2382 * Set static variables that hold the user set maximum peak current
2383 * and reverse current. Update limiters.
2384 *
2385 * @param[in] maxCurrent_mA
2386 * Set the maximum peak current that the DCDC can draw from the power source.
2387 * @param[in] reverseCurrentControl
2388 * Reverse the current control as defined by
2389 * @ref EMU_DcdcLnReverseCurrentControl_TypeDef. Positive values have unit mA.
2390 ******************************************************************************/
userCurrentLimitsSet(uint32_t maxCurrent_mA,EMU_DcdcLnReverseCurrentControl_TypeDef reverseCurrentControl)2391 static void userCurrentLimitsSet(uint32_t maxCurrent_mA,
2392 EMU_DcdcLnReverseCurrentControl_TypeDef reverseCurrentControl)
2393 {
2394 dcdcMaxCurrent_mA = (uint16_t)maxCurrent_mA;
2395 dcdcReverseCurrentControl = reverseCurrentControl;
2396 }
2397
2398 /***************************************************************************//**
2399 * @brief
2400 * Set DCDC low noise compensator control register.
2401 *
2402 * @param[in] comp
2403 * Low-noise mode compensator trim setpoint.
2404 ******************************************************************************/
compCtrlSet(EMU_DcdcLnCompCtrl_TypeDef comp)2405 static void compCtrlSet(EMU_DcdcLnCompCtrl_TypeDef comp)
2406 {
2407 switch (comp) {
2408 case emuDcdcLnCompCtrl_1u0F:
2409 EMU->DCDCLNCOMPCTRL = 0x57204077UL;
2410 break;
2411
2412 case emuDcdcLnCompCtrl_4u7F:
2413 EMU->DCDCLNCOMPCTRL = 0xB7102137UL;
2414 break;
2415
2416 default:
2417 EFM_ASSERT(false);
2418 break;
2419 }
2420 }
2421
2422 /***************************************************************************//**
2423 * @brief
2424 * Load EMU_DCDCLPCTRL_LPCMPHYSSEL depending on LP bias, LP feedback
2425 * attenuation, and DEVINFOREV.
2426 *
2427 * @param[in] lpAttenuation
2428 * LP feedback attenuation.
2429 * @param[in] lpCmpBias
2430 * lpCmpBias selection.
2431 * @param[in] trimMode
2432 * DCDC trim mode.
2433 ******************************************************************************/
lpCmpHystCalibrationLoad(bool lpAttenuation,uint8_t lpCmpBias,dcdcTrimMode_TypeDef trimMode)2434 static bool lpCmpHystCalibrationLoad(bool lpAttenuation,
2435 uint8_t lpCmpBias,
2436 dcdcTrimMode_TypeDef trimMode)
2437 {
2438 uint32_t lpcmpHystSel;
2439 #if !defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
2440 (void)lpAttenuation;
2441 #endif
2442
2443 /* Get calibration data revision. */
2444 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
2445 uint8_t devinfoRev = SYSTEM_GetDevinfoRev();
2446
2447 /* Load LPATT indexed calibration data. */
2448 if (devinfoRev < 4) {
2449 lpcmpHystSel = DEVINFO->DCDCLPCMPHYSSEL0;
2450
2451 if (lpAttenuation) {
2452 lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT1_MASK)
2453 >> _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT1_SHIFT;
2454 } else {
2455 lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT0_MASK)
2456 >> _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT0_SHIFT;
2457 }
2458 } else
2459 #endif
2460 {
2461 /* devinfoRev >= 4: load LPCMPBIAS indexed calibration data. */
2462 lpcmpHystSel = DEVINFO->DCDCLPCMPHYSSEL1;
2463 switch (lpCmpBias) {
2464 case 0:
2465 lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS0_MASK)
2466 >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS0_SHIFT;
2467 break;
2468
2469 case 1:
2470 lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS1_MASK)
2471 >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS1_SHIFT;
2472 break;
2473
2474 case 2:
2475 lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS2_MASK)
2476 >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS2_SHIFT;
2477 break;
2478
2479 case 3:
2480 lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS3_MASK)
2481 >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS3_SHIFT;
2482 break;
2483
2484 default:
2485 EFM_ASSERT(false);
2486 /* Return when assertions are disabled. */
2487 return false;
2488 }
2489 }
2490
2491 /* Set trims. */
2492 if (trimMode == dcdcTrimMode_EM234H_LP) {
2493 /* Make sure the sel value is within the field range. */
2494 lpcmpHystSel <<= _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_SHIFT;
2495 if ((lpcmpHystSel & ~_GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK) != 0U) {
2496 EFM_ASSERT(false);
2497 /* Return when assertions are disabled. */
2498 return false;
2499 }
2500 EMU->DCDCLPCTRL = (EMU->DCDCLPCTRL & ~_GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK) | lpcmpHystSel;
2501 }
2502
2503 #if defined(_EMU_DCDCLPEM01CFG_LPCMPHYSSELEM01_MASK)
2504 if (trimMode == dcdcTrimMode_EM01_LP) {
2505 /* Make sure the sel value is within the field range. */
2506 lpcmpHystSel <<= _EMU_DCDCLPEM01CFG_LPCMPHYSSELEM01_SHIFT;
2507 if ((lpcmpHystSel & ~_EMU_DCDCLPEM01CFG_LPCMPHYSSELEM01_MASK) != 0U) {
2508 EFM_ASSERT(false);
2509 /* Return when assertions are disabled. */
2510 return false;
2511 }
2512 EMU->DCDCLPEM01CFG = (EMU->DCDCLPEM01CFG & ~_EMU_DCDCLPEM01CFG_LPCMPHYSSELEM01_MASK) | lpcmpHystSel;
2513 }
2514 #endif
2515
2516 return true;
2517 }
2518
2519 /***************************************************************************//**
2520 * @brief
2521 * Load LPVREF low and high from DEVINFO.
2522 *
2523 * @param[out] vrefL
2524 * LPVREF low from DEVINFO.
2525 * @param[out] vrefH
2526 * LPVREF high from DEVINFO.
2527 * @param[in] lpAttenuation
2528 * LP feedback attenuation.
2529 * @param[in] lpcmpBias
2530 * lpcmpBias to look up in DEVINFO.
2531 ******************************************************************************/
lpGetDevinfoVrefLowHigh(uint32_t * vrefL,uint32_t * vrefH,bool lpAttenuation,uint8_t lpcmpBias)2532 static void lpGetDevinfoVrefLowHigh(uint32_t *vrefL,
2533 uint32_t *vrefH,
2534 bool lpAttenuation,
2535 uint8_t lpcmpBias)
2536 {
2537 uint32_t vrefLow = 0;
2538 uint32_t vrefHigh = 0;
2539
2540 /* Find VREF high and low in DEVINFO indexed by LPCMPBIAS (lpcmpBias)
2541 and LPATT (lpAttenuation) */
2542 uint32_t switchVal = ((uint32_t)lpcmpBias << 8) | (lpAttenuation ? 1U : 0U);
2543 switch (switchVal) {
2544 case ((0 << 8) | 1):
2545 vrefLow = DEVINFO->DCDCLPVCTRL2;
2546 vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS0_MASK)
2547 >> _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS0_SHIFT;
2548 vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS0_MASK)
2549 >> _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS0_SHIFT;
2550 break;
2551
2552 case ((1 << 8) | 1):
2553 vrefLow = DEVINFO->DCDCLPVCTRL2;
2554 vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS1_MASK)
2555 >> _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS1_SHIFT;
2556 vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS1_MASK)
2557 >> _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS1_SHIFT;
2558 break;
2559
2560 case ((2 << 8) | 1):
2561 vrefLow = DEVINFO->DCDCLPVCTRL3;
2562 vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS2_MASK)
2563 >> _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS2_SHIFT;
2564 vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS2_MASK)
2565 >> _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS2_SHIFT;
2566 break;
2567
2568 case ((3 << 8) | 1):
2569 vrefLow = DEVINFO->DCDCLPVCTRL3;
2570 vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS3_MASK)
2571 >> _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS3_SHIFT;
2572 vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS3_MASK)
2573 >> _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS3_SHIFT;
2574 break;
2575
2576 case ((0 << 8) | 0):
2577 vrefLow = DEVINFO->DCDCLPVCTRL0;
2578 vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS0_MASK)
2579 >> _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS0_SHIFT;
2580 vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS0_MASK)
2581 >> _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS0_SHIFT;
2582 break;
2583
2584 case ((1 << 8) | 0):
2585 vrefLow = DEVINFO->DCDCLPVCTRL0;
2586 vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS1_MASK)
2587 >> _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS1_SHIFT;
2588 vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS1_MASK)
2589 >> _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS1_SHIFT;
2590 break;
2591
2592 case ((2 << 8) | 0):
2593 vrefLow = DEVINFO->DCDCLPVCTRL1;
2594 vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS2_MASK)
2595 >> _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS2_SHIFT;
2596 vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS2_MASK)
2597 >> _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS2_SHIFT;
2598 break;
2599
2600 case ((3 << 8) | 0):
2601 vrefLow = DEVINFO->DCDCLPVCTRL1;
2602 vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS3_MASK)
2603 >> _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS3_SHIFT;
2604 vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS3_MASK)
2605 >> _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS3_SHIFT;
2606 break;
2607
2608 default:
2609 EFM_ASSERT(false);
2610 break;
2611 }
2612 *vrefL = vrefLow;
2613 *vrefH = vrefHigh;
2614 }
2615
2616 /***************************************************************************//**
2617 * @brief
2618 * Configure the DCDC regulator.
2619 *
2620 * @note
2621 * Do not call this function if the power circuit is configured for NODCDC as
2622 * described in the Power Configurations section of the Reference Manual.
2623 * Instead, call @ref EMU_DCDCPowerOff().
2624 *
2625 * @param[in] dcdcInit
2626 * The DCDC initialization structure.
2627 *
2628 * @return
2629 * True if initialization parameters are valid.
2630 ******************************************************************************/
EMU_DCDCInit(const EMU_DCDCInit_TypeDef * dcdcInit)2631 bool EMU_DCDCInit(const EMU_DCDCInit_TypeDef *dcdcInit)
2632 {
2633 uint32_t lpCmpBiasSelEM234H;
2634
2635 #if defined(_EMU_PWRCFG_MASK)
2636 /* Set the external power configuration. This enables writing to the other
2637 DCDC registers. */
2638 EMU->PWRCFG = EMU_PWRCFG_PWRCFG_DCDCTODVDD;
2639
2640 /* EMU->PWRCFG is write-once and POR reset only. Check that
2641 the desired power configuration was set. */
2642 if ((EMU->PWRCFG & _EMU_PWRCFG_PWRCFG_MASK) != EMU_PWRCFG_PWRCFG_DCDCTODVDD) {
2643 /* If this assert triggers unexpectedly, power cycle the
2644 kit to reset the power configuration. */
2645 EFM_ASSERT(false);
2646 /* Return when assertions are disabled. */
2647 return false;
2648 }
2649 #endif
2650
2651 /* Load DCDC calibration data from the DI page. */
2652 (void)dcdcConstCalibrationLoad();
2653
2654 /* Check current parameters */
2655 EFM_ASSERT(dcdcInit->maxCurrent_mA <= 200U);
2656 EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= dcdcInit->maxCurrent_mA);
2657 EFM_ASSERT(dcdcInit->reverseCurrentControl <= 200);
2658
2659 if (dcdcInit->dcdcMode == emuDcdcMode_LowNoise) {
2660 /* DCDC low-noise supports max 200 mA. */
2661 EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= 200U);
2662 }
2663 #if (_SILICON_LABS_GECKO_INTERNAL_SDID != 80)
2664 else if (dcdcInit->dcdcMode == emuDcdcMode_LowPower) {
2665 /* Up to 10 mA is supported for EM01-LP mode. */
2666 EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= 10U);
2667 }
2668 #endif
2669 else {
2670 /* No need to check the EM01 load limit. */
2671 }
2672
2673 /* EM2/3/4 current above 10 mA is not supported. */
2674 EFM_ASSERT(dcdcInit->em234LoadCurrent_uA <= 10000U);
2675
2676 if (dcdcInit->em234LoadCurrent_uA < 75U) {
2677 lpCmpBiasSelEM234H = 0;
2678 } else if (dcdcInit->em234LoadCurrent_uA < 500U) {
2679 lpCmpBiasSelEM234H = 1U << _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT;
2680 } else if (dcdcInit->em234LoadCurrent_uA < 2500U) {
2681 lpCmpBiasSelEM234H = 2U << _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT;
2682 } else {
2683 lpCmpBiasSelEM234H = 3U << _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT;
2684 }
2685
2686 /* ==== THESE NEXT STEPS ARE STRONGLY ORDER DEPENDENT ==== */
2687
2688 /* Set DCDC low-power mode comparator bias selection. */
2689
2690 /* 1. Set DCDC low-power mode comparator bias selection and forced CCM.
2691 => Updates DCDCMISCCTRL_LNFORCECCM */
2692 EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_MASK
2693 | _EMU_DCDCMISCCTRL_LNFORCECCM_MASK))
2694 | ((uint32_t)lpCmpBiasSelEM234H
2695 | (dcdcInit->reverseCurrentControl >= 0
2696 ? EMU_DCDCMISCCTRL_LNFORCECCM : 0U));
2697 #if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
2698 /* Only 10 mA EM01-LP current is supported. */
2699 EMU->DCDCLPEM01CFG = (EMU->DCDCLPEM01CFG & ~_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
2700 | EMU_DCDCLPEM01CFG_LPCMPBIASEM01_BIAS3;
2701 #endif
2702
2703 /* 2. Set recommended and validated current optimization settings.
2704 <= Depends on LNFORCECCM
2705 => Updates DCDCLNFREQCTRL_RCOBAND */
2706 dcdcEm01LoadCurrent_mA = dcdcInit->em01LoadCurrent_mA;
2707 dcdcValidatedConfigSet();
2708
2709 /* 3. Updated static currents and limits user data.
2710 Limiters are updated in @ref EMU_DCDCOptimizeSlice(). */
2711 userCurrentLimitsSet(dcdcInit->maxCurrent_mA,
2712 dcdcInit->reverseCurrentControl);
2713
2714 /* 4. Optimize LN slice based on the given user input load current.
2715 <= Depends on DCDCMISCCTRL_LNFORCECCM and DCDCLNFREQCTRL_RCOBAND
2716 <= Depends on dcdcInit->maxCurrent_mA and dcdcInit->reverseCurrentControl
2717 => Updates DCDCMISCCTRL_P/NFETCNT
2718 => Updates DCDCMISCCTRL_LNCLIMILIMSEL and DCDCMISCCTRL_LPCLIMILIMSEL
2719 => Updates DCDCZDETCTRL_ZDETILIMSEL */
2720 EMU_DCDCOptimizeSlice(dcdcInit->em01LoadCurrent_mA);
2721
2722 /* ======================================================= */
2723
2724 /* Set DCDC low noise mode compensator control register. */
2725 compCtrlSet(dcdcInit->dcdcLnCompCtrl);
2726
2727 /* Set DCDC output voltage. */
2728 if (!EMU_DCDCOutputVoltageSet(dcdcInit->mVout, true, true)) {
2729 EFM_ASSERT(false);
2730 /* Return when assertions are disabled. */
2731 return false;
2732 }
2733
2734 #if (_SILICON_LABS_GECKO_INTERNAL_SDID == 80)
2735 /* Select analog peripheral power supply. This must be done before
2736 DCDC mode is set for all EFM32xG1 and EFR32xG1 devices. */
2737 BUS_RegBitWrite(&EMU->PWRCTRL,
2738 _EMU_PWRCTRL_ANASW_SHIFT,
2739 dcdcInit->anaPeripheralPower ? 1 : 0);
2740 #endif
2741
2742 #if defined(_EMU_PWRCTRL_REGPWRSEL_MASK)
2743 /* Select DVDD as input to the digital regulator. The switch to DVDD will take
2744 effect once the DCDC output is stable. */
2745 EMU->PWRCTRL |= EMU_PWRCTRL_REGPWRSEL_DVDD;
2746 #endif
2747
2748 /* Set EM0 DCDC operating mode. Output voltage set in
2749 @ref EMU_DCDCOutputVoltageSet() above takes effect if mode
2750 is changed from bypass/off mode. */
2751 EMU_DCDCModeSet(dcdcInit->dcdcMode);
2752
2753 #if (_SILICON_LABS_GECKO_INTERNAL_SDID != 80)
2754 /* Select the analog peripheral power supply. This must be done after
2755 DCDC mode is set for all devices other than EFM32xG1 and EFR32xG1. */
2756 BUS_RegBitWrite(&EMU->PWRCTRL,
2757 _EMU_PWRCTRL_ANASW_SHIFT,
2758 dcdcInit->anaPeripheralPower
2759 == emuDcdcAnaPeripheralPower_DCDC ? 1U : 0U);
2760 #endif
2761
2762 return true;
2763 }
2764
2765 /***************************************************************************//**
2766 * @brief
2767 * Set DCDC regulator operating mode.
2768 *
2769 * @param[in] dcdcMode
2770 * DCDC mode.
2771 ******************************************************************************/
EMU_DCDCModeSet(EMU_DcdcMode_TypeDef dcdcMode)2772 void EMU_DCDCModeSet(EMU_DcdcMode_TypeDef dcdcMode)
2773 {
2774 bool dcdcLocked;
2775 uint32_t currentDcdcMode;
2776
2777 dcdcLocked = (EMU->PWRLOCK == EMU_PWRLOCK_LOCKKEY_LOCKED);
2778 EMU_PowerUnlock();
2779
2780 /* Wait for any previous write sync to complete and read DCDC mode. */
2781 while ((EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) != 0U) {
2782 }
2783 currentDcdcMode = (EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK);
2784
2785 /* Enable bypass current limiter when not in bypass mode to prevent
2786 excessive current between VREGVDD and DVDD supplies when reentering bypass mode. */
2787 if (currentDcdcMode != EMU_DCDCCTRL_DCDCMODE_BYPASS) {
2788 BUS_RegBitWrite(&EMU->DCDCCLIMCTRL, _EMU_DCDCCLIMCTRL_BYPLIMEN_SHIFT, 1);
2789 }
2790
2791 if ((EMU_DcdcMode_TypeDef)currentDcdcMode == dcdcMode) {
2792 /* Mode already set. If already in bypass, make sure the bypass current limiter
2793 is disabled. */
2794 if (dcdcMode == emuDcdcMode_Bypass) {
2795 BUS_RegBitWrite(&EMU->DCDCCLIMCTRL, _EMU_DCDCCLIMCTRL_BYPLIMEN_SHIFT, 0);
2796 }
2797 return;
2798 }
2799
2800 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
2801
2802 /* Fix for errata DCDC_E203. */
2803 if ((currentDcdcMode == EMU_DCDCCTRL_DCDCMODE_BYPASS)
2804 && (dcdcMode == emuDcdcMode_LowNoise)) {
2805 errataFixDcdcHsState = errataFixDcdcHsBypassLn;
2806 }
2807 #endif // (_SILICON_LABS_GECKO_INTERNAL_SDID_80)
2808
2809 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_84)
2810
2811 /* Fix for errata DCDC_E204. */
2812 if (((currentDcdcMode == EMU_DCDCCTRL_DCDCMODE_OFF) || (currentDcdcMode == EMU_DCDCCTRL_DCDCMODE_BYPASS))
2813 && ((dcdcMode == emuDcdcMode_LowPower) || (dcdcMode == emuDcdcMode_LowNoise))) {
2814 /* Always start in LOWNOISE. Switch to LOWPOWER mode once LOWNOISE startup is complete. */
2815 EMU_IntClear(EMU_IFC_DCDCLNRUNNING);
2816 while ((EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) != 0U) {
2817 }
2818 EMU->DCDCCTRL = (EMU->DCDCCTRL & ~_EMU_DCDCCTRL_DCDCMODE_MASK) | EMU_DCDCCTRL_DCDCMODE_LOWNOISE;
2819 while ((EMU_IntGet() & EMU_IF_DCDCLNRUNNING) == 0U) {
2820 }
2821 }
2822 #endif // (_SILICON_LABS_GECKO_INTERNAL_SDID_84)
2823
2824 /* Set user-requested mode. */
2825 while ((EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) != 0UL) {
2826 }
2827 EMU->DCDCCTRL = (EMU->DCDCCTRL & ~_EMU_DCDCCTRL_DCDCMODE_MASK)
2828 | (uint32_t)dcdcMode;
2829
2830 /* Disable bypass current limiter after bypass mode is entered.
2831 Enable the limiter if any other mode is entered. */
2832 while ((EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) != 0U) {
2833 }
2834 BUS_RegBitWrite(&EMU->DCDCCLIMCTRL,
2835 _EMU_DCDCCLIMCTRL_BYPLIMEN_SHIFT,
2836 dcdcMode == emuDcdcMode_Bypass ? 0U : 1U);
2837
2838 if (dcdcLocked) {
2839 EMU_PowerLock();
2840 }
2841 }
2842
2843 #if defined(EMU_DCDCCTRL_DCDCMODEEM23)
2844 /***************************************************************************//**
2845 * @brief
2846 * Set DCDC Mode EM23 operating mode.
2847 *
2848 * @param[in] dcdcModeEM23
2849 * DCDC mode EM23.
2850 ******************************************************************************/
EMU_DCDCModeEM23Set(EMU_DcdcModeEM23_TypeDef dcdcModeEM23)2851 void EMU_DCDCModeEM23Set(EMU_DcdcModeEM23_TypeDef dcdcModeEM23)
2852 {
2853 bool dcdcLocked;
2854
2855 dcdcLocked = (EMU->PWRLOCK == EMU_PWRLOCK_LOCKKEY_LOCKED);
2856 EMU_PowerUnlock();
2857
2858 /* Set user-requested mode. */
2859 while ((EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) != 0UL) {
2860 }
2861 EMU->DCDCCTRL = (EMU->DCDCCTRL & ~_EMU_DCDCCTRL_DCDCMODEEM23_MASK)
2862 | (uint32_t)dcdcModeEM23;
2863
2864 if (dcdcLocked) {
2865 EMU_PowerLock();
2866 }
2867 }
2868 #endif
2869
2870 /***************************************************************************//**
2871 * @brief
2872 * Power off the DCDC regulator.
2873 *
2874 * @details
2875 * This function powers off the DCDC controller. This function should only be
2876 * used if the external power circuit is wired for no DCDC. If the external power
2877 * circuit is wired for DCDC usage, use @ref EMU_DCDCInit() and set the
2878 * DCDC in bypass mode to disable DCDC.
2879 *
2880 * @return
2881 * Return false if the DCDC could not be disabled.
2882 ******************************************************************************/
EMU_DCDCPowerOff(void)2883 bool EMU_DCDCPowerOff(void)
2884 {
2885 bool dcdcModeSet;
2886
2887 #if defined(_EMU_PWRCFG_MASK)
2888 /* Set DCDCTODVDD only to enable write access to EMU->DCDCCTRL. */
2889 EMU->PWRCFG = EMU_PWRCFG_PWRCFG_DCDCTODVDD;
2890 #endif
2891
2892 /* Select DVDD as input to the digital regulator. */
2893 #if defined(EMU_PWRCTRL_IMMEDIATEPWRSWITCH)
2894 EMU->PWRCTRL |= EMU_PWRCTRL_REGPWRSEL_DVDD | EMU_PWRCTRL_IMMEDIATEPWRSWITCH;
2895 #elif defined(EMU_PWRCTRL_REGPWRSEL_DVDD)
2896 EMU->PWRCTRL |= EMU_PWRCTRL_REGPWRSEL_DVDD;
2897 #endif
2898
2899 /* Set DCDC to OFF and disable LP in EM2/3/4. Verify that the required
2900 mode could be set. */
2901 while ((EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) != 0U) {
2902 }
2903 EMU->DCDCCTRL = EMU_DCDCCTRL_DCDCMODE_OFF;
2904
2905 dcdcModeSet = (EMU->DCDCCTRL == EMU_DCDCCTRL_DCDCMODE_OFF);
2906 EFM_ASSERT(dcdcModeSet);
2907
2908 return dcdcModeSet;
2909 }
2910
2911 /***************************************************************************//**
2912 * @brief
2913 * Set DCDC LN regulator conduction mode.
2914 *
2915 * @param[in] conductionMode
2916 * DCDC LN conduction mode.
2917 * @param[in] rcoDefaultSet
2918 * The default DCDC RCO band for the conductionMode will be used if true.
2919 * Otherwise, the current RCO configuration is used.
2920 ******************************************************************************/
EMU_DCDCConductionModeSet(EMU_DcdcConductionMode_TypeDef conductionMode,bool rcoDefaultSet)2921 void EMU_DCDCConductionModeSet(EMU_DcdcConductionMode_TypeDef conductionMode,
2922 bool rcoDefaultSet)
2923 {
2924 EMU_DcdcMode_TypeDef currentDcdcMode
2925 = (EMU_DcdcMode_TypeDef)((uint32_t)
2926 (EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK));
2927 EMU_DcdcLnRcoBand_TypeDef rcoBand
2928 = (EMU_DcdcLnRcoBand_TypeDef)((uint32_t)
2929 ((EMU->DCDCLNFREQCTRL
2930 & _EMU_DCDCLNFREQCTRL_RCOBAND_MASK)
2931 >> _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT));
2932
2933 /* Set bypass mode and wait for bypass mode to settle before
2934 EMU_DCDCMISCCTRL_LNFORCECCM is set. Restore current DCDC mode. */
2935 EMU_IntClear(EMU_IFC_DCDCINBYPASS);
2936 EMU_DCDCModeSet(emuDcdcMode_Bypass);
2937 while ((EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) != 0U) {
2938 }
2939 while ((EMU_IntGet() & EMU_IF_DCDCINBYPASS) == 0U) {
2940 }
2941 if (conductionMode == emuDcdcConductionMode_DiscontinuousLN) {
2942 EMU->DCDCMISCCTRL &= ~EMU_DCDCMISCCTRL_LNFORCECCM;
2943 if (rcoDefaultSet) {
2944 EMU_DCDCLnRcoBandSet(emuDcdcLnRcoBand_3MHz);
2945 } else {
2946 /* emuDcdcConductionMode_DiscontinuousLN supports up to 4MHz LN RCO. */
2947 EFM_ASSERT(rcoBand <= emuDcdcLnRcoBand_4MHz);
2948 }
2949 } else {
2950 EMU->DCDCMISCCTRL |= EMU_DCDCMISCCTRL_LNFORCECCM;
2951 if (rcoDefaultSet) {
2952 EMU_DCDCLnRcoBandSet(emuDcdcLnRcoBand_7MHz);
2953 }
2954 }
2955 EMU_DCDCModeSet(currentDcdcMode);
2956 /* Update slice configuration as it depends on conduction mode and RCO band.*/
2957 EMU_DCDCOptimizeSlice(dcdcEm01LoadCurrent_mA);
2958 }
2959
2960 /***************************************************************************//**
2961 * @brief
2962 * Set the DCDC output voltage.
2963 *
2964 * @note
2965 * The DCDC is not characterized for the entire valid output voltage range.
2966 * For that reason an upper limit of 3.0V output voltage is enforced.
2967 *
2968 * @param[in] mV
2969 * Target DCDC output voltage in mV.
2970 *
2971 * @param[in] setLpVoltage
2972 * Update LP voltage
2973 *
2974 * @param[in] setLnVoltage
2975 * Update LN voltage
2976 *
2977 * @return
2978 * True if the mV parameter is valid.
2979 ******************************************************************************/
EMU_DCDCOutputVoltageSet(uint32_t mV,bool setLpVoltage,bool setLnVoltage)2980 bool EMU_DCDCOutputVoltageSet(uint32_t mV,
2981 bool setLpVoltage,
2982 bool setLnVoltage)
2983 {
2984 #if defined(_DEVINFO_DCDCLNVCTRL0_3V0LNATT1_MASK)
2985
2986 bool validOutVoltage;
2987 bool attenuationSet;
2988 uint32_t mVlow = 0;
2989 uint32_t mVhigh = 0;
2990 uint32_t mVdiff;
2991 uint32_t vrefVal[DCDC_TRIM_MODES] = { 0 };
2992 uint32_t vrefLow[DCDC_TRIM_MODES] = { 0 };
2993 uint32_t vrefHigh[DCDC_TRIM_MODES] = { 0 };
2994 uint8_t lpcmpBias[DCDC_TRIM_MODES] = { 0 };
2995
2996 /* Check that the set voltage is within valid range.
2997 Voltages are obtained from the data sheet. */
2998 validOutVoltage = (mV >= PWRCFG_DCDCTODVDD_VMIN)
2999 && (mV <= PWRCFG_DCDCTODVDD_VMAX);
3000
3001 if (!validOutVoltage) {
3002 EFM_ASSERT(false);
3003 /* Return when assertions are disabled. */
3004 return false;
3005 }
3006
3007 /* Set attenuation to use and low/high range. */
3008 attenuationSet = mV > 1800U;
3009 if (attenuationSet) {
3010 mVlow = 1800;
3011 mVhigh = 3000;
3012 mVdiff = mVhigh - mVlow;
3013 } else {
3014 mVlow = 1200;
3015 mVhigh = 1800;
3016 mVdiff = mVhigh - mVlow;
3017 }
3018
3019 /* Get 2-point calibration data from DEVINFO. */
3020
3021 /* LN mode */
3022 if (attenuationSet) {
3023 vrefLow[dcdcTrimMode_LN] = DEVINFO->DCDCLNVCTRL0;
3024 vrefHigh[dcdcTrimMode_LN] = (vrefLow[dcdcTrimMode_LN] & _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_MASK)
3025 >> _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_SHIFT;
3026 vrefLow[dcdcTrimMode_LN] = (vrefLow[dcdcTrimMode_LN] & _DEVINFO_DCDCLNVCTRL0_1V8LNATT1_MASK)
3027 >> _DEVINFO_DCDCLNVCTRL0_1V8LNATT1_SHIFT;
3028 } else {
3029 vrefLow[dcdcTrimMode_LN] = DEVINFO->DCDCLNVCTRL0;
3030 vrefHigh[dcdcTrimMode_LN] = (vrefLow[dcdcTrimMode_LN] & _DEVINFO_DCDCLNVCTRL0_1V8LNATT0_MASK)
3031 >> _DEVINFO_DCDCLNVCTRL0_1V8LNATT0_SHIFT;
3032 vrefLow[dcdcTrimMode_LN] = (vrefLow[dcdcTrimMode_LN] & _DEVINFO_DCDCLNVCTRL0_1V2LNATT0_MASK)
3033 >> _DEVINFO_DCDCLNVCTRL0_1V2LNATT0_SHIFT;
3034 }
3035
3036 /* LP EM234H mode */
3037 lpcmpBias[dcdcTrimMode_EM234H_LP] = (uint8_t)
3038 ((EMU->DCDCMISCCTRL & _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_MASK)
3039 >> _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT);
3040 lpGetDevinfoVrefLowHigh(&vrefLow[dcdcTrimMode_EM234H_LP],
3041 &vrefHigh[dcdcTrimMode_EM234H_LP],
3042 attenuationSet,
3043 lpcmpBias[dcdcTrimMode_EM234H_LP]);
3044
3045 #if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
3046 /* LP EM01 mode */
3047 lpcmpBias[dcdcTrimMode_EM01_LP] = (uint8_t)
3048 ((EMU->DCDCLPEM01CFG & _EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
3049 >> _EMU_DCDCLPEM01CFG_LPCMPBIASEM01_SHIFT);
3050 lpGetDevinfoVrefLowHigh(&vrefLow[dcdcTrimMode_EM01_LP],
3051 &vrefHigh[dcdcTrimMode_EM01_LP],
3052 attenuationSet,
3053 lpcmpBias[dcdcTrimMode_EM01_LP]);
3054 #endif
3055
3056 /* Calculate output voltage trims. */
3057 vrefVal[dcdcTrimMode_LN] = ((mV - mVlow) * (vrefHigh[dcdcTrimMode_LN] - vrefLow[dcdcTrimMode_LN]))
3058 / mVdiff;
3059 vrefVal[dcdcTrimMode_LN] += vrefLow[dcdcTrimMode_LN];
3060
3061 vrefVal[dcdcTrimMode_EM234H_LP] = ((mV - mVlow) * (vrefHigh[dcdcTrimMode_EM234H_LP] - vrefLow[dcdcTrimMode_EM234H_LP]))
3062 / mVdiff;
3063 vrefVal[dcdcTrimMode_EM234H_LP] += vrefLow[dcdcTrimMode_EM234H_LP];
3064
3065 #if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
3066 vrefVal[dcdcTrimMode_EM01_LP] = ((mV - mVlow) * (vrefHigh[dcdcTrimMode_EM01_LP] - vrefLow[dcdcTrimMode_EM01_LP]))
3067 / mVdiff;
3068 vrefVal[dcdcTrimMode_EM01_LP] += vrefLow[dcdcTrimMode_EM01_LP];
3069 #endif
3070
3071 /* Range checks */
3072 if ((vrefVal[dcdcTrimMode_LN] > vrefHigh[dcdcTrimMode_LN])
3073 || (vrefVal[dcdcTrimMode_LN] < vrefLow[dcdcTrimMode_LN])
3074 #if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
3075 || (vrefVal[dcdcTrimMode_EM01_LP] > vrefHigh[dcdcTrimMode_EM01_LP])
3076 || (vrefVal[dcdcTrimMode_EM01_LP] < vrefLow[dcdcTrimMode_EM01_LP])
3077 #endif
3078 || (vrefVal[dcdcTrimMode_EM234H_LP] > vrefHigh[dcdcTrimMode_EM234H_LP])
3079 || (vrefVal[dcdcTrimMode_EM234H_LP] < vrefLow[dcdcTrimMode_EM234H_LP])) {
3080 EFM_ASSERT(false);
3081 /* Return when assertions are disabled. */
3082 return false;
3083 }
3084
3085 /* Update output voltage tuning for LN and LP modes. */
3086 if (setLnVoltage) {
3087 EMU->DCDCLNVCTRL = (EMU->DCDCLNVCTRL & ~(_EMU_DCDCLNVCTRL_LNVREF_MASK | _EMU_DCDCLNVCTRL_LNATT_MASK))
3088 | (vrefVal[dcdcTrimMode_LN] << _EMU_DCDCLNVCTRL_LNVREF_SHIFT)
3089 | (attenuationSet ? EMU_DCDCLNVCTRL_LNATT : 0U);
3090 }
3091
3092 if (setLpVoltage) {
3093 /* Load LP EM234H comparator hysteresis calibration. */
3094 if (!(lpCmpHystCalibrationLoad(attenuationSet, lpcmpBias[dcdcTrimMode_EM234H_LP], dcdcTrimMode_EM234H_LP))) {
3095 EFM_ASSERT(false);
3096 /* Return when assertions are disabled. */
3097 return false;
3098 }
3099
3100 #if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
3101 /* Load LP EM234H comparator hysteresis calibration. */
3102 if (!(lpCmpHystCalibrationLoad(attenuationSet, lpcmpBias[dcdcTrimMode_EM01_LP], dcdcTrimMode_EM01_LP))) {
3103 EFM_ASSERT(false);
3104 /* Return when assertions are disabled. */
3105 return false;
3106 }
3107
3108 /* LP VREF is that maximum of trims for EM01 and EM234H. */
3109 vrefVal[dcdcTrimMode_EM234H_LP] = SL_MAX(vrefVal[dcdcTrimMode_EM234H_LP], vrefVal[dcdcTrimMode_EM01_LP]);
3110 #endif
3111
3112 /* Don't exceed the maximum available code as specified in the reference manual for EMU_DCDCLPVCTRL. */
3113 vrefVal[dcdcTrimMode_EM234H_LP] = SL_MIN(vrefVal[dcdcTrimMode_EM234H_LP], 0xE7U);
3114 EMU->DCDCLPVCTRL = (EMU->DCDCLPVCTRL & ~(_EMU_DCDCLPVCTRL_LPVREF_MASK | _EMU_DCDCLPVCTRL_LPATT_MASK))
3115 | (vrefVal[dcdcTrimMode_EM234H_LP] << _EMU_DCDCLPVCTRL_LPVREF_SHIFT)
3116 | (attenuationSet ? EMU_DCDCLPVCTRL_LPATT : 0U);
3117 }
3118 #endif
3119 return true;
3120 }
3121
3122 /***************************************************************************//**
3123 * @brief
3124 * Optimize the DCDC slice count based on the estimated average load current
3125 * in EM0.
3126 *
3127 * @param[in] em0LoadCurrentmA
3128 * Estimated average EM0 load current in mA.
3129 ******************************************************************************/
EMU_DCDCOptimizeSlice(uint32_t em0LoadCurrentmA)3130 void EMU_DCDCOptimizeSlice(uint32_t em0LoadCurrentmA)
3131 {
3132 uint32_t sliceCount = 0;
3133 uint32_t rcoBand = (EMU->DCDCLNFREQCTRL & _EMU_DCDCLNFREQCTRL_RCOBAND_MASK)
3134 >> _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT;
3135
3136 /* Set the recommended slice count. */
3137 if (((EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK) != 0U)
3138 && (rcoBand >= (uint32_t)emuDcdcLnRcoBand_5MHz)) {
3139 if (em0LoadCurrentmA < 20U) {
3140 sliceCount = 4;
3141 } else if ((em0LoadCurrentmA >= 20U) && (em0LoadCurrentmA < 40U)) {
3142 sliceCount = 8;
3143 } else {
3144 sliceCount = 16;
3145 }
3146 } else if (((EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK) == 0U)
3147 && (rcoBand <= (uint32_t)emuDcdcLnRcoBand_4MHz)) {
3148 if (em0LoadCurrentmA < 10U) {
3149 sliceCount = 4;
3150 } else if ((em0LoadCurrentmA >= 10U) && (em0LoadCurrentmA < 20U)) {
3151 sliceCount = 8;
3152 } else {
3153 sliceCount = 16;
3154 }
3155 } else if (((EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK) != 0U)
3156 && (rcoBand <= (uint32_t)emuDcdcLnRcoBand_4MHz)) {
3157 if (em0LoadCurrentmA < 40U) {
3158 sliceCount = 8;
3159 } else {
3160 sliceCount = 16;
3161 }
3162 } else {
3163 /* This configuration is not recommended. @ref EMU_DCDCInit() applies a recommended
3164 configuration. */
3165 EFM_ASSERT(false);
3166 }
3167
3168 /* The selected slices are PSLICESEL + 1. */
3169 sliceCount--;
3170
3171 /* Apply slice count to both N and P slice. */
3172 sliceCount = (sliceCount << _EMU_DCDCMISCCTRL_PFETCNT_SHIFT
3173 | sliceCount << _EMU_DCDCMISCCTRL_NFETCNT_SHIFT);
3174 EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_EMU_DCDCMISCCTRL_PFETCNT_MASK
3175 | _EMU_DCDCMISCCTRL_NFETCNT_MASK))
3176 | sliceCount;
3177
3178 /* Update the current limiters. */
3179 currentLimitersUpdate();
3180 }
3181
3182 /***************************************************************************//**
3183 * @brief
3184 * Set DCDC Low-noise RCO band.
3185 *
3186 * @param[in] band
3187 * RCO band to set.
3188 ******************************************************************************/
EMU_DCDCLnRcoBandSet(EMU_DcdcLnRcoBand_TypeDef band)3189 void EMU_DCDCLnRcoBandSet(EMU_DcdcLnRcoBand_TypeDef band)
3190 {
3191 uint32_t forcedCcm;
3192 forcedCcm = BUS_RegBitRead(&EMU->DCDCMISCCTRL, _EMU_DCDCMISCCTRL_LNFORCECCM_SHIFT);
3193
3194 /* DCM mode supports up to 4 MHz LN RCO. */
3195 EFM_ASSERT(((forcedCcm == 0U) && band <= emuDcdcLnRcoBand_4MHz)
3196 || (forcedCcm != 0U));
3197
3198 EMU->DCDCLNFREQCTRL = (EMU->DCDCLNFREQCTRL & ~_EMU_DCDCLNFREQCTRL_RCOBAND_MASK)
3199 | ((uint32_t)band << _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT);
3200
3201 /* Update slice configuration as this depends on the RCO band. */
3202 EMU_DCDCOptimizeSlice(dcdcEm01LoadCurrent_mA);
3203 }
3204 #endif /* EMU_SERIES1_DCDC_BUCK_PRESENT */
3205
3206 #if defined(EMU_SERIES2_DCDC_BOOST_PRESENT)
3207 /***************************************************************************//**
3208 * @brief
3209 * Configure the DCDC Boost regulator.
3210 *
3211 * @param[in] dcdcBoostInit
3212 * The DCDC initialization structure.
3213 *
3214 * @return
3215 * True if initialization parameters are valid.
3216 ******************************************************************************/
EMU_DCDCBoostInit(const EMU_DCDCBoostInit_TypeDef * dcdcBoostInit)3217 bool EMU_DCDCBoostInit(const EMU_DCDCBoostInit_TypeDef *dcdcBoostInit)
3218 {
3219 bool dcdcLocked;
3220
3221 CMU->CLKEN0_SET = CMU_CLKEN0_DCDC;
3222 #if defined(_DCDC_EN_EN_MASK)
3223 DCDC->EN_SET = DCDC_EN_EN;
3224 #endif
3225 dcdcLocked = ((DCDC->LOCKSTATUS & DCDC_LOCKSTATUS_LOCK) != 0);
3226 EMU_DCDCUnlock();
3227
3228 #if defined(_DCDC_SYNCBUSY_MASK)
3229 EMU_DCDCSync(_DCDC_SYNCBUSY_MASK);
3230 #endif
3231
3232 DCDC->BSTCTRL = (DCDC->BSTCTRL & ~(_DCDC_BSTCTRL_IPKTMAXCTRL_MASK))
3233 | ((uint32_t)dcdcBoostInit->tonMax << _DCDC_BSTCTRL_IPKTMAXCTRL_SHIFT);
3234 DCDC->BSTEM01CTRL = ((uint32_t)dcdcBoostInit->driveSpeedEM01 << _DCDC_BSTEM01CTRL_DRVSPEED_SHIFT)
3235 | ((uint32_t)dcdcBoostInit->peakCurrentEM01 << _DCDC_BSTEM01CTRL_IPKVAL_SHIFT);
3236 DCDC->BSTEM23CTRL = ((uint32_t)dcdcBoostInit->driveSpeedEM23 << _DCDC_BSTEM23CTRL_DRVSPEED_SHIFT)
3237 | ((uint32_t)dcdcBoostInit->peakCurrentEM23 << _DCDC_BSTEM23CTRL_IPKVAL_SHIFT);
3238
3239 EMU_BoostExternalShutdownEnable(dcdcBoostInit->externalShutdownEn);
3240
3241 EMU_DCDCModeSet(emuDcdcMode_Regulation);
3242
3243 if (dcdcLocked) {
3244 EMU_DCDCLock();
3245 }
3246
3247 EMU_DCDCUpdatedHook();
3248
3249 return true;
3250 }
3251
3252 /***************************************************************************//**
3253 * @brief
3254 * Set EMO1 mode Boost Peak Current setting.
3255 *
3256 * @param[in] peakCurrentEM01
3257 * Boost Peak load current coefficient in EM01 mode.
3258 ******************************************************************************/
EMU_EM01BoostPeakCurrentSet(const EMU_DcdcBoostEM01PeakCurrent_TypeDef boostPeakCurrentEM01)3259 void EMU_EM01BoostPeakCurrentSet(const EMU_DcdcBoostEM01PeakCurrent_TypeDef boostPeakCurrentEM01)
3260 {
3261 bool dcdcLocked = false;
3262 bool dcdcClkWasEnabled = false;
3263
3264 dcdcClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_DCDC) != 0);
3265 CMU->CLKEN0_SET = CMU_CLKEN0_DCDC;
3266
3267 dcdcLocked = ((DCDC->LOCKSTATUS & DCDC_LOCKSTATUS_LOCK) != 0);
3268 EMU_DCDCUnlock();
3269
3270 /* Wait for synchronization before writing new value */
3271 #if defined(_DCDC_SYNCBUSY_MASK)
3272 EMU_DCDCSync(_DCDC_SYNCBUSY_MASK);
3273 #endif
3274
3275 BUS_RegMaskedWrite(&DCDC->BSTEM01CTRL,
3276 _DCDC_BSTEM01CTRL_IPKVAL_MASK,
3277 ((uint32_t)boostPeakCurrentEM01 << _DCDC_BSTEM01CTRL_IPKVAL_SHIFT));
3278
3279 if (dcdcLocked) {
3280 EMU_DCDCLock();
3281 }
3282
3283 if (!dcdcClkWasEnabled) {
3284 CMU->CLKEN0_CLR = CMU_CLKEN0_DCDC;
3285 }
3286
3287 EMU_DCDCUpdatedHook();
3288 }
3289
3290 /***************************************************************************//**
3291 * @brief
3292 * Enable/disable Boost External Shutdown Mode.
3293 *
3294 * @param[in] enable
3295 * The boost DC-DC converter can be activated or deactivated
3296 * from a dedicated BOOST_EN pin on the device if enable is true.
3297 ******************************************************************************/
EMU_BoostExternalShutdownEnable(bool enable)3298 void EMU_BoostExternalShutdownEnable(bool enable)
3299 {
3300 if (enable) {
3301 EMU->BOOSTCTRL_CLR = EMU_BOOSTCTRL_BOOSTENCTRL;
3302 } else {
3303 EMU->BOOSTCTRL_SET = EMU_BOOSTCTRL_BOOSTENCTRL;
3304 }
3305 }
3306 #endif /* EMU_SERIES2_DCDC_BOOST_PRESENT */
3307
3308 #if defined(EMU_SERIES2_DCDC_BUCK_PRESENT) \
3309 || defined(EMU_SERIES2_DCDC_BOOST_PRESENT)
3310 /***************************************************************************//**
3311 * @brief
3312 * Indicate that the DCDC peripheral bus clock enable has changed allowing
3313 * RAIL to react accordingly.
3314 *
3315 * @details
3316 * This function is called after DCDC has been enabled or disabled.
3317 * The function implementation does not perform anything, but it is SL_WEAK
3318 * so that it can use the RAIL version if needed.
3319 ******************************************************************************/
EMU_DCDCUpdatedHook(void)3320 SL_WEAK void EMU_DCDCUpdatedHook(void)
3321 {
3322 }
3323
3324 /***************************************************************************//**
3325 * @brief
3326 * Set DCDC regulator operating mode.
3327 *
3328 * @param[in] dcdcMode
3329 * DCDC mode.
3330 ******************************************************************************/
EMU_DCDCModeSet(EMU_DcdcMode_TypeDef dcdcMode)3331 void EMU_DCDCModeSet(EMU_DcdcMode_TypeDef dcdcMode)
3332 {
3333 bool dcdcLocked;
3334 uint32_t currentDcdcMode;
3335
3336 CMU->CLKEN0_SET = CMU_CLKEN0_DCDC;
3337 #if defined(_DCDC_EN_EN_MASK)
3338 DCDC->EN_SET = DCDC_EN_EN;
3339 #endif
3340 dcdcLocked = ((DCDC->LOCKSTATUS & DCDC_LOCKSTATUS_LOCK) != 0);
3341 EMU_DCDCUnlock();
3342
3343 if (dcdcMode == emuDcdcMode_Bypass) {
3344 #if defined(_DCDC_SYNCBUSY_MASK)
3345 #if defined(_DCDC_SYNCBUSY_CTRL_MASK)
3346 EMU_DCDCSync(DCDC_SYNCBUSY_CTRL);
3347 #else
3348 EMU_DCDCSync(_DCDC_SYNCBUSY_MASK);
3349 #endif
3350 #endif
3351 currentDcdcMode = (DCDC->CTRL & _DCDC_CTRL_MODE_MASK) >> _DCDC_CTRL_MODE_SHIFT;
3352
3353 if (currentDcdcMode != emuDcdcMode_Bypass) {
3354 /* Switch to BYPASS mode if it is not the current mode */
3355 DCDC->CTRL_CLR = DCDC_CTRL_MODE;
3356 while ((DCDC->STATUS & DCDC_STATUS_BYPSW) == 0U) {
3357 /* Wait for BYPASS switch enable. */
3358 }
3359 }
3360 #if defined(_DCDC_EN_EN_MASK)
3361 DCDC->EN_CLR = DCDC_EN_EN;
3362 #endif
3363 } else {
3364 while ((DCDC->STATUS & DCDC_STATUS_VREGIN) != 0U) {
3365 /* Wait for VREGIN voltage to rise above threshold. */
3366 }
3367
3368 DCDC->IF_CLR = DCDC_IF_REGULATION;
3369 DCDC->CTRL_SET = DCDC_CTRL_MODE;
3370 while ((DCDC->IF & DCDC_IF_REGULATION) == 0U) {
3371 /* Wait for DCDC to complete it's startup. */
3372 }
3373 }
3374
3375 if (dcdcLocked) {
3376 EMU_DCDCLock();
3377 }
3378
3379 EMU_DCDCUpdatedHook();
3380 }
3381 #endif /* EMU_SERIES2_DCDC_BOOST_PRESENT */
3382
3383 #if defined(EMU_SERIES2_DCDC_BUCK_PRESENT)
3384 /***************************************************************************//**
3385 * @brief
3386 * Configure the DCDC regulator.
3387 *
3388 * @param[in] dcdcInit
3389 * The DCDC initialization structure.
3390 *
3391 * @return
3392 * True if initialization parameters are valid.
3393 ******************************************************************************/
EMU_DCDCInit(const EMU_DCDCInit_TypeDef * dcdcInit)3394 bool EMU_DCDCInit(const EMU_DCDCInit_TypeDef *dcdcInit)
3395 {
3396 bool dcdcLocked;
3397
3398 CMU->CLKEN0_SET = CMU_CLKEN0_DCDC;
3399 #if defined(_DCDC_EN_EN_MASK)
3400 DCDC->EN_SET = DCDC_EN_EN;
3401 #endif
3402 dcdcLocked = ((DCDC->LOCKSTATUS & DCDC_LOCKSTATUS_LOCK) != 0);
3403 EMU_DCDCUnlock();
3404
3405 EMU->VREGVDDCMPCTRL = ((uint32_t)dcdcInit->cmpThreshold
3406 << _EMU_VREGVDDCMPCTRL_THRESSEL_SHIFT)
3407 | EMU_VREGVDDCMPCTRL_VREGINCMPEN;
3408
3409 #if defined(_DCDC_SYNCBUSY_MASK)
3410 #if defined(_DCDC_SYNCBUSY_CTRL_MASK)
3411 EMU_DCDCSync(DCDC_SYNCBUSY_CTRL | DCDC_SYNCBUSY_EM01CTRL0 | DCDC_SYNCBUSY_EM23CTRL0);
3412 #else
3413 EMU_DCDCSync(_DCDC_SYNCBUSY_MASK);
3414 #endif
3415 #endif
3416 #if defined(_DCDC_CTRL_DCMONLYEN_MASK)
3417 DCDC->CTRL = (DCDC->CTRL & ~(_DCDC_CTRL_IPKTMAXCTRL_MASK
3418 | _DCDC_CTRL_DCMONLYEN_MASK))
3419 | ((uint32_t)dcdcInit->tonMax << _DCDC_CTRL_IPKTMAXCTRL_SHIFT)
3420 | ((uint32_t)(dcdcInit->dcmOnlyEn ? 1U : 0U) << _DCDC_CTRL_DCMONLYEN_SHIFT);
3421 #else
3422 DCDC->CTRL = (DCDC->CTRL & ~(_DCDC_CTRL_IPKTMAXCTRL_MASK))
3423 | ((uint32_t)dcdcInit->tonMax << _DCDC_CTRL_IPKTMAXCTRL_SHIFT);
3424 #endif
3425 DCDC->EM01CTRL0 = ((uint32_t)dcdcInit->driveSpeedEM01 << _DCDC_EM01CTRL0_DRVSPEED_SHIFT)
3426 | ((uint32_t)dcdcInit->peakCurrentEM01 << _DCDC_EM01CTRL0_IPKVAL_SHIFT);
3427 DCDC->EM23CTRL0 = ((uint32_t)dcdcInit->driveSpeedEM23 << _DCDC_EM23CTRL0_DRVSPEED_SHIFT)
3428 | ((uint32_t)dcdcInit->peakCurrentEM23 << _DCDC_EM23CTRL0_IPKVAL_SHIFT);
3429
3430 EMU_DCDCModeSet(dcdcInit->mode);
3431
3432 if (dcdcLocked) {
3433 EMU_DCDCLock();
3434 }
3435
3436 EMU_DCDCUpdatedHook();
3437
3438 return true;
3439 }
3440
3441 /***************************************************************************//**
3442 * @brief
3443 * Power off the DCDC regulator.
3444 *
3445 * @return
3446 * Returns true.
3447 ******************************************************************************/
EMU_DCDCPowerOff(void)3448 bool EMU_DCDCPowerOff(void)
3449 {
3450 EMU_DCDCModeSet(emuDcdcMode_Bypass);
3451 return true;
3452 }
3453
3454 /***************************************************************************//**
3455 * @brief
3456 * Set EMO1 mode Peak Current setting.
3457 *
3458 * @param[in] peakCurrentEM01
3459 * Peak load current coefficient in EM01 mode.
3460 ******************************************************************************/
EMU_EM01PeakCurrentSet(const EMU_DcdcPeakCurrent_TypeDef peakCurrentEM01)3461 void EMU_EM01PeakCurrentSet(const EMU_DcdcPeakCurrent_TypeDef peakCurrentEM01)
3462 {
3463 bool dcdcLocked = false;
3464 bool dcdcClkWasEnabled = false;
3465
3466 dcdcClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_DCDC) != 0);
3467 CMU->CLKEN0_SET = CMU_CLKEN0_DCDC;
3468
3469 #if defined(_DCDC_EN_EN_MASK)
3470 bool dcdcWasEnabled = ((DCDC->EN & DCDC_EN_EN) != 0);
3471 DCDC->EN_SET = DCDC_EN_EN;
3472 #endif
3473
3474 dcdcLocked = ((DCDC->LOCKSTATUS & DCDC_LOCKSTATUS_LOCK) != 0);
3475 EMU_DCDCUnlock();
3476
3477 /* Wait for synchronization before writing new value */
3478 #if defined(_DCDC_SYNCBUSY_MASK)
3479 #if defined(_DCDC_SYNCBUSY_EM01CTRL0_MASK)
3480 EMU_DCDCSync(DCDC_SYNCBUSY_EM01CTRL0);
3481 #else
3482 EMU_DCDCSync(_DCDC_SYNCBUSY_MASK);
3483 #endif
3484 #endif
3485
3486 BUS_RegMaskedWrite(&DCDC->EM01CTRL0,
3487 _DCDC_EM01CTRL0_IPKVAL_MASK,
3488 ((uint32_t)peakCurrentEM01 << _DCDC_EM01CTRL0_IPKVAL_SHIFT));
3489
3490 #if defined(_DCDC_EN_EN_MASK)
3491 if (!dcdcWasEnabled) {
3492 DCDC->EN_CLR = DCDC_EN_EN;
3493 }
3494 #endif
3495
3496 if (dcdcLocked) {
3497 EMU_DCDCLock();
3498 }
3499
3500 if (!dcdcClkWasEnabled) {
3501 CMU->CLKEN0_CLR = CMU_CLKEN0_DCDC;
3502 }
3503
3504 EMU_DCDCUpdatedHook();
3505 }
3506
3507 #if defined(_DCDC_PFMXCTRL_IPKVAL_MASK)
3508 /***************************************************************************//**
3509 * @brief
3510 * Set PFMX mode Peak Current setting.
3511 *
3512 * @param[in] value
3513 * Peak load current coefficient in PFMX mode.
3514 ******************************************************************************/
EMU_DCDCSetPFMXModePeakCurrent(uint32_t value)3515 void EMU_DCDCSetPFMXModePeakCurrent(uint32_t value)
3516 {
3517 bool dcdcLocked = false;
3518 bool dcdcClkWasEnabled = false;
3519
3520 /* Verification that the parameter is in range. */
3521 /* if not, restrict value to maximum allowed. */
3522 EFM_ASSERT(value <= (_DCDC_PFMXCTRL_IPKVAL_MASK >> _DCDC_PFMXCTRL_IPKVAL_SHIFT));
3523 if (value > (_DCDC_PFMXCTRL_IPKVAL_MASK >> _DCDC_PFMXCTRL_IPKVAL_SHIFT)) {
3524 value = (_DCDC_PFMXCTRL_IPKVAL_MASK >> _DCDC_PFMXCTRL_IPKVAL_SHIFT);
3525 }
3526
3527 dcdcClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_DCDC) != 0);
3528 CMU->CLKEN0_SET = CMU_CLKEN0_DCDC;
3529
3530 dcdcLocked = ((DCDC->LOCKSTATUS & DCDC_LOCKSTATUS_LOCK) != 0);
3531 EMU_DCDCUnlock();
3532
3533 #if defined(_DCDC_SYNCBUSY_MASK)
3534 /* Wait for synchronization before writing new value */
3535 EMU_DCDCSync(DCDC_SYNCBUSY_PFMXCTRL);
3536 #endif
3537
3538 DCDC->PFMXCTRL = ((DCDC->PFMXCTRL & ~_DCDC_PFMXCTRL_IPKVAL_MASK)
3539 | value << _DCDC_PFMXCTRL_IPKVAL_SHIFT);
3540
3541 if (dcdcLocked) {
3542 EMU_DCDCLock();
3543 }
3544
3545 if (!dcdcClkWasEnabled) {
3546 CMU->CLKEN0_CLR = CMU_CLKEN0_DCDC;
3547 }
3548
3549 EMU_DCDCUpdatedHook();
3550 }
3551 #endif /* _DCDC_PFMXCTRL_IPKVAL_MASK */
3552
3553 #if defined(_DCDC_PFMXCTRL_IPKTMAXCTRL_MASK)
3554 /***************************************************************************//**
3555 * @brief
3556 * Set Ton_max timeout control.
3557 *
3558 * @param[in] value
3559 * Maximum time for peak current detection.
3560 ******************************************************************************/
EMU_DCDCSetPFMXTimeoutMaxCtrl(EMU_DcdcTonMaxTimeout_TypeDef value)3561 void EMU_DCDCSetPFMXTimeoutMaxCtrl(EMU_DcdcTonMaxTimeout_TypeDef value)
3562 {
3563 bool dcdcLocked = false;
3564 bool dcdcClkWasEnabled = false;
3565
3566 dcdcClkWasEnabled = ((CMU->CLKEN0 & CMU_CLKEN0_DCDC) != 0);
3567 CMU->CLKEN0_SET = CMU_CLKEN0_DCDC;
3568
3569 dcdcLocked = ((DCDC->LOCKSTATUS & DCDC_LOCKSTATUS_LOCK) != 0);
3570 EMU_DCDCUnlock();
3571
3572 #if defined(_DCDC_SYNCBUSY_MASK)
3573 /* Wait for synchronization before writing new value */
3574 EMU_DCDCSync(DCDC_SYNCBUSY_PFMXCTRL);
3575 #endif
3576
3577 DCDC->PFMXCTRL = ((DCDC->PFMXCTRL & ~_DCDC_PFMXCTRL_IPKTMAXCTRL_MASK)
3578 | value << _DCDC_PFMXCTRL_IPKTMAXCTRL_SHIFT);
3579
3580 if (dcdcLocked) {
3581 EMU_DCDCLock();
3582 }
3583
3584 if (!dcdcClkWasEnabled) {
3585 CMU->CLKEN0_CLR = CMU_CLKEN0_DCDC;
3586 }
3587
3588 EMU_DCDCUpdatedHook();
3589 }
3590 #endif /* _DCDC_PFMXCTRL_IPKTMAXCTRL_MASK */
3591 #endif /* EMU_SERIES2_DCDC_BUCK_PRESENT */
3592
3593 #if defined(EMU_STATUS_VMONRDY)
3594
3595 /***************************************************************************//**
3596 * @brief
3597 * Get the calibrated threshold value.
3598 *
3599 * @details
3600 * All VMON channels have two calibration fields in the DI page that
3601 * describes the threshold at 1.86 V and 2.98 V. This function will convert
3602 * the uncalibrated input voltage threshold in millivolts into a calibrated
3603 * threshold.
3604 *
3605 * @param[in] channel
3606 * A VMON channel.
3607 *
3608 * @param[in] threshold
3609 * A desired threshold in millivolts.
3610 *
3611 * @return
3612 * A calibrated threshold value to use. The first digit of the return value is placed
3613 * in the "fine" register fields while the next digits are placed in the
3614 * "coarse" register fields.
3615 ******************************************************************************/
vmonCalibratedThreshold(EMU_VmonChannel_TypeDef channel,int threshold)3616 static uint32_t vmonCalibratedThreshold(EMU_VmonChannel_TypeDef channel,
3617 int threshold)
3618 {
3619 uint32_t tDiff = 0;
3620 uint32_t tLow = 0;
3621 uint32_t tHigh = 0;
3622 uint32_t calReg;
3623
3624 /* Get calibration values for 1.86 V and 2.98 V */
3625 switch (channel) {
3626 case emuVmonChannel_AVDD:
3627 calReg = DEVINFO->VMONCAL0;
3628 tLow = (10U * ((calReg & _DEVINFO_VMONCAL0_AVDD1V86THRESCOARSE_MASK)
3629 >> _DEVINFO_VMONCAL0_AVDD1V86THRESCOARSE_SHIFT))
3630 + ((calReg & _DEVINFO_VMONCAL0_AVDD1V86THRESFINE_MASK)
3631 >> _DEVINFO_VMONCAL0_AVDD1V86THRESFINE_SHIFT);
3632 tHigh = (10U * ((calReg & _DEVINFO_VMONCAL0_AVDD2V98THRESCOARSE_MASK)
3633 >> _DEVINFO_VMONCAL0_AVDD2V98THRESCOARSE_SHIFT))
3634 + ((calReg & _DEVINFO_VMONCAL0_AVDD2V98THRESFINE_MASK)
3635 >> _DEVINFO_VMONCAL0_AVDD2V98THRESFINE_SHIFT);
3636 break;
3637 case emuVmonChannel_ALTAVDD:
3638 calReg = DEVINFO->VMONCAL0;
3639 tLow = (10U * ((calReg & _DEVINFO_VMONCAL0_ALTAVDD1V86THRESCOARSE_MASK)
3640 >> _DEVINFO_VMONCAL0_ALTAVDD1V86THRESCOARSE_SHIFT))
3641 + ((calReg & _DEVINFO_VMONCAL0_ALTAVDD1V86THRESFINE_MASK)
3642 >> _DEVINFO_VMONCAL0_ALTAVDD1V86THRESFINE_SHIFT);
3643 tHigh = (10U * ((calReg & _DEVINFO_VMONCAL0_ALTAVDD2V98THRESCOARSE_MASK)
3644 >> _DEVINFO_VMONCAL0_ALTAVDD2V98THRESCOARSE_SHIFT))
3645 + ((calReg & _DEVINFO_VMONCAL0_ALTAVDD2V98THRESFINE_MASK)
3646 >> _DEVINFO_VMONCAL0_ALTAVDD2V98THRESFINE_SHIFT);
3647 break;
3648 case emuVmonChannel_DVDD:
3649 calReg = DEVINFO->VMONCAL1;
3650 tLow = (10U * ((calReg & _DEVINFO_VMONCAL1_DVDD1V86THRESCOARSE_MASK)
3651 >> _DEVINFO_VMONCAL1_DVDD1V86THRESCOARSE_SHIFT))
3652 + ((calReg & _DEVINFO_VMONCAL1_DVDD1V86THRESFINE_MASK)
3653 >> _DEVINFO_VMONCAL1_DVDD1V86THRESFINE_SHIFT);
3654 tHigh = (10U * ((calReg & _DEVINFO_VMONCAL1_DVDD2V98THRESCOARSE_MASK)
3655 >> _DEVINFO_VMONCAL1_DVDD2V98THRESCOARSE_SHIFT))
3656 + ((calReg & _DEVINFO_VMONCAL1_DVDD2V98THRESFINE_MASK)
3657 >> _DEVINFO_VMONCAL1_DVDD2V98THRESFINE_SHIFT);
3658 break;
3659 case emuVmonChannel_IOVDD0:
3660 calReg = DEVINFO->VMONCAL1;
3661 tLow = (10U * ((calReg & _DEVINFO_VMONCAL1_IO01V86THRESCOARSE_MASK)
3662 >> _DEVINFO_VMONCAL1_IO01V86THRESCOARSE_SHIFT))
3663 + ((calReg & _DEVINFO_VMONCAL1_IO01V86THRESFINE_MASK)
3664 >> _DEVINFO_VMONCAL1_IO01V86THRESFINE_SHIFT);
3665 tHigh = (10U * ((calReg & _DEVINFO_VMONCAL1_IO02V98THRESCOARSE_MASK)
3666 >> _DEVINFO_VMONCAL1_IO02V98THRESCOARSE_SHIFT))
3667 + ((calReg & _DEVINFO_VMONCAL1_IO02V98THRESFINE_MASK)
3668 >> _DEVINFO_VMONCAL1_IO02V98THRESFINE_SHIFT);
3669 break;
3670 #if defined(_EMU_VMONIO1CTRL_EN_MASK)
3671 case emuVmonChannel_IOVDD1:
3672 calReg = DEVINFO->VMONCAL2;
3673 tLow = (10U * ((calReg & _DEVINFO_VMONCAL2_IO11V86THRESCOARSE_MASK)
3674 >> _DEVINFO_VMONCAL2_IO11V86THRESCOARSE_SHIFT))
3675 + ((calReg & _DEVINFO_VMONCAL2_IO11V86THRESFINE_MASK)
3676 >> _DEVINFO_VMONCAL2_IO11V86THRESFINE_SHIFT);
3677 tHigh = (10U * ((calReg & _DEVINFO_VMONCAL2_IO12V98THRESCOARSE_MASK)
3678 >> _DEVINFO_VMONCAL2_IO12V98THRESCOARSE_SHIFT))
3679 + ((calReg & _DEVINFO_VMONCAL2_IO12V98THRESFINE_MASK)
3680 >> _DEVINFO_VMONCAL2_IO12V98THRESFINE_SHIFT);
3681 break;
3682 #endif
3683 #if defined(_EMU_VMONBUVDDCTRL_EN_MASK)
3684 case emuVmonChannel_BUVDD:
3685 calReg = DEVINFO->VMONCAL2;
3686 tLow = (10U * ((calReg & _DEVINFO_VMONCAL2_BUVDD1V86THRESCOARSE_MASK)
3687 >> _DEVINFO_VMONCAL2_BUVDD1V86THRESCOARSE_SHIFT))
3688 + ((calReg & _DEVINFO_VMONCAL2_BUVDD1V86THRESFINE_MASK)
3689 >> _DEVINFO_VMONCAL2_BUVDD1V86THRESFINE_SHIFT);
3690 tHigh = (10U * ((calReg & _DEVINFO_VMONCAL2_BUVDD2V98THRESCOARSE_MASK)
3691 >> _DEVINFO_VMONCAL2_BUVDD2V98THRESCOARSE_SHIFT))
3692 + ((calReg & _DEVINFO_VMONCAL2_BUVDD2V98THRESFINE_MASK)
3693 >> _DEVINFO_VMONCAL2_BUVDD2V98THRESFINE_SHIFT);
3694 break;
3695 #endif
3696 default:
3697 EFM_ASSERT(false);
3698 break;
3699 }
3700
3701 tDiff = tHigh - tLow;
3702 if (tDiff > 0) {
3703 /* Calculate threshold.
3704 *
3705 * Note that volt is used in the reference manual. However, the results
3706 * should be in millivolts. The precision of Va and Vb are increased in the
3707 * calculation instead of using floating points.
3708 */
3709 uint32_t va = (1120U * 100U) / (tDiff);
3710 uint32_t vb = (1860U * 100U) - (va * tLow);
3711 // If (tHigh - tLow) is large, Va could be zero. Caught by CSTAT.
3712 if (va != 0) {
3713 /* Round the threshold to the nearest integer value. */
3714 return (((uint32_t)threshold * 100U) - vb + (va / 2U)) / va;
3715 }
3716 }
3717
3718 /* Uncalibrated device guard. */
3719 return (uint32_t)threshold;
3720 }
3721
3722 /***************************************************************************//**
3723 * @brief
3724 * Initialize a VMON channel.
3725 *
3726 * @details
3727 * Initialize a VMON channel without hysteresis. If the channel supports
3728 * separate rise and fall triggers, both thresholds will be set to the same
3729 * value. The threshold will be converted to a register field value based
3730 * on calibration values from the DI page.
3731 *
3732 * @param[in] vmonInit
3733 * The VMON initialization structure.
3734 ******************************************************************************/
EMU_VmonInit(const EMU_VmonInit_TypeDef * vmonInit)3735 void EMU_VmonInit(const EMU_VmonInit_TypeDef *vmonInit)
3736 {
3737 uint32_t thresholdCoarse, thresholdFine;
3738 uint32_t threshold;
3739
3740 EFM_ASSERT((vmonInit->threshold >= 1620) && (vmonInit->threshold <= 3400));
3741
3742 threshold = vmonCalibratedThreshold(vmonInit->channel, vmonInit->threshold);
3743 thresholdFine = threshold % 10U;
3744 thresholdCoarse = threshold / 10U;
3745
3746 /* Saturate the threshold to maximum values. */
3747 if (thresholdCoarse > 0xFU) {
3748 thresholdCoarse = 0xF;
3749 thresholdFine = 9;
3750 }
3751
3752 switch (vmonInit->channel) {
3753 case emuVmonChannel_AVDD:
3754 EMU->VMONAVDDCTRL = (thresholdCoarse << _EMU_VMONAVDDCTRL_RISETHRESCOARSE_SHIFT)
3755 | (thresholdFine << _EMU_VMONAVDDCTRL_RISETHRESFINE_SHIFT)
3756 | (thresholdCoarse << _EMU_VMONAVDDCTRL_FALLTHRESCOARSE_SHIFT)
3757 | (thresholdFine << _EMU_VMONAVDDCTRL_FALLTHRESFINE_SHIFT)
3758 | (vmonInit->riseWakeup ? EMU_VMONAVDDCTRL_RISEWU : 0U)
3759 | (vmonInit->fallWakeup ? EMU_VMONAVDDCTRL_FALLWU : 0U)
3760 | (vmonInit->enable ? EMU_VMONAVDDCTRL_EN : 0U);
3761 break;
3762 case emuVmonChannel_ALTAVDD:
3763 EMU->VMONALTAVDDCTRL = (thresholdCoarse << _EMU_VMONALTAVDDCTRL_THRESCOARSE_SHIFT)
3764 | (thresholdFine << _EMU_VMONALTAVDDCTRL_THRESFINE_SHIFT)
3765 | (vmonInit->riseWakeup ? EMU_VMONALTAVDDCTRL_RISEWU : 0U)
3766 | (vmonInit->fallWakeup ? EMU_VMONALTAVDDCTRL_FALLWU : 0U)
3767 | (vmonInit->enable ? EMU_VMONALTAVDDCTRL_EN : 0U);
3768 break;
3769 case emuVmonChannel_DVDD:
3770 EMU->VMONDVDDCTRL = (thresholdCoarse << _EMU_VMONDVDDCTRL_THRESCOARSE_SHIFT)
3771 | (thresholdFine << _EMU_VMONDVDDCTRL_THRESFINE_SHIFT)
3772 | (vmonInit->riseWakeup ? EMU_VMONDVDDCTRL_RISEWU : 0U)
3773 | (vmonInit->fallWakeup ? EMU_VMONDVDDCTRL_FALLWU : 0U)
3774 | (vmonInit->enable ? EMU_VMONDVDDCTRL_EN : 0U);
3775 break;
3776 case emuVmonChannel_IOVDD0:
3777 EMU->VMONIO0CTRL = (thresholdCoarse << _EMU_VMONIO0CTRL_THRESCOARSE_SHIFT)
3778 | (thresholdFine << _EMU_VMONIO0CTRL_THRESFINE_SHIFT)
3779 | (vmonInit->retDisable ? EMU_VMONIO0CTRL_RETDIS : 0U)
3780 | (vmonInit->riseWakeup ? EMU_VMONIO0CTRL_RISEWU : 0U)
3781 | (vmonInit->fallWakeup ? EMU_VMONIO0CTRL_FALLWU : 0U)
3782 | (vmonInit->enable ? EMU_VMONIO0CTRL_EN : 0U);
3783 break;
3784 #if defined(_EMU_VMONIO1CTRL_EN_MASK)
3785 case emuVmonChannel_IOVDD1:
3786 EMU->VMONIO1CTRL = (thresholdCoarse << _EMU_VMONIO1CTRL_THRESCOARSE_SHIFT)
3787 | (thresholdFine << _EMU_VMONIO1CTRL_THRESFINE_SHIFT)
3788 | (vmonInit->retDisable ? EMU_VMONIO1CTRL_RETDIS : 0U)
3789 | (vmonInit->riseWakeup ? EMU_VMONIO1CTRL_RISEWU : 0U)
3790 | (vmonInit->fallWakeup ? EMU_VMONIO1CTRL_FALLWU : 0U)
3791 | (vmonInit->enable ? EMU_VMONIO1CTRL_EN : 0U);
3792 break;
3793 #endif
3794 #if defined(_EMU_VMONBUVDDCTRL_EN_MASK)
3795 case emuVmonChannel_BUVDD:
3796 EMU->VMONBUVDDCTRL = (thresholdCoarse << _EMU_VMONBUVDDCTRL_THRESCOARSE_SHIFT)
3797 | (thresholdFine << _EMU_VMONBUVDDCTRL_THRESFINE_SHIFT)
3798 | (vmonInit->riseWakeup ? EMU_VMONBUVDDCTRL_RISEWU : 0U)
3799 | (vmonInit->fallWakeup ? EMU_VMONBUVDDCTRL_FALLWU : 0U)
3800 | (vmonInit->enable ? EMU_VMONBUVDDCTRL_EN : 0U);
3801 break;
3802 #endif
3803 default:
3804 EFM_ASSERT(false);
3805 return;
3806 }
3807 }
3808
3809 /***************************************************************************//**
3810 * @brief
3811 * Initialize a VMON channel with hysteresis (separate rise and fall triggers).
3812 *
3813 * @details
3814 * Initialize a VMON channel which supports hysteresis. The AVDD channel is
3815 * the only channel to support separate rise and fall triggers. The rise and
3816 * fall thresholds will be converted to a register field value based on the
3817 * calibration values from the DI page.
3818 *
3819 * @param[in] vmonInit
3820 * The VMON hysteresis initialization structure.
3821 ******************************************************************************/
EMU_VmonHystInit(const EMU_VmonHystInit_TypeDef * vmonInit)3822 void EMU_VmonHystInit(const EMU_VmonHystInit_TypeDef *vmonInit)
3823 {
3824 uint32_t riseThreshold;
3825 uint32_t fallThreshold;
3826
3827 /* VMON supports voltages between 1620 mV and 3400 mV (inclusive). */
3828 EFM_ASSERT((vmonInit->riseThreshold >= 1620) && (vmonInit->riseThreshold <= 3400));
3829 EFM_ASSERT((vmonInit->fallThreshold >= 1620) && (vmonInit->fallThreshold <= 3400));
3830 /* The fall threshold has to be lower than rise threshold. */
3831 EFM_ASSERT(vmonInit->fallThreshold <= vmonInit->riseThreshold);
3832
3833 riseThreshold = vmonCalibratedThreshold(vmonInit->channel, vmonInit->riseThreshold);
3834 fallThreshold = vmonCalibratedThreshold(vmonInit->channel, vmonInit->fallThreshold);
3835
3836 switch (vmonInit->channel) {
3837 case emuVmonChannel_AVDD:
3838 EMU->VMONAVDDCTRL = ((riseThreshold / 10U) << _EMU_VMONAVDDCTRL_RISETHRESCOARSE_SHIFT)
3839 | ((riseThreshold % 10U) << _EMU_VMONAVDDCTRL_RISETHRESFINE_SHIFT)
3840 | ((fallThreshold / 10U) << _EMU_VMONAVDDCTRL_FALLTHRESCOARSE_SHIFT)
3841 | ((fallThreshold % 10U) << _EMU_VMONAVDDCTRL_FALLTHRESFINE_SHIFT)
3842 | (vmonInit->riseWakeup ? EMU_VMONAVDDCTRL_RISEWU : 0U)
3843 | (vmonInit->fallWakeup ? EMU_VMONAVDDCTRL_FALLWU : 0U)
3844 | (vmonInit->enable ? EMU_VMONAVDDCTRL_EN : 0U);
3845 break;
3846 default:
3847 EFM_ASSERT(false);
3848 return;
3849 }
3850 }
3851
3852 /***************************************************************************//**
3853 * @brief
3854 * Enable or disable a VMON channel.
3855 *
3856 * @param[in] channel
3857 * A VMON channel to enable/disable.
3858 *
3859 * @param[in] enable
3860 * Indicates whether to enable or disable.
3861 ******************************************************************************/
EMU_VmonEnable(EMU_VmonChannel_TypeDef channel,bool enable)3862 void EMU_VmonEnable(EMU_VmonChannel_TypeDef channel, bool enable)
3863 {
3864 uint32_t volatile * reg;
3865 uint32_t bit;
3866
3867 switch (channel) {
3868 case emuVmonChannel_AVDD:
3869 reg = &(EMU->VMONAVDDCTRL);
3870 bit = _EMU_VMONAVDDCTRL_EN_SHIFT;
3871 break;
3872 case emuVmonChannel_ALTAVDD:
3873 reg = &(EMU->VMONALTAVDDCTRL);
3874 bit = _EMU_VMONALTAVDDCTRL_EN_SHIFT;
3875 break;
3876 case emuVmonChannel_DVDD:
3877 reg = &(EMU->VMONDVDDCTRL);
3878 bit = _EMU_VMONDVDDCTRL_EN_SHIFT;
3879 break;
3880 case emuVmonChannel_IOVDD0:
3881 reg = &(EMU->VMONIO0CTRL);
3882 bit = _EMU_VMONIO0CTRL_EN_SHIFT;
3883 break;
3884 #if defined(_EMU_VMONIO1CTRL_EN_MASK)
3885 case emuVmonChannel_IOVDD1:
3886 reg = &(EMU->VMONIO1CTRL);
3887 bit = _EMU_VMONIO1CTRL_EN_SHIFT;
3888 break;
3889 #endif
3890 #if defined(_EMU_VMONBUVDDCTRL_EN_MASK)
3891 case emuVmonChannel_BUVDD:
3892 reg = &(EMU->VMONBUVDDCTRL);
3893 bit = _EMU_VMONBUVDDCTRL_EN_SHIFT;
3894 break;
3895 #endif
3896 default:
3897 EFM_ASSERT(false);
3898 return;
3899 }
3900
3901 BUS_RegBitWrite(reg, bit, (uint32_t)enable);
3902 }
3903
3904 /***************************************************************************//**
3905 * @brief
3906 * Get the status of a voltage monitor channel.
3907 *
3908 * @param[in] channel
3909 * A VMON channel to get the status for.
3910 *
3911 * @return
3912 * A status of the selected VMON channel. True if the channel is triggered.
3913 ******************************************************************************/
EMU_VmonChannelStatusGet(EMU_VmonChannel_TypeDef channel)3914 bool EMU_VmonChannelStatusGet(EMU_VmonChannel_TypeDef channel)
3915 {
3916 uint32_t bit;
3917 switch (channel) {
3918 case emuVmonChannel_AVDD:
3919 bit = _EMU_STATUS_VMONAVDD_SHIFT;
3920 break;
3921 case emuVmonChannel_ALTAVDD:
3922 bit = _EMU_STATUS_VMONALTAVDD_SHIFT;
3923 break;
3924 case emuVmonChannel_DVDD:
3925 bit = _EMU_STATUS_VMONDVDD_SHIFT;
3926 break;
3927 case emuVmonChannel_IOVDD0:
3928 bit = _EMU_STATUS_VMONIO0_SHIFT;
3929 break;
3930 #if defined(_EMU_VMONIO1CTRL_EN_MASK)
3931 case emuVmonChannel_IOVDD1:
3932 bit = _EMU_STATUS_VMONIO1_SHIFT;
3933 break;
3934 #endif
3935 #if defined(_EMU_VMONBUVDDCTRL_EN_MASK)
3936 case emuVmonChannel_BUVDD:
3937 bit = _EMU_STATUS_VMONBUVDD_SHIFT;
3938 break;
3939 #endif
3940 default:
3941 bit = 0;
3942 EFM_ASSERT(false);
3943 break;
3944 }
3945
3946 return BUS_RegBitRead(&EMU->STATUS, bit) != 0U;
3947 }
3948 #endif /* EMU_STATUS_VMONRDY */
3949
3950 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
3951 /***************************************************************************//**
3952 * @brief
3953 * Adjust the bias refresh rate.
3954 *
3955 * @details
3956 * This function is only meant to be used under high-temperature operation on
3957 * EFR32xG1 and EFM32xG1 devices. Adjusting the bias mode will
3958 * increase the typical current consumption. See application note 1027
3959 * and errata documents for more details.
3960 *
3961 * @param [in] mode
3962 * The new bias refresh rate.
3963 ******************************************************************************/
EMU_SetBiasMode(EMU_BiasMode_TypeDef mode)3964 void EMU_SetBiasMode(EMU_BiasMode_TypeDef mode)
3965 {
3966 uint32_t freq = 0x2u;
3967 bool emuTestLocked = false;
3968
3969 if (mode == emuBiasMode_1KHz) {
3970 freq = 0x0u;
3971 }
3972
3973 if (EMU_TESTLOCK == 0x1u) {
3974 emuTestLocked = true;
3975 EMU_TESTLOCK = 0xADE8u;
3976 }
3977
3978 if (mode == emuBiasMode_Continuous) {
3979 EMU_BIASCONF &= ~0x74u;
3980 } else {
3981 EMU_BIASCONF |= 0x74u;
3982 }
3983
3984 EMU_BIASTESTCTRL |= 0x8u;
3985 CMU_ULFRCOCTRL = (CMU_ULFRCOCTRL & ~0xC00u)
3986 | ((freq & 0x3u) << 10u);
3987 EMU_BIASTESTCTRL &= ~0x8u;
3988
3989 if (emuTestLocked) {
3990 EMU_TESTLOCK = 0u;
3991 }
3992 }
3993 #endif
3994
3995 #if defined(_EMU_TEMP_TEMP_MASK)
3996 /***************************************************************************//**
3997 * @brief
3998 * Get temperature in degrees Celsius
3999 *
4000 * @return
4001 * Temperature in degrees Celsius
4002 ******************************************************************************/
EMU_TemperatureGet(void)4003 float EMU_TemperatureGet(void)
4004 {
4005 #if defined(_EMU_TEMP_TEMPLSB_MASK)
4006 return ((float) ((EMU->TEMP & (_EMU_TEMP_TEMP_MASK | _EMU_TEMP_TEMPLSB_MASK) )
4007 >> _EMU_TEMP_TEMPLSB_SHIFT)
4008 ) / 4.0f - EMU_TEMP_ZERO_C_IN_KELVIN;
4009 #else
4010 uint32_t val1;
4011 uint32_t val2;
4012 float tempCo;
4013 uint32_t diTemp, diEmu;
4014
4015 // Calculate calibration temp based on DI page values
4016 diTemp = ((DEVINFO->CAL & _DEVINFO_CAL_TEMP_MASK) >> _DEVINFO_CAL_TEMP_SHIFT);
4017 diEmu = ((DEVINFO->EMUTEMP & _DEVINFO_EMUTEMP_EMUTEMPROOM_MASK) >> _DEVINFO_EMUTEMP_EMUTEMPROOM_SHIFT);
4018 tempCo = EMU_TEMPCO_CONST + (diEmu / 100.0f);
4019
4020 // Read temperature twice to ensure a stable value
4021 do {
4022 val1 = (EMU->TEMP & _EMU_TEMP_TEMP_MASK)
4023 >> _EMU_TEMP_TEMP_SHIFT;
4024 val2 = (EMU->TEMP & _EMU_TEMP_TEMP_MASK)
4025 >> _EMU_TEMP_TEMP_SHIFT;
4026 } while (val1 != val2);
4027
4028 return diTemp + tempCo * ((int) diEmu - (int) val1);
4029 #endif
4030 }
4031 #endif // defined(_EMU_TEMP_TEMP_MASK)
4032
4033 #if defined(EMU_CTRL_EFPDIRECTMODEEN)
4034 /***************************************************************************//**
4035 * @brief
4036 * Enable/disable EFP Direct Mode.
4037 *
4038 * @param[in] enable
4039 * True to enable direct mode.
4040 ******************************************************************************/
EMU_EFPDirectModeEnable(bool enable)4041 void EMU_EFPDirectModeEnable(bool enable)
4042 {
4043 if (enable) {
4044 EMU->CTRL_SET = EMU_CTRL_EFPDIRECTMODEEN;
4045 } else {
4046 EMU->CTRL_CLR = EMU_CTRL_EFPDIRECTMODEEN;
4047 }
4048 }
4049 #endif
4050
4051 #if defined(EMU_CTRL_EFPDRVDECOUPLE)
4052 /***************************************************************************//**
4053 * @brief
4054 * Set to enable EFP to drive Decouple voltage.
4055 *
4056 * @details
4057 * Once set, internal LDO will be disabled, and the EMU will control EFP for
4058 * voltage-scaling. Note that because this bit disables the internal LDO
4059 * powering the core, it should not be set until after EFP's DECOUPLE output has
4060 * been configured and enabled.
4061 *
4062 * @param[in] enable
4063 * True to enable EFP to drive Decouple voltage.
4064 ******************************************************************************/
EMU_EFPDriveDecoupleSet(bool enable)4065 void EMU_EFPDriveDecoupleSet(bool enable)
4066 {
4067 if (enable) {
4068 EMU->CTRL_SET = EMU_CTRL_EFPDRVDECOUPLE;
4069 } else {
4070 EMU->CTRL_CLR = EMU_CTRL_EFPDRVDECOUPLE;
4071 }
4072 }
4073 #endif
4074
4075 #if defined(EMU_CTRL_EFPDRVDVDD)
4076 /***************************************************************************//**
4077 * @brief
4078 * Set to enable EFP to drive DVDD voltage.
4079 *
4080 * @details
4081 * Set this if EFP's DCDC output is powering DVDD supply. This mode assumes that
4082 * internal DCDC is not being used.
4083 *
4084 * @param[in] enable
4085 * True to enable EFP to drive DVDD voltage.
4086 ******************************************************************************/
EMU_EFPDriveDvddSet(bool enable)4087 void EMU_EFPDriveDvddSet(bool enable)
4088 {
4089 if (enable) {
4090 EMU->CTRL_SET = EMU_CTRL_EFPDRVDVDD;
4091 } else {
4092 EMU->CTRL_CLR = EMU_CTRL_EFPDRVDVDD;
4093 }
4094 }
4095 #endif
4096
4097 /** @} (end addtogroup emu) */
4098 #endif /* __EM_EMU_H */
4099