Initial commit of firmware
This commit is contained in:
591
Libs/platform/service/power_manager/inc/sl_power_manager.h
Normal file
591
Libs/platform/service/power_manager/inc/sl_power_manager.h
Normal file
@@ -0,0 +1,591 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Power 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 SL_POWER_MANAGER_H
|
||||
#define SL_POWER_MANAGER_H
|
||||
|
||||
#ifndef SL_POWER_MANAGER_DEBUG
|
||||
#include "sl_power_manager_config.h"
|
||||
#endif
|
||||
#include "sl_slist.h"
|
||||
#include "sl_status.h"
|
||||
#include "sl_sleeptimer.h"
|
||||
#include "sl_enum.h"
|
||||
#include "sl_core.h"
|
||||
#include "sl_code_classification.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup power_manager Power Manager
|
||||
*
|
||||
* @details Power manager is a platform level software module that manages
|
||||
* the system's energy modes. Its main purpose is to transition the system to a
|
||||
* low energy mode when the processor has nothing to execute. The energy mode the
|
||||
* system will transition to is determined each time the system goes to sleep
|
||||
* using requirements. These requirements are set by the different software modules
|
||||
* (drivers, stacks, application code, etc...). Power manager also ensures a
|
||||
* strict control of some power hungry resources such as the high frequency
|
||||
* external oscillator (normally called HFXO). Power manager also
|
||||
* offers a notification mechanism through which any piece of software module can be
|
||||
* notified of energy mode transitions through callbacks.
|
||||
*
|
||||
* @note Sleep Driver is deprecated. Use Power Manager for all sleep-related
|
||||
* operations. See <a href="https://www.silabs.com/documents/
|
||||
* public/application-notes/
|
||||
* an1358-migrating-from-sleep-driver-to-power-manager.pdf">AN1358:
|
||||
* Migrating from Sleep Driver to Power Manager</a> for information on how
|
||||
* to migrate from Sleep Driver to Power Manager.
|
||||
* @note Emlib EMU functions EMU_EnterEM1()/EMU_EnterEM2()/EMU_EnterEM3() must not
|
||||
* be used when the Power Manager is present. The Power Manager module must be
|
||||
* the one deciding at which EM level the device sleeps to ensure the application
|
||||
* properly works. Using both at the same time could lead to undefined behavior
|
||||
* in the application.
|
||||
*
|
||||
* @details
|
||||
* ## Initialization
|
||||
*
|
||||
* Power manager must be initialized prior to any call to power manager API.
|
||||
* If sl_system is used, only sl_system_init() must be called, otherwise
|
||||
* sl_power_manager_init() must be called manually. Note that power manager
|
||||
* must be initialized after the clock(s), when initialized manually, as the
|
||||
* power manager check which oscillators are used during the initialization phase.
|
||||
*
|
||||
* ## Add and remove requirements
|
||||
*
|
||||
* The drivers should add and remove energy mode requirements, at runtime, on the
|
||||
* lowest energy mode for them depending on their state. When calling
|
||||
* sl_power_manager_sleep(), the lowest possible Energy mode will be automatically
|
||||
* selected.
|
||||
*
|
||||
* It is possible to add and remove requirements from ISR. If a specific energy mode
|
||||
* is required in the ISR, but not required to generate the interrupt, a requirement
|
||||
* on the energy mode can be added from the ISR. It is guaranteed that the associated
|
||||
* clock will be active once sl_power_manager_add_requirement() returns. The EM
|
||||
* requirement can be also be removed from an ISR.
|
||||
*
|
||||
* Requirements should not be removed if it was not previously added.
|
||||
*
|
||||
* ## Subscribe to events
|
||||
*
|
||||
* It possible to get notified when the system transition from a power level to
|
||||
* another power level. This can allow to do some operations depending on which level
|
||||
* the system goes, such as saving/restoring context.
|
||||
*
|
||||
* ## Sleep
|
||||
*
|
||||
* When the software has no more operation and only need to wait for an event, the
|
||||
* software must call sl_power_manager_sleep(). This is automatically done when the
|
||||
* kernel is present, but it needs to be called from the super loop in a baremetal
|
||||
* project.
|
||||
*
|
||||
* ## Query callback functions
|
||||
*
|
||||
* ### Is OK to sleep
|
||||
*
|
||||
* Between the time `sl_power_manager_sleep` is called and the MCU is really put
|
||||
* in a lower Energy mode, it is possible that an ISR occur and require the system
|
||||
* to resume at that time instead of sleeping. So a callback is called in a critical
|
||||
* section to validate that the MCU can go to sleep.
|
||||
*
|
||||
* In case of an application that runs on an RTOS, the RTOS will take care of determining
|
||||
* if it is ok to sleep. In case of a baremetal application, the function `sl_power_manager_is_ok_to_sleep()`
|
||||
* will be generated automatically by Simplicity Studio's wizard.
|
||||
* The function will look at multiple software modules from the SDK to take a decision.
|
||||
* The application can contribute to the decision by defining the function `app_is_ok_to_sleep()`.
|
||||
* If any of the software modules (including the application via `app_is_ok_to_sleep()`) return false,
|
||||
* the process of entering in sleep will be aborted.
|
||||
*
|
||||
* ### Sleep on ISR exit
|
||||
*
|
||||
* When the system enters sleep, the only way to wake it up is via an interrupt or
|
||||
* exception. By default, power manager will assume that when an interrupt
|
||||
* occurs and the corresponding ISR has been executed, the system must not go back
|
||||
* to sleep. However, in the case where all the processing related to this interrupt
|
||||
* is performed in the ISR, it is possible to go back to sleep by using this hook.
|
||||
*
|
||||
* In case of an application that runs on an RTOS, the RTOS will take care of determining
|
||||
* if the system can go back to sleep on ISR exit. Power manager will ensure the system resumes
|
||||
* its operations as soon as a task is resumed, posted or that its delay expires.
|
||||
* In case of a baremetal application, the function `sl_power_manager_sleep_on_isr_exit()` will be generated
|
||||
* automatically by Simplicity Studio's wizard. The function will look at multiple software modules from the SDK
|
||||
* to take a decision. The application can contribute to the decision by defining the
|
||||
* function `app_sleep_on_isr_exit()`.
|
||||
* The generated function will take a decision based on the value returned by the different software modules
|
||||
* (including the application via `app_sleep_on_isr_exit()`):
|
||||
*
|
||||
* `SL_POWER_MANAGER_IGNORE`: if the software module did not cause the system wakeup and/or doesn't want to contribute to the decision.
|
||||
* `SL_POWER_MANAGER_SLEEP`: if the software module did cause the system wakeup, but the system should go back to sleep.
|
||||
* `SL_POWER_MANAGER_WAKEUP`: if the software module did cause the system wakeup, and the system should not go back to sleep.
|
||||
*
|
||||
* If any software module returned `SL_POWER_MANAGER_SLEEP` and none returned `SL_POWER_MANAGER_WAKEUP`,
|
||||
* the system will go back to sleep. Any other combination will cause the system not to go back to sleep.
|
||||
*
|
||||
* ### Debugging feature
|
||||
*
|
||||
* By setting the configuration define SL_POWER_MANAGER_DEBUG to 1, it is possible
|
||||
* to record the requirements currently set and their owner. It is possible to print
|
||||
* at any time a table that lists all the added requirements and their owner. This
|
||||
* table can be printed by caling the function
|
||||
* sl_power_manager_debug_print_em_requirements().
|
||||
* Make sure to add the following define
|
||||
* ```
|
||||
* #define CURRENT_MODULE_NAME "<Module printable name here>"
|
||||
* ```
|
||||
* to any application code source file that adds and removes requirements.
|
||||
*
|
||||
* ## Usage Example
|
||||
*
|
||||
* ```
|
||||
* #define EM_EVENT_MASK_ALL (SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM0 \
|
||||
* | SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM0 \
|
||||
* | SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM1 \
|
||||
* | SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM1 \
|
||||
* | SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM2 \
|
||||
* | SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM2 \
|
||||
* | SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM3 \
|
||||
* | SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM3)
|
||||
*
|
||||
* sl_power_manager_em_transition_event_handle_t event_handle;
|
||||
* sl_power_manager_em_transition_event_info_t event_info = {
|
||||
* .event_mask = EM_EVENT_MASK_ALL,
|
||||
* .on_event = my_events_callback,
|
||||
* }
|
||||
*
|
||||
* void main(void)
|
||||
* {
|
||||
* // Initialize power manager; not needed if sl_system_init() is used.
|
||||
* sl_power_manager_init();
|
||||
*
|
||||
* // Limit sleep level to EM1
|
||||
* sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM1);
|
||||
*
|
||||
* // Subscribe to all event types; get notified for every power transition.
|
||||
* sl_power_manager_subscribe_em_transition_event(&event_handle, &event_info);
|
||||
* while (1) {
|
||||
* // Actions
|
||||
* [...]
|
||||
* if (completed) {
|
||||
* // Remove energy mode requirement, can go to EM2 or EM3 now, depending on the configuration
|
||||
* sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1);
|
||||
* }
|
||||
*
|
||||
* // Sleep to lowest possible energy mode; This call is not needed when using the kernel.
|
||||
* sl_power_manager_sleep();
|
||||
* // Will resume after an interrupt or exception
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* void my_events_callback(sl_power_manager_em_t from,
|
||||
* sl_power_manager_em_t to)
|
||||
* {
|
||||
* printf("Event:%s-%s\r\n", string_lookup_table[from], string_lookup_table[to]);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Defines
|
||||
|
||||
// Current module name for debugging features
|
||||
#ifndef CURRENT_MODULE_NAME
|
||||
#define CURRENT_MODULE_NAME "Anonymous" ///< current module name
|
||||
#endif
|
||||
|
||||
// Power transition events
|
||||
#define SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM0 (1 << 0) ///< sl power manager event transition entering em0
|
||||
#define SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM0 (1 << 1) ///< sl power manager event transition leaving em0
|
||||
#define SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM1 (1 << 2) ///< sl power manager event transition entering em1
|
||||
#define SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM1 (1 << 3) ///< sl power manager event transition leaving em1
|
||||
#define SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM2 (1 << 4) ///< sl power manager event transition entering em2
|
||||
#define SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM2 (1 << 5) ///< sl power manager event transition leaving em2
|
||||
#define SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM3 (1 << 6) ///< sl power manager event transition entering em3 (DEPRECATED)
|
||||
#define SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM3 (1 << 7) ///< sl power manager event transition leaving em3 (DEPRECATED)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Data Types
|
||||
|
||||
/// @brief Energy modes
|
||||
typedef enum {
|
||||
SL_POWER_MANAGER_EM0 = 0, ///< Run Mode (Energy Mode 0)
|
||||
SL_POWER_MANAGER_EM1, ///< Sleep Mode (Energy Mode 1)
|
||||
SL_POWER_MANAGER_EM2, ///< Deep Sleep Mode (Energy Mode 2)
|
||||
SL_POWER_MANAGER_EM3, ///< Stop Mode (Energy Mode 3)
|
||||
SL_POWER_MANAGER_EM4, ///< Shutoff Mode (Energy Mode 4)
|
||||
} sl_power_manager_em_t;
|
||||
|
||||
/// @brief Mask of all the event(s) to listen to.
|
||||
typedef uint32_t sl_power_manager_em_transition_event_t;
|
||||
|
||||
/***************************************************************************//**
|
||||
* Typedef for the user supplied callback function which is called when
|
||||
* an energy mode transition occurs.
|
||||
*
|
||||
* @param from Energy mode we are leaving.
|
||||
* @param to Energy mode we are entering.
|
||||
******************************************************************************/
|
||||
typedef void (*sl_power_manager_em_transition_on_event_t)(sl_power_manager_em_t from,
|
||||
sl_power_manager_em_t to);
|
||||
|
||||
/// @brief Struct representing energy mode transition event information
|
||||
typedef struct {
|
||||
const sl_power_manager_em_transition_event_t event_mask; ///< Mask of the transitions on which the callback should be called.
|
||||
const sl_power_manager_em_transition_on_event_t on_event; ///< Function that must be called when the event occurs.
|
||||
} sl_power_manager_em_transition_event_info_t;
|
||||
|
||||
/// @brief Struct representing energy mode transition event handle
|
||||
typedef struct {
|
||||
sl_slist_node_t node; ///< List node.
|
||||
const sl_power_manager_em_transition_event_info_t *info; ///< Handle event info.
|
||||
} sl_power_manager_em_transition_event_handle_t;
|
||||
|
||||
/// On ISR Exit Hook answer
|
||||
SL_ENUM(sl_power_manager_on_isr_exit_t) {
|
||||
SL_POWER_MANAGER_IGNORE = (1UL << 0UL), ///< The module did not trigger an ISR and it doesn't want to contribute to the decision
|
||||
SL_POWER_MANAGER_SLEEP = (1UL << 1UL), ///< The module was the one that caused the system wakeup and the system SHOULD go back to sleep
|
||||
SL_POWER_MANAGER_WAKEUP = (1UL << 2UL), ///< The module was the one that caused the system wakeup and the system MUST NOT go back to sleep
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Internal Prototypes only to be used by Power Manager module
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sli_power_manager_update_em_requirement(sl_power_manager_em_t em,
|
||||
bool add);
|
||||
|
||||
// To make sure that we are able to optimize out the string argument when the
|
||||
// debug feature is disable, we use a pre-processor macro resulting in a no-op.
|
||||
// We also make sure to always have a definition for the function regardless if
|
||||
// the debug feature is enable or not for binary compatibility.
|
||||
#if (SL_POWER_MANAGER_DEBUG == 1)
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sli_power_manager_debug_log_em_requirement(sl_power_manager_em_t em,
|
||||
bool add,
|
||||
const char *name);
|
||||
#else
|
||||
#define sli_power_manager_debug_log_em_requirement(em, add, name) /* no-op */
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Prototypes
|
||||
|
||||
/***************************************************************************//**
|
||||
* Initialize Power Manager module.
|
||||
* @return Status code
|
||||
******************************************************************************/
|
||||
sl_status_t sl_power_manager_init(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Sleep at the lowest allowed energy mode.
|
||||
*
|
||||
* @note Must not be called from ISR
|
||||
* @par
|
||||
* @note This function will expect and call a callback with the following
|
||||
* signature: `bool sl_power_manager_is_ok_to_sleep(void)`.
|
||||
*
|
||||
* @note This function can be used to cancel a sleep action and handle the
|
||||
* possible race condition where an ISR that would cause a wakeup is
|
||||
* triggered right after the decision to call sl_power_manager_sleep()
|
||||
* has been made.
|
||||
*
|
||||
* @note This function must NOT be called with interrupts disabled. This means
|
||||
* both BASEPRI and PRIMASK MUST have a value of 0 when invoking this
|
||||
* function.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* ```c
|
||||
* void main(void)
|
||||
* {
|
||||
* sl_power_manager_init();
|
||||
* while (1) {
|
||||
* tick();
|
||||
* sl_power_manager_sleep();
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sl_power_manager_sleep(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Adds requirement on given energy mode.
|
||||
*
|
||||
* @param em Energy mode to add the requirement to:
|
||||
* - ::SL_POWER_MANAGER_EM1
|
||||
* - ::SL_POWER_MANAGER_EM2 (DEPRECATED)
|
||||
*
|
||||
* @note Adding EM requirements on SL_POWER_MANAGER_EM2 is now DEPRECATED.
|
||||
* The calls can simply be removed since the system will go to deepsleep
|
||||
* (EM2/EM3) in the absence of EM1 requirements.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
__STATIC_INLINE void sl_power_manager_add_em_requirement(sl_power_manager_em_t em)
|
||||
{
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
|
||||
CORE_ENTER_CRITICAL();
|
||||
sli_power_manager_update_em_requirement(em, true);
|
||||
|
||||
sli_power_manager_debug_log_em_requirement(em, true, (const char *)CURRENT_MODULE_NAME);
|
||||
CORE_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Removes requirement on given energy mode.
|
||||
*
|
||||
* @param em Energy mode to remove the requirement to:
|
||||
* - ::SL_POWER_MANAGER_EM1
|
||||
* - ::SL_POWER_MANAGER_EM2 (DEPRECATED)
|
||||
*
|
||||
* @note Removing EM requirements on SL_POWER_MANAGER_EM2 is now DEPRECATED.
|
||||
* The calls can simply be removed since the system will go to deepsleep
|
||||
* (EM2/EM3) in the absence of EM1 requirements.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
__STATIC_INLINE void sl_power_manager_remove_em_requirement(sl_power_manager_em_t em)
|
||||
{
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
|
||||
CORE_ENTER_CRITICAL();
|
||||
sli_power_manager_update_em_requirement(em, false);
|
||||
|
||||
sli_power_manager_debug_log_em_requirement(em, false, (const char *)CURRENT_MODULE_NAME);
|
||||
CORE_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Registers a callback to be called on given Energy Mode transition(s).
|
||||
*
|
||||
* @param event_handle Event handle (no initialization needed).
|
||||
*
|
||||
* @param event_info Event info structure that contains the event mask and the
|
||||
* callback that must be called.
|
||||
*
|
||||
* @note Adding and removing requirement(s) from a callback on a transition event
|
||||
* is not supported.
|
||||
*
|
||||
* @note The parameters passed must be persistent, meaning that they need to survive
|
||||
* until the callback fires.
|
||||
*
|
||||
* @note SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM3 and
|
||||
* SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM3 are now DEPRECATED and should
|
||||
* not be used in the event_info argument.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* ```c
|
||||
* #define EM_EVENT_MASK_ALL ( SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM0 \
|
||||
* | SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM0 \
|
||||
* | SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM1 \
|
||||
* | SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM1 \
|
||||
* | SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM2 \
|
||||
* | SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM2)
|
||||
*
|
||||
* sl_power_manager_em_transition_event_handle_t event_handle;
|
||||
* sl_power_manager_em_transition_event_info_t event_info = {
|
||||
* .event_mask = EM_EVENT_MASK_ALL,
|
||||
* .on_event = my_callback,
|
||||
* };
|
||||
*
|
||||
* void my_callback(sl_power_manager_em_t from,
|
||||
* sl_power_manager_em_t to)
|
||||
* {
|
||||
* [...]
|
||||
* }
|
||||
*
|
||||
* void main(void)
|
||||
* {
|
||||
* sl_power_manager_init();
|
||||
* sl_power_manager_subscribe_em_transition_event(&event_handle, &event_info);
|
||||
* }
|
||||
* ```
|
||||
******************************************************************************/
|
||||
void sl_power_manager_subscribe_em_transition_event(sl_power_manager_em_transition_event_handle_t *event_handle,
|
||||
const sl_power_manager_em_transition_event_info_t *event_info);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Unregisters an event callback handle on Energy mode transition.
|
||||
*
|
||||
* @param event_handle Event handle which must be unregistered (must have been
|
||||
* registered previously).
|
||||
*
|
||||
* @note An EFM_ASSERT is thrown if the handle is not found.
|
||||
******************************************************************************/
|
||||
void sl_power_manager_unsubscribe_em_transition_event(sl_power_manager_em_transition_event_handle_t *event_handle);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Get configurable overhead value for early restore time in Sleeptimer ticks
|
||||
* when a schedule wake-up is set.
|
||||
*
|
||||
* @return Current overhead value for early restore time.
|
||||
*
|
||||
* @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);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Set configurable overhead value for early restore time in Sleeptimer ticks
|
||||
* used for schedule wake-up.
|
||||
* Must be called after initialization else the value will be overwritten.
|
||||
*
|
||||
* @param overhead_tick Overhead value to set for early restore time.
|
||||
*
|
||||
* @note The overhead value can also be negative to remove time from the restore
|
||||
* process.
|
||||
*
|
||||
* @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);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Get configurable minimum off-time value for schedule wake-up in Sleeptimer
|
||||
* ticks.
|
||||
*
|
||||
* @return Current minimum off-time value for schedule wake-up.
|
||||
*
|
||||
* @note Turning on external high frequency clock, such as HFXO, requires more
|
||||
* energy since we must supply higher current for the wake-up.
|
||||
* Therefore, when an 'external high frequency clock enable' is scheduled
|
||||
* in 'x' time, there is a threshold 'x' value where turning off the clock
|
||||
* is not worthwhile since the energy consumed by taking into account the
|
||||
* wake-up will be greater than if we just keep the clock on until the next
|
||||
* scheduled clock enabled. This threshold value is what we refer as the
|
||||
* minimum off-time.
|
||||
*
|
||||
* @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);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Set configurable minimum off-time value for schedule wake-up in Sleeptimer
|
||||
* ticks.
|
||||
*
|
||||
* @param minimum_offtime_tick minimum off-time value to set for schedule
|
||||
* wake-up.
|
||||
*
|
||||
* @note Turning on external high frequency clock, such as HFXO, requires more
|
||||
* energy since we must supply higher current for the wake-up.
|
||||
* Therefore, when an 'external high frequency clock enable' is scheduled
|
||||
* in 'x' time, there is a threshold 'x' value where turning off the clock
|
||||
* is not worthwhile since the energy consumed by taking into account the
|
||||
* wake-up will be greater than if we just keep the clock on until the next
|
||||
* scheduled clock enabled. This threshold value is what we refer as the
|
||||
* minimum off-time.
|
||||
*
|
||||
* @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);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Enable or disable fast wake-up in EM2 and EM3
|
||||
*
|
||||
* @param enable True False variable act as a switch for this api
|
||||
*
|
||||
* @note Will also update the wake up time from EM2 to EM0.
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**************************************************************************//**
|
||||
* Determines if the HFXO interrupt was part of the last wake-up and/or if
|
||||
* the HFXO early wakeup expired during the last ISR
|
||||
* and if it was the only timer to expire in that period.
|
||||
*
|
||||
* @return true if power manager sleep can return to sleep,
|
||||
* false otherwise.
|
||||
*
|
||||
* @note This function will always return false in case a requirement
|
||||
* is added on SL_POWER_MANAGER_EM1, since we will
|
||||
* never sleep at a lower level than EM1.
|
||||
*****************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
bool sl_power_manager_is_latest_wakeup_internal(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Enter energy mode 4 (EM4).
|
||||
*
|
||||
* @note You should not expect to return from this function. Once the device
|
||||
* enters EM4, only a power on reset or external reset pin can wake the
|
||||
* device.
|
||||
*
|
||||
* @note On xG22 devices, this function re-configures the IADC if EM4 entry
|
||||
* is possible.
|
||||
******************************************************************************/
|
||||
void sl_power_manager_enter_em4(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* When EM4 pin retention is set to power_manager_pin_retention_latch,
|
||||
* then pins are retained through EM4 entry and wakeup. The pin state is
|
||||
* released by calling this function. The feature allows peripherals or
|
||||
* GPIO to be re-initialized after EM4 exit (reset), and when
|
||||
* initialization is done, this function can release pins and return
|
||||
* control to the peripherals or GPIO.
|
||||
*
|
||||
* @note When the EM4 Pin Retention feature is not available on a device,
|
||||
* calling this function will do nothing.
|
||||
******************************************************************************/
|
||||
void sl_power_manager_em4_unlatch_pin_retention(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Energy mode 4 pre-sleep hook function.
|
||||
*
|
||||
* @note This function is called by @ref sl_power_manager_enter_em4 just
|
||||
* prior to the sequence of writes to put the device in EM4. The
|
||||
* function implementation does not perform anything, but it is
|
||||
* SL_WEAK so that it can be re-implemented in application code if
|
||||
* actions are needed.
|
||||
******************************************************************************/
|
||||
void sl_power_manager_em4_presleep_hook(void);
|
||||
|
||||
/** @} (end addtogroup power_manager) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SL_POWER_MANAGER_H
|
||||
@@ -0,0 +1,60 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Power 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 SL_POWER_MANAGER_DEBUG_H
|
||||
#define SL_POWER_MANAGER_DEBUG_H
|
||||
|
||||
#include "sl_power_manager.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* @addtogroup power_manager
|
||||
* @{
|
||||
******************************************************************************/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Prototypes
|
||||
|
||||
/***************************************************************************//**
|
||||
* Print a table that describes the current requirements on each energy
|
||||
* mode and their owner.
|
||||
******************************************************************************/
|
||||
void sl_power_manager_debug_print_em_requirements(void);
|
||||
|
||||
/** @} (end addtogroup power_manager) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
172
Libs/platform/service/power_manager/inc/sli_power_manager.h
Normal file
172
Libs/platform/service/power_manager/inc/sli_power_manager.h
Normal file
@@ -0,0 +1,172 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Power Manager Private 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_POWER_MANAGER_H
|
||||
#define SLI_POWER_MANAGER_H
|
||||
|
||||
#include "sl_power_manager.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
****************************** HOOK REFERENCES ****************************
|
||||
******************************************************************************/
|
||||
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
bool sl_power_manager_sleep_on_isr_exit(void);
|
||||
|
||||
// Callback to application after wakeup but before restoring interrupts.
|
||||
// For internal Silicon Labs use only
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
__WEAK void sli_power_manager_on_wakeup(void);
|
||||
|
||||
// Hook that can be used by the log outputer to suspend transmission of logs
|
||||
// in case it would require energy mode changes while in the sleep loop.
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
__WEAK void sli_power_manager_suspend_log_transmission(void);
|
||||
|
||||
// Hook that can be used by the log outputer to resume transmission of logs.
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
__WEAK void sli_power_manager_resume_log_transmission(void);
|
||||
|
||||
// Callback to notify possible transition from EM1P to EM2.
|
||||
// For internal Silicon Labs use only
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
__WEAK void sli_power_manager_em1p_to_em2_notification(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Mandatory callback that allows to cancel sleeping action.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
bool sl_power_manager_is_ok_to_sleep(void);
|
||||
|
||||
/*******************************************************************************
|
||||
***************************** PROTOTYPES **********************************
|
||||
******************************************************************************/
|
||||
|
||||
void sli_power_manager_update_hf_clock_settings_preservation_requirement(bool add);
|
||||
|
||||
/***************************************************************************//**
|
||||
* 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);
|
||||
|
||||
/***************************************************************************//**
|
||||
* 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);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Informs the power manager module that the high accuracy/high frequency clock
|
||||
* is used.
|
||||
*
|
||||
* @note FOR INTERNAL USE ONLY.
|
||||
*
|
||||
* @note Must be called by RAIL initialization in case radio clock settings
|
||||
* are not set before the Power Manager initialization.
|
||||
******************************************************************************/
|
||||
__WEAK void sli_power_manager_set_high_accuracy_hf_clock_as_used(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Gets the wake-up restore process time.
|
||||
* If we are not in the context of a deepsleep and therefore don't need to
|
||||
* do a restore, the return value is 0.
|
||||
*
|
||||
*
|
||||
* @return Wake-up restore process time.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
uint32_t sli_power_manager_get_restore_delay(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Initiates the wake-up restore process.
|
||||
******************************************************************************/
|
||||
void sli_power_manager_initiate_restore(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Performs pre sleep operations.
|
||||
*
|
||||
* @note Must only be called by the RTOS integration code.
|
||||
******************************************************************************/
|
||||
void sli_power_manager_pre_sleep(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Fetches current energy mode
|
||||
*
|
||||
* @return Returns current energy mode
|
||||
******************************************************************************/
|
||||
sl_power_manager_em_t sli_power_manager_get_current_em(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Update Energy Mode 4 configurations.
|
||||
******************************************************************************/
|
||||
void sli_power_manager_init_em4(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* 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);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Initializes energy mode transition list.
|
||||
******************************************************************************/
|
||||
void sli_power_manager_em_transition_event_list_init(void);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Notify subscribers about energy mode transition.
|
||||
*
|
||||
* @param from Energy mode from which CPU comes from.
|
||||
*
|
||||
* @param to Energy mode to which CPU is going to.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sli_power_manager_notify_em_transition(sl_power_manager_em_t from,
|
||||
sl_power_manager_em_t to);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SLI_POWER_MANAGER_H */
|
||||
@@ -0,0 +1,213 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Power Manager common API implementation.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2024 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 "sl_power_manager.h"
|
||||
#include "sl_power_manager_config.h"
|
||||
#include "sli_power_manager.h"
|
||||
#include "sli_clock_manager.h"
|
||||
#include "sl_assert.h"
|
||||
#include "sl_atomic.h"
|
||||
#include "sl_clock_manager.h"
|
||||
|
||||
#if defined(SL_COMPONENT_CATALOG_PRESENT)
|
||||
#include "sl_component_catalog.h"
|
||||
#endif
|
||||
|
||||
#include "em_device.h"
|
||||
#if !defined(_SILICON_LABS_32B_SERIES_3)
|
||||
#include "em_emu.h"
|
||||
#else
|
||||
#include "sli_power_manager_execution_modes_private.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/*******************************************************************************
|
||||
*************************** LOCAL VARIABLES ********************************
|
||||
******************************************************************************/
|
||||
|
||||
// Events subscribers lists
|
||||
static sl_slist_node_t *power_manager_em_transition_event_list = NULL;
|
||||
|
||||
/*******************************************************************************
|
||||
************************** GLOBAL FUNCTIONS *******************************
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* Last-chance check before sleep.
|
||||
*
|
||||
* @return True, if the system should actually sleep.
|
||||
* False, if not.
|
||||
*
|
||||
* @note This is the fallback implementation of the callback, it can be
|
||||
* overridden by the application or other components.
|
||||
******************************************************************************/
|
||||
__WEAK bool sl_power_manager_is_ok_to_sleep(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Check if the MCU can sleep after an interrupt.
|
||||
*
|
||||
* @return True, if the system can sleep after the interrupt.
|
||||
* False, otherwise.
|
||||
*
|
||||
* @note This is the fallback implementation of the callback, it can be
|
||||
* overridden by the application or other components.
|
||||
******************************************************************************/
|
||||
__WEAK bool sl_power_manager_sleep_on_isr_exit(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* 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 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 (defined(EMU_VSCALE_PRESENT) && !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT))
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
|
||||
CORE_ENTER_CRITICAL();
|
||||
|
||||
sli_power_manager_em23_voltage_scaling_enable_fast_wakeup(enable);
|
||||
|
||||
CORE_EXIT_CRITICAL();
|
||||
#else
|
||||
(void)enable;
|
||||
#endif
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Registers a callback to be called on given Energy Mode transition(s).
|
||||
*
|
||||
* @note Adding/Removing requirement(s) from the callback is not supported.
|
||||
******************************************************************************/
|
||||
void sl_power_manager_subscribe_em_transition_event(sl_power_manager_em_transition_event_handle_t *event_handle,
|
||||
const sl_power_manager_em_transition_event_info_t *event_info)
|
||||
{
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
|
||||
event_handle->info = event_info;
|
||||
CORE_ENTER_CRITICAL();
|
||||
sl_slist_push(&power_manager_em_transition_event_list, &event_handle->node);
|
||||
CORE_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Unregisters an event callback handle on Energy mode transition.
|
||||
******************************************************************************/
|
||||
void sl_power_manager_unsubscribe_em_transition_event(sl_power_manager_em_transition_event_handle_t *event_handle)
|
||||
{
|
||||
CORE_DECLARE_IRQ_STATE;
|
||||
|
||||
CORE_ENTER_CRITICAL();
|
||||
sl_slist_remove(&power_manager_em_transition_event_list, &event_handle->node);
|
||||
CORE_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Initializes energy mode transition list.
|
||||
******************************************************************************/
|
||||
void sli_power_manager_em_transition_event_list_init(void)
|
||||
{
|
||||
sl_slist_init(&power_manager_em_transition_event_list);
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Notify subscribers about energy mode transition.
|
||||
******************************************************************************/
|
||||
void sli_power_manager_notify_em_transition(sl_power_manager_em_t from,
|
||||
sl_power_manager_em_t to)
|
||||
{
|
||||
sl_power_manager_em_transition_event_handle_t *handle;
|
||||
sl_power_manager_em_transition_event_t transition = 0;
|
||||
|
||||
switch (to) {
|
||||
case SL_POWER_MANAGER_EM0:
|
||||
transition = SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM0;
|
||||
break;
|
||||
|
||||
case SL_POWER_MANAGER_EM1:
|
||||
transition = SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM1;
|
||||
break;
|
||||
|
||||
case SL_POWER_MANAGER_EM2:
|
||||
transition = SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM2;
|
||||
break;
|
||||
|
||||
#if !defined(SL_CATALOG_POWER_MANAGER_ARM_SLEEP_ON_EXIT)
|
||||
case SL_POWER_MANAGER_EM3:
|
||||
transition = SL_POWER_MANAGER_EVENT_TRANSITION_ENTERING_EM3;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
EFM_ASSERT(0);
|
||||
}
|
||||
|
||||
switch (from) {
|
||||
case SL_POWER_MANAGER_EM0:
|
||||
transition |= SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM0;
|
||||
break;
|
||||
|
||||
case SL_POWER_MANAGER_EM1:
|
||||
transition |= SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM1;
|
||||
break;
|
||||
|
||||
case SL_POWER_MANAGER_EM2:
|
||||
transition |= SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM2;
|
||||
break;
|
||||
|
||||
#if !defined(SL_CATALOG_POWER_MANAGER_ARM_SLEEP_ON_EXIT)
|
||||
case SL_POWER_MANAGER_EM3:
|
||||
transition |= SL_POWER_MANAGER_EVENT_TRANSITION_LEAVING_EM3;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
EFM_ASSERT(0);
|
||||
}
|
||||
|
||||
SL_SLIST_FOR_EACH_ENTRY(power_manager_em_transition_event_list, handle, sl_power_manager_em_transition_event_handle_t, node) {
|
||||
if ((handle->info->event_mask & transition) > 0) {
|
||||
handle->info->on_event(from, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Power Manager EM4 API implementation.
|
||||
*******************************************************************************
|
||||
* # License
|
||||
* <b>Copyright 2024 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 "sl_power_manager.h"
|
||||
#include "sl_power_manager_config.h"
|
||||
#include "sli_power_manager.h"
|
||||
|
||||
#if defined(SL_COMPONENT_CATALOG_PRESENT)
|
||||
#include "sl_component_catalog.h"
|
||||
#endif
|
||||
|
||||
#include "em_device.h"
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2)
|
||||
#include "em_emu.h"
|
||||
#include "em_cmu.h"
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
|
||||
#include "em_iadc.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*******************************************************************************
|
||||
****************************** DEFINES ************************************
|
||||
******************************************************************************/
|
||||
|
||||
#if defined(WDOG_PRESENT)
|
||||
// Macros to determine if WDOG instances are clocked or not
|
||||
|
||||
#if defined(CMU_CLKEN0_WDOG0)
|
||||
#define WDOG0_CLOCK_ENABLED_BIT (CMU->CLKEN0 & CMU_CLKEN0_WDOG0)
|
||||
#else
|
||||
// There's no CMU->CLKEN1 so assume the WDOG0 is clocked
|
||||
#define WDOG0_CLOCK_ENABLED_BIT 1
|
||||
#endif
|
||||
|
||||
#if defined(CMU_CLKEN1_WDOG1)
|
||||
#define WDOG1_CLOCK_ENABLED_BIT (CMU->CLKEN1 & CMU_CLKEN1_WDOG1)
|
||||
#else
|
||||
// There's no CMU->CLKEN1 so assume the WDOG1 is clocked
|
||||
#define WDOG1_CLOCK_ENABLED_BIT 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
************************** LOCAL FUNCTIONS ********************************
|
||||
******************************************************************************/
|
||||
|
||||
static bool is_em4_blocked(void);
|
||||
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) && (SL_POWER_MANAGER_RAMP_DVDD_EN == 1)
|
||||
static void ramp_dvdd_and_switch_to_dcdc_bypass_mode(void);
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
************************** GLOBAL FUNCTIONS *******************************
|
||||
******************************************************************************/
|
||||
|
||||
/***************************************************************************//**
|
||||
* update energy mode 4 configurations.
|
||||
******************************************************************************/
|
||||
void sli_power_manager_init_em4(void)
|
||||
{
|
||||
#if !defined(_SILICON_LABS_32B_SERIES_2)
|
||||
EMU->EM4CTRL = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4IORETMODE_MASK)
|
||||
| (uint32_t)SL_POWER_MANAGER_INIT_EMU_EM4_PIN_RETENTION_MODE;
|
||||
#else
|
||||
EMU_EM4Init_TypeDef em4_init = EMU_EM4INIT_DEFAULT;
|
||||
em4_init.pinRetentionMode = (EMU_EM4PinRetention_TypeDef)SL_POWER_MANAGER_INIT_EMU_EM4_PIN_RETENTION_MODE;
|
||||
EMU_EM4Init(&em4_init);
|
||||
#endif
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Event called before entering EM4 sleep.
|
||||
*****************************************************************************/
|
||||
SL_WEAK void sl_power_manager_em4_presleep_hook(void)
|
||||
{
|
||||
// This implementation is empty, but this function can be redefined as it's a weak implementation.
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Enter energy mode 4 (EM4).
|
||||
*
|
||||
* @note You should not expect to return from this function. Once the device
|
||||
* enters EM4, only a power on reset or external reset pin can wake the
|
||||
* device.
|
||||
*
|
||||
* @note On xG22 devices, this function re-configures the IADC if EM4 entry
|
||||
* is possible.
|
||||
******************************************************************************/
|
||||
__NO_RETURN void sl_power_manager_enter_em4(void)
|
||||
{
|
||||
/* Device with Boost DC-DC cannot enter EM4 because Boost DC-DC module does not
|
||||
* have BYPASS switch so DC-DC converter can not be set to bypass mode. */
|
||||
#if (defined(_SILICON_LABS_DCDC_FEATURE) \
|
||||
&& (_SILICON_LABS_DCDC_FEATURE == _SILICON_LABS_DCDC_FEATURE_DCDC_BOOST))
|
||||
EFM_ASSERT(false);
|
||||
#endif
|
||||
|
||||
// Make sure that we are not interrupted while we are entering em4
|
||||
CORE_CRITICAL_IRQ_DISABLE();
|
||||
|
||||
EFM_ASSERT(is_em4_blocked() == false);
|
||||
|
||||
#if defined(SL_CATALOG_METRIC_EM4_WAKE_PRESENT)
|
||||
sli_metric_em4_wake_init();
|
||||
#endif
|
||||
|
||||
uint32_t em4seq2 = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4ENTRY_MASK)
|
||||
| (2U << _EMU_EM4CTRL_EM4ENTRY_SHIFT);
|
||||
uint32_t em4seq3 = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4ENTRY_MASK)
|
||||
| (3U << _EMU_EM4CTRL_EM4ENTRY_SHIFT);
|
||||
|
||||
// Make sure that the register write lock is disabled.
|
||||
EMU->LOCK = EMU_LOCK_LOCKKEY_UNLOCK;
|
||||
|
||||
#if defined(_DCDC_IF_EM4ERR_MASK)
|
||||
// Workaround for bug that may cause a Hard Fault on EM4 entry
|
||||
CMU_CLOCK_SELECT_SET(SYSCLK, FSRCO);
|
||||
// The buck DC-DC is available in all energy modes except for EM4.
|
||||
// The DC-DC converter must first be turned off and switched over to bypass mode.
|
||||
#if (defined(EMU_SERIES2_DCDC_BUCK_PRESENT) \
|
||||
|| defined(EMU_SERIES2_DCDC_BOOST_PRESENT))
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) && (SL_POWER_MANAGER_RAMP_DVDD_EN == 1)
|
||||
ramp_dvdd_and_switch_to_dcdc_bypass_mode();
|
||||
#else
|
||||
EMU_DCDCModeSet(emuDcdcMode_Bypass);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
sl_power_manager_em4_presleep_hook();
|
||||
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
EMU->EM4CTRL = em4seq2;
|
||||
EMU->EM4CTRL = em4seq3;
|
||||
}
|
||||
EMU->EM4CTRL = em4seq2;
|
||||
__WFI();
|
||||
|
||||
for (;; ) {
|
||||
// __NO_RETURN
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* When EM4 pin retention is set to power_manager_pin_retention_latch,
|
||||
* then pins are retained through EM4 entry and wakeup. The pin state is
|
||||
* released by calling this function. The feature allows peripherals or
|
||||
* GPIO to be re-initialized after EM4 exit (reset), and when
|
||||
* initialization is done, this function can release pins and return
|
||||
* control to the peripherals or GPIO.
|
||||
******************************************************************************/
|
||||
void sl_power_manager_em4_unlatch_pin_retention(void)
|
||||
{
|
||||
#if defined(_EMU_EM4CTRL_EM4IORETMODE_MASK)
|
||||
EMU->CMD = EMU_CMD_EM4UNLATCH;
|
||||
#endif
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Returns true if em4 entry is blocked by a watchdog peripheral.
|
||||
******************************************************************************/
|
||||
static bool is_em4_blocked(void)
|
||||
{
|
||||
#if defined(WDOG_PRESENT)
|
||||
#if WDOG_COUNT > 0
|
||||
if ( WDOG0_CLOCK_ENABLED_BIT && (WDOG0->CFG & WDOG_CFG_EM4BLOCK) && (WDOG0->EN & WDOG_EN_EN) ) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if WDOG_COUNT > 1
|
||||
if ( WDOG1_CLOCK_ENABLED_BIT && (WDOG1->CFG & WDOG_CFG_EM4BLOCK) && (WDOG1->EN & WDOG_EN_EN) ) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) && (SL_POWER_MANAGER_RAMP_DVDD_EN == 1)
|
||||
|
||||
/* The following section provides an optimization to improve peak current
|
||||
* consumption on xG22 devices.
|
||||
*/
|
||||
|
||||
// ADC clock frequency (source and after prescale)
|
||||
#define CLK_SRC_ADC_FREQ 9600000 // CLK_SRC_ADC
|
||||
#define CLK_ADC_FREQ 1000000 // CLK_ADC
|
||||
|
||||
extern void sli_delay_loop(uint32_t cycles);
|
||||
|
||||
uint32_t * dcdc_test_addr = (uint32_t *)(DCDC_NS_BASE + 0x80);
|
||||
uint32_t ipkval = 7;
|
||||
uint32_t ipktimeout = 1;
|
||||
|
||||
/* Pulse generation sequence TOCTRIG (bit 3) TOCMODE (bit 2)*/
|
||||
uint32_t cmd[2] = { (1 << 2) | (1 << 3), (1 << 2) };
|
||||
|
||||
/***************************************************************************//**
|
||||
* The voltage of Dvdd is ramped up to VMCU by sending pulses to a DCDC test
|
||||
* register. These pulses are delayed, and ipkval and ipktimeout are tuned
|
||||
* such that the voltage at Dvdd increases gradually to the voltage level of
|
||||
* VMCU. Using the IADC, once Dvdd has gotten sufficiently close to VMCU,
|
||||
* the DCDC peripheral is then switched into bypass mode. The IADC is used to
|
||||
* detect this by sampling the voltage of Dvdd periodically, and calculating the
|
||||
* difference between samples, when the difference is within some margin of zero
|
||||
* then we know that the ramp sequence has reached a plateau.
|
||||
******************************************************************************/
|
||||
static void ramp_dvdd_and_switch_to_dcdc_bypass_mode(void)
|
||||
{
|
||||
// Initialize the IADC for the purposes of detecting when the Dvdd ramp
|
||||
// reaches a plateau.
|
||||
IADC_Init_t init = IADC_INIT_DEFAULT;
|
||||
IADC_AllConfigs_t initAllConfigs = IADC_ALLCONFIGS_DEFAULT;
|
||||
IADC_InitSingle_t initSingle = IADC_INITSINGLE_DEFAULT;
|
||||
IADC_SingleInput_t initSingleInput = IADC_SINGLEINPUT_DEFAULT;
|
||||
CMU_ClockEnable(cmuClock_IADC0, true);
|
||||
|
||||
init.srcClkPrescale = IADC_calcSrcClkPrescale(IADC0, CLK_SRC_ADC_FREQ, 0);
|
||||
initAllConfigs.configs[0].reference = iadcCfgReferenceInt1V2;
|
||||
initAllConfigs.configs[0].vRef = 1210;
|
||||
initAllConfigs.configs[0].analogGain = iadcCfgAnalogGain1x;
|
||||
initAllConfigs.configs[0].digAvg = iadcDigitalAverage1;
|
||||
initAllConfigs.configs[0].adcClkPrescale =
|
||||
IADC_calcAdcClkPrescale(IADC0,
|
||||
CLK_ADC_FREQ,
|
||||
0,
|
||||
iadcCfgModeNormal,
|
||||
init.srcClkPrescale);
|
||||
init.warmup = iadcWarmupKeepWarm;
|
||||
|
||||
IADC_reset(IADC0);
|
||||
CMU_ClockSelectSet(cmuClock_IADCCLK, cmuSelect_EM01GRPACLK);
|
||||
initSingle.triggerAction = iadcTriggerActionContinuous;
|
||||
initSingle.alignment = iadcAlignRight12;
|
||||
initSingleInput.compare = false; // Disable Window CMP
|
||||
initSingleInput.posInput = iadcPosInputDvdd;
|
||||
IADC_init(IADC0, &init, &initAllConfigs);
|
||||
IADC_initSingle(IADC0, &initSingle, &initSingleInput);
|
||||
|
||||
// Start capturing
|
||||
IADC_command(IADC0, iadcCmdStartSingle);
|
||||
|
||||
// Initialize DCDC peak current value and timeout to reach peak current value
|
||||
DCDC->EM01CTRL0 = (DCDC->EM01CTRL0 & ~_DCDC_EM01CTRL0_IPKVAL_MASK) | (ipkval << 0);
|
||||
DCDC->CTRL = (DCDC->CTRL & ~_DCDC_CTRL_IPKTMAXCTRL_MASK) | (ipktimeout << 4);
|
||||
|
||||
/* Generate pulses */
|
||||
uint32_t iter = 1U;
|
||||
IADC_Result_t prev_result;
|
||||
volatile IADC_Result_t current_result = IADC_readSingleResult(IADC0);
|
||||
while (true) {
|
||||
// If the algorithm doesn't converge after 500 pulses, switch to dcdc
|
||||
// bypass anyways.
|
||||
if (iter >= 500) {
|
||||
DCDC->CTRL_CLR = DCDC_CTRL_MODE;
|
||||
EFM_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pulse generation sequence TOCTRIG (bit 3) TOCMODE (bit 2)*/
|
||||
*dcdc_test_addr = cmd[0];
|
||||
*dcdc_test_addr = cmd[1];
|
||||
|
||||
// In DCDC mode, MCU input voltage VREGVDD cannot be directly measured, so
|
||||
// we can't know what the target DVDD voltage is. Instead, since DVDD
|
||||
// ramp-up should follow a RC charge curve, measure DVDD and keep charging
|
||||
// until the delta between measures is smaller than the set tolerance.
|
||||
if (iter % 20U == 0U) {
|
||||
prev_result = current_result;
|
||||
current_result = IADC_readSingleResult(IADC0);
|
||||
if ( abs((int32_t)(current_result.data - prev_result.data)) < SL_POWER_MANAGER_RAMP_DVDD_TOLERANCE ) {
|
||||
DCDC->CTRL_CLR = DCDC_CTRL_MODE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (DCDC->IF & DCDC_IF_TMAX) {
|
||||
if (ipkval) {
|
||||
ipkval--; // DCDC peak current value
|
||||
}
|
||||
|
||||
if (ipktimeout < 7) {
|
||||
ipktimeout++; // Timeout to reach peak current value
|
||||
}
|
||||
|
||||
DCDC->EM01CTRL0 = (DCDC->EM01CTRL0 & ~_DCDC_EM01CTRL0_IPKVAL_MASK) | (ipkval << 0);
|
||||
DCDC->CTRL = (DCDC->CTRL & ~_DCDC_CTRL_IPKTMAXCTRL_MASK) | (ipktimeout << 4);
|
||||
|
||||
DCDC->IF_CLR = DCDC_IF_TMAX;
|
||||
}
|
||||
|
||||
/* delay for 8 clock cycles */
|
||||
sli_delay_loop(8);
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) && (SL_POWER_MANAGER_RAMP_DVDD_EN == 1)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,165 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Power Manager Debug 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 "sl_power_manager.h"
|
||||
#include "sl_power_manager_config.h"
|
||||
#include "sl_power_manager_debug.h"
|
||||
#include "sli_power_manager_private.h"
|
||||
|
||||
#if (SL_POWER_MANAGER_DEBUG == 1)
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
static sl_slist_node_t *power_manager_debug_requirement_em_table[SLI_POWER_MANAGER_EM_TABLE_SIZE];
|
||||
static sli_power_debug_requirement_entry_t power_debug_entry_table[SL_POWER_MANAGER_DEBUG_POOL_SIZE];
|
||||
static sl_slist_node_t *power_debug_free_entry_list = NULL;
|
||||
static bool power_debug_ran_out_of_entry = false;
|
||||
|
||||
static void power_manager_log_add_requirement(sl_slist_node_t **p_list,
|
||||
bool add,
|
||||
const char *name);
|
||||
|
||||
/***************************************************************************//**
|
||||
* Print a fancy table that describes the current requirements on each energy
|
||||
* mode and their owner.
|
||||
******************************************************************************/
|
||||
void sl_power_manager_debug_print_em_requirements(void)
|
||||
{
|
||||
uint8_t i;
|
||||
sli_power_debug_requirement_entry_t *entry;
|
||||
|
||||
if (power_debug_ran_out_of_entry) {
|
||||
printf("WARNING: The system ran out of Debug Entry; This report is likely to be incomplete. Increase SL_POWER_MANAGER_DEBUG_POOL_SIZE\n\n");
|
||||
}
|
||||
printf("------------------------------------------\n");
|
||||
printf("| EM requirements\n");
|
||||
printf("------------------------------------------\n");
|
||||
for (i = 0; i < SLI_POWER_MANAGER_EM_TABLE_SIZE; i++) {
|
||||
if (power_manager_debug_requirement_em_table[i] != NULL) {
|
||||
printf("| EM%d requirement module owners:\n", i + 1);
|
||||
}
|
||||
SL_SLIST_FOR_EACH_ENTRY(power_manager_debug_requirement_em_table[i], entry, sli_power_debug_requirement_entry_t, node) {
|
||||
printf("| %s\n", entry->module_name);
|
||||
}
|
||||
if (power_manager_debug_requirement_em_table[i] != NULL) {
|
||||
printf("------------------------------------------\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Initialize debugging feature.
|
||||
******************************************************************************/
|
||||
void sli_power_manager_debug_init(void)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < SL_POWER_MANAGER_DEBUG_POOL_SIZE; i++) {
|
||||
sli_power_debug_requirement_entry_t *entry = &power_debug_entry_table[i];
|
||||
sl_slist_push(&power_debug_free_entry_list, &entry->node);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* Log requirement to a list
|
||||
*
|
||||
* @param p_list List where to push or remove the requirement.
|
||||
*
|
||||
* @param add Add (true) or remove (false) the requirement.
|
||||
*
|
||||
* @param name Module name that acquired or remove the requirement.
|
||||
******************************************************************************/
|
||||
static void power_manager_log_add_requirement(sl_slist_node_t **p_list,
|
||||
bool add,
|
||||
const char *name)
|
||||
{
|
||||
sl_slist_node_t *node;
|
||||
sli_power_debug_requirement_entry_t *entry;
|
||||
|
||||
if (add == true) {
|
||||
// Get entry from free list
|
||||
node = sl_slist_pop(&power_debug_free_entry_list);
|
||||
if (node == NULL) {
|
||||
power_debug_ran_out_of_entry = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Push entry to the EMx requirement debug list
|
||||
entry = SL_SLIST_ENTRY(node, sli_power_debug_requirement_entry_t, node);
|
||||
entry->module_name = name;
|
||||
sl_slist_push(p_list, &entry->node);
|
||||
} else {
|
||||
sli_power_debug_requirement_entry_t *entry_remove = NULL;
|
||||
|
||||
// Search in the EMx requirement debug list
|
||||
SL_SLIST_FOR_EACH_ENTRY(*p_list, entry, sli_power_debug_requirement_entry_t, node) {
|
||||
// Current module name and entry module name
|
||||
if (strcmp(entry->module_name, name) == 0) {
|
||||
entry_remove = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry_remove == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
sl_slist_remove(p_list, &entry_remove->node);
|
||||
sl_slist_push(&power_debug_free_entry_list, &entry_remove->node);
|
||||
}
|
||||
}
|
||||
#endif // SL_POWER_MANAGER_DEBUG
|
||||
|
||||
#undef sli_power_manager_debug_log_em_requirement
|
||||
/***************************************************************************//**
|
||||
* Log energy mode (EM) requirement
|
||||
*
|
||||
* @param em Energy mode added or removed.
|
||||
*
|
||||
* @param add Add (true) or remove (false) the requirement.
|
||||
*
|
||||
* @param name Module name that adds or removes the requirement.
|
||||
******************************************************************************/
|
||||
void sli_power_manager_debug_log_em_requirement(sl_power_manager_em_t em,
|
||||
bool add,
|
||||
const char *name)
|
||||
{
|
||||
#if (SL_POWER_MANAGER_DEBUG == 1)
|
||||
if (em != SL_POWER_MANAGER_EM0) {
|
||||
power_manager_log_add_requirement(&power_manager_debug_requirement_em_table[em - 1], add, name);
|
||||
}
|
||||
#else
|
||||
(void)em;
|
||||
(void)add;
|
||||
(void)name;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,706 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Power Manager HAL 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"
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2)
|
||||
|
||||
#include "em_emu.h"
|
||||
#include "em_cmu.h"
|
||||
#include "sl_assert.h"
|
||||
#include "sl_power_manager.h"
|
||||
#include "sli_power_manager.h"
|
||||
#include "sli_power_manager_private.h"
|
||||
#include "sl_sleeptimer.h"
|
||||
#include "sli_sleeptimer.h"
|
||||
#include "sl_power_manager_config.h"
|
||||
|
||||
#if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2)
|
||||
#include "em_iadc.h"
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#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>
|
||||
|
||||
/*******************************************************************************
|
||||
********************************* DEFINES *********************************
|
||||
******************************************************************************/
|
||||
|
||||
// Time required by the hardware to come out of EM2 in microseconds.
|
||||
// This value includes HW startup, emlib and sleepdrv execution time.
|
||||
// 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.
|
||||
#if (_SILICON_LABS_32B_SERIES_2_CONFIG == 1)
|
||||
#define EM2_WAKEUP_PROCESS_TIME_OVERHEAD_US (31u)
|
||||
#else // (_SILICON_LABS_32B_SERIES_2_CONFIG == 2),
|
||||
#define EM2_WAKEUP_PROCESS_TIME_OVERHEAD_US (31u)
|
||||
#endif
|
||||
|
||||
// DPLL Locking delay related defines
|
||||
#define DPLL_COARSECOUNT_VALUE (5u)
|
||||
|
||||
// Time it takes to upscale voltage after EM2 in microseconds.
|
||||
// This value represents the time for scaling from VSCALE0 to VSCALE2.
|
||||
#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 (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%.
|
||||
#define HFXO_START_UP_TIME_OVERHEAD_LOG2 3
|
||||
|
||||
// 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 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 */
|
||||
|
||||
/*******************************************************************************
|
||||
******************************* MACROS *************************************
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* DPLL lock time can be approximately calculated by the equation:
|
||||
* COARSECOUNT * (M + 1) * Tref
|
||||
* Where
|
||||
* - COARSECOUNT is calibration value in a hidden register. Its default value
|
||||
* is 5 and should not change with calibration.
|
||||
* - M is one the DPLL configuration parameter.
|
||||
* - Tref is the reference clock period.
|
||||
*******************************************************************************/
|
||||
#define DPLL_LOCKING_DELAY_US_FUNCTION(M, freq_ref) \
|
||||
(uint32_t)(((uint64_t)(DPLL_COARSECOUNT_VALUE * ((M) +1)) * 1000000 + ((freq_ref) - 1)) / (freq_ref))
|
||||
|
||||
/*******************************************************************************
|
||||
*************************** LOCAL VARIABLES ********************************
|
||||
******************************************************************************/
|
||||
|
||||
#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.
|
||||
static uint32_t process_wakeup_overhead_tick = 0;
|
||||
|
||||
#if defined(EMU_VSCALE_PRESENT)
|
||||
static bool is_fast_wakeup_enabled = true;
|
||||
#endif
|
||||
|
||||
static bool is_hf_x_oscillator_used = false;
|
||||
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
|
||||
|
||||
/***************************************************************************//**
|
||||
* Do some hardware initialization if necessary.
|
||||
******************************************************************************/
|
||||
void sli_power_manager_init_hardware(void)
|
||||
{
|
||||
// Initializes EMU (voltage scaling in EM2/3)
|
||||
#if defined(EMU_VSCALE_EM01_PRESENT)
|
||||
EMU_EM01Init_TypeDef em01_init = EMU_EM01INIT_DEFAULT;
|
||||
|
||||
EMU_EM01Init(&em01_init);
|
||||
#endif
|
||||
|
||||
#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)
|
||||
sli_power_manager_em23_voltage_scaling_enable_fast_wakeup(false);
|
||||
#else
|
||||
sli_power_manager_em23_voltage_scaling_enable_fast_wakeup(true);
|
||||
#endif
|
||||
#else
|
||||
sli_power_manager_em23_voltage_scaling_enable_fast_wakeup(false);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Get the current HF oscillator for the SYSCLK
|
||||
cmu_sys_clock_register = CMU->SYSCLKCTRL & _CMU_SYSCLKCTRL_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)
|
||||
CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
|
||||
|
||||
CMU->CLKEN0_SET = CMU_CLKEN0_DPLL0;
|
||||
#endif
|
||||
|
||||
is_dpll_used = ((DPLL0->STATUS & _DPLL_STATUS_ENS_MASK) != 0);
|
||||
|
||||
is_hf_x_oscillator_used = ((cmu_sys_clock_register == CMU_SYSCLKCTRL_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 = is_hf_x_oscillator_used || ((CMU->RADIOCLKCTRL & _CMU_RADIOCLKCTRL_EN_MASK) != 0);
|
||||
#endif
|
||||
|
||||
#if defined(CMU_EM01GRPBCLKCTRL_CLKSEL_HFXO)
|
||||
is_hf_x_oscillator_used = 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 = 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) {
|
||||
is_hf_x_oscillator_used = is_hf_x_oscillator_used || ((CMU->DPLLREFCLKCTRL & _CMU_DPLLREFCLKCTRL_CLKSEL_MASK) == _CMU_DPLLREFCLKCTRL_CLKSEL_HFXO);
|
||||
}
|
||||
|
||||
// Calculate DPLL locking delay from its configuration
|
||||
if (is_dpll_used) {
|
||||
uint32_t freq = 0;
|
||||
|
||||
switch (CMU->DPLLREFCLKCTRL & _CMU_DPLLREFCLKCTRL_CLKSEL_MASK) {
|
||||
case _CMU_DPLLREFCLKCTRL_CLKSEL_HFXO:
|
||||
freq = SystemHFXOClockGet();
|
||||
break;
|
||||
|
||||
case _CMU_DPLLREFCLKCTRL_CLKSEL_LFXO:
|
||||
freq = SystemLFXOClockGet();
|
||||
break;
|
||||
|
||||
case _CMU_DPLLREFCLKCTRL_CLKSEL_CLKIN0:
|
||||
freq = SystemCLKIN0Get();
|
||||
break;
|
||||
|
||||
default:
|
||||
EFM_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
if (freq > 0) { // Avoid division by 0
|
||||
// Add DPLL Locking delay
|
||||
process_wakeup_overhead_tick += sli_power_manager_convert_delay_us_to_tick(DPLL_LOCKING_DELAY_US_FUNCTION((DPLL0->CFG1 & _DPLL_CFG1_M_MASK) >> _DPLL_CFG1_M_SHIFT, freq));
|
||||
}
|
||||
}
|
||||
|
||||
process_wakeup_overhead_tick += sli_power_manager_convert_delay_us_to_tick(EM2_WAKEUP_PROCESS_TIME_OVERHEAD_US);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* 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;
|
||||
}
|
||||
|
||||
EMU_EM23Init_TypeDef em23_init = EMU_EM23INIT_DEFAULT;
|
||||
|
||||
// Enable/disable EMU voltage scaling in EM2/3
|
||||
if (enable) {
|
||||
em23_init.vScaleEM23Voltage = emuVScaleEM23_FastWakeup;
|
||||
} else {
|
||||
em23_init.vScaleEM23Voltage = emuVScaleEM23_LowPower;
|
||||
}
|
||||
|
||||
EMU_EM23Init(&em23_init);
|
||||
|
||||
// Calculate and add voltage scaling wake-up delays in ticks
|
||||
if (enable) {
|
||||
// Remove voltage scaling delay if it was added before
|
||||
process_wakeup_overhead_tick -= sli_power_manager_convert_delay_us_to_tick(EM2_WAKEUP_VSCALE_OVERHEAD_US);
|
||||
} else {
|
||||
// Add voltage scaling delay if it was not added before
|
||||
process_wakeup_overhead_tick += sli_power_manager_convert_delay_us_to_tick(EM2_WAKEUP_VSCALE_OVERHEAD_US);
|
||||
}
|
||||
|
||||
is_fast_wakeup_enabled = enable;
|
||||
#else
|
||||
(void)enable;
|
||||
#endif
|
||||
}
|
||||
|
||||
#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 !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
|
||||
/***************************************************************************//**
|
||||
* Handle pre-sleep operations if any are necessary, like manually disabling
|
||||
* oscillators, change clock settings, etc.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void EMU_EM23PresleepHook(void)
|
||||
{
|
||||
// Change the HF Clocks to be on FSRCO before sleep
|
||||
if (is_entering_deepsleep) {
|
||||
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) {
|
||||
// Wait for DPLL to be disabled.
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
SystemCoreClockUpdate();
|
||||
}
|
||||
// Clear HFXO IEN RDY before entering sleep to prevent HFXO HW requests from waking up the system
|
||||
HFXO0->IEN_CLR = HFXO_IEN_RDY;
|
||||
}
|
||||
#endif
|
||||
|
||||
#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.
|
||||
*
|
||||
* @note In case HFXO is already started when we wake-up (ENS flag is up),
|
||||
* the hidden flag STARTUPDONE is check to see if the HFXO was just
|
||||
* enabled or not. If HFXO is enabled automatically following the wake-up,
|
||||
* the STARTUPDONE flag will not yet be up, and it's an indication that
|
||||
* we can still process to the HFXO restore time measurement.
|
||||
******************************************************************************/
|
||||
void EMU_EM23PostsleepHook(void)
|
||||
{
|
||||
// Re enable HFXO IEN RDY since it was disabled in EMU_EM23PresleepHook
|
||||
HFXO0->IEN_SET = HFXO_IEN_RDY;
|
||||
|
||||
// Poke sleeptimer to determine if power manager's timer expired before the
|
||||
// ISR handler executes.
|
||||
// Also, check if HFXO is used.
|
||||
if (is_hf_x_oscillator_used
|
||||
&& sli_sleeptimer_hal_is_int_status_set(SLEEPTIMER_EVENT_COMP)
|
||||
&& 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)
|
||||
|| (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 !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
|
||||
/***************************************************************************//**
|
||||
* Handle pre-deepsleep operations if any are necessary, like manually disabling
|
||||
* oscillators, change clock settings, etc.
|
||||
******************************************************************************/
|
||||
void sli_power_manager_handle_pre_deepsleep_operations(void)
|
||||
{
|
||||
is_entering_deepsleep = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#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.
|
||||
******************************************************************************/
|
||||
void sli_power_manager_restore_high_freq_accuracy_clk(void)
|
||||
{
|
||||
if (!is_hf_x_oscillator_used) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For the cases where it's not started from an early wake up
|
||||
// And if HFXO is not already running.
|
||||
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)
|
||||
|| (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 !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
|
||||
/***************************************************************************//**
|
||||
* Checks if HF accuracy clocks is fully restored and, if needed, waits for it.
|
||||
*
|
||||
* @param wait True, to wait for HF accuracy clocks to be ready
|
||||
* False, otherwise.
|
||||
*
|
||||
* @return True, if HFXO ready.
|
||||
* False, otherwise.
|
||||
******************************************************************************/
|
||||
bool sli_power_manager_is_high_freq_accuracy_clk_ready(bool wait)
|
||||
{
|
||||
if (!is_hf_x_oscillator_used) {
|
||||
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 !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) {
|
||||
// Wait for DPLL to be ready.
|
||||
}
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
||||
SystemCoreClockUpdate();
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************//**
|
||||
* Applies energy mode.
|
||||
*
|
||||
* @param em Energy mode to apply:
|
||||
* SL_POWER_MANAGER_EM0
|
||||
* SL_POWER_MANAGER_EM1
|
||||
* SL_POWER_MANAGER_EM2
|
||||
*
|
||||
* @note EMU_EnterEM2() and EMU_EnterEM3() has the parameter 'restore' set to
|
||||
* true in the Power Manager. When set to true, the parameter 'restore'
|
||||
* allows the EMU driver to save and restore oscillators, clocks and
|
||||
* voltage scaling. When the processor returns from EM2 or EM3, its
|
||||
* execution resumes in a clean and stable state.
|
||||
******************************************************************************/
|
||||
void sli_power_manager_apply_em(sl_power_manager_em_t em)
|
||||
{
|
||||
#if defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
|
||||
// Perform required actions according to energy mode
|
||||
switch (em) {
|
||||
case SL_POWER_MANAGER_EM1:
|
||||
case SL_POWER_MANAGER_EM2:
|
||||
case SL_POWER_MANAGER_EM3:
|
||||
#if (SL_EMLIB_CORE_ENABLE_INTERRUPT_DISABLED_TIMING == 1)
|
||||
// when measuring interrupt disabled time, we don't
|
||||
// want to count the time spent in sleep
|
||||
sl_cycle_counter_pause();
|
||||
#endif
|
||||
EMU_EnterEM1();
|
||||
#if (SL_EMLIB_CORE_ENABLE_INTERRUPT_DISABLED_TIMING == 1)
|
||||
sl_cycle_counter_resume();
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
EFM_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
// Perform required actions according to energy mode
|
||||
switch (em) {
|
||||
case SL_POWER_MANAGER_EM1:
|
||||
#if (SL_EMLIB_CORE_ENABLE_INTERRUPT_DISABLED_TIMING == 1)
|
||||
// when measuring interrupt disabled time, we don't
|
||||
// want to count the time spent in sleep
|
||||
sl_cycle_counter_pause();
|
||||
#endif
|
||||
EMU_EnterEM1();
|
||||
#if (SL_EMLIB_CORE_ENABLE_INTERRUPT_DISABLED_TIMING == 1)
|
||||
sl_cycle_counter_resume();
|
||||
#endif
|
||||
break;
|
||||
|
||||
case SL_POWER_MANAGER_EM2:
|
||||
EMU_EnterEM2(false);
|
||||
break;
|
||||
|
||||
case SL_POWER_MANAGER_EM3:
|
||||
EMU_EnterEM3(false);
|
||||
break;
|
||||
|
||||
default:
|
||||
EFM_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
#endif // SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT
|
||||
}
|
||||
|
||||
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
|
||||
/*******************************************************************************
|
||||
* Returns the default minimum offtime for HFXO.
|
||||
******************************************************************************/
|
||||
uint32_t sli_power_manager_get_default_high_frequency_minimum_offtime(void)
|
||||
{
|
||||
return sli_power_manager_convert_delay_us_to_tick(HFXO_MINIMUM_OFFTIME_DEFAULT_VALUE_US);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Gets the delay associated the wake-up process from EM23.
|
||||
*
|
||||
* @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)
|
||||
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;
|
||||
}
|
||||
|
||||
// Add all additional overhead wake-up delays (DPLL, VSCALE, general wake-up process)
|
||||
delay += process_wakeup_overhead_tick;
|
||||
|
||||
return delay;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
|
||||
/***************************************************************************//**
|
||||
* Informs the power manager module that the high accuracy/high frequency clock
|
||||
* is used.
|
||||
******************************************************************************/
|
||||
void sli_power_manager_set_high_accuracy_hf_clock_as_used(void)
|
||||
{
|
||||
is_hf_x_oscillator_used = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
|
||||
/*******************************************************************************
|
||||
* Restores the Low Frequency clocks according to what LF oscillators are used.
|
||||
*
|
||||
* @note On series 2, the on-demand will enable automatically the oscillators
|
||||
* used when coming from sleep.
|
||||
******************************************************************************/
|
||||
void sli_power_manager_low_frequency_restore(void)
|
||||
{
|
||||
// Nothing to do as on-demand feature will enable the LF oscillators automatically.
|
||||
}
|
||||
|
||||
/***************************************************************************//**
|
||||
* 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
|
||||
|
||||
#if defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
|
||||
/*******************************************************************************
|
||||
* HAL hook function for pre EM1HCLKDIV sleep.
|
||||
******************************************************************************/
|
||||
void sli_power_manager_em1hclkdiv_presleep_operations(void)
|
||||
{
|
||||
// No operations to do before EM1HCLKDIV sleep on series 2 devices
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* HAL hook function for post EM1HCLKDIV sleep.
|
||||
******************************************************************************/
|
||||
void sli_power_manager_em1hclkdiv_postsleep_operations(void)
|
||||
{
|
||||
// No operations to do before EM1HCLKDIV sleep on series 2 devices
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,164 @@
|
||||
/***************************************************************************//**
|
||||
* @file
|
||||
* @brief Power Manager Internal 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.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "sl_power_manager.h"
|
||||
#include "sl_slist.h"
|
||||
#include "sl_code_classification.h"
|
||||
|
||||
#if defined(SL_COMPONENT_CATALOG_PRESENT)
|
||||
#include "sl_component_catalog.h"
|
||||
#endif
|
||||
|
||||
#if defined(SL_CATALOG_EMLIB_CORE_DEBUG_CONFIG_PRESENT)
|
||||
#include "emlib_core_debug_config.h"
|
||||
#endif
|
||||
|
||||
#if !defined(SL_EMLIB_CORE_ENABLE_INTERRUPT_DISABLED_TIMING)
|
||||
#define SL_EMLIB_CORE_ENABLE_INTERRUPT_DISABLED_TIMING 0
|
||||
#endif
|
||||
|
||||
#if (SL_EMLIB_CORE_ENABLE_INTERRUPT_DISABLED_TIMING == 1)
|
||||
#include "sl_cycle_counter.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
******************************* DEFINES ***********************************
|
||||
******************************************************************************/
|
||||
|
||||
#define SLI_POWER_MANAGER_EM_TABLE_SIZE 2
|
||||
|
||||
#define SLI_POWER_MANAGER_EM4_ENTRY_WAIT_LOOPS 200
|
||||
/*******************************************************************************
|
||||
***************************** DATA TYPES *********************************
|
||||
******************************************************************************/
|
||||
|
||||
// Debug entry
|
||||
typedef struct {
|
||||
sl_slist_node_t node;
|
||||
const char *module_name;
|
||||
} sli_power_debug_requirement_entry_t;
|
||||
|
||||
/*******************************************************************************
|
||||
***************************** PROTOTYPES **********************************
|
||||
******************************************************************************/
|
||||
|
||||
void sli_power_manager_init_hardware(void);
|
||||
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sli_power_manager_apply_em(sl_power_manager_em_t em);
|
||||
|
||||
void sli_power_manager_debug_init(void);
|
||||
|
||||
#if !defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sli_power_manager_save_states(void);
|
||||
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sli_power_manager_handle_pre_deepsleep_operations(void);
|
||||
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sli_power_manager_restore_high_freq_accuracy_clk(void);
|
||||
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
bool sli_power_manager_is_high_freq_accuracy_clk_ready(bool wait);
|
||||
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sli_power_manager_restore_states(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Converts microseconds time in sleeptimer ticks.
|
||||
******************************************************************************/
|
||||
uint32_t sli_power_manager_convert_delay_us_to_tick(uint32_t time_us);
|
||||
|
||||
/*******************************************************************************
|
||||
* Returns the default minimum offtime for xtal high frequency oscillator.
|
||||
******************************************************************************/
|
||||
uint32_t sli_power_manager_get_default_high_frequency_minimum_offtime(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* Restores the Low Frequency clocks according to which LF oscillators are used.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
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.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
bool sli_power_manager_is_high_freq_accuracy_clk_used(void);
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Gets the delay associated the wake-up process from EM23.
|
||||
*
|
||||
* @return Delay for the complete wake-up process with full restore.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
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
|
||||
|
||||
#if defined(SL_CATALOG_POWER_MANAGER_NO_DEEPSLEEP_PRESENT)
|
||||
/*******************************************************************************
|
||||
* HAL hook function for pre EM1HCLKDIV sleep.
|
||||
*
|
||||
* @note FOR INTERNAL USE ONLY.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sli_power_manager_em1hclkdiv_presleep_operations(void);
|
||||
|
||||
/*******************************************************************************
|
||||
* HAL hook function for post EM1HCLKDIV sleep.
|
||||
*
|
||||
* @note FOR INTERNAL USE ONLY.
|
||||
******************************************************************************/
|
||||
SL_CODE_CLASSIFY(SL_CODE_COMPONENT_POWER_MANAGER, SL_CODE_CLASS_TIME_CRITICAL)
|
||||
void sli_power_manager_em1hclkdiv_postsleep_operations(void);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user