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