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