gecko: service files updated | Update to GSDK 4.4.0

Updated the files present in device_init, hfxo_manager, power_manager and
sleeptimer folder as per latest version of gecko_sdk. Purpose of this PR
is to align the codebase of hal_silabs with gecko_sdk 4.4.0

Signed-off-by: Sateesh Kotapati <sateesh.kotapati@silabs.com>
This commit is contained in:
Sateesh Kotapati 2024-01-19 15:12:28 +05:30 committed by Filip Kokosiński
parent 11ab59175a
commit 2ea874714e
32 changed files with 1968 additions and 843 deletions

View File

@ -68,7 +68,7 @@
// <cmuDPLLLockMode_Freq=> Frequency-Lock Loop
// <cmuDPLLLockMode_Phase=> Phase-Lock Loop
// <i> Default: cmuDPLLLockMode_Freq
#define SL_DEVICE_INIT_DPLL_LOCKMODE cmuDPLLLockMode_Freq
#define SL_DEVICE_INIT_DPLL_LOCKMODE cmuDPLLLockMode_Phase
// <q SL_DEVICE_INIT_DPLL_AUTORECOVER> Automatic Lock Recovery
// <i> Default: 1

View File

@ -0,0 +1,57 @@
/***************************************************************************//**
* @file
* @brief DEVICE_INIT_HFXO Config
*******************************************************************************
* # License
* <b>Copyright 2022 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef SL_DEVICE_INIT_HFXO_CONFIG_H
#define SL_DEVICE_INIT_HFXO_CONFIG_H
// <<< Use Configuration Wizard in Context Menu >>>
// <o SL_DEVICE_INIT_HFXO_MODE> Mode
// <i>
// <cmuHfxoOscMode_Crystal=> Crystal oscillator
// <cmuHfxoOscMode_ExternalSine=> External sine wave
// <i> Default: cmuHfxoOscMode_Crystal
#define SL_DEVICE_INIT_HFXO_MODE cmuHfxoOscMode_Crystal
// <o SL_DEVICE_INIT_HFXO_FREQ> Frequency <38000000-40000000>
// <i> Default: 38400000
#define SL_DEVICE_INIT_HFXO_FREQ 38400000
// <o SL_DEVICE_INIT_HFXO_PRECISION> HFXO precision in PPM <0-65535>
// <i> Default: 50
#define SL_DEVICE_INIT_HFXO_PRECISION 50
// <o SL_DEVICE_INIT_HFXO_CTUNE> CTUNE <0-255>
// <i> Default: 140
#define SL_DEVICE_INIT_HFXO_CTUNE 140
// <<< end of configuration section >>>
#endif // SL_DEVICE_INIT_HFXO_CONFIG_H

View File

@ -0,0 +1,58 @@
/***************************************************************************//**
* @file
* @brief DEVICE_INIT_DCDC Config
*******************************************************************************
* # License
* <b>Copyright 2022 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef SL_DEVICE_INIT_DCDC_CONFIG_H
#define SL_DEVICE_INIT_DCDC_CONFIG_H
// <<< Use Configuration Wizard in Context Menu >>>
// <q SL_DEVICE_INIT_DCDC_ENABLE> Enable DC/DC Converter
// <i>
// <i> Default: 1
#define SL_DEVICE_INIT_DCDC_ENABLE 1
// <q SL_DEVICE_INIT_DCDC_BYPASS> Set DC/DC Converter in Bypass Mode
// <i>
// <i> Default: 0
#define SL_DEVICE_INIT_DCDC_BYPASS 0
// <q SL_DEVICE_INIT_DCDC_PFMX_IPKVAL_OVERRIDE> Override for DCDC PFMX Mode Peak Current Setting
// <i>
// <i> Default: 1
#define SL_DEVICE_INIT_DCDC_PFMX_IPKVAL_OVERRIDE 1
// <o SL_DEVICE_INIT_DCDC_PFMX_IPKVAL> DCDC PFMX Mode Peak Current Setting <0-15>
// <i>
// <i> Default: DCDC_PFMXCTRL_IPKVAL_DEFAULT
#define SL_DEVICE_INIT_DCDC_PFMX_IPKVAL 12
// <<< end of configuration section >>>
#endif // SL_DEVICE_INIT_DCDC_CONFIG_H

View File

@ -0,0 +1,58 @@
/***************************************************************************//**
* @file
* @brief DEVICE_INIT_DCDC Config
*******************************************************************************
* # License
* <b>Copyright 2022 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef SL_DEVICE_INIT_DCDC_CONFIG_H
#define SL_DEVICE_INIT_DCDC_CONFIG_H
// <<< Use Configuration Wizard in Context Menu >>>
// <q SL_DEVICE_INIT_DCDC_ENABLE> Enable DC/DC Converter
// <i>
// <i> Default: 1
#define SL_DEVICE_INIT_DCDC_ENABLE 1
// <q SL_DEVICE_INIT_DCDC_BYPASS> Set DC/DC Converter in Bypass Mode
// <i>
// <i> Default: 0
#define SL_DEVICE_INIT_DCDC_BYPASS 0
// <q SL_DEVICE_INIT_DCDC_PFMX_IPKVAL_OVERRIDE> Override for DCDC PFMX Mode Peak Current Setting
// <i>
// <i> Default: 1
#define SL_DEVICE_INIT_DCDC_PFMX_IPKVAL_OVERRIDE 1
// <o SL_DEVICE_INIT_DCDC_PFMX_IPKVAL> DCDC PFMX Mode Peak Current Setting <0-15>
// <i>
// <i> Default: DCDC_PFMXCTRL_IPKVAL_DEFAULT
#define SL_DEVICE_INIT_DCDC_PFMX_IPKVAL 9
// <<< end of configuration section >>>
#endif // SL_DEVICE_INIT_DCDC_CONFIG_H

View File

@ -68,7 +68,7 @@
// <cmuDPLLLockMode_Freq=> Frequency-Lock Loop
// <cmuDPLLLockMode_Phase=> Phase-Lock Loop
// <i> Default: cmuDPLLLockMode_Freq
#define SL_DEVICE_INIT_DPLL_LOCKMODE cmuDPLLLockMode_Freq
#define SL_DEVICE_INIT_DPLL_LOCKMODE cmuDPLLLockMode_Phase
// <q SL_DEVICE_INIT_DPLL_AUTORECOVER> Automatic Lock Recovery
// <i> Default: 1

View File

@ -0,0 +1,57 @@
/***************************************************************************//**
* @file
* @brief DEVICE_INIT_HFXO Config
*******************************************************************************
* # License
* <b>Copyright 2022 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef SL_DEVICE_INIT_HFXO_CONFIG_H
#define SL_DEVICE_INIT_HFXO_CONFIG_H
// <<< Use Configuration Wizard in Context Menu >>>
// <o SL_DEVICE_INIT_HFXO_MODE> Mode
// <i>
// <cmuHfxoOscMode_Crystal=> Crystal oscillator
// <cmuHfxoOscMode_ExternalSine=> External sine wave
// <i> Default: cmuHfxoOscMode_Crystal
#define SL_DEVICE_INIT_HFXO_MODE cmuHfxoOscMode_Crystal
// <o SL_DEVICE_INIT_HFXO_FREQ> Frequency <38000000-40000000>
// <i> Default: 39000000
#define SL_DEVICE_INIT_HFXO_FREQ 39000000
// <o SL_DEVICE_INIT_HFXO_PRECISION> HFXO precision in PPM <0-65535>
// <i> Default: 50
#define SL_DEVICE_INIT_HFXO_PRECISION 50
// <o SL_DEVICE_INIT_HFXO_CTUNE> CTUNE <0-255>
// <i> Default: 140
#define SL_DEVICE_INIT_HFXO_CTUNE 140
// <<< end of configuration section >>>
#endif // SL_DEVICE_INIT_HFXO_CONFIG_H

View File

@ -0,0 +1,72 @@
/***************************************************************************//**
* @file
* @brief DEVICE_INIT_DCDC Config
*******************************************************************************
* # License
* <b>Copyright 2022 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef SL_DEVICE_INIT_DCDC_CONFIG_H
#define SL_DEVICE_INIT_DCDC_CONFIG_H
#include "sl_device_init_dcdc.h"
#include "em_device.h"
// <<< Use Configuration Wizard in Context Menu >>>
// <q SL_DEVICE_INIT_DCDC_ENABLE> Enable DC/DC Converter
// <i>
// <i> Default: 1
#define SL_DEVICE_INIT_DCDC_ENABLE 1
// <o SL_DEVICE_INIT_DCDC_TYPE> DC/DC Type
// <SL_DEVICE_INIT_DCDC_TYPE_BUCK=> Buck
// <SL_DEVICE_INIT_DCDC_TYPE_BOOST=> Boost
// <i>
// <i> Default: SL_DEVICE_INIT_DCDC_TYPE_BUCK
#define SL_DEVICE_INIT_DCDC_TYPE SL_DEVICE_INIT_DCDC_TYPE_BOOST
// <h> DC/DC Buck Settings
// <q SL_DEVICE_INIT_DCDC_BYPASS> Set DC/DC Converter in Bypass Mode
// <i>
// <i> Default: 0
#define SL_DEVICE_INIT_DCDC_BYPASS 0
// <q SL_DEVICE_INIT_DCDC_PFMX_IPKVAL_OVERRIDE> Override for DCDC PFMX Mode Peak Current Setting
// <i>
// <i> Default: 0
#define SL_DEVICE_INIT_DCDC_PFMX_IPKVAL_OVERRIDE 0
// <o SL_DEVICE_INIT_DCDC_PFMX_IPKVAL> DCDC PFMX Mode Peak Current Setting <0-15>
// <i>
// <i> Default: DCDC_PFMXCTRL_IPKVAL_DEFAULT
#define SL_DEVICE_INIT_DCDC_PFMX_IPKVAL DCDC_PFMXCTRL_IPKVAL_DEFAULT
// </h>
// <<< end of configuration section >>>
#endif // SL_DEVICE_INIT_DCDC_CONFIG_H

View File

@ -0,0 +1,72 @@
/***************************************************************************//**
* @file
* @brief DEVICE_INIT_DCDC Config
*******************************************************************************
* # License
* <b>Copyright 2022 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef SL_DEVICE_INIT_DCDC_CONFIG_H
#define SL_DEVICE_INIT_DCDC_CONFIG_H
#include "sl_device_init_dcdc.h"
#include "em_device.h"
// <<< Use Configuration Wizard in Context Menu >>>
// <q SL_DEVICE_INIT_DCDC_ENABLE> Enable DC/DC Converter
// <i>
// <i> Default: 1
#define SL_DEVICE_INIT_DCDC_ENABLE 1
// <o SL_DEVICE_INIT_DCDC_TYPE> DC/DC Type
// <SL_DEVICE_INIT_DCDC_TYPE_BUCK=> Buck
// <SL_DEVICE_INIT_DCDC_TYPE_BOOST=> Boost
// <i>
// <i> Default: SL_DEVICE_INIT_DCDC_TYPE_BUCK
#define SL_DEVICE_INIT_DCDC_TYPE SL_DEVICE_INIT_DCDC_TYPE_BUCK
// <h> DC/DC Buck Settings
// <q SL_DEVICE_INIT_DCDC_BYPASS> Set DC/DC Converter in Bypass Mode
// <i>
// <i> Default: 0
#define SL_DEVICE_INIT_DCDC_BYPASS 0
// <q SL_DEVICE_INIT_DCDC_PFMX_IPKVAL_OVERRIDE> Override for DCDC PFMX Mode Peak Current Setting
// <i>
// <i> Default: 0
#define SL_DEVICE_INIT_DCDC_PFMX_IPKVAL_OVERRIDE 0
// <o SL_DEVICE_INIT_DCDC_PFMX_IPKVAL> DCDC PFMX Mode Peak Current Setting <0-15>
// <i>
// <i> Default: DCDC_PFMXCTRL_IPKVAL_DEFAULT
#define SL_DEVICE_INIT_DCDC_PFMX_IPKVAL DCDC_PFMXCTRL_IPKVAL_DEFAULT
// </h>
// <<< end of configuration section >>>
#endif // SL_DEVICE_INIT_DCDC_CONFIG_H

View File

@ -68,7 +68,7 @@
// <cmuDPLLLockMode_Freq=> Frequency-Lock Loop
// <cmuDPLLLockMode_Phase=> Phase-Lock Loop
// <i> Default: cmuDPLLLockMode_Freq
#define SL_DEVICE_INIT_DPLL_LOCKMODE cmuDPLLLockMode_Freq
#define SL_DEVICE_INIT_DPLL_LOCKMODE cmuDPLLLockMode_Phase
// <q SL_DEVICE_INIT_DPLL_AUTORECOVER> Automatic Lock Recovery
// <i> Default: 1

View File

@ -0,0 +1,57 @@
/***************************************************************************//**
* @file
* @brief DEVICE_INIT_HFXO Config
*******************************************************************************
* # License
* <b>Copyright 2022 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef SL_DEVICE_INIT_HFXO_CONFIG_H
#define SL_DEVICE_INIT_HFXO_CONFIG_H
// <<< Use Configuration Wizard in Context Menu >>>
// <o SL_DEVICE_INIT_HFXO_MODE> Mode
// <i>
// <cmuHfxoOscMode_Crystal=> Crystal oscillator
// <cmuHfxoOscMode_ExternalSine=> External sine wave
// <i> Default: cmuHfxoOscMode_Crystal
#define SL_DEVICE_INIT_HFXO_MODE cmuHfxoOscMode_Crystal
// <o SL_DEVICE_INIT_HFXO_FREQ> Frequency <38000000-40000000>
// <i> Default: 38400000
#define SL_DEVICE_INIT_HFXO_FREQ 38400000
// <o SL_DEVICE_INIT_HFXO_PRECISION> HFXO precision in PPM <0-65535>
// <i> Default: 50
#define SL_DEVICE_INIT_HFXO_PRECISION 50
// <o SL_DEVICE_INIT_HFXO_CTUNE> CTUNE <0-255>
// <i> Default: 140
#define SL_DEVICE_INIT_HFXO_CTUNE 140
// <<< end of configuration section >>>
#endif // SL_DEVICE_INIT_HFXO_CONFIG_H

View File

@ -32,6 +32,10 @@
#include "sl_status.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup device_init
* @{
@ -54,6 +58,13 @@
* @{
*/
// -----------------------------------------------------------------------------
// Defines
/// @brief DC/DC Converter Type
#define SL_DEVICE_INIT_DCDC_TYPE_BUCK 0 ///< Buck Type
#define SL_DEVICE_INIT_DCDC_TYPE_BOOST 1 ///< Boost Type
/**
* Initialize DCDC
*
@ -70,4 +81,8 @@ sl_status_t sl_device_init_dcdc(void);
* @} device_init
*/
#ifdef __cplusplus
}
#endif
#endif // SL_DEVICE_INIT_DCDC_H

View File

@ -32,6 +32,10 @@
#include "sl_status.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup device_init
* @{
@ -67,4 +71,8 @@ sl_status_t sl_device_init_dpll(void);
* @} device_init
*/
#ifdef __cplusplus
}
#endif
#endif // SL_DEVICE_INIT_DPLL_H

View File

@ -32,6 +32,10 @@
#include "sl_status.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup device_init
* @{
@ -63,4 +67,8 @@ sl_status_t sl_device_init_hfrco(void);
* @} device_init
*/
#ifdef __cplusplus
}
#endif
#endif // SL_DEVICE_INIT_HFRCO_H

View File

@ -32,6 +32,10 @@
#include "sl_status.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup device_init
* @{
@ -77,4 +81,8 @@ sl_status_t sl_device_init_hfxo(void);
* @} device_init
*/
#ifdef __cplusplus
}
#endif
#endif // SL_DEVICE_INIT_HFXO_H

View File

@ -32,6 +32,10 @@
#include "sl_status.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup device_init
* @{
@ -67,4 +71,8 @@ sl_status_t sl_device_init_lfrco(void);
* @} device_init
*/
#ifdef __cplusplus
}
#endif
#endif // SL_DEVICE_INIT_LFRCO_H

View File

@ -34,6 +34,7 @@
sl_status_t sl_device_init_dcdc(void)
{
#if !defined(SL_DEVICE_INIT_DCDC_TYPE) || (defined(SL_DEVICE_INIT_DCDC_TYPE) && (SL_DEVICE_INIT_DCDC_TYPE == SL_DEVICE_INIT_DCDC_TYPE_BUCK))
#if SL_DEVICE_INIT_DCDC_ENABLE
EMU_DCDCInit_TypeDef dcdcInit = EMU_DCDCINIT_DEFAULT;
#if SL_DEVICE_INIT_DCDC_BYPASS
@ -46,6 +47,11 @@ sl_status_t sl_device_init_dcdc(void)
#else // SL_DEVICE_INIT_DCDC_ENABLE
EMU_DCDCPowerOff();
#endif // SL_DEVICE_INIT_DCDC_ENABLE
#else // SL_DEVICE_INIT_DCDC_TYPE
#if SL_DEVICE_INIT_DCDC_ENABLE
EMU_DCDCBoostInit_TypeDef dcdcBoostInit = EMU_DCDCBOOSTINIT_DEFAULT;
EMU_DCDCBoostInit(&dcdcBoostInit);
#endif
#endif //SL_DEVICE_INIT_DCDC_TYPE
return SL_STATUS_OK;
}

View File

@ -52,7 +52,7 @@ sl_status_t sl_device_init_dpll(void)
// The CMU should not be running from the HFRCO. If necessary, the CMU
// should switch to the FSRCO until after the DPLL has locked to avoid
// over-clocking due to overshoot.
CMU_ClockSelectSet(cmuClock_SYSCLK, cmuSelect_FSRCO);
CMU_CLOCK_SELECT_SET(SYSCLK, FSRCO);
}
#if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
@ -62,7 +62,7 @@ sl_status_t sl_device_init_dpll(void)
bool success = CMU_DPLLLock(&dpll_init);
if (selected_sysclk == cmuSelect_HFRCODPLL) {
CMU_ClockSelectSet(cmuClock_SYSCLK, selected_sysclk);
CMU_CLOCK_SELECT_SET(SYSCLK, HFRCODPLL);
}
if (success) {

View File

@ -41,6 +41,10 @@ sl_status_t sl_device_init_hfxo(void)
CMU_HFXOInit_TypeDef hfxoInit = CMU_HFXOINIT_DEFAULT;
hfxoInit.mode = SL_DEVICE_INIT_HFXO_MODE;
if (SL_DEVICE_INIT_HFXO_MODE == cmuHfxoOscMode_ExternalSine) {
hfxoInit = (CMU_HFXOInit_TypeDef)CMU_HFXOINIT_EXTERNAL_SINE;
}
int ctune = -1;
#if defined(_DEVINFO_MODXOCAL_HFXOCTUNEXIANA_MASK)
@ -72,11 +76,12 @@ sl_status_t sl_device_init_hfxo(void)
} else if (ctune > ((int)(_HFXO_XTALCTRL_CTUNEXOANA_MASK >> _HFXO_XTALCTRL_CTUNEXOANA_SHIFT))) {
ctune = (int)(_HFXO_XTALCTRL_CTUNEXOANA_MASK >> _HFXO_XTALCTRL_CTUNEXOANA_SHIFT);
}
hfxoInit.ctuneXoAna = ctune;
hfxoInit.ctuneXoAna = (uint8_t)ctune;
}
SystemHFXOClockSet(SL_DEVICE_INIT_HFXO_FREQ);
CMU_HFXOInit(&hfxoInit);
CMU_HFXOPrecisionSet(SL_DEVICE_INIT_HFXO_PRECISION);
return SL_STATUS_OK;
}

View File

@ -1,84 +1,102 @@
/***************************************************************************//**
* @file
* @brief HFXO Manager API definition.
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef SLI_HFXO_MANAGER_H
#define SLI_HFXO_MANAGER_H
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* HFXO Manager module hardware specific initialization.
******************************************************************************/
void sli_hfxo_manager_init_hardware(void);
/***************************************************************************//**
* Function to call just before starting HFXO, to save current tick count.
******************************************************************************/
void sli_hfxo_manager_begin_startup_measurement(void);
/***************************************************************************//**
* Function to call just after HFXO becomes ready, to save current tick count
* and calculate HFXO startup time.
******************************************************************************/
void sli_hfxo_manager_end_startup_measurement(void);
/***************************************************************************//**
* Retrieves HFXO startup time average value.
******************************************************************************/
uint32_t sli_hfxo_manager_get_startup_time(void);
/***************************************************************************//**
* Retrieves HFXO startup time latest value.
******************************************************************************/
uint32_t sli_hfxo_manager_get_latest_startup_time(void);
/***************************************************************************//**
* Checks if HFXO is ready and, if needed, waits for it to be.
*
* @param wait True, to wait for HFXO to be ready.
* False, otherwise.
*
* @return True, if HFXO is ready.
* False, otherwise.
*
* @note This will also make sure we are not in the process of restarting HFXO
* with different settings.
******************************************************************************/
bool sli_hfxo_manager_is_hfxo_ready(bool wait);
#ifdef __cplusplus
}
#endif
#endif /* SLI_HFXO_MANAGER_H */
/***************************************************************************//**
* @file
* @brief HFXO Manager API definition.
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef SLI_HFXO_MANAGER_H
#define SLI_HFXO_MANAGER_H
#include <stdbool.h>
#if defined(SL_COMPONENT_CATALOG_PRESENT)
#include "sl_component_catalog.h"
#endif
#if defined(SL_CATALOG_SLEEPTIMER_PRESENT) && defined(SYSRTC_PRESENT)
#include "sli_sleeptimer.h"
#if (SL_SLEEPTIMER_PERIPHERAL == SL_SLEEPTIMER_PERIPHERAL_SYSRTC)
#define HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* HFXO Manager module hardware specific initialization.
******************************************************************************/
void sli_hfxo_manager_init_hardware(void);
/***************************************************************************//**
* Function to call just before starting HFXO, to save current tick count.
******************************************************************************/
void sli_hfxo_manager_begin_startup_measurement(void);
#if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
/***************************************************************************//**
* Function to call when a SYSRTC compare match event produces a PRS signal to
start HFXO.
******************************************************************************/
void sli_hfxo_manager_retrieve_begining_startup_measurement(void);
#endif
/***************************************************************************//**
* Function to call just after HFXO becomes ready, to save current tick count
* and calculate HFXO startup time.
******************************************************************************/
void sli_hfxo_manager_end_startup_measurement(void);
/***************************************************************************//**
* Retrieves HFXO startup time average value.
******************************************************************************/
uint32_t sli_hfxo_manager_get_startup_time(void);
/***************************************************************************//**
* Retrieves HFXO startup time latest value.
******************************************************************************/
uint32_t sli_hfxo_manager_get_latest_startup_time(void);
/***************************************************************************//**
* Checks if HFXO is ready and, if needed, waits for it to be.
*
* @param wait True, to wait for HFXO to be ready.
* False, otherwise.
*
* @return True, if HFXO is ready.
* False, otherwise.
*
* @note This will also make sure we are not in the process of restarting HFXO
* with different settings.
******************************************************************************/
bool sli_hfxo_manager_is_hfxo_ready(bool wait);
#ifdef __cplusplus
}
#endif
#endif /* SLI_HFXO_MANAGER_H */

View File

@ -1,196 +1,235 @@
/***************************************************************************//**
* @file
* @brief HFXO Manager API implementation.
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include "em_device.h"
#include "sl_hfxo_manager.h"
#include "sli_hfxo_manager.h"
#include "sli_hfxo_manager_internal.h"
#include "sl_sleeptimer.h"
#include "sl_assert.h"
#include "sl_status.h"
#include <stdbool.h>
/*******************************************************************************
********************************* DEFINES *********************************
******************************************************************************/
// Table size of HFXO wake-up time measurement
#define HFXO_STARTUP_TIME_TABLE_SIZE 10
// Default time value in microseconds required to wake-up the hfxo oscillator.
#define HFXO_STARTUP_TIME_DEFAULT_VALUE_US (600u)
/*******************************************************************************
***************************** DATA TYPES **********************************
******************************************************************************/
/*******************************************************************************
*************************** LOCAL VARIABLES ********************************
******************************************************************************/
// Time in ticks required for HFXO start-up after wake-up from sleep.
static uint32_t hfxo_startup_time_tick = 0;
static uint32_t hfxo_last_startup_time = 0;
static uint32_t hfxo_startup_time_table[HFXO_STARTUP_TIME_TABLE_SIZE];
static uint8_t hfxo_startup_time_table_index = 0;
static uint32_t hfxo_startup_time_sum_average = 0;
static uint32_t hfxo_startup_time_tc_inital = 0;
static bool hfxo_measurement_on = false;
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* HFXO Manager module hardware specific initialization.
******************************************************************************/
void sl_hfxo_manager_init_hardware(void)
{
sli_hfxo_manager_init_hardware();
}
/***************************************************************************//**
* Initialize HFXO Manager module.
******************************************************************************/
sl_status_t sl_hfxo_manager_init(void)
{
sl_status_t status;
// Initialize Sleeptimer module in case not already done.
status = sl_sleeptimer_init();
if (status != SL_STATUS_OK) {
return status;
}
// Set HFXO startup time to conservative default value
hfxo_startup_time_tick = (((HFXO_STARTUP_TIME_DEFAULT_VALUE_US * sl_sleeptimer_get_timer_frequency()) + (1000000 - 1)) / 1000000);
for (uint8_t i = 0; i < HFXO_STARTUP_TIME_TABLE_SIZE; i++) {
hfxo_startup_time_table[i] = hfxo_startup_time_tick;
hfxo_startup_time_sum_average += hfxo_startup_time_tick;
}
return SL_STATUS_OK;
}
/***************************************************************************//**
* Updates Sleepy Crystal settings.
*
* @param settings Pointer to settings structure
*
* @return Status Code.
*
* @note Those settings are temporarily used to force oscillation on sleepy
* crystal.
* Default values should be enough to wake-up sleepy crystals. Otherwise,
* this function can be used.
******************************************************************************/
sl_status_t sl_hfxo_manager_update_sleepy_xtal_settings(sl_hfxo_manager_sleepy_xtal_settings_t *settings)
{
return sli_hfxo_manager_update_sleepy_xtal_settings_hardware(settings);
}
/***************************************************************************//**
* When this callback function is called, it means that HFXO failed twice in
* a row to start with normal configurations. This may mean that there is a
* bad crystal. When getting this callback, HFXO is running but its properties
* (frequency, precision) are not guaranteed. This should be considered as an
* error situation.
******************************************************************************/
__WEAK void sl_hfxo_manager_notify_consecutive_failed_startups(void)
{
EFM_ASSERT(false);
}
/*******************************************************************************
********************** GLOBAL INTERNAL FUNCTIONS **************************
******************************************************************************/
/***************************************************************************//**
* Function to call just before starting HFXO, to save current tick count.
******************************************************************************/
void sli_hfxo_manager_begin_startup_measurement(void)
{
hfxo_measurement_on = true;
hfxo_startup_time_tc_inital = sl_sleeptimer_get_tick_count();
}
/***************************************************************************//**
* Function to call just after HFXO becomes ready, to save current tick count
* and calculate HFXO startup time.
******************************************************************************/
void sli_hfxo_manager_end_startup_measurement(void)
{
if (hfxo_measurement_on == false) {
return;
}
// Complete HFXO restore time measurement
hfxo_last_startup_time = sl_sleeptimer_get_tick_count() - hfxo_startup_time_tc_inital;
// With low precision clock, the HFXO startup time measure could be zero.
// In that case, ensure it's a least 1 tick.
hfxo_last_startup_time = (hfxo_last_startup_time == 0) ? 1 : hfxo_last_startup_time;
// Calculate average for HFXO restore time
hfxo_startup_time_sum_average -= (int32_t)hfxo_startup_time_table[hfxo_startup_time_table_index] - (int32_t)hfxo_last_startup_time;
hfxo_startup_time_table[hfxo_startup_time_table_index] = hfxo_last_startup_time;
hfxo_startup_time_tick = ((hfxo_startup_time_sum_average + (HFXO_STARTUP_TIME_TABLE_SIZE - 1) ) / HFXO_STARTUP_TIME_TABLE_SIZE);
// Update index of wakeup time table
hfxo_startup_time_table_index++;
hfxo_startup_time_table_index %= HFXO_STARTUP_TIME_TABLE_SIZE;
hfxo_measurement_on = false;
}
/***************************************************************************//**
* Retrieves HFXO startup time average value.
*
* @return HFXO startup time average value.
******************************************************************************/
uint32_t sli_hfxo_manager_get_startup_time(void)
{
return hfxo_startup_time_tick;
}
/***************************************************************************//**
* Retrieves HFXO startup time latest value.
*
* @return HFXO startup time latest value.
******************************************************************************/
uint32_t sli_hfxo_manager_get_latest_startup_time(void)
{
return hfxo_last_startup_time;
}
/***************************************************************************//**
* @file
* @brief HFXO Manager API implementation.
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include "em_device.h"
#include "sl_hfxo_manager.h"
#include "sli_hfxo_manager.h"
#include "sli_hfxo_manager_internal.h"
#include "sl_sleeptimer.h"
#include "sl_assert.h"
#include "sl_status.h"
#include <stdbool.h>
/*******************************************************************************
********************************* DEFINES *********************************
******************************************************************************/
// Table size of HFXO wake-up time measurement
#define HFXO_STARTUP_TIME_TABLE_SIZE 10
// Default time value in microseconds required to wake-up the hfxo oscillator.
#define HFXO_STARTUP_TIME_DEFAULT_VALUE_US (600u)
/*******************************************************************************
***************************** DATA TYPES **********************************
******************************************************************************/
/*******************************************************************************
*************************** LOCAL VARIABLES ********************************
******************************************************************************/
// Time in ticks required for HFXO start-up after wake-up from sleep.
static uint32_t hfxo_startup_time_tick = 0;
static uint32_t hfxo_last_startup_time = 0;
static uint32_t hfxo_startup_time_table[HFXO_STARTUP_TIME_TABLE_SIZE];
static uint8_t hfxo_startup_time_table_index = 0;
static uint32_t hfxo_startup_time_sum_average = 0;
static uint32_t hfxo_startup_time_tc_initial = 0;
static bool hfxo_measurement_on = false;
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* HFXO Manager module hardware specific initialization.
******************************************************************************/
void sl_hfxo_manager_init_hardware(void)
{
sli_hfxo_manager_init_hardware();
}
/***************************************************************************//**
* Initialize HFXO Manager module.
******************************************************************************/
sl_status_t sl_hfxo_manager_init(void)
{
sl_status_t status;
// Initialize Sleeptimer module in case not already done.
status = sl_sleeptimer_init();
if (status != SL_STATUS_OK) {
return status;
}
#if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
// Additional Sleeptimer HW configuration if SYSRTC is used
sli_sleeptimer_hal_hfxo_manager_integration_init();
#endif
// Set HFXO startup time to conservative default value
hfxo_startup_time_tick = (((HFXO_STARTUP_TIME_DEFAULT_VALUE_US * sl_sleeptimer_get_timer_frequency()) + (1000000 - 1)) / 1000000);
for (uint8_t i = 0; i < HFXO_STARTUP_TIME_TABLE_SIZE; i++) {
hfxo_startup_time_table[i] = hfxo_startup_time_tick;
hfxo_startup_time_sum_average += hfxo_startup_time_tick;
}
return SL_STATUS_OK;
}
/***************************************************************************//**
* Updates Sleepy Crystal settings.
*
* @param settings Pointer to settings structure
*
* @return Status Code.
*
* @note Those settings are temporarily used to force oscillation on sleepy
* crystal.
* Default values should be enough to wake-up sleepy crystals. Otherwise,
* this function can be used.
******************************************************************************/
sl_status_t sl_hfxo_manager_update_sleepy_xtal_settings(sl_hfxo_manager_sleepy_xtal_settings_t *settings)
{
return sli_hfxo_manager_update_sleepy_xtal_settings_hardware(settings);
}
/***************************************************************************//**
* When this callback function is called, it means that HFXO failed twice in
* a row to start with normal configurations. This may mean that there is a
* bad crystal. When getting this callback, HFXO is running but its properties
* (frequency, precision) are not guaranteed. This should be considered as an
* error situation.
******************************************************************************/
__WEAK void sl_hfxo_manager_notify_consecutive_failed_startups(void)
{
EFM_ASSERT(false);
}
/*******************************************************************************
********************** GLOBAL INTERNAL FUNCTIONS **************************
******************************************************************************/
/***************************************************************************//**
* Function to call just before starting HFXO, to save current tick count.
******************************************************************************/
void sli_hfxo_manager_begin_startup_measurement(void)
{
hfxo_measurement_on = true;
hfxo_startup_time_tc_initial = sl_sleeptimer_get_tick_count();
}
#if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
/***************************************************************************//**
* Function to retrieve the capture channel value that was saved when
* HFXO became enabled.
*
* @note SYSRTC Capture channel is used to save when HFXO becomes enabled.
* The HFXO startup measurement will only be done based on the capture
* channel if the capture value is valid.
******************************************************************************/
void sli_hfxo_manager_retrieve_begining_startup_measurement(void)
{
// ULFRCO does not have the precision to measure the HFXO startup time.
// So just return if ULFRCO is used as source oscillator.
if (sl_sleeptimer_get_timer_frequency() <= SystemULFRCOClockGet()) {
return;
}
uint32_t startup_time = sli_sleeptimer_get_capture();
if (startup_time != 0) {
hfxo_startup_time_tc_initial = startup_time;
hfxo_measurement_on = true;
}
}
#endif
/***************************************************************************//**
* Function to call just after HFXO becomes ready, to save current tick count
* and calculate HFXO startup time.
******************************************************************************/
void sli_hfxo_manager_end_startup_measurement(void)
{
uint32_t default_startup_ticks;
if (hfxo_measurement_on == false) {
return;
}
hfxo_last_startup_time = sl_sleeptimer_get_tick_count() - hfxo_startup_time_tc_initial;
// With low precision clock, the HFXO startup time measure could be zero.
// In that case, ensure it's a least 1 tick.
hfxo_last_startup_time = (hfxo_last_startup_time == 0) ? 1 : hfxo_last_startup_time;
// Skip measurement if value is out of bound
default_startup_ticks = (((HFXO_STARTUP_TIME_DEFAULT_VALUE_US * sl_sleeptimer_get_timer_frequency()) + (1000000 - 1)) / 1000000);
EFM_ASSERT(hfxo_last_startup_time <= default_startup_ticks);
if (hfxo_last_startup_time > default_startup_ticks) {
hfxo_measurement_on = false;
return;
}
// Calculate average for HFXO restore time
hfxo_startup_time_sum_average -= (int32_t)hfxo_startup_time_table[hfxo_startup_time_table_index] - (int32_t)hfxo_last_startup_time;
hfxo_startup_time_table[hfxo_startup_time_table_index] = hfxo_last_startup_time;
hfxo_startup_time_tick = ((hfxo_startup_time_sum_average + (HFXO_STARTUP_TIME_TABLE_SIZE - 1) ) / HFXO_STARTUP_TIME_TABLE_SIZE);
// Update index of wakeup time table
hfxo_startup_time_table_index++;
hfxo_startup_time_table_index %= HFXO_STARTUP_TIME_TABLE_SIZE;
hfxo_measurement_on = false;
}
/***************************************************************************//**
* Retrieves HFXO startup time average value.
*
* @return HFXO startup time average value.
******************************************************************************/
uint32_t sli_hfxo_manager_get_startup_time(void)
{
return hfxo_startup_time_tick;
}
/***************************************************************************//**
* Retrieves HFXO startup time latest value.
*
* @return HFXO startup time latest value.
******************************************************************************/
uint32_t sli_hfxo_manager_get_latest_startup_time(void)
{
return hfxo_last_startup_time;
}

View File

@ -1,365 +1,407 @@
/***************************************************************************//**
* @file
* @brief HFXO Manager HAL series 2 Devices.
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include "em_device.h"
#if defined(_SILICON_LABS_32B_SERIES_2)
#include "sl_assert.h"
#include "sli_hfxo_manager.h"
#include "sl_hfxo_manager.h"
#include "sl_hfxo_manager_config.h"
#include "sl_status.h"
#include <stdbool.h>
/*******************************************************************************
********************************* DEFINES *********************************
******************************************************************************/
// Defines for hidden field FORCERAWCLK in HFXO_CTRL register
#define _HFXO_MANAGER_CTRL_FORCERAWCLK_SHIFT 31
#define _HFXO_MANAGER_CTRL_FORCERAWCLK_MASK 0x80000000UL
#define HFXO_MANAGER_CTRL_FORCERAWCLK (0x1UL << _HFXO_MANAGER_CTRL_FORCERAWCLK_SHIFT)
// Defines for hidden PKDETCTRL register
#ifndef _HFXO_PKDETCTRL_MASK
#if (_SILICON_LABS_32B_SERIES_2_CONFIG <= 2)
#define PKDETCTRL RESERVED4[2]
#else
#define PKDETCTRL RESERVED3[0]
#endif
#endif
#define _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT 8
#define _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK 0xF00UL
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V105MV (0x00000000UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V132MV (0x00000001UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V157MV (0x00000002UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V184MV (0x00000003UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V210MV (0x00000004UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V236MV (0x00000005UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V262MV (0x00000006UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V289MV (0x00000007UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V315MV (0x00000008UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V341MV (0x00000009UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V367MV (0x0000000AUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V394MV (0x0000000BUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V420MV (0x0000000CUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V446MV (0x0000000DUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V472MV (0x0000000EUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V499MV (0x0000000FUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
// IRQ Name depending on devices
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
#define HFXO_IRQ_NUMBER HFXO00_IRQn
#define HFXO_IRQ_HANDLER_FUNCTION HFXO00_IRQHandler
#else
#define HFXO_IRQ_NUMBER HFXO0_IRQn
#define HFXO_IRQ_HANDLER_FUNCTION HFXO0_IRQHandler
#endif
// Default values for the Sleepy Crystal settings
// Should be enough to guaranty HFXO startup
#define SLEEPY_XTAL_SETTING_DEFAULT_PKDETTHSTARTUPI HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V157MV
#define SLEEPY_XTAL_SETTING_DEFAULT_CTUNEANA 100u
#define SLEEPY_XTAL_SETTING_DEFAULT_COREBIAS 255u
/*******************************************************************************
*************************** LOCAL VARIABLES ********************************
******************************************************************************/
// Error flag to indicate if we failed the startup process
static bool error_flag = false;
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
// Error retry counter
static uint8_t error_try_cnt = 0;
// Error State status
static bool in_error_state = false;
// Variables to save normal settings
static uint32_t pkdettusstartupi_saved;
static uint32_t ctunexiana_saved;
static uint32_t ctunexoana_saved;
static uint32_t corebiasana_saved;
static uint32_t corebiasstartup_saved;
static uint32_t corebiasstartupi_saved;
// Variables for Sleepy Crystal settings
static uint32_t sleepy_xtal_settings_pkdettusstartupi = SLEEPY_XTAL_SETTING_DEFAULT_PKDETTHSTARTUPI; // Value already shifted
static uint32_t sleepy_xtal_settings_ctuneana = SLEEPY_XTAL_SETTING_DEFAULT_CTUNEANA;
static uint32_t sleepy_xtal_settings_corebias = SLEEPY_XTAL_SETTING_DEFAULT_COREBIAS;
#endif
/***************************************************************************//**
* HFXO ready notification callback for internal use with power manager
******************************************************************************/
__WEAK void sli_hfxo_manager_notify_ready_for_power_manager(void);
/***************************************************************************//**
* Hardware specific initialization.
******************************************************************************/
void sli_hfxo_manager_init_hardware(void)
{
// Increase HFXO Interrupt priority so that it won't be masked by BASEPRI
// and will preempt other interrupts.
NVIC_SetPriority(HFXO_IRQ_NUMBER, 2);
// Enable HFXO Interrupt if HFXO is used
#if _SILICON_LABS_32B_SERIES_2_CONFIG >= 2
CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
#endif
HFXO0->IEN_CLR = HFXO_IEN_RDY | HFXO_IEN_DNSERR | HFXO_IEN_COREBIASOPTERR;
HFXO0->IF_CLR = HFXO_IF_RDY | HFXO_IF_DNSERR | HFXO_IEN_COREBIASOPTERR;
NVIC_ClearPendingIRQ(HFXO_IRQ_NUMBER);
NVIC_EnableIRQ(HFXO_IRQ_NUMBER);
HFXO0->IEN_SET = HFXO_IEN_RDY | HFXO_IEN_DNSERR | HFXO_IEN_COREBIASOPTERR;
}
/***************************************************************************//**
* Updates sleepy crystal settings in specific hardware registers.
******************************************************************************/
sl_status_t sli_hfxo_manager_update_sleepy_xtal_settings_hardware(sl_hfxo_manager_sleepy_xtal_settings_t *settings)
{
(void)settings;
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
EFM_ASSERT(settings->ana_ctune <= (_HFXO_XTALCTRL_CTUNEXIANA_MASK >> _HFXO_XTALCTRL_CTUNEXIANA_SHIFT));
EFM_ASSERT(settings->core_bias_current <= (_HFXO_XTALCTRL_COREBIASANA_MASK >> _HFXO_XTALCTRL_COREBIASANA_SHIFT));
sleepy_xtal_settings_ctuneana = settings->ana_ctune;
sleepy_xtal_settings_corebias = settings->core_bias_current;
return SL_STATUS_OK;
#else
return SL_STATUS_NOT_AVAILABLE;
#endif
}
/***************************************************************************//**
* Checks if HFXO is ready and, if needed, waits for it to be.
*
* @note This will also make sure we are not in the process of restarting HFXO
* with different settings.
******************************************************************************/
bool sli_hfxo_manager_is_hfxo_ready(bool wait)
{
bool ready = false;
do {
ready = (((HFXO0->STATUS & HFXO_STATUS_RDY) != 0) && !error_flag) ? true : false;
} while (!ready && wait);
return ready;
}
#if (SL_HFXO_MANAGER_CUSTOM_HFXO_IRQ_HANDLER == 0)
/*******************************************************************************
* HFXO interrupt handler.
*
* @note The HFXOx_IRQHandler provided by HFXO Manager will call
* @ref sl_hfxo_manager_irq_handler. Configure SL_HFXO_MANAGER_CUSTOM_HFXO_IRQ_HANDLER
* if the application wants to implement its own HFXOx_IRQHandler.
******************************************************************************/
void HFXO_IRQ_HANDLER_FUNCTION(void)
{
sl_hfxo_manager_irq_handler();
}
#endif
/*******************************************************************************
* HFXO Manager HFXO interrupt handler.
******************************************************************************/
void sl_hfxo_manager_irq_handler(void)
{
uint32_t irq_flag = HFXO0->IF;
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
bool disondemand = (HFXO0->CTRL & _HFXO_CTRL_DISONDEMAND_MASK) ? true : false;
bool forceen = (HFXO0->CTRL & _HFXO_CTRL_FORCEEN_MASK) ? true : false;
#endif
// RDY Interrupt Flag Handling
if (irq_flag & HFXO_IF_RDY) {
// Clear Ready flag
HFXO0->IF_CLR = irq_flag & HFXO_IF_RDY;
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
if (error_flag) {
// Clear error flag, i.e. we successfully stated HFXO with the modified settings
error_flag = false;
// If it's the first time we succeed after an error, try back the normal settings
if (error_try_cnt <= 1) {
// Disable HFXO.
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
while ((HFXO0->STATUS & HFXO_STATUS_ENS) != 0) {
}
// Put back normal settings
HFXO0->PKDETCTRL = (HFXO0->PKDETCTRL & ~_HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK) | pkdettusstartupi_saved;
HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~(_HFXO_XTALCTRL_CTUNEXIANA_MASK | _HFXO_XTALCTRL_CTUNEXOANA_MASK))
| ctunexiana_saved
| ctunexoana_saved;
HFXO0->XTALCFG = (HFXO0->XTALCFG & ~(_HFXO_XTALCFG_COREBIASSTARTUPI_MASK | _HFXO_XTALCFG_COREBIASSTARTUP_MASK))
| corebiasstartup_saved
| corebiasstartupi_saved;
HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~_HFXO_XTALCTRL_COREBIASANA_MASK) | corebiasana_saved;
// Put back FORCEEN and DISONDEMAND state
if (!disondemand) {
HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
} else {
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
}
if (forceen) {
HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
} else {
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
}
} else {
// Call notification function to tell users that sleepy crystal settings are kept
// This should only happen if you are in test condition or if you have a bad crystal.
sl_hfxo_manager_notify_consecutive_failed_startups();
in_error_state = true;
}
} else {
sli_hfxo_manager_end_startup_measurement();
sli_hfxo_manager_notify_ready_for_power_manager();
// Clear counter since we successfully started HFXO with normal settings
// or we are just keeping sleepy crystal settings indefinitely.
error_try_cnt = 0;
}
#else
sli_hfxo_manager_end_startup_measurement();
sli_hfxo_manager_notify_ready_for_power_manager();
#endif
}
// DNSERR Interrupt Flag Handling
if (irq_flag & HFXO_IF_DNSERR) {
// Clear error flag
HFXO0->IF_CLR = irq_flag & HFXO_IF_DNSERR;
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
// We should not fail twice in a row
EFM_ASSERT(error_flag == false);
// Update global variables related to error.
error_flag = true;
error_try_cnt++;
// Save current settings
pkdettusstartupi_saved = (HFXO0->PKDETCTRL & _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK);
ctunexiana_saved = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_CTUNEXIANA_MASK);
ctunexoana_saved = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_CTUNEXOANA_MASK);
corebiasana_saved = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_COREBIASANA_MASK);
corebiasstartup_saved = (HFXO0->XTALCFG & _HFXO_XTALCFG_COREBIASSTARTUP_MASK);
corebiasstartupi_saved = (HFXO0->XTALCFG & _HFXO_XTALCFG_COREBIASSTARTUPI_MASK);
// Disable HFXO.
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
// Use FORCERAWCLK bit to exit error state when disabling
HFXO0->CTRL_SET = HFXO_MANAGER_CTRL_FORCERAWCLK;
while ((HFXO0->STATUS & _HFXO_STATUS_ENS_MASK) != 0U) {
}
HFXO0->CTRL_CLR = HFXO_MANAGER_CTRL_FORCERAWCLK;
// Change settings:
//Reduce Peak Detection Threshold for Startup Intermediate stage to 2 (V157MV)
HFXO0->PKDETCTRL = (HFXO0->PKDETCTRL & ~_HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK) | sleepy_xtal_settings_pkdettusstartupi;
// Reduce CTUNE values for steady stage
if (((ctunexiana_saved >> _HFXO_XTALCTRL_CTUNEXIANA_SHIFT) > 100)
|| ((ctunexoana_saved >> _HFXO_XTALCTRL_CTUNEXOANA_SHIFT) > 100)) {
HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~(_HFXO_XTALCTRL_CTUNEXIANA_MASK | _HFXO_XTALCTRL_CTUNEXOANA_MASK))
| (sleepy_xtal_settings_ctuneana << _HFXO_XTALCTRL_CTUNEXIANA_SHIFT)
| (sleepy_xtal_settings_ctuneana << _HFXO_XTALCTRL_CTUNEXOANA_SHIFT);
}
// Increase core bias current at all stages
HFXO0->XTALCFG = (HFXO0->XTALCFG & ~(_HFXO_XTALCFG_COREBIASSTARTUPI_MASK | _HFXO_XTALCFG_COREBIASSTARTUP_MASK))
| ((sleepy_xtal_settings_corebias >> 2) << _HFXO_XTALCFG_COREBIASSTARTUPI_SHIFT)
| ((sleepy_xtal_settings_corebias >> 2) << _HFXO_XTALCFG_COREBIASSTARTUP_SHIFT);
HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~_HFXO_XTALCTRL_COREBIASANA_MASK)
| (sleepy_xtal_settings_corebias << _HFXO_XTALCTRL_COREBIASANA_SHIFT);
// Put back FORCEEN and DISONDEMAND state
if (!disondemand) {
HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
} else {
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
}
if (forceen) {
HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
} else {
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
}
#endif
}
if (irq_flag & HFXO_IF_COREBIASOPTERR) {
// Clear Core Bias Optimization error flag
HFXO0->IF_CLR = irq_flag & HFXO_IF_COREBIASOPTERR;
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
// In case the Core Bias Optimization fails during error handling,
// we disable it
if (in_error_state == true) {
// Disable HFXO.
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
while ((HFXO0->STATUS & HFXO_STATUS_ENS) != 0) {
}
// Skip Core Bias Optimization in case of error
HFXO0->XTALCTRL_SET = HFXO_XTALCTRL_SKIPCOREBIASOPT;
// Put back FORCEEN and DISONDEMAND state
if (!disondemand) {
HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
} else {
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
}
if (forceen) {
HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
} else {
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
}
}
#endif
}
}
#endif // _SILICON_LABS_32B_SERIES_2
/***************************************************************************//**
* @file
* @brief HFXO Manager HAL series 2 Devices.
*******************************************************************************
* # License
* <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include "em_device.h"
#if defined(_SILICON_LABS_32B_SERIES_2)
#include "sl_assert.h"
#include "sli_hfxo_manager.h"
#include "sl_hfxo_manager.h"
#include "sl_hfxo_manager_config.h"
#include "sl_status.h"
#include <stdbool.h>
/*******************************************************************************
********************************* DEFINES *********************************
******************************************************************************/
#if (defined(SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT) \
&& (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1) \
&& defined(SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT))
#error Component power_manager_deepsleep_blocking_hfxo_restore is not compatible with SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT configuration
#endif
// Defines for hidden field FORCERAWCLK in HFXO_CTRL register
#define _HFXO_MANAGER_CTRL_FORCERAWCLK_SHIFT 31
#define _HFXO_MANAGER_CTRL_FORCERAWCLK_MASK 0x80000000UL
#define HFXO_MANAGER_CTRL_FORCERAWCLK (0x1UL << _HFXO_MANAGER_CTRL_FORCERAWCLK_SHIFT)
// Defines for hidden PKDETCTRL register
#define HFXO_MANAGER_PKDETCTRL (*((volatile uint32_t *)(HFXO0_BASE + 0x34UL)))
#define _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT 8
#define _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK 0xF00UL
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V105MV (0x00000000UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V132MV (0x00000001UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V157MV (0x00000002UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V184MV (0x00000003UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V210MV (0x00000004UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V236MV (0x00000005UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V262MV (0x00000006UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V289MV (0x00000007UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V315MV (0x00000008UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V341MV (0x00000009UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V367MV (0x0000000AUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V394MV (0x0000000BUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V420MV (0x0000000CUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V446MV (0x0000000DUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V472MV (0x0000000EUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
#define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V499MV (0x0000000FUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
// IRQ Name depending on devices
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
#define HFXO_IRQ_NUMBER HFXO00_IRQn
#define HFXO_IRQ_HANDLER_FUNCTION HFXO00_IRQHandler
#else
#define HFXO_IRQ_NUMBER HFXO0_IRQn
#define HFXO_IRQ_HANDLER_FUNCTION HFXO0_IRQHandler
#endif
// Default values for the Sleepy Crystal settings
// Should be enough to guaranty HFXO startup
#define SLEEPY_XTAL_SETTING_DEFAULT_PKDETTHSTARTUPI HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V157MV
#define SLEEPY_XTAL_SETTING_DEFAULT_CTUNEANA 100u
#define SLEEPY_XTAL_SETTING_DEFAULT_COREBIAS 255u
/*******************************************************************************
*************************** LOCAL VARIABLES ********************************
******************************************************************************/
// Error flag to indicate if we failed the startup process
static bool error_flag = false;
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
// Error retry counter
static uint8_t error_try_cnt = 0;
// Error State status
static bool in_error_state = false;
// Variables to save normal settings
static uint32_t pkdettusstartupi_saved;
static uint32_t ctunexiana_saved;
static uint32_t ctunexoana_saved;
static uint32_t corebiasana_saved;
static uint32_t corebiasstartup_saved;
static uint32_t corebiasstartupi_saved;
// Variables for Sleepy Crystal settings
static uint32_t sleepy_xtal_settings_pkdettusstartupi = SLEEPY_XTAL_SETTING_DEFAULT_PKDETTHSTARTUPI; // Value already shifted
static uint32_t sleepy_xtal_settings_ctuneana = SLEEPY_XTAL_SETTING_DEFAULT_CTUNEANA;
static uint32_t sleepy_xtal_settings_corebias = SLEEPY_XTAL_SETTING_DEFAULT_COREBIAS;
#endif
/***************************************************************************//**
* HFXO ready notification callback for internal use with power manager
******************************************************************************/
__WEAK void sli_hfxo_manager_notify_ready_for_power_manager(void);
/***************************************************************************//**
* HFXO PRS ready notification callback for internal use with power manager
******************************************************************************/
__WEAK void sli_hfxo_notify_ready_for_power_manager_from_prs(void);
/***************************************************************************//**
* Hardware specific initialization.
******************************************************************************/
void sli_hfxo_manager_init_hardware(void)
{
// Increase HFXO Interrupt priority so that it won't be masked by BASEPRI
// and will preempt other interrupts.
NVIC_SetPriority(HFXO_IRQ_NUMBER, 2);
// Enable HFXO Interrupt if HFXO is used
#if _SILICON_LABS_32B_SERIES_2_CONFIG >= 2
CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
#endif
HFXO0->IEN_CLR = HFXO_IEN_RDY | HFXO_IEN_DNSERR | HFXO_IEN_COREBIASOPTERR;
#if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
HFXO0->IEN_CLR = HFXO_IEN_PRSRDY;
#endif
HFXO0->IF_CLR = HFXO_IF_RDY | HFXO_IF_DNSERR | HFXO_IEN_COREBIASOPTERR;
#if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
HFXO0->IF_CLR = HFXO_IF_PRSRDY;
#endif
NVIC_ClearPendingIRQ(HFXO_IRQ_NUMBER);
NVIC_EnableIRQ(HFXO_IRQ_NUMBER);
HFXO0->IEN_SET = HFXO_IEN_RDY | HFXO_IEN_DNSERR | HFXO_IEN_COREBIASOPTERR;
#if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
HFXO0->IEN_SET = HFXO_IEN_PRSRDY;
HFXO0->CTRL &= ~(_HFXO_CTRL_DISONDEMANDPRS_MASK & HFXO_CTRL_DISONDEMANDPRS_DEFAULT);
HFXO0->CTRL |= HFXO_CTRL_PRSSTATUSSEL1_ENS;
#endif
}
/***************************************************************************//**
* Updates sleepy crystal settings in specific hardware registers.
******************************************************************************/
sl_status_t sli_hfxo_manager_update_sleepy_xtal_settings_hardware(sl_hfxo_manager_sleepy_xtal_settings_t *settings)
{
(void)settings;
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
EFM_ASSERT(settings->ana_ctune <= (_HFXO_XTALCTRL_CTUNEXIANA_MASK >> _HFXO_XTALCTRL_CTUNEXIANA_SHIFT));
EFM_ASSERT(settings->core_bias_current <= (_HFXO_XTALCTRL_COREBIASANA_MASK >> _HFXO_XTALCTRL_COREBIASANA_SHIFT));
sleepy_xtal_settings_ctuneana = settings->ana_ctune;
sleepy_xtal_settings_corebias = settings->core_bias_current;
return SL_STATUS_OK;
#else
return SL_STATUS_NOT_AVAILABLE;
#endif
}
/***************************************************************************//**
* Checks if HFXO is ready and, if needed, waits for it to be.
*
* @note This will also make sure we are not in the process of restarting HFXO
* with different settings.
******************************************************************************/
bool sli_hfxo_manager_is_hfxo_ready(bool wait)
{
bool ready = false;
do {
#if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
ready = (((HFXO0->STATUS & (HFXO_STATUS_RDY | HFXO_STATUS_PRSRDY)) != 0) && !error_flag) ? true : false;
#else
ready = (((HFXO0->STATUS & HFXO_STATUS_RDY) != 0) && !error_flag) ? true : false;
#endif
} while (!ready && wait);
return ready;
}
#if (SL_HFXO_MANAGER_CUSTOM_HFXO_IRQ_HANDLER == 0)
/*******************************************************************************
* HFXO interrupt handler.
*
* @note The HFXOx_IRQHandler provided by HFXO Manager will call
* @ref sl_hfxo_manager_irq_handler. Configure SL_HFXO_MANAGER_CUSTOM_HFXO_IRQ_HANDLER
* if the application wants to implement its own HFXOx_IRQHandler.
******************************************************************************/
void HFXO_IRQ_HANDLER_FUNCTION(void)
{
sl_hfxo_manager_irq_handler();
}
#endif
/*******************************************************************************
* HFXO Manager HFXO interrupt handler.
******************************************************************************/
void sl_hfxo_manager_irq_handler(void)
{
uint32_t irq_flag = HFXO0->IF;
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
bool disondemand = (HFXO0->CTRL & _HFXO_CTRL_DISONDEMAND_MASK) ? true : false;
bool forceen = (HFXO0->CTRL & _HFXO_CTRL_FORCEEN_MASK) ? true : false;
#endif
#if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
if (irq_flag & HFXO_IF_PRSRDY) {
// Clear PRS RDY flag and EM23ONDEMAND
HFXO0->IF_CLR = irq_flag & HFXO_IF_PRSRDY;
HFXO0->CTRL_CLR = HFXO_CTRL_EM23ONDEMAND;
sli_hfxo_manager_retrieve_begining_startup_measurement();
// Notify power manager HFXO is ready
sli_hfxo_notify_ready_for_power_manager_from_prs();
sli_hfxo_manager_notify_ready_for_power_manager();
// Update sleep on isr exit flag
sli_sleeptimer_update_sleep_on_isr_exit(true);
// Reset PRS signal through Sleeptimer
sli_sleeptimer_reset_prs_signal();
}
#endif
// RDY Interrupt Flag Handling
if (irq_flag & HFXO_IF_RDY) {
// Clear Ready flag
HFXO0->IF_CLR = irq_flag & HFXO_IF_RDY;
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
if (error_flag) {
// Clear error flag, i.e. we successfully stated HFXO with the modified settings
error_flag = false;
// If it's the first time we succeed after an error, try back the normal settings
if (error_try_cnt <= 1) {
// Disable HFXO.
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
while ((HFXO0->STATUS & HFXO_STATUS_ENS) != 0) {
}
// Put back normal settings
HFXO_MANAGER_PKDETCTRL = (HFXO_MANAGER_PKDETCTRL & ~_HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK) | pkdettusstartupi_saved;
HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~(_HFXO_XTALCTRL_CTUNEXIANA_MASK | _HFXO_XTALCTRL_CTUNEXOANA_MASK))
| ctunexiana_saved
| ctunexoana_saved;
HFXO0->XTALCFG = (HFXO0->XTALCFG & ~(_HFXO_XTALCFG_COREBIASSTARTUPI_MASK | _HFXO_XTALCFG_COREBIASSTARTUP_MASK))
| corebiasstartup_saved
| corebiasstartupi_saved;
HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~_HFXO_XTALCTRL_COREBIASANA_MASK) | corebiasana_saved;
// Put back FORCEEN and DISONDEMAND state
if (!disondemand) {
HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
} else {
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
}
if (forceen) {
HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
} else {
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
}
} else {
// Call notification function to tell users that sleepy crystal settings are kept
// This should only happen if you are in test condition or if you have a bad crystal.
sl_hfxo_manager_notify_consecutive_failed_startups();
in_error_state = true;
}
} else {
sli_hfxo_manager_end_startup_measurement();
sli_hfxo_manager_notify_ready_for_power_manager();
// Clear counter since we successfully started HFXO with normal settings
// or we are just keeping sleepy crystal settings indefinitely.
error_try_cnt = 0;
}
#else
sli_hfxo_manager_end_startup_measurement();
sli_hfxo_manager_notify_ready_for_power_manager();
#endif
}
// DNSERR Interrupt Flag Handling
if (irq_flag & HFXO_IF_DNSERR) {
// Clear error flag
HFXO0->IF_CLR = irq_flag & HFXO_IF_DNSERR;
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
// We should not fail twice in a row
EFM_ASSERT(error_flag == false);
// Update global variables related to error.
error_flag = true;
error_try_cnt++;
// Save current settings
pkdettusstartupi_saved = (HFXO_MANAGER_PKDETCTRL & _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK);
ctunexiana_saved = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_CTUNEXIANA_MASK);
ctunexoana_saved = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_CTUNEXOANA_MASK);
corebiasana_saved = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_COREBIASANA_MASK);
corebiasstartup_saved = (HFXO0->XTALCFG & _HFXO_XTALCFG_COREBIASSTARTUP_MASK);
corebiasstartupi_saved = (HFXO0->XTALCFG & _HFXO_XTALCFG_COREBIASSTARTUPI_MASK);
// Disable HFXO.
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
// Use FORCERAWCLK bit to exit error state when disabling
HFXO0->CTRL_SET = HFXO_MANAGER_CTRL_FORCERAWCLK;
while ((HFXO0->STATUS & _HFXO_STATUS_ENS_MASK) != 0U) {
}
HFXO0->CTRL_CLR = HFXO_MANAGER_CTRL_FORCERAWCLK;
// Change settings:
//Reduce Peak Detection Threshold for Startup Intermediate stage to 2 (V157MV)
HFXO_MANAGER_PKDETCTRL = (HFXO_MANAGER_PKDETCTRL & ~_HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK) | sleepy_xtal_settings_pkdettusstartupi;
// Reduce CTUNE values for steady stage
if (((ctunexiana_saved >> _HFXO_XTALCTRL_CTUNEXIANA_SHIFT) > 100)
|| ((ctunexoana_saved >> _HFXO_XTALCTRL_CTUNEXOANA_SHIFT) > 100)) {
HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~(_HFXO_XTALCTRL_CTUNEXIANA_MASK | _HFXO_XTALCTRL_CTUNEXOANA_MASK))
| (sleepy_xtal_settings_ctuneana << _HFXO_XTALCTRL_CTUNEXIANA_SHIFT)
| (sleepy_xtal_settings_ctuneana << _HFXO_XTALCTRL_CTUNEXOANA_SHIFT);
}
// Increase core bias current at all stages
HFXO0->XTALCFG = (HFXO0->XTALCFG & ~(_HFXO_XTALCFG_COREBIASSTARTUPI_MASK | _HFXO_XTALCFG_COREBIASSTARTUP_MASK))
| ((sleepy_xtal_settings_corebias >> 2) << _HFXO_XTALCFG_COREBIASSTARTUPI_SHIFT)
| ((sleepy_xtal_settings_corebias >> 2) << _HFXO_XTALCFG_COREBIASSTARTUP_SHIFT);
HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~_HFXO_XTALCTRL_COREBIASANA_MASK)
| (sleepy_xtal_settings_corebias << _HFXO_XTALCTRL_COREBIASANA_SHIFT);
// Put back FORCEEN and DISONDEMAND state
if (!disondemand) {
HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
} else {
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
}
if (forceen) {
HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
} else {
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
}
#endif
}
if (irq_flag & HFXO_IF_COREBIASOPTERR) {
// Clear Core Bias Optimization error flag
HFXO0->IF_CLR = irq_flag & HFXO_IF_COREBIASOPTERR;
#if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
// In case the Core Bias Optimization fails during error handling,
// we disable it
if (in_error_state == true) {
// Disable HFXO.
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
while ((HFXO0->STATUS & HFXO_STATUS_ENS) != 0) {
}
// Skip Core Bias Optimization in case of error
HFXO0->XTALCTRL_SET = HFXO_XTALCTRL_SKIPCOREBIASOPT;
// Put back FORCEEN and DISONDEMAND state
if (!disondemand) {
HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
} else {
HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
}
if (forceen) {
HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
} else {
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
}
}
#endif
}
}
#endif // _SILICON_LABS_32B_SERIES_2

View File

@ -41,13 +41,6 @@
// <i> Default: 0
#define SL_POWER_MANAGER_CUSTOM_HF_OSCILLATOR_IRQ_HANDLER 0
// <o SL_POWER_MANAGER_LOWEST_EM_ALLOWED> Lowest Energy mode allowed
// <1=> EM1
// <2=> EM2
// <3=> EM3
// <i> Default: 2
#define SL_POWER_MANAGER_LOWEST_EM_ALLOWED 2
// <q SL_POWER_MANAGER_CONFIG_VOLTAGE_SCALING_FAST_WAKEUP> Enable fast wakeup (disable voltage scaling in EM2/3 mode)
// <i> Enable or disable voltage scaling in EM2/3 modes (when available). This decreases wakeup time by about 30 us.
// <i> Deprecated. It is replaced by the function sl_power_manager_em23_voltage_scaling_enable_fast_wakeup()

View File

@ -32,7 +32,6 @@
#define SLI_POWER_MANAGER_H
#include "sl_power_manager.h"
#include "em_device.h"
#include <stdbool.h>
#include <stdint.h>
@ -41,21 +40,11 @@
extern "C" {
#endif
/*******************************************************************************
******************************* DEFINES ***********************************
******************************************************************************/
#if !defined(SLI_DEVICE_SUPPORTS_EM1P) && defined(_SILICON_LABS_32B_SERIES_2_CONFIG) && _SILICON_LABS_32B_SERIES_2_CONFIG >= 2
#define SLI_DEVICE_SUPPORTS_EM1P
#endif
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
#if defined(SLI_DEVICE_SUPPORTS_EM1P)
void sli_power_manager_update_hf_clock_settings_preservation_requirement(bool add);
#endif
/***************************************************************************//**
* Adds requirement on the preservation of the High Frequency Clocks settings.
@ -64,14 +53,7 @@ void sli_power_manager_update_hf_clock_settings_preservation_requirement(bool ad
*
* @note Must be used together with adding an EM2 requirement.
******************************************************************************/
__STATIC_INLINE void sli_power_manager_add_hf_clock_settings_preservation_requirement(void)
{
#if defined(SLI_DEVICE_SUPPORTS_EM1P)
sli_power_manager_update_hf_clock_settings_preservation_requirement(true);
#else
sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM1);
#endif
}
void sli_power_manager_add_hf_clock_settings_preservation_requirement(void);
/***************************************************************************//**
* Removes requirement on the preservation of the High Frequency Clocks settings.
@ -80,14 +62,7 @@ __STATIC_INLINE void sli_power_manager_add_hf_clock_settings_preservation_requir
*
* @note Must be used together with removing an EM2 requirement.
******************************************************************************/
__STATIC_INLINE void sli_power_manager_remove_hf_clock_settings_preservation_requirement(void)
{
#if defined(SLI_DEVICE_SUPPORTS_EM1P)
sli_power_manager_update_hf_clock_settings_preservation_requirement(false);
#else
sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1);
#endif
}
void sli_power_manager_remove_hf_clock_settings_preservation_requirement(void);
/***************************************************************************//**
* Informs the power manager module that the high accuracy/high frequency clock

View File

@ -36,6 +36,11 @@
#include "sl_assert.h"
#include "sl_atomic.h"
#include "em_device.h"
#if !defined(_SILICON_LABS_32B_SERIES_3)
#include "em_emu.h"
#endif
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
@ -44,16 +49,15 @@
********************************* DEFINES *********************************
******************************************************************************/
#if ((SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1) \
&& (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 2) \
&& (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 3))
#error "Lowest Energy mode allowed is invalid."
#endif
// Default overhead value for the wake-up time used for the schedule wake-up
// functionality.
#define SCHEDULE_WAKEUP_DEFAULT_RESTORE_TIME_OVERHEAD_TICK 0
// Determine if the device supports EM1P
#if !defined(SLI_DEVICE_SUPPORTS_EM1P) && defined(_SILICON_LABS_32B_SERIES_2_CONFIG) && _SILICON_LABS_32B_SERIES_2_CONFIG >= 2
#define SLI_DEVICE_SUPPORTS_EM1P
#endif
/*******************************************************************************
*************************** LOCAL VARIABLES ********************************
******************************************************************************/
@ -67,7 +71,7 @@ static sl_power_manager_em_t current_em = SL_POWER_MANAGER_EM0;
// Events subscribers lists
static sl_slist_node_t *power_manager_em_transition_event_list = NULL;
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
// Store the sleeptimer module clock frequency for conversion calculation
static uint32_t sleeptimer_frequency;
@ -156,7 +160,7 @@ bool sl_power_manager_is_ok_to_sleep(void);
************************** LOCAL FUNCTIONS ********************************
******************************************************************************/
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
static sl_power_manager_em_t get_lowest_em(void);
static void evaluate_wakeup(sl_power_manager_em_t to);
@ -174,6 +178,12 @@ static void clock_restore(void);
static void power_manager_notify_em_transition(sl_power_manager_em_t from,
sl_power_manager_em_t to);
// Use PriMask to enter critical section by disabling interrupts.
static CORE_irqState_t enter_critical_with_primask();
// Exit critical section by re-enabling interrupts in PriMask.
static void exit_critical_with_primask(CORE_irqState_t primask_state);
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
@ -195,13 +205,22 @@ sl_status_t sl_power_manager_init(void)
CORE_EXIT_CRITICAL();
return status;
}
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT) \
&& !defined(SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT)
// Additional Sleeptimer HW configuration if the "power_manager_deepsleep" component is used
sli_sleeptimer_hal_power_manager_integration_init();
#endif
#if (SL_POWER_MANAGER_DEBUG == 1)
sli_power_manager_debug_init();
#endif
sl_slist_init(&power_manager_em_transition_event_list);
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
// If lowest energy mode is not restricted to EM1, determine and set lowest energy mode
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
sli_sleeptimer_set_pm_em_requirement();
#endif
// Set the default wake-up overhead value
wakeup_time_config_overhead_tick = SCHEDULE_WAKEUP_DEFAULT_RESTORE_TIME_OVERHEAD_TICK;
@ -213,7 +232,7 @@ sl_status_t sl_power_manager_init(void)
// Do all necessary hardware initialization.
sli_power_manager_init_hardware();
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
// Set the HF minimum offtime in sleeptimer ticks
high_frequency_min_offtime_tick = sli_power_manager_get_default_high_frequency_minimum_offtime();
#endif
@ -229,19 +248,19 @@ sl_status_t sl_power_manager_init(void)
******************************************************************************/
void sl_power_manager_sleep(void)
{
CORE_DECLARE_IRQ_STATE;
CORE_irqState_t primask_state;
CORE_ENTER_CRITICAL();
primask_state = enter_critical_with_primask();
sli_power_manager_suspend_log_transmission();
if (sl_power_manager_is_ok_to_sleep() != true) {
sli_power_manager_resume_log_transmission();
CORE_EXIT_CRITICAL();
exit_critical_with_primask(primask_state);
return;
}
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
sl_power_manager_em_t lowest_em;
// Go to another energy mode (same, higher to lower or lower to higher)
@ -308,8 +327,8 @@ void sl_power_manager_sleep(void)
// For internal Silicon Labs use only
sli_power_manager_on_wakeup();
CORE_EXIT_CRITICAL();
CORE_ENTER_CRITICAL();
exit_critical_with_primask(primask_state);
primask_state = enter_critical_with_primask();
// In case the HF restore was completed from the HFXO ISR,
// and notification not done elsewhere, do it here
@ -339,8 +358,8 @@ void sl_power_manager_sleep(void)
// If possible, go back to sleep in EM1 while waiting for HF accuracy restore
while (!sli_power_manager_is_high_freq_accuracy_clk_ready(false)) {
sli_power_manager_apply_em(SL_POWER_MANAGER_EM1);
CORE_EXIT_CRITICAL();
CORE_ENTER_CRITICAL();
exit_critical_with_primask(primask_state);
primask_state = enter_critical_with_primask();
}
sli_power_manager_restore_states();
is_states_saved = false;
@ -356,8 +375,8 @@ void sl_power_manager_sleep(void)
// Apply EM1 energy mode
sli_power_manager_apply_em(SL_POWER_MANAGER_EM1);
CORE_EXIT_CRITICAL();
CORE_ENTER_CRITICAL();
exit_critical_with_primask(primask_state);
primask_state = enter_critical_with_primask();
} while (sl_power_manager_sleep_on_isr_exit() == true);
#endif
@ -367,7 +386,7 @@ void sl_power_manager_sleep(void)
sli_power_manager_resume_log_transmission();
CORE_EXIT_CRITICAL();
exit_critical_with_primask(primask_state);
}
/***************************************************************************//**
@ -382,13 +401,14 @@ void sl_power_manager_sleep(void)
*
* @note Need to be call inside a critical section.
*
* @note This function will do nothing when SL_POWER_MANAGER_LOWEST_EM_ALLOWED
* config is set to EM1.
* @note This function will do nothing when a project contains the
* power_manager_no_deepsleep component, which configures the
* lowest energy mode as EM1.
******************************************************************************/
void sli_power_manager_update_em_requirement(sl_power_manager_em_t em,
bool add)
{
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
// EM0 is not allowed
EFM_ASSERT((em > SL_POWER_MANAGER_EM0) && (em < SL_POWER_MANAGER_EM3));
@ -429,7 +449,6 @@ void sli_power_manager_update_em_requirement(sl_power_manager_em_t em,
#endif
}
#if defined(SLI_DEVICE_SUPPORTS_EM1P)
/***************************************************************************//**
* Updates requirement on preservation of High Frequency Clocks settings.
*
@ -438,7 +457,7 @@ void sli_power_manager_update_em_requirement(sl_power_manager_em_t em,
******************************************************************************/
void sli_power_manager_update_hf_clock_settings_preservation_requirement(bool add)
{
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if (defined(SLI_DEVICE_SUPPORTS_EM1P) && !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT))
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
@ -461,7 +480,38 @@ void sli_power_manager_update_hf_clock_settings_preservation_requirement(bool ad
(void)add;
#endif
}
/***************************************************************************//**
* Adds requirement on the preservation of the High Frequency Clocks settings.
*
* @note FOR INTERNAL USE ONLY.
*
* @note Must be used together with adding an EM2 requirement.
******************************************************************************/
void sli_power_manager_add_hf_clock_settings_preservation_requirement(void)
{
#if defined(SLI_DEVICE_SUPPORTS_EM1P)
sli_power_manager_update_hf_clock_settings_preservation_requirement(true);
#else
sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM1);
#endif
}
/***************************************************************************//**
* Removes requirement on the preservation of the High Frequency Clocks settings.
*
* @note FOR INTERNAL USE ONLY.
*
* @note Must be used together with removing an EM2 requirement.
******************************************************************************/
void sli_power_manager_remove_hf_clock_settings_preservation_requirement(void)
{
#if defined(SLI_DEVICE_SUPPORTS_EM1P)
sli_power_manager_update_hf_clock_settings_preservation_requirement(false);
#else
sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1);
#endif
}
/***************************************************************************//**
* Gets the wake-up restore process time.
@ -472,7 +522,7 @@ void sli_power_manager_update_hf_clock_settings_preservation_requirement(bool ad
******************************************************************************/
uint32_t sli_power_manager_get_restore_delay(void)
{
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
uint32_t wakeup_delay = 0;
CORE_DECLARE_IRQ_STATE;
@ -501,7 +551,7 @@ uint32_t sli_power_manager_get_restore_delay(void)
******************************************************************************/
void sli_power_manager_initiate_restore(void)
{
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
@ -513,6 +563,16 @@ void sli_power_manager_initiate_restore(void)
#endif
}
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/*******************************************************************************
* Gets the status of power manager variable is_sleeping_waiting_for_clock_restore.
******************************************************************************/
bool sli_power_manager_get_clock_restore_status(void)
{
return is_sleeping_waiting_for_clock_restore;
}
#endif
/***************************************************************************//**
* Registers a callback to be called on given Energy Mode transition(s).
*
@ -547,12 +607,13 @@ void sl_power_manager_unsubscribe_em_transition_event(sl_power_manager_em_transi
*
* @return Current overhead value for early wake-up time.
*
* @note This function will return 0 in case SL_POWER_MANAGER_LOWEST_EM_ALLOWED
* config is set to EM1.
* @note This function will do nothing when a project contains the
* power_manager_no_deepsleep component, which configures the
* lowest energy mode as EM1.
******************************************************************************/
int32_t sl_power_manager_schedule_wakeup_get_restore_overhead_tick(void)
{
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
int32_t overhead_tick;
sl_atomic_load(overhead_tick, wakeup_time_config_overhead_tick);
@ -572,12 +633,13 @@ int32_t sl_power_manager_schedule_wakeup_get_restore_overhead_tick(void)
* @note The overhead value can also be negative to remove time from the restore
* process.
*
* @note This function will do nothing when SL_POWER_MANAGER_LOWEST_EM_ALLOWED
* config is set to EM1.
* @note This function will do nothing when a project contains the
* power_manager_no_deepsleep component, which configures the
* lowest energy mode as EM1.
******************************************************************************/
void sl_power_manager_schedule_wakeup_set_restore_overhead_tick(int32_t overhead_tick)
{
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
sl_atomic_store(wakeup_time_config_overhead_tick, overhead_tick);
#else
(void)overhead_tick;
@ -599,12 +661,13 @@ void sl_power_manager_schedule_wakeup_set_restore_overhead_tick(int32_t overhead
* the oscillator on until the next scheduled oscillator enabled. This
* threshold value is what we refer as the minimum off-time.
*
* @note This function will return 0 in case SL_POWER_MANAGER_LOWEST_EM_ALLOWED
* config is set to EM1.
* @note This function will do nothing when a project contains the
* power_manager_no_deepsleep component, which configures the
* lowest energy mode as EM1.
******************************************************************************/
uint32_t sl_power_manager_schedule_wakeup_get_minimum_offtime_tick(void)
{
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
uint32_t offtime_tick;
sl_atomic_load(offtime_tick, high_frequency_min_offtime_tick);
@ -630,19 +693,20 @@ uint32_t sl_power_manager_schedule_wakeup_get_minimum_offtime_tick(void)
* the oscillator on until the next scheduled oscillator enabled. This
* threshold value is what we refer as the minimum off-time.
*
* @note This function will do nothing when SL_POWER_MANAGER_LOWEST_EM_ALLOWED
* config is set to EM1.
* @note This function will do nothing when a project contains the
* power_manager_no_deepsleep component, which configures the
* lowest energy mode as EM1.
******************************************************************************/
void sl_power_manager_schedule_wakeup_set_minimum_offtime_tick(uint32_t minimum_offtime_tick)
{
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
sl_atomic_store(high_frequency_min_offtime_tick, minimum_offtime_tick);
#else
(void)minimum_offtime_tick;
#endif
}
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/*******************************************************************************
* Converts microseconds time in sleeptimer ticks.
******************************************************************************/
@ -689,12 +753,12 @@ __WEAK bool sl_power_manager_sleep_on_isr_exit(void)
* false otherwise.
*
* @note This function will always return false in case
* SL_POWER_MANAGER_LOWEST_EM_ALLOWED config is set to EM1, since we will
* never sleep at a lower level than EM1.
* a requirement is added on SL_POWER_MANAGER_EM1,
* since we will never sleep at a lower level than EM1.
*****************************************************************************/
bool sl_power_manager_is_latest_wakeup_internal(void)
{
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
CORE_DECLARE_IRQ_STATE;
bool sleep;
@ -714,7 +778,7 @@ bool sl_power_manager_is_latest_wakeup_internal(void)
************************** LOCAL FUNCTIONS ********************************
******************************************************************************/
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/***************************************************************************//**
* Get lowest energy mode to apply given the requirements on the different
* energy modes.
@ -730,7 +794,7 @@ static sl_power_manager_em_t get_lowest_em(void)
sl_power_manager_em_t em;
// Retrieve lowest Energy mode allowed given the requirements
for (em_ix = 1; (em_ix < SL_POWER_MANAGER_LOWEST_EM_ALLOWED) && (requirement_em_table[em_ix - 1] == 0); em_ix++) {
for (em_ix = 1; (em_ix < 3) && (requirement_em_table[em_ix - 1] == 0); em_ix++) {
;
}
@ -802,6 +866,33 @@ static void power_manager_notify_em_transition(sl_power_manager_em_t from,
}
}
/***************************************************************************//**
* Enter critical section by disabling interrupts using PriMask.
*
* @return primask Initial primask state.
*
* @note @ref sl_power_manager_sleep() function should use PriMask to disable
* interrupts.
******************************************************************************/
static CORE_irqState_t enter_critical_with_primask(void)
{
CORE_irqState_t irqState = __get_PRIMASK();
__disable_irq();
return irqState;
}
/***************************************************************************//**
* Exit critical section by re-enabling interrupts using PriMask.
*
* @param primask_state Initial primask state.
******************************************************************************/
static void exit_critical_with_primask(CORE_irqState_t primask_state)
{
if (primask_state == 0U) {
__enable_irq();
}
}
/***************************************************************************//**
* Evaluates scheduled wakeup and restart timer based on the wakeup time.
* If the remaining time is shorter than the wakeup time then add a requirement
@ -809,7 +900,7 @@ static void power_manager_notify_em_transition(sl_power_manager_em_t from,
*
* @note Must be called in a critical section.
******************************************************************************/
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
static void evaluate_wakeup(sl_power_manager_em_t to)
{
sl_status_t status;
@ -852,13 +943,17 @@ static void evaluate_wakeup(sl_power_manager_em_t to)
update_em1_requirement(true);
requirement_on_em1_added = true;
} else {
uint16_t hf_accuracy_clk_flag = 0;
if (sli_power_manager_is_high_freq_accuracy_clk_used()) {
hf_accuracy_clk_flag = SLI_SLEEPTIMER_POWER_MANAGER_HF_ACCURACY_CLK_FLAG;
}
// Start internal sleeptimer to do the early wake-up.
sl_sleeptimer_restart_timer(&clock_wakeup_timer_handle,
(tick_remaining - (uint32_t)wakeup_delay),
on_clock_wakeup_timeout,
NULL,
0,
SLI_SLEEPTIMER_POWER_MANAGER_EARLY_WAKEUP_TIMER_FLAG);
(SLI_SLEEPTIMER_POWER_MANAGER_EARLY_WAKEUP_TIMER_FLAG | hf_accuracy_clk_flag));
}
}
}
@ -870,7 +965,7 @@ static void evaluate_wakeup(sl_power_manager_em_t to)
}
#endif
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/***************************************************************************//**
* Updates internal EM1 requirement.
* We add an internal EM1 requirement when we would usually go into EM2/EM3
@ -917,7 +1012,7 @@ static void update_em1_requirement(bool add)
}
#endif
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/***************************************************************************//**
* Do clock restore process and wait for it to be completed.
******************************************************************************/
@ -954,7 +1049,7 @@ static void clock_restore_and_wait(void)
}
#endif
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/***************************************************************************//**
* Start clock restore process.
*
@ -987,7 +1082,7 @@ static void clock_restore(void)
}
#endif
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/***************************************************************************//**
* Callback for clock enable timer.
*
@ -1031,11 +1126,11 @@ static void on_clock_wakeup_timeout(sl_sleeptimer_timer_handle_t *handle,
******************************************************************************/
void sli_hfxo_manager_notify_ready_for_power_manager(void)
{
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
// Complete HF restore and change current Energy mode
// The notification will be done once back in the sleep loop
if (current_em != SL_POWER_MANAGER_EM0
&& is_sleeping_waiting_for_clock_restore == true) {
&& (is_sleeping_waiting_for_clock_restore == true)) {
sli_power_manager_restore_states();
is_sleeping_waiting_for_clock_restore = false;
is_states_saved = false;
@ -1045,18 +1140,35 @@ void sli_hfxo_manager_notify_ready_for_power_manager(void)
#endif
}
#if defined(EMU_VSCALE_PRESENT)
/***************************************************************************//**
* HFXO PRS ready notification callback for internal use with power manager
*
* @note Will only be used on series 2 devices when HFXO Manager and SYSRTC
* is present.
******************************************************************************/
void sli_hfxo_notify_ready_for_power_manager_from_prs(void)
{
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
// Set clock restore to true to indicate that HFXO has been restored from a
// PRS interrupt unless already in EM0 indicating HFXO didn't need to be restored.
if (current_em != SL_POWER_MANAGER_EM0) {
is_sleeping_waiting_for_clock_restore = true;
}
#endif
}
/***************************************************************************//**
* Enable or disable fast wake-up in EM2 and EM3
*
* @note Will also update the wake up time from EM2 to EM0.
*
* @note This function will do nothing when SL_POWER_MANAGER_LOWEST_EM_ALLOWED
* config is set to EM1.
* @note This function will do nothing when a project contains the
* power_manager_no_deepsleep component, which configures the
* lowest energy mode as EM1.
******************************************************************************/
void sl_power_manager_em23_voltage_scaling_enable_fast_wakeup(bool enable)
{
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if (defined(EMU_VSCALE_PRESENT) && !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT))
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
@ -1068,4 +1180,3 @@ void sl_power_manager_em23_voltage_scaling_enable_fast_wakeup(bool enable)
(void)enable;
#endif
}
#endif

View File

@ -38,7 +38,13 @@
#include "sli_power_manager_private.h"
#include "sl_sleeptimer.h"
#include "sli_sleeptimer.h"
#if defined(SL_COMPONENT_CATALOG_PRESENT)
#include "sl_component_catalog.h"
#endif
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT) \
&& !defined(SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT)
#include "sli_hfxo_manager.h"
#endif
#include <stdbool.h>
@ -51,11 +57,10 @@
// Voltage scaling, HFXO startup and HFXO steady times are excluded from
// this because they are handled separately. RTCCSYNC time is also
// excluded and it is handled by RTCCSYNC code itself.
//TODO need to validate this value. how?
#if (_SILICON_LABS_32B_SERIES_2_CONFIG == 1)
#define EM2_WAKEUP_PROCESS_TIME_OVERHEAD_US (100u) //(380u)
#define EM2_WAKEUP_PROCESS_TIME_OVERHEAD_US (31u)
#else // (_SILICON_LABS_32B_SERIES_2_CONFIG == 2),
#define EM2_WAKEUP_PROCESS_TIME_OVERHEAD_US (100u) //(345u)
#define EM2_WAKEUP_PROCESS_TIME_OVERHEAD_US (31u)
#endif
// DPLL Locking delay related defines
@ -66,7 +71,7 @@
#define EM2_WAKEUP_VSCALE_OVERHEAD_US (64u)
// Default time value in microseconds required to wake-up the hfxo oscillator.
#define HFXO_WAKE_UP_TIME_DEFAULT_VALUE_US (600u)
#define HFXO_WAKE_UP_TIME_DEFAULT_VALUE_US (400u)
// high frequency oscillator wake-up time margin for possible variation
// A shift by 3 will be like a division by 8, so a percentage of 12.5%.
@ -75,11 +80,13 @@
// Default time value in microseconds for the HFXO minimum off time.
#define HFXO_MINIMUM_OFFTIME_DEFAULT_VALUE_US (400u)
#if defined(SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT)
// Table size of HFXO wake-up time measurement
#define HFXO_WAKE_UP_TIME_TABLE_SIZE 10
#endif
// Defines for hidden DBGSTATUS register and STARTUPDONE flag
#define DBGSTATUS RESERVED6[0]
// Defines for hidden HFXO0 DBGSTATUS register and STARTUPDONE flag
#define HFXO0_DBGSTATUS (*(volatile uint32_t *)(HFXO0_BASE + 0x05C))
#define HFXO_DBGSTATUS_STARTUPDONE (0x1UL << 1) /**< Startup Done Status */
#define _HFXO_DBGSTATUS_STARTUPDONE_SHIFT 1 /**< Shift value for HFXO_STARTUPDONE */
#define _HFXO_DBGSTATUS_STARTUPDONE_MASK 0x2UL /**< Bit mask for HFXO_STARTUPDONE */
@ -104,8 +111,19 @@
*************************** LOCAL VARIABLES ********************************
******************************************************************************/
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
// Variables to save the relevant clock registers.
uint32_t cmu_em01_grpA_clock_register;
#if defined(_CMU_EM01GRPBCLKCTRL_CLKSEL_MASK)
uint32_t cmu_em01_grpB_clock_register;
#endif
#if defined(_CMU_EM01GRPCCLKCTRL_CLKSEL_MASK)
uint32_t cmu_em01_grpC_clock_register;
#endif
#if defined(_CMU_DPLLREFCLKCTRL_CLKSEL_MASK)
uint32_t cmu_dpll_ref_clock_register;
#endif
uint32_t cmu_sys_clock_register;
// Time in ticks required for the general wake-up process.
@ -120,6 +138,17 @@ static bool is_dpll_used = false;
static bool is_entering_deepsleep = false;
static bool is_hf_x_oscillator_already_started = false;
#if defined(SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT)
static uint32_t hf_x_oscillator_wakeup_time_tc_inital = 0;
static uint32_t hfxo_wakeup_time_table[HFXO_WAKE_UP_TIME_TABLE_SIZE];
static uint8_t hfxo_wakeup_time_table_index = 0;
static uint32_t hfxo_wakeup_time_sum_average = 0;
// Time in ticks required for HFXO start-up after wake-up from sleep.
static uint32_t hfxo_wakeup_time_tick = 0;
#endif
#endif
/*******************************************************************************
@ -131,13 +160,6 @@ static bool is_hf_x_oscillator_already_started = false;
******************************************************************************/
void sli_power_manager_init_hardware(void)
{
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
uint32_t cmu_em01_grpA_clock_register;
#if defined(CMU_EM01GRPBCLKCTRL_CLKSEL_HFXO)
uint32_t cmu_em01_grpB_clock_register;
#endif
#endif
// Initializes EMU (voltage scaling in EM2/3)
#if defined(EMU_VSCALE_EM01_PRESENT)
EMU_EM01Init_TypeDef em01_init = EMU_EM01INIT_DEFAULT;
@ -145,7 +167,7 @@ void sli_power_manager_init_hardware(void)
EMU_EM01Init(&em01_init);
#endif
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
#if defined(EMU_VSCALE_PRESENT)
#if defined(SL_POWER_MANAGER_CONFIG_VOLTAGE_SCALING_FAST_WAKEUP)
#if (SL_POWER_MANAGER_CONFIG_VOLTAGE_SCALING_FAST_WAKEUP == 0)
@ -160,9 +182,8 @@ void sli_power_manager_init_hardware(void)
// Get the current HF oscillator for the SYSCLK
cmu_sys_clock_register = CMU->SYSCLKCTRL & _CMU_SYSCLKCTRL_CLKSEL_MASK;
cmu_em01_grpA_clock_register = CMU->EM01GRPACLKCTRL & _CMU_EM01GRPACLKCTRL_CLKSEL_MASK;
#if defined(CMU_EM01GRPBCLKCTRL_CLKSEL_HFXO)
cmu_em01_grpB_clock_register = CMU->EM01GRPBCLKCTRL & _CMU_EM01GRPBCLKCTRL_CLKSEL_MASK;
#if defined(_CMU_DPLLREFCLKCTRL_CLKSEL_MASK)
cmu_dpll_ref_clock_register = CMU->DPLLREFCLKCTRL & _CMU_DPLLREFCLKCTRL_CLKSEL_MASK;
#endif
#if defined(CMU_CLKEN0_DPLL0)
@ -174,14 +195,27 @@ void sli_power_manager_init_hardware(void)
is_dpll_used = ((DPLL0->STATUS & _DPLL_STATUS_ENS_MASK) != 0);
is_hf_x_oscillator_used = ((cmu_sys_clock_register == CMU_SYSCLKCTRL_CLKSEL_HFXO)
|| (cmu_em01_grpA_clock_register == CMU_EM01GRPACLKCTRL_CLKSEL_HFXO));
|| ((CMU->EM01GRPACLKCTRL & _CMU_EM01GRPACLKCTRL_CLKSEL_MASK) == CMU_EM01GRPACLKCTRL_CLKSEL_HFXO));
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
is_hf_x_oscillator_used |= (CMU->RADIOCLKCTRL & _CMU_RADIOCLKCTRL_EN_MASK) != 0;
#endif
#if defined(CMU_EM01GRPBCLKCTRL_CLKSEL_HFXO)
is_hf_x_oscillator_used |= (cmu_em01_grpB_clock_register == CMU_EM01GRPBCLKCTRL_CLKSEL_HFXO);
is_hf_x_oscillator_used |= ((CMU->EM01GRPBCLKCTRL & _CMU_EM01GRPBCLKCTRL_CLKSEL_MASK) == CMU_EM01GRPBCLKCTRL_CLKSEL_HFXO);
#endif
#if defined(CMU_EM01GRPCCLKCTRL_CLKSEL_HFXO)
is_hf_x_oscillator_used |= ((CMU->EM01GRPCCLKCTRL & _CMU_EM01GRPCCLKCTRL_CLKSEL_MASK) == CMU_EM01GRPCCLKCTRL_CLKSEL_HFXO);
#endif
#if defined(SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT)
// Set HFXO wakeup time to conservative default value
hfxo_wakeup_time_tick = sli_power_manager_convert_delay_us_to_tick(HFXO_WAKE_UP_TIME_DEFAULT_VALUE_US);
for (uint8_t i = 0; i < HFXO_WAKE_UP_TIME_TABLE_SIZE; i++) {
hfxo_wakeup_time_table[i] = hfxo_wakeup_time_tick;
hfxo_wakeup_time_sum_average += hfxo_wakeup_time_tick;
}
#endif
if (is_dpll_used && !is_hf_x_oscillator_used) {
@ -219,13 +253,13 @@ void sli_power_manager_init_hardware(void)
#endif
}
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if defined(EMU_VSCALE_PRESENT)
/***************************************************************************//**
* Enable or disable fast wake-up in EM2 and EM3.
******************************************************************************/
void sli_power_manager_em23_voltage_scaling_enable_fast_wakeup(bool enable)
{
#if (defined(EMU_VSCALE_PRESENT) && !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT))
if (enable == is_fast_wakeup_enabled) {
return;
}
@ -251,21 +285,31 @@ void sli_power_manager_em23_voltage_scaling_enable_fast_wakeup(bool enable)
}
is_fast_wakeup_enabled = enable;
#else
(void)enable;
#endif
}
#endif
#endif
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/***************************************************************************//**
* Save the CMU HF clock select state, oscillator enable, and voltage scaling.
******************************************************************************/
void sli_power_manager_save_states(void)
{
// Save HF clock sources
cmu_em01_grpA_clock_register = CMU->EM01GRPACLKCTRL & _CMU_EM01GRPACLKCTRL_CLKSEL_MASK;
#if defined(_CMU_EM01GRPBCLKCTRL_CLKSEL_MASK)
cmu_em01_grpB_clock_register = CMU->EM01GRPBCLKCTRL & _CMU_EM01GRPBCLKCTRL_CLKSEL_MASK;
#endif
#if defined(_CMU_EM01GRPCCLKCTRL_CLKSEL_MASK)
cmu_em01_grpC_clock_register = CMU->EM01GRPCCLKCTRL & _CMU_EM01GRPCCLKCTRL_CLKSEL_MASK;
#endif
EMU_Save();
}
#endif
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/***************************************************************************//**
* Handle pre-sleep operations if any are necessary, like manually disabling
* oscillators, change clock settings, etc.
@ -277,13 +321,31 @@ void EMU_EM23PresleepHook(void)
is_entering_deepsleep = false;
CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~_CMU_SYSCLKCTRL_CLKSEL_MASK) | _CMU_SYSCLKCTRL_CLKSEL_FSRCO;
// Switch the HF Clocks oscillator's to FSRCO before deepsleep
CMU->EM01GRPACLKCTRL = (CMU->EM01GRPACLKCTRL & ~_CMU_EM01GRPACLKCTRL_CLKSEL_MASK) | _CMU_EM01GRPACLKCTRL_CLKSEL_FSRCO;
#if defined(_CMU_EM01GRPBCLKCTRL_CLKSEL_MASK)
CMU->EM01GRPBCLKCTRL = (CMU->EM01GRPBCLKCTRL & ~_CMU_EM01GRPBCLKCTRL_CLKSEL_MASK) | _CMU_EM01GRPBCLKCTRL_CLKSEL_FSRCO;
#endif
#if defined(_CMU_EM01GRPCCLKCTRL_CLKSEL_MASK)
CMU->EM01GRPCCLKCTRL = (CMU->EM01GRPCCLKCTRL & ~_CMU_EM01GRPCCLKCTRL_CLKSEL_MASK) | _CMU_EM01GRPCCLKCTRL_CLKSEL_FSRCO;
#endif
// Disable DPLL before deepsleep
#if (_DPLL_IPVERSION_IPVERSION_DEFAULT >= 1)
#if defined(_CMU_DPLLREFCLKCTRL_CLKSEL_MASK)
if (is_dpll_used) {
DPLL0->EN_CLR = DPLL_EN_EN;
while ((DPLL0->EN & _DPLL_EN_DISABLING_MASK) != 0) {
}
}
#endif
#endif
SystemCoreClockUpdate();
}
}
#endif
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/***************************************************************************//**
* Handle post-sleep operations. The idea is to start HFXO ASAP when we know we
* will need it.
@ -304,25 +366,37 @@ void EMU_EM23PostsleepHook(void)
&& sli_sleeptimer_is_power_manager_timer_next_to_expire()) {
// Check if HFXO is already running and has finished its startup.
// If yes, don't do the HFXO restore time measurement.
if ((HFXO0->STATUS & _HFXO_STATUS_ENS_MASK) != 0
&& (HFXO0->DBGSTATUS & _HFXO_DBGSTATUS_STARTUPDONE_MASK) != 0) {
if (((HFXO0->STATUS & _HFXO_STATUS_ENS_MASK) != 0
&& (HFXO0_DBGSTATUS & _HFXO_DBGSTATUS_STARTUPDONE_MASK) != 0)
|| (HFXO0->STATUS & _HFXO_STATUS_RDY_MASK) != 0) {
#if !defined(SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT)
// Force-enable HFXO in case the HFXO on-demand request would be removed
// before we finish the restore process.
HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
#endif
return;
}
// Start measure HFXO restore time.
is_hf_x_oscillator_already_started = true;
#if defined(SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT)
hf_x_oscillator_wakeup_time_tc_inital = sl_sleeptimer_get_tick_count();
// Switch SYSCLK to HFXO to measure restore time
CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~_CMU_SYSCLKCTRL_CLKSEL_MASK) | cmuSelect_HFXO;
SystemCoreClockUpdate();
#else
sli_hfxo_manager_begin_startup_measurement();
// Force enable HFXO to measure restore time
HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
#endif
}
}
#endif
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/***************************************************************************//**
* Handle pre-deepsleep operations if any are necessary, like manually disabling
* oscillators, change clock settings, etc.
@ -333,7 +407,7 @@ void sli_power_manager_handle_pre_deepsleep_operations(void)
}
#endif
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/***************************************************************************//**
* Handle post-sleep operations if any are necessary, like manually enabling
* oscillators, change clock settings, etc.
@ -349,26 +423,49 @@ void sli_power_manager_restore_high_freq_accuracy_clk(void)
if (!is_hf_x_oscillator_already_started) {
// Check if HFXO is already running and has finished its startup.
// If yes, don't do the HFXO restore time measurement.
if ((HFXO0->STATUS & _HFXO_STATUS_ENS_MASK) != 0
&& (HFXO0->DBGSTATUS & _HFXO_DBGSTATUS_STARTUPDONE_MASK) != 0) {
if (((HFXO0->STATUS & _HFXO_STATUS_ENS_MASK) != 0
&& (HFXO0_DBGSTATUS & _HFXO_DBGSTATUS_STARTUPDONE_MASK) != 0)
|| (HFXO0->STATUS & _HFXO_STATUS_RDY_MASK) != 0) {
#if !defined(SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT)
// Force-enable HFXO in case the HFXO on-demand request would be removed
// before we finish the restore process.
HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
#endif
return;
}
#if defined(SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT)
hf_x_oscillator_wakeup_time_tc_inital = sl_sleeptimer_get_tick_count();
// Switch SYSCLK to HFXO to measure restore time
CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~_CMU_SYSCLKCTRL_CLKSEL_MASK) | cmuSelect_HFXO;
SystemCoreClockUpdate();
#else
// Start measure HFXO restore time
sli_hfxo_manager_begin_startup_measurement();
// Force enable HFXO to measure restore time
HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
#endif
}
#if defined(SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT)
uint32_t current_time = sl_sleeptimer_get_tick_count() - hf_x_oscillator_wakeup_time_tc_inital;
// Calculate average for HFXO restore time
hfxo_wakeup_time_sum_average -= (int32_t)hfxo_wakeup_time_table[hfxo_wakeup_time_table_index] - (int32_t)current_time;
hfxo_wakeup_time_table[hfxo_wakeup_time_table_index] = current_time;
hfxo_wakeup_time_tick = ((hfxo_wakeup_time_sum_average + (HFXO_WAKE_UP_TIME_TABLE_SIZE - 1) ) / HFXO_WAKE_UP_TIME_TABLE_SIZE);
// Update index of wakeup time table
hfxo_wakeup_time_table_index++;
hfxo_wakeup_time_table_index %= HFXO_WAKE_UP_TIME_TABLE_SIZE;
#endif
is_hf_x_oscillator_already_started = false;
}
#endif
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/***************************************************************************//**
* Checks if HF accuracy clocks is fully restored and, if needed, waits for it.
*
@ -384,21 +481,47 @@ bool sli_power_manager_is_high_freq_accuracy_clk_ready(bool wait)
return true;
}
#if defined(SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT)
(void)wait;
return true;
#else
return sli_hfxo_manager_is_hfxo_ready(wait);
#endif
}
#endif
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/***************************************************************************//**
* Restore CMU HF clock select state, oscillator enable, and voltage scaling.
******************************************************************************/
void sli_power_manager_restore_states(void)
{
// Restore specific EMU saved contexts
EMU_Restore();
// Restore DPLL after deepsleep
#if (_DPLL_IPVERSION_IPVERSION_DEFAULT >= 1)
#if defined(_CMU_DPLLREFCLKCTRL_CLKSEL_MASK)
if (is_dpll_used) {
DPLL0->EN_SET = DPLL_EN_EN;
while ((DPLL0->STATUS & _DPLL_STATUS_RDY_MASK) == 0U) {
}
}
#endif
#endif
// Restore SYSCLK to what it was before the deepsleep
CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~_CMU_SYSCLKCTRL_CLKSEL_MASK) | cmu_sys_clock_register;
// Restore the HF Clocks to what they were before deepsleep
CMU->EM01GRPACLKCTRL = (CMU->EM01GRPACLKCTRL & ~_CMU_EM01GRPACLKCTRL_CLKSEL_MASK) | cmu_em01_grpA_clock_register;
#if defined(_CMU_EM01GRPBCLKCTRL_CLKSEL_MASK)
CMU->EM01GRPBCLKCTRL = (CMU->EM01GRPBCLKCTRL & ~_CMU_EM01GRPBCLKCTRL_CLKSEL_MASK) | cmu_em01_grpB_clock_register;
#endif
#if defined(_CMU_EM01GRPCCLKCTRL_CLKSEL_MASK)
CMU->EM01GRPCCLKCTRL = (CMU->EM01GRPCCLKCTRL & ~_CMU_EM01GRPCCLKCTRL_CLKSEL_MASK) | cmu_em01_grpC_clock_register;
#endif
// Remove FORCEEN on HFXO
if (is_hf_x_oscillator_used) {
HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
@ -406,8 +529,8 @@ void sli_power_manager_restore_states(void)
SystemCoreClockUpdate();
#if 0 // TODO PLATFORM_MTL-8499
// Wait for DPLL to lock
#if 0 // TODO This seems to cause issues in some cases. That has to be fixed.
if (is_dpll_used) {
while (!(DPLL0->STATUS && _DPLL_STATUS_RDY_MASK)) {
}
@ -461,7 +584,7 @@ void sli_power_manager_apply_em(sl_power_manager_em_t em)
}
}
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/*******************************************************************************
* Returns the default minimum offtime for HFXO.
******************************************************************************/
@ -478,12 +601,16 @@ uint32_t sli_power_manager_get_default_high_frequency_minimum_offtime(void)
******************************************************************************/
uint32_t sli_power_manager_get_wakeup_process_time_overhead(void)
{
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
uint32_t delay = 0;
// Add HFXO start-up delay if applicable
if (is_hf_x_oscillator_used) {
#if defined(SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT)
delay = hfxo_wakeup_time_tick;
#else
delay = sli_hfxo_manager_get_startup_time();
#endif
delay += delay >> HFXO_START_UP_TIME_OVERHEAD_LOG2;
}
@ -496,7 +623,7 @@ uint32_t sli_power_manager_get_wakeup_process_time_overhead(void)
#endif
}
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/***************************************************************************//**
* Informs the power manager module that the high accuracy/high frequency clock
* is used.
@ -507,7 +634,7 @@ void sli_power_manager_set_high_accuracy_hf_clock_as_used(void)
}
#endif
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/*******************************************************************************
* Restores the Low Frequency clocks according to what LF oscillators are used.
*
@ -517,5 +644,16 @@ void sli_power_manager_set_high_accuracy_hf_clock_as_used(void)
void sli_power_manager_low_frequency_restore(void)
{
}
/***************************************************************************//**
* Informs the power manager if the high accuracy/high frequency clock
* is used, prior to scheduling an early clock restore.
*
* @return true if HFXO is used, else false.
******************************************************************************/
bool sli_power_manager_is_high_freq_accuracy_clk_used(void)
{
return is_hf_x_oscillator_used;
}
#endif
#endif

View File

@ -47,6 +47,10 @@
#include "sl_cycle_counter.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
******************************* DEFINES ***********************************
******************************************************************************/
@ -73,7 +77,7 @@ void sli_power_manager_apply_em(sl_power_manager_em_t em);
void sli_power_manager_debug_init(void);
#if (SL_POWER_MANAGER_LOWEST_EM_ALLOWED != 1)
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
void sli_power_manager_save_states(void);
void sli_power_manager_handle_pre_deepsleep_operations(void);
@ -94,20 +98,26 @@ uint32_t sli_power_manager_convert_delay_us_to_tick(uint32_t time_us);
******************************************************************************/
uint32_t sli_power_manager_get_default_high_frequency_minimum_offtime(void);
#if defined(EMU_VSCALE_PRESENT)
/*******************************************************************************
* Restores the Low Frequency clocks according to which LF oscillators are used.
******************************************************************************/
void sli_power_manager_low_frequency_restore(void);
/***************************************************************************//**
* Informs the power manager if the high accuracy/high frequency clock
* is used, prior to scheduling an early clock restore.
*
* @return true if HFXO is used, else false.
******************************************************************************/
bool sli_power_manager_is_high_freq_accuracy_clk_used(void);
#endif
/***************************************************************************//**
* Enable or disable fast wake-up in EM2 and EM3
*
* @note Will also update the wake up time from EM2 to EM0.
******************************************************************************/
void sli_power_manager_em23_voltage_scaling_enable_fast_wakeup(bool enable);
#endif
/*******************************************************************************
* Restores the Low Frequency clocks according to which LF oscillators are used.
******************************************************************************/
void sli_power_manager_low_frequency_restore(void);
#endif
/*******************************************************************************
* Gets the delay associated the wake-up process from EM23.
@ -115,3 +125,18 @@ void sli_power_manager_low_frequency_restore(void);
* @return Delay for the complete wake-up process with full restore.
******************************************************************************/
uint32_t sli_power_manager_get_wakeup_process_time_overhead(void);
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
/*******************************************************************************
* Gets the status of power manager variable is_sleeping_waiting_for_clock_restore.
*
* @return true if Power Manager is sleeping waiting for clock restore, else false.
*
* @note FOR INTERNAL USE ONLY.
******************************************************************************/
bool sli_power_manager_get_clock_restore_status(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -39,6 +39,8 @@
#define SL_SLEEPTIMER_PERIPHERAL_RTC 3
#define SL_SLEEPTIMER_PERIPHERAL_SYSRTC 4
#define SL_SLEEPTIMER_PERIPHERAL_BURTC 5
#define SL_SLEEPTIMER_PERIPHERAL_WTIMER 6
#define SL_SLEEPTIMER_PERIPHERAL_TIMER 7
// <o SL_SLEEPTIMER_PERIPHERAL> Timer Peripheral Used by Sleeptimer
// <SL_SLEEPTIMER_PERIPHERAL_DEFAULT=> Default (auto select)
@ -47,15 +49,23 @@
// <SL_SLEEPTIMER_PERIPHERAL_RTC=> RTC
// <SL_SLEEPTIMER_PERIPHERAL_SYSRTC=> SYSRTC
// <SL_SLEEPTIMER_PERIPHERAL_BURTC=> Back-Up RTC (BURTC)
// <SL_SLEEPTIMER_PERIPHERAL_WTIMER=> WTIMER
// <SL_SLEEPTIMER_PERIPHERAL_TIMER=> TIMER
// <i> Selection of the Timer Peripheral Used by the Sleeptimer
#define SL_SLEEPTIMER_PERIPHERAL SL_SLEEPTIMER_PERIPHERAL_DEFAULT
// <o SL_SLEEPTIMER_TIMER_INSTANCE> TIMER/WTIMER Instance Used by Sleeptimer (not applicable for other peripherals)
// <i> Make sure TIMER instance size is 32bits. Check datasheet for 32bits TIMERs.
// <i> Default: 0
#define SL_SLEEPTIMER_TIMER_INSTANCE 0
// <q SL_SLEEPTIMER_WALLCLOCK_CONFIG> Enable wallclock functionality
// <i> Enable or disable wallclock functionalities (get_time, get_date, etc).
// <i> Default: 0
#define SL_SLEEPTIMER_WALLCLOCK_CONFIG 0
// <o SL_SLEEPTIMER_FREQ_DIVIDER> Timer frequency divider
// <o SL_SLEEPTIMER_FREQ_DIVIDER> Timer frequency divider (not applicable for WTIMER/TIMER)
// <i> WTIMER/TIMER peripherals are always prescaled to 1024.
// <i> Default: 1
#define SL_SLEEPTIMER_FREQ_DIVIDER 1

View File

@ -35,16 +35,50 @@
#include <stddef.h>
#include <stdbool.h>
#include "em_device.h"
#include "sl_sleeptimer_config.h"
#define SLEEPTIMER_EVENT_OF (0x01)
#define SLEEPTIMER_EVENT_COMP (0x02)
#define SLI_SLEEPTIMER_POWER_MANAGER_EARLY_WAKEUP_TIMER_FLAG 0x02
#define SLI_SLEEPTIMER_POWER_MANAGER_HF_ACCURACY_CLK_FLAG 0x04
#if SL_SLEEPTIMER_PERIPHERAL == SL_SLEEPTIMER_PERIPHERAL_DEFAULT
#if defined(RTCC_PRESENT) && RTCC_COUNT >= 1
#undef SL_SLEEPTIMER_PERIPHERAL
#define SL_SLEEPTIMER_PERIPHERAL SL_SLEEPTIMER_PERIPHERAL_RTCC
#elif defined(RTC_PRESENT) && RTC_COUNT >= 1
#undef SL_SLEEPTIMER_PERIPHERAL
#define SL_SLEEPTIMER_PERIPHERAL SL_SLEEPTIMER_PERIPHERAL_RTC
#elif defined(SYSRTC_PRESENT) && SYSRTC_COUNT >= 1
#undef SL_SLEEPTIMER_PERIPHERAL
#define SL_SLEEPTIMER_PERIPHERAL SL_SLEEPTIMER_PERIPHERAL_SYSRTC
#elif defined(BURTC_PRESENT) && BURTC_COUNT >= 1
#undef SL_SLEEPTIMER_PERIPHERAL
#define SL_SLEEPTIMER_PERIPHERAL SL_SLEEPTIMER_PERIPHERAL_BURTC
#elif defined(WTIMER_PRESENT) && WTIMER_COUNT >= 1
#undef SL_SLEEPTIMER_PERIPHERAL
#define SL_SLEEPTIMER_PERIPHERAL SL_SLEEPTIMER_PERIPHERAL_WTIMER
#elif defined(TIMER_PRESENT) && TIMER_COUNT >= 1
#undef SL_SLEEPTIMER_PERIPHERAL
#define SL_SLEEPTIMER_PERIPHERAL SL_SLEEPTIMER_PERIPHERAL_TIMER
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
* Hardware Abstraction Layer to perform initialization related to Power Manager.
******************************************************************************/
__WEAK void sli_sleeptimer_hal_power_manager_integration_init(void);
/*******************************************************************************
* Hardware Abstraction Layer to perform initialization related to HFXO Manager.
******************************************************************************/
__WEAK void sli_sleeptimer_hal_hfxo_manager_integration_init(void);
/*******************************************************************************
* Hardware Abstraction Layer to get interrupt status.
*
@ -63,6 +97,38 @@ bool sli_sleeptimer_hal_is_int_status_set(uint8_t local_flag);
*****************************************************************************/
bool sli_sleeptimer_is_power_manager_timer_next_to_expire(void);
/***************************************************************************//**
* Set lowest energy mode based on a project's configurations and clock source
*
* @note If power_manager_no_deepsleep component is included in a project, the
* lowest possible energy mode is EM1, else lowest energy mode is
* determined by clock source.
******************************************************************************/
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
void sli_sleeptimer_set_pm_em_requirement(void);
#endif
/***************************************************************************//**
* @brief
* Update sleep_on_isr_exit flag.
*
* @param flag Boolean value update_sleep_on_isr_exit will be set to.
******************************************************************************/
void sli_sleeptimer_update_sleep_on_isr_exit(bool flag);
/*******************************************************************************
* Gets the associated peripheral capture channel current value.
*
* @return Capture value
* 0 if capture channel is not valid
******************************************************************************/
uint32_t sli_sleeptimer_get_capture(void);
/*******************************************************************************
* Resets the PRS signal triggered by the associated peripheral.
******************************************************************************/
void sli_sleeptimer_reset_prs_signal(void);
#ifdef __cplusplus
}
#endif

View File

@ -1900,3 +1900,43 @@ static bool is_valid_date_64(sl_sleeptimer_date_t *date)
return true;
}
#endif
/*******************************************************************************
* @brief
* Gets the precision (in PPM) of the sleeptimer's clock.
*
* @return
* Clock accuracy, in PPM.
*
******************************************************************************/
uint16_t sl_sleeptimer_get_clock_accuracy(void)
{
return sleeptimer_hal_get_clock_accuracy();
}
/***************************************************************************//**
* @brief
* Update sleep_on_isr_exit flag.
*
* @param flag Value update_sleep_on_isr_exit will be set to.
******************************************************************************/
void sli_sleeptimer_update_sleep_on_isr_exit(bool flag)
{
sleep_on_isr_exit = flag;
}
/*******************************************************************************
* Gets the associated peripheral capture channel current value.
******************************************************************************/
uint32_t sli_sleeptimer_get_capture(void)
{
return sleeptimer_hal_get_capture();
}
/*******************************************************************************
* Resets the PRS signal triggered by the associated peripheral.
******************************************************************************/
void sli_sleeptimer_reset_prs_signal(void)
{
sleeptimer_hal_reset_prs_signal();
}

View File

@ -34,6 +34,10 @@
#include "em_core.h"
#include "em_cmu.h"
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
#include "sl_power_manager.h"
#endif
#if SL_SLEEPTIMER_PERIPHERAL == SL_SLEEPTIMER_PERIPHERAL_RTCC
// Minimum difference between current count value and what the comparator of the timer can be set to.
@ -256,4 +260,82 @@ __STATIC_INLINE uint32_t get_time_diff(uint32_t a,
return (a - b);
}
/*******************************************************************************
* @brief
* Gets the precision (in PPM) of the sleeptimer's clock.
*
* @return
* Clock accuracy, in PPM.
*
******************************************************************************/
uint16_t sleeptimer_hal_get_clock_accuracy(void)
{
#if defined(_SILICON_LABS_32B_SERIES_2)
return CMU_LF_ClockPrecisionGet(cmuClock_RTCC);
#else
return CMU_LF_ClockPrecisionGet(cmuClock_LFE);
#endif
}
/*******************************************************************************
* Hardware Abstraction Layer to get the capture channel value.
******************************************************************************/
uint32_t sleeptimer_hal_get_capture(void)
{
// Invalid for RTCC peripheral
EFM_ASSERT(0);
return 0;
}
/*******************************************************************************
* Hardware Abstraction Layer to reset PRS signal triggered by the associated
* peripheral.
******************************************************************************/
void sleeptimer_hal_reset_prs_signal(void)
{
// Invalid for RTCC peripheral
EFM_ASSERT(0);
}
/***************************************************************************//**
* Set lowest energy mode based on a project's configurations and clock source
*
* @note If power_manager_no_deepsleep component is included in a project, the
* lowest possible energy mode is EM1, else lowest energy mode is
* determined by clock source.
******************************************************************************/
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
void sli_sleeptimer_set_pm_em_requirement(void)
{
#if defined(_CMU_RTCCCLKCTRL_CLKSEL_MASK)
switch (CMU->RTCCCLKCTRL & _CMU_RTCCCLKCTRL_CLKSEL_MASK) {
case CMU_RTCCCLKCTRL_CLKSEL_LFRCO:
case CMU_RTCCCLKCTRL_CLKSEL_LFXO:
sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM2);
break;
default:
break;
}
#elif defined(_CMU_LFECLKEN0_RTCC_MASK)
switch ((CMU->LFECLKSEL & _CMU_LFECLKSEL_LFE_MASK) >> _CMU_LFECLKSEL_LFE_SHIFT) {
case CMU_LFECLKSEL_LFE_LFRCO:
case CMU_LFECLKSEL_LFE_LFXO:
sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM2);
break;
default:
break;
}
#elif defined(_CMU_LFACLKEN0_RTCC_MASK)
switch ((CMU->LFACLKSEL & _CMU_LFACLKSEL_LFA_MASK) >> _CMU_LFACLKSEL_LFA_SHIFT) {
case CMU_LFACLKSEL_LFA_LFRCO:
case CMU_LFACLKSEL_LFA_LFXO:
sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM2);
break;
default:
break;
}
#endif
}
#endif
#endif

View File

@ -28,20 +28,27 @@
*
******************************************************************************/
#if defined(SL_COMPONENT_CATALOG_PRESENT)
#include "sl_component_catalog.h"
#endif
#include "peripheral_sysrtc.h"
#include "sl_sleeptimer.h"
#include "sli_sleeptimer_hal.h"
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT) && defined(SL_CATALOG_POWER_MANAGER_PRESENT)
#include "sli_hfxo_manager.h"
#endif
#include "em_core.h"
#include "em_cmu.h"
#include "em_prs.h"
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
#include "sl_power_manager.h"
#endif
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT) || defined(SL_CATALOG_HFXO_MANAGER_PRESENT)
#if defined(_SILICON_LABS_32B_SERIES_2)
#include "em_prs.h"
#else
#include "sl_peripheral_prs.h"
#endif
#endif
#if SL_SLEEPTIMER_PERIPHERAL == SL_SLEEPTIMER_PERIPHERAL_SYSRTC
// Minimum difference between current count value and what the comparator of the timer can be set to.
@ -63,9 +70,8 @@ __STATIC_INLINE uint32_t get_time_diff(uint32_t a,
*****************************************************************************/
void sleeptimer_hal_init_timer(void)
{
sl_sysrtc_config_t sysrtc_config = SYSRTC_CONFIG_DEFAULT;
sl_sysrtc_group_config_t group_config = SYSRTC_GROUP_CONFIG_DEFAULT;
const sl_sysrtc_group_channel_compare_config_t group_compare_channel_config = SYSRTC_GROUP_CHANNEL_COMPARE_CONFIG_EARLY_WAKEUP;
sl_hal_sysrtc_config_t sysrtc_config = SYSRTC_CONFIG_DEFAULT;
sl_hal_sysrtc_group_config_t group_config = SYSRTC_GROUP_CONFIG_DEFAULT;
CMU_ClockEnable(cmuClock_SYSRTC, true);
@ -73,33 +79,71 @@ void sleeptimer_hal_init_timer(void)
sysrtc_config.enable_debug_run = true;
#endif
sl_sysrtc_init(&sysrtc_config);
sl_hal_sysrtc_init(&sysrtc_config);
group_config.compare_channel0_enable = false;
group_config.compare_channel1_enable = false;
group_config.p_compare_channel1_config = &group_compare_channel_config;
sl_sysrtc_init_group(0u, &group_config);
sl_sysrtc_disable_group_interrupts(0u, _SYSRTC_GRP0_IEN_MASK);
sl_sysrtc_clear_group_interrupts(0u, _SYSRTC_GRP0_IF_MASK);
sl_sysrtc_enable();
sl_sysrtc_set_counter(0u);
sl_hal_sysrtc_init_group(0u, &group_config);
sl_hal_sysrtc_disable_group_interrupts(0u, _SYSRTC_GRP0_IEN_MASK);
sl_hal_sysrtc_clear_group_interrupts(0u, _SYSRTC_GRP0_IF_MASK);
sl_hal_sysrtc_enable();
sl_hal_sysrtc_set_counter(0u);
NVIC_ClearPendingIRQ(SYSRTC_APP_IRQn);
NVIC_EnableIRQ(SYSRTC_APP_IRQn);
}
/*******************************************************************************
* Hardware Abstraction Layer to perform initialization related to Power Manager.
******************************************************************************/
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
void sli_sleeptimer_hal_power_manager_integration_init(void)
{
// Initialize PRS to start HFXO for early wakeup
CMU_ClockEnable(cmuClock_PRS, true);
#if defined(_SILICON_LABS_32B_SERIES_2)
PRS_ConnectSignal(1UL, prsTypeAsync, prsSignalSYSRTC0_GRP0OUT1);
PRS_ConnectConsumer(1UL, prsTypeAsync, prsConsumerHFXO0_OSCREQ);
#else
sl_hal_prs_async_connect_channel_producer(1UL, SL_HAL_PRS_ASYNC_SYSRTC0_GRP0OUT1);
sl_hal_prs_connect_channel_consumer(1UL, SL_HAL_PRS_TYPE_ASYNC, SL_HAL_PRS_CONSUMER_HFXO0_OSCREQ);
#endif
// Set SYSRTC Compare Channel 1
SYSRTC0->GRP0_CTRL |= (_SYSRTC_GRP0_CTRL_CMP1CMOA_CMPIF << _SYSRTC_GRP0_CTRL_CMP1CMOA_SHIFT);
}
#endif
/*******************************************************************************
* Hardware Abstraction Layer to perform initialization related to HFXO Manager.
******************************************************************************/
#if defined(SL_CATALOG_HFXO_MANAGER_PRESENT)
void sli_sleeptimer_hal_hfxo_manager_integration_init(void)
{
// Set PRS signal from HFXO to SYSRTC capture channel
CMU_ClockEnable(cmuClock_PRS, true);
#if defined(_SILICON_LABS_32B_SERIES_2)
PRS_ConnectSignal(2UL, prsTypeAsync, prsSignalHFXO0L_STATUS1);
PRS_ConnectConsumer(2UL, prsTypeAsync, prsConsumerSYSRTC0_SRC0);
#else
sl_hal_prs_async_connect_channel_producer(2UL, SL_HAL_PRS_ASYNC_SYXO0L_STATUS1);
sl_hal_prs_connect_channel_consumer(2UL, SL_HAL_PRS_TYPE_ASYNC, SL_HAL_PRS_CONSUMER_SYSRTC0_IN0);
#endif
// Set SYSRTC Capture Channel
SYSRTC0->GRP0_CTRL |= (_SYSRTC_GRP0_CTRL_CAP0EDGE_RISING << _SYSRTC_GRP0_CTRL_CAP0EDGE_SHIFT);
}
#endif
/******************************************************************************
* Gets SYSRTC counter value.
*****************************************************************************/
uint32_t sleeptimer_hal_get_counter(void)
{
return sl_sysrtc_get_counter();
return sl_hal_sysrtc_get_counter();
}
/******************************************************************************
@ -107,14 +151,14 @@ uint32_t sleeptimer_hal_get_counter(void)
*****************************************************************************/
uint32_t sleeptimer_hal_get_compare(void)
{
return sl_sysrtc_get_group_compare_channel_value(0u, 0u);
return sl_hal_sysrtc_get_group_compare_channel_value(0u, 0u);
}
/******************************************************************************
* Sets SYSRTC channel zero's compare value.
*
* @note Compare match value is set to the requested value - 1. This is done
* to compensate for the fact that the BURTC compare match interrupt always
* to compensate for the fact that the SYSRTC compare match interrupt always
* triggers at the end of the requested ticks and that the IRQ handler is
* executed when current tick count == compare_value + 1.
*****************************************************************************/
@ -129,7 +173,7 @@ void sleeptimer_hal_set_compare(uint32_t value)
counter = sleeptimer_hal_get_counter();
compare = sleeptimer_hal_get_compare();
if (((sl_sysrtc_get_group_interrupts(0u) & SYSRTC_GRP0_IEN_CMP0) != 0)
if (((sl_hal_sysrtc_get_group_interrupts(0u) & SYSRTC_GRP0_IEN_CMP0) != 0)
|| get_time_diff(compare, counter) > SLEEPTIMER_COMPARE_MIN_DIFF
|| compare == counter) {
// Add margin if necessary
@ -138,7 +182,7 @@ void sleeptimer_hal_set_compare(uint32_t value)
}
compare_value %= SLEEPTIMER_TMR_WIDTH;
sl_sysrtc_set_group_compare_channel_value(0u, 0u, compare_value - 1);
sl_hal_sysrtc_set_group_compare_channel_value(0u, 0u, compare_value - 1);
sleeptimer_hal_enable_int(SLEEPTIMER_EVENT_COMP);
}
CORE_EXIT_CRITICAL();
@ -153,7 +197,7 @@ void sleeptimer_hal_set_compare(uint32_t value)
* Sets SYSRTC channel one's compare value.
*
* @note Compare match value is set to the requested value - 1. This is done
* to compensate for the fact that the BURTC compare match interrupt always
* to compensate for the fact that the SYSRTC compare match interrupt always
* triggers at the end of the requested ticks and that the IRQ handler is
* executed when current tick count == compare_value + 1.
******************************************************************************/
@ -174,18 +218,15 @@ void sleeptimer_hal_set_compare_prs_hfxo_startup(int32_t value)
compare_value = counter + SLEEPTIMER_COMPARE_MIN_DIFF;
}
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT) && defined(SL_CATALOG_POWER_MANAGER_PRESENT)
sli_hfxo_prs_manager_begin_startup_measurement(compare_value);
#endif
compare_value %= SLEEPTIMER_TMR_WIDTH;
sl_sysrtc_set_group_compare_channel_value(0u, 1u, compare_value - 1);
sl_hal_sysrtc_set_group_compare_channel_value(0u, 1u, compare_value - 1);
CORE_EXIT_CRITICAL();
if (cc1_disabled) {
SYSRTC0->GRP0_CTRL |= SYSRTC_GRP0_CTRL_CMP1EN;
SYSRTC0->GRP0_CTRL |= SYSRTC_GRP0_CTRL_CAP0EN;
cc1_disabled = false;
}
}
@ -205,7 +246,7 @@ void sleeptimer_hal_enable_int(uint8_t local_flag)
sysrtc_ien |= SYSRTC_GRP0_IEN_CMP0;
}
sl_sysrtc_enable_group_interrupts(0u, sysrtc_ien);
sl_hal_sysrtc_enable_group_interrupts(0u, sysrtc_ien);
}
/******************************************************************************
@ -226,7 +267,7 @@ void sleeptimer_hal_disable_int(uint8_t local_flag)
SYSRTC0->GRP0_CTRL &= ~_SYSRTC_GRP0_CTRL_CMP0EN_MASK;
}
sl_sysrtc_disable_group_interrupts(0u, sysrtc_int_dis);
sl_hal_sysrtc_disable_group_interrupts(0u, sysrtc_int_dis);
}
/*******************************************************************************
@ -247,7 +288,7 @@ void sleeptimer_hal_set_int(uint8_t local_flag)
bool sli_sleeptimer_hal_is_int_status_set(uint8_t local_flag)
{
bool int_is_set = false;
uint32_t irq_flag = sl_sysrtc_get_group_interrupts(0u);
uint32_t irq_flag = sl_hal_sysrtc_get_group_interrupts(0u);
switch (local_flag) {
case SLEEPTIMER_EVENT_COMP:
@ -275,7 +316,7 @@ void SYSRTC_APP_IRQHandler(void)
uint32_t irq_flag;
CORE_ENTER_ATOMIC();
irq_flag = sl_sysrtc_get_group_interrupts(0u);
irq_flag = sl_hal_sysrtc_get_group_interrupts(0u);
if (irq_flag & SYSRTC_GRP0_IF_OVF) {
local_flag |= SLEEPTIMER_EVENT_OF;
@ -284,7 +325,7 @@ void SYSRTC_APP_IRQHandler(void)
if (irq_flag & SYSRTC_GRP0_IF_CMP0) {
local_flag |= SLEEPTIMER_EVENT_COMP;
}
sl_sysrtc_clear_group_interrupts(0u, irq_flag & (SYSRTC_GRP0_IF_OVF | SYSRTC_GRP0_IF_CMP0));
sl_hal_sysrtc_clear_group_interrupts(0u, irq_flag & (SYSRTC_GRP0_IF_OVF | SYSRTC_GRP0_IF_CMP0));
process_timer_irq(local_flag);
@ -326,6 +367,40 @@ uint16_t sleeptimer_hal_get_clock_accuracy(void)
return CMU_LF_ClockPrecisionGet(cmuClock_SYSRTC);
}
/*******************************************************************************
* Hardware Abstraction Layer to get the capture channel value.
******************************************************************************/
uint32_t sleeptimer_hal_get_capture(void)
{
if ((sl_hal_sysrtc_get_group_interrupts(0) & _SYSRTC_GRP0_IF_CAP0_MASK) != 0) {
sl_hal_sysrtc_clear_group_interrupts(0, _SYSRTC_GRP0_IF_CAP0_MASK);
return sl_hal_sysrtc_get_group_capture_channel_value(0);
} else {
return 0;
}
}
/*******************************************************************************
* Hardware Abstraction Layer to reset PRS signal triggered by the associated
* peripheral.
******************************************************************************/
void sleeptimer_hal_reset_prs_signal(void)
{
sl_hal_sysrtc_clear_group_interrupts(0, SYSRTC_GRP0_IF_CMP1);
}
/*******************************************************************************
* Hardware Abstraction Layer to disable PRS compare and capture channel.
******************************************************************************/
void sleeptimer_hal_disable_prs_compare_and_capture_channel(void)
{
if (!cc1_disabled) {
SYSRTC0->GRP0_CTRL &= ~SYSRTC_GRP0_CTRL_CMP1EN;
SYSRTC0->GRP0_CTRL &= ~SYSRTC_GRP0_CTRL_CAP0EN;
cc1_disabled = true;
}
}
/***************************************************************************//**
* Set lowest energy mode based on a project's configurations and clock source
*

View File

@ -36,23 +36,6 @@
#include <stdbool.h>
#include "em_device.h"
#include "sli_sleeptimer.h"
#include "sl_sleeptimer_config.h"
#if SL_SLEEPTIMER_PERIPHERAL == SL_SLEEPTIMER_PERIPHERAL_DEFAULT
#if defined(RTCC_PRESENT) && RTCC_COUNT >= 1
#undef SL_SLEEPTIMER_PERIPHERAL
#define SL_SLEEPTIMER_PERIPHERAL SL_SLEEPTIMER_PERIPHERAL_RTCC
#elif defined(RTC_PRESENT) && RTC_COUNT >= 1
#undef SL_SLEEPTIMER_PERIPHERAL
#define SL_SLEEPTIMER_PERIPHERAL SL_SLEEPTIMER_PERIPHERAL_RTC
#elif defined(SYSRTC_PRESENT) && SYSRTC_COUNT >= 1
#undef SL_SLEEPTIMER_PERIPHERAL
#define SL_SLEEPTIMER_PERIPHERAL SL_SLEEPTIMER_PERIPHERAL_SYSRTC
#elif defined(BURTC_PRESENT) && BURTC_COUNT >= 1
#undef SL_SLEEPTIMER_PERIPHERAL
#define SL_SLEEPTIMER_PERIPHERAL SL_SLEEPTIMER_PERIPHERAL_BURTC
#endif
#endif
#ifdef __cplusplus
extern "C" {
@ -84,6 +67,14 @@ uint32_t sleeptimer_hal_get_compare(void);
******************************************************************************/
void sleeptimer_hal_set_compare(uint32_t value);
/*******************************************************************************
* Hardware Abstraction Layer to set a comparator value to trigger a
* peripheral request signal to initialize.
*
* @param value Number of ticks to set.
******************************************************************************/
void sleeptimer_hal_set_compare_prs_hfxo_startup(int32_t value);
/*******************************************************************************
* Hardware Abstraction Layer to get the timer frequency.
******************************************************************************/
@ -110,6 +101,37 @@ void sleeptimer_hal_disable_int(uint8_t local_flag);
******************************************************************************/
void sleeptimer_hal_set_int(uint8_t local_flag);
/*******************************************************************************
* Hardware Abstraction Layer to get the sleeptimer's clock accuracy.
*
* @return Clock accuracy in PPM.
******************************************************************************/
uint16_t sleeptimer_hal_get_clock_accuracy(void);
/*******************************************************************************
* Hardware Abstraction Layer to get the capture channel value.
*
* @note Not supported by all peripherals Sleeptimer can use.
*
* @return Capture value.
******************************************************************************/
uint32_t sleeptimer_hal_get_capture(void);
/*******************************************************************************
* Hardware Abstraction Layer to reset PRS signal triggered by the associated
* peripheral.
*
* @note Not supported by all peripherals Sleeptimer can use.
******************************************************************************/
void sleeptimer_hal_reset_prs_signal(void);
/*******************************************************************************
* Hardware Abstraction Layer to disable PRS compare and capture channel.
*
* @note Not supported by all peripherals Sleeptimer can use.
******************************************************************************/
void sleeptimer_hal_disable_prs_compare_and_capture_channel(void);
/*******************************************************************************
* Process the timer interrupt.
*